Files
mdm-ordinis/docs-internal/design/dictionary-marketplace.md
T
2026-05-12 17:05:24 +00:00

339 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Design: Bundle Hygiene (formerly "Dictionary Marketplace")
**Author:** zimin.an
**Date:** 2026-05-12
**Status:** PROPOSED v2 (post `/office-hours` + cross-model challenge)
**Supersedes:** v1 «Dictionary Marketplace» (Approach B: full registry + browse UI + dry-run preview + install dialog, 10-14d)
**Scope:** ДЗЗ domain, single-tenant (Approach C-revised — bundle format spec + publisher CLI, NO consumer UI)
**Sprint estimate:** **2-3 days CC**, hard cap. Anything beyond requires new design doc.
**Blockers:** none
---
## TL;DR
v1 предлагал full marketplace (Nexus registry + browse UI + install dialog + dry-run preview + multi-tenancy + dep resolution) за 10-14 days. После `/office-hours` premise challenge + cross-model challenge — **v1 был over-scoped для N=1 customer** (ЦУОД anchor only сегодня).
**Revised:** Formalize bundle format spec + publisher CLI. **No consumer-side UI.** This is **bundle hygiene**, не marketplace.
**Why bundle hygiene matters at N=1:**
1. **Java team handoff** требует documented manifest spec в любом случае — без этого new engineers не знают как добавить новый dict без полного code review pipeline
2. **Sales artifact** — demo prospects «ЦУОД bundle is independently signed/versioned, here's how you'd ship your own» без shipping консьюмерского UI
3. **Optionality** — когда customer #2 signs, bundle format уже defined, можно ship UI quickly (consumer UI = 5-7d incremental)
**What this design explicitly is NOT:**
- ❌ Browse catalog UI
- ❌ Install dialog в admin-ui
- ❌ Dry-run preview UI
- ❌ Public marketplace
- ❌ Bundle dep resolution / topological install
- ❌ Multi-tenant Nexus namespacing
**Anti-feature:** если scope expands beyond 2-3 days hard cap → STOP, re-design doc. Don't let founder weekend-prototyping pull this into Approach B by accident.
---
## Premises (validated через `/office-hours` 2026-05-12, including cross-model challenge)
**P1.** Marketplace UI/registry **value scales с N customers.** At N=1 → near-zero. Build **only когда customer #2 LOI/contract стадия с extensibility language**.
**P2.** Bundle **format + signing + manifest** valuable AT N=1 — separable concern от marketplace UI. Doubles as Java handoff spec + sales demo.
**P3.** ЦУОД go-live (anchor v1) **уже live на v2.14.0 prod.** Дальнейший development must support handoff readiness, не speculative future features.
**P4.** **No customer #2 named with deadline as of 2026-05-12.** Sales conversations ongoing (Альтум integration в process, гидрометео preliminary discussions). Marketplace UI build now = infrastructure ahead of validated need.
**P5.** **«Defer entirely» (Approach A) was directionally right но oversold.** Cross-model challenge revealed: pure defer assumes founder won't drift to greenfield work. Pre-committed scoped C contains damage better than aspirational pure-defer.
**P6.** **Bundle hygiene work ROI положителен независимо** от marketplace decision: даже если marketplace UI shipped'нется только в Q4 2026 или никогда — formal bundle spec нужен для Java handoff (target 2-3 months).
**P7.** **Hard cap 2-3 days CC.** No scope creep. If пилот results in «we should add UI now», that's NEW design doc, new /office-hours, fresh decision.
---
## What ships в v2 (bundle hygiene, 2-3 days)
### 1. Bundle manifest format spec
`ordinis-cuod-bundle/manifest.yaml` (NEW file, replaces ad-hoc Maven module structure):
```yaml
apiVersion: ordinis.io/v1
kind: Bundle
metadata:
id: ru.cuod.dzz-ground-segment
name: ЦУОД ДЗЗ — наземный сегмент
version: 1.0.0 # semver, follows Maven artifact version
description: |
40 dictionaries для управления наземным сегментом ДЗЗ:
КА, типы КА, наземные станции, антенны, частотные диапазоны.
domain: dzz
scope: PUBLIC
author: ЦУОД team
license: proprietary
signature: ed25519:base64... # added by publisher CLI
dictionaries:
# Existing list from ordinis-cuod-bundle/src/main/resources/bundles/cuod/
- name: spacecraft
schemaVersion: 1.0.0
scope: PUBLIC
schemaRef: dictionaries/spacecraft/schema.json # relative path
sampleDataRef: dictionaries/spacecraft/sample.json # optional
- name: satellite_type
schemaVersion: 1.0.0
scope: PUBLIC
schemaRef: dictionaries/satellite_type/schema.json
# ... 38 more
```
**Migration:** Existing ad-hoc `ordinis-cuod-bundle/src/main/resources/bundles/cuod/` structure refactored to match manifest. **No behavior change** — bundle still loaded via existing Maven module pattern. Just **adds spec on top**.
### 2. Publisher CLI (`ordinis-bundle-publisher` Maven plugin)
```bash
mvn ordinis:bundle-publish \
-Dbundle.path=ordinis-cuod-bundle \
-Dnexus.url=https://nexus.corp/ordinis-bundles/private/cuod \
-Dsigning.key=$BUNDLE_SIGNING_KEY
```
Steps плагина:
1. Read `manifest.yaml`
2. Validate каждый `schemaRef` is valid JSON Schema 7 via existing `SchemaValidator`
3. Compute bundle archive (tar.gz of manifest + schemas + sample data)
4. Sign archive с ed25519 key
5. Upload to corp Nexus с canonical path `<bundle-id>/<version>/bundle.tar.gz`
6. Generate `bundle.sig` adjacent
**Reuses:** existing Maven publish patterns в repo, corp Nexus credentials через GitLab CI variables.
### 3. Signature verification helper
`BundleSignatureVerifier.java` в new module `ordinis-bundle-spec` (lightweight):
```java
public class BundleSignatureVerifier {
public boolean verify(byte[] archive, byte[] signature, PublicKey publicKey);
}
```
**Не consumed в v2** (no consumer side). Built **as documentation artifact** для future marketplace work — defines verification contract.
### 4. Documentation
`docs/user-guide/bundle-authoring.md`:
- Bundle structure spec (manifest.yaml format)
- How to publish (mvn command + Nexus setup)
- Versioning semantics (semver, breaking change rules)
- Schema authoring conventions reused from existing JavaDoc patterns
`docs/integration/bundle-format-spec.md`:
- Formal spec для Java team handoff
- Manifest schema definition
- Signing contract
- Future consumer protocol (placeholder)
---
## What does NOT ship в v2 (explicit non-goals)
| Feature | Why not |
|---|---|
| ❌ Admin UI «browse bundles» | No customer #2 with browse use case |
| ❌ Install dialog в admin-ui | Customer-specific deployment = helm + values, не runtime install |
| ❌ Dry-run preview UI | No install operation to preview |
| ❌ Multi-tenant Nexus namespacing | N=1 customer, single namespace OK |
| ❌ Dep resolution / topological install | Single bundle, no inter-bundle deps yet |
| ❌ Public catalog | Customer #2+ + community curation = v3 |
| ❌ Bundle uninstall flow | No install in admin UI → no uninstall |
| ❌ Bundle update / migration scripts | Manual helm upgrade pattern remains |
**Anti-feature commitment:** If during 2-3d implementation эти items появляются «just a bit more», STOP. Write new design doc, fresh /office-hours, fresh approval.
---
## Architecture
```
ordinis-cuod-bundle/ ordinis-bundle-spec/ (NEW module)
├── manifest.yaml ← NEW ├── BundleManifest.java
├── pom.xml ├── BundleSignatureVerifier.java
└── src/main/resources/ └── pom.xml
└── bundles/cuod/
├── dictionaries/ ordinis-bundle-publisher/ (NEW Maven plugin)
│ ├── spacecraft/ ├── BundlePublishMojo.java
│ │ ├── schema.json ├── ManifestValidator.java
│ │ └── sample.json └── pom.xml
│ └── ... (39 more)
└── (existing Maven structure)
│ mvn ordinis:bundle-publish
Corp Nexus
ordinis-bundles/private/cuod/
└── ru.cuod.dzz-ground-segment/
└── 1.0.0/
├── bundle.tar.gz
└── bundle.sig
```
No new pods. No runtime changes к ordinis-app / ordinis-admin-ui. Only build-time tooling + Nexus artifacts.
---
## Approaches Considered
### Approach A — Defer entirely (0 days now)
- **Pros:** Zero sunk cost. Capacity goes to AI metric work / prod hardening / customer #2 acquisition.
- **Cons:** Java handoff still needs bundle format spec eventually — built later under deadline pressure. Pure defer ~20% adherence (cross-model challenge): founder likely drifts to greenfield marketplace prototyping anyway.
### Approach B — Full marketplace v1 (10-14 days, v1 doc original)
- **Pros:** Real differentiator if customer #2 ships. Demo wow factor.
- **Cons:** Infrastructure ahead of validated need. Spec drift между hypothetical и real customer #2 requirements. 10-14d sunk cost if N never grows. Triggers Brooks's «is this solving real problem или one we created?»
### Approach C-revised — **Bundle hygiene** (2-3 days, CHOSEN)
- **Pros:**
- Java handoff readiness (must-have anyway, due in 2-3 months)
- Sales demo asset («signed versioned bundle artifact, here's our hygiene story»)
- Contains founder's marketplace energy в legitimate scope-bounded work
- 5× cheaper than B, не «do nothing» of A
- Future-leverage: when customer #2 needs UI, format already defined → UI 5-7d вместо 10-14d
- **Cons:**
- «Half feature» if framed as marketplace — мы НЕ frame'им так
- Not consumer-visible (no UI screenshot for demo deck)
- 2-3 days still > 0 days (Approach A); risk founder drifts beyond cap
---
## Recommended Approach: **C-revised — Bundle Hygiene**
Rationale per `/office-hours` cross-model synthesis:
1. **Java handoff debt avoidance:** Manifest spec mandatory anyway when team scales beyond zimin.an. Build now while context fresh, cheaper than retro-spec under deadline.
2. **Sales conversation enablement:** Prospects asking «can we extend this с our own dictionaries?» get pointed at published bundle artifact + manifest spec — concrete answer без «we'll build it for you».
3. **Founder behavior containment:** Cross-model challenge правильно отметил: pure defer has ~20% follow-through odds. Pre-committed 2-3d scope легитимизирует bundle work, prevents weekend prototyping что expanded beyond bounds.
4. **Optionality preserved для customer #2:** If LOI signs Q3-Q4 — UI work spawn separate design doc, builds on this manifest, ships 5-7 days (smaller scope than ahead-of-time 10-14d).
5. **Engineering preference «explicit over clever»:** Manifest format defined upfront prevents implicit conventions, helpful for Java team handoff.
---
## Implementation plan
| Step | Effort (CC) | Notes |
|---|---|---|
| 1. New module `ordinis-bundle-spec` (manifest POJO + verifier) | 3h | Pure Java, no Spring dep |
| 2. New module `ordinis-bundle-publisher` (Maven plugin) | 4h | Standard Maven plugin scaffolding |
| 3. `manifest.yaml` for `ordinis-cuod-bundle` (1.0.0 release) | 1h | Generated from existing bundle structure |
| 4. Migrate ad-hoc bundle structure → match manifest paths | 2h | File moves, no logic change |
| 5. Publisher CLI: tar.gz + ed25519 sign + Nexus upload | 4h | BouncyCastle for ed25519 |
| 6. Manifest schema validation в publisher | 2h | Reuses existing SchemaValidator |
| 7. GitLab CI integration (publish job on bundle tag) | 2h | New `.gitlab-ci.yml` job |
| 8. Tests (publisher Mojo + verifier + manifest parse) | 4h | unit tests, no integration tests needed |
| 9. `docs/user-guide/bundle-authoring.md` + `docs/integration/bundle-format-spec.md` | 3h | Java handoff artifact |
| **Total** | **~25h (2-3 days CC)** | **Hard cap. No scope creep.** |
**Anti-creep checkpoint:** After step 9, **STOP**. Don't add «just one consumer endpoint». Don't add «just a tiny browse list». Those are new design doc territory.
---
## Test plan
| # | Test | Type |
|---|---|---|
| 1 | Manifest parser: valid YAML → typed object | unit |
| 2 | Manifest validation: missing required field → error | unit |
| 3 | Publisher Mojo: happy path → archive + signature generated | unit (Mojo) |
| 4 | Publisher Mojo: invalid schemaRef → fail fast | unit |
| 5 | Signature verifier: signed archive → returns true | unit |
| 6 | Signature verifier: tampered archive → returns false | unit |
| 7 | Signature verifier: wrong public key → returns false | unit |
| 8 | Schema validation reuse: invalid JSON Schema в dict → publisher fails | unit |
No integration / E2E tests — no runtime behavior changes.
---
## Open questions
1. **Where do signing keys live?** GitLab CI variables protected? Vault? Corp HSM? → Defer to ops decision при implement.
2. **Nexus namespace structure?** `ordinis-bundles/private/<customer>/<bundle-id>/<version>/` — fine для v1. Multi-tenant adjustments в v2.
3. **Migration breaking?** Existing `ordinis-cuod-bundle` deployment relies on Maven module loaded at app startup. Manifest spec adds metadata, doesn't change loading. **Verify:** ordinis-app still loads bundle when manifest.yaml present но new spec module not on classpath (graceful degradation для existing v2.14.0 prod).
---
## Distribution plan
Publisher Maven plugin distributed как corp internal artifact в Nexus. Authors add к their bundle's `pom.xml`:
```xml
<build>
<plugins>
<plugin>
<groupId>cloud.nstart.terravault.ordinis</groupId>
<artifactId>ordinis-bundle-publisher</artifactId>
<version>1.0.0</version>
</plugin>
</plugins>
</build>
```
Then `mvn ordinis:bundle-publish` triggered by GitLab CI on tag push (e.g. `cuod-bundle-1.0.0`).
Bundle.tar.gz uploaded к Nexus. No deployment changes к prod ordinis cluster — bundle archive consumed только by external authors / sales demos.
---
## Success criteria
**Quantitative:**
- Publisher Mojo completes < 60 sec на ЦУОД bundle (~40 dicts)
- Signature verification < 10ms
- Manifest validation catches 100% malformed manifests in unit tests
**Qualitative:**
- Java team handoff doc references `bundle-format-spec.md` as authoritative spec
- Sales conversations с prospects use «signed versioned bundle» as differentiator
- After 1 month: zero «founder drifted into consumer UI work» violations (scope cap held)
**Failure criteria (rollback):**
- Publisher Mojo bugs surface в > 2 releases of ordinis-cuod-bundle → reconsider as build-time vs separate plugin
- No sales conversation uses bundle artifact within 3 months → format спека correct, distribution wrong (rare; spec stays anyway)
---
## What I noticed about how you think (during /office-hours)
- **Initial position «build full marketplace» (v1 doc) → accepted «defer entirely» recommendation от me → accepted «bundle hygiene» revision после cross-model challenge.** Two reversals in one session = openness to push-back. Это редко — большинство founders defend original scope harder.
- **«давай как рекомендуешь»** = trust calibrated на анализ + cross-model agreement. You didn't dismiss subagent challenge OR over-weight it — accepted synthesis as honest reading.
- **Cross-model challenge value:** subagent found 4 things I missed (sales artifact, Java handoff, founder psychology drift risk, «treading water» mis-framing). Без cross-model call recommendation бы вышел overly conservative. **Session demonstrates value of /office-hours Phase 3.5 even когда первый instinct = skip it.**
- **Anti-scope-creep pre-commitment** — `Hard cap 2-3 days. No scope creep.` line — это founder-level discipline, не engineering preference. Most founders write «target effort 2-3 days» что effectively unconstrained.
---
## Reviewer Concerns
(Spec review skipped в этой session due to context length. Recommend `/plan-eng-review` separately когда implement starts, especially on:)
- Module dependency graph (`ordinis-bundle-spec` standalone OK? circular dep risk если consumed by ordinis-app later?)
- Nexus auth credentials lifecycle (GitLab CI vs Vault tradeoff)
- Compatibility: existing prod v2.14.0 deployment should keep working без bundle-spec module
---
## See also
- v1 SUPERSEDED (был «Dictionary Marketplace», full UI + registry + 10-14d). Reasoning for v1 → v2 revision lives в section «Approaches Considered».
- Companion: `ai-schema-assist.md` — separate /office-hours design, AI assist authorship. **Sequencing:** AI assist baseline measurement (P5 prereq) before this. This work doesn't compete для bandwidth — separable.
- Office-hours formal doc: `~/.gstack/projects/claude/zimin-main-design-bundle-hygiene-20260512.md` (cross-skill discoverable)