Skip to content

Commit 6c7043e

Browse files
dmealingclaude
andcommitted
Merge: neutral metadata documentation + ADR-0020 codegen tiering
ADR-0020 records the standing codegen-tiering rule: native code generators stay per-port and idiomatic (Tier 1); language-neutral artifacts (migrations, metadata docs, future OpenAPI/Mermaid) are one shared engine (Tier 2). Dividing test: does the output depend on the implementing language? Applies it to documentation (Tier 2, TS — the single shared engine): - Root templates/ canonical doc-template source + per-port byte-identity gate (templates are language-neutral Mustache; one source, never forked per port). - Entity page fully neutralized: dropped the Zod 'Validation' + 'Generated code' SDK sections AND the Storage section's TypeScript-type column + Drizzle DDL; added a neutral Constraints table (from field metadata) and a neutral Storage table (physical column mapping). Renders for value-objects without storage. - New neutral template.output documentation page (render contract: kind/output/ input/contract/source/capability) — no language types or helper signatures. - New 'meta docs <metadata> --out <dir>' standalone CLI command emitting both page kinds from metadata alone (reuses docsFile via a constructed GenContext). - Naming reconciled (raw node names) so entity<->template cross-links resolve. Docs builder NOT ported per-port (ADR-0020 Tier 2). SDK/API docs (Tier 1) and embedding framework templates in the compiled binary are documented follow-ups. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2 parents 486bcd3 + 55fcd21 commit 6c7043e

33 files changed

Lines changed: 2224 additions & 338 deletions
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# Neutral metadata documentation — implementation plan
2+
3+
> **For agentic workers:** REQUIRED SUB-SKILL: superpowers:subagent-driven-development. Steps use checkbox (`- [ ]`) tracking.
4+
5+
**Goal:** Generate neutral metadata documentation (entity + `template.output`
6+
pages) from a single shared TS engine, with one canonical doc-template source,
7+
runnable standalone via `meta docs`. No language assumptions, no `--target`.
8+
9+
**Architecture:** Tier-2 per ADR-0020 — one shared engine (TS), language-neutral
10+
output. Canonical Mustache templates live at root `templates/`; the codegen-ts
11+
package ships a byte-identity-gated copy. Entity page is neutralized (drop
12+
Zod/generated SDK sections; document constraint metadata). New neutral template
13+
page documents the render contract. New `meta docs` CLI command emits both from
14+
metadata alone.
15+
16+
**Tech Stack:** TypeScript, bun, the existing `render()`/`templateGenerator()`
17+
engine, Mustache.
18+
19+
**Scope guard:** TS only (single engine). Do NOT port the docs builder to
20+
C#/Python/Java/Kotlin. Do NOT touch native code generators. SDK/API docs are out
21+
of scope (Tier 1, future).
22+
23+
---
24+
25+
## Reference files (read before starting)
26+
27+
- `server/typescript/packages/codegen-ts/src/generators/docs-data.ts``EntityDocData` shape.
28+
- `server/typescript/packages/codegen-ts/src/generators/docs-data-builder.ts` — builder; `constraintsCell()` (~L159), `validation` (~L370), `generated` (~L392-443).
29+
- `server/typescript/packages/codegen-ts/src/generators/docs-file.ts` — per-entity emission; iterates `ctx.loadedRoot.objects().filter(ctx.matches)`.
30+
- `server/typescript/packages/codegen-ts/src/generators/render-helper-file.ts` — reference for walking `template.output` nodes (`@kind`/`@payloadRef`/`@format`/`@textRef`/`@subjectRef`/`@htmlBodyRef`/`@textBodyRef`/`@maxChars`/`@requiredTags`).
31+
- `server/typescript/packages/codegen-ts/src/render-engine/framework-provider.ts` — how templates resolve (the package `templates/` dir; `CANONICAL_TEMPLATE_REL`).
32+
- `server/typescript/packages/codegen-ts/templates/docs/entity-page.md.mustache` — current template.
33+
- `server/typescript/packages/codegen-ts/test/golden/docs-file-conformance.test.ts` — current golden.
34+
- `server/typescript/packages/cli/src/commands/migrate.ts` — model for a standalone metadata-loading command (mirror for `docs.ts`).
35+
36+
---
37+
38+
## Task 1: Canonical `templates/` source + byte-identity gate (pure relocation)
39+
40+
**Intent:** Establish root `templates/` as the single source of truth for doc
41+
templates; the codegen-ts package keeps a bundled copy (needed in the npm
42+
tarball) that is byte-identity-gated against root. No output change — golden must
43+
still pass.
44+
45+
**Files:**
46+
- Create: `templates/docs/entity-page.md.mustache` (root canonical — copy of the current package template, byte-for-byte)
47+
- Create: `scripts/sync-doc-templates.sh` (copies `templates/` → consuming packages' bundled `templates/`; idempotent)
48+
- Keep: `server/typescript/packages/codegen-ts/templates/docs/entity-page.md.mustache` (bundled copy, now generated/synced)
49+
- Test: `server/typescript/packages/codegen-ts/test/templates-canonical.test.ts`
50+
51+
- [ ] **Step 1: Write the failing byte-identity test.** Reads the repo-root `templates/docs/entity-page.md.mustache` and the package copy; asserts they are byte-identical (`readFileSync` both, `toEqual`). Resolve repo root by walking up from the test file to the dir containing `templates/` + `server/`.
52+
- [ ] **Step 2: Run → FAIL** (root file doesn't exist yet). `cd server/typescript && bun test packages/codegen-ts/test/templates-canonical.test.ts`.
53+
- [ ] **Step 3: Create root canonical** by copying the existing package template verbatim into `templates/docs/entity-page.md.mustache`. Add `scripts/sync-doc-templates.sh` that copies root → `server/typescript/packages/codegen-ts/templates/docs/` (so the package copy is reproducible; future ports add their dest here).
54+
- [ ] **Step 4: Run → PASS** (byte-identical). Also run the existing docs golden to confirm NO output change: `bun test packages/codegen-ts/test/golden/docs-file-conformance.test.ts`.
55+
- [ ] **Step 5: Commit.** `feat(docs): root templates/ canonical doc-template source + byte-identity gate`
56+
57+
---
58+
59+
## Task 2: Neutralize the entity page
60+
61+
**Intent:** Remove the language-specific sections. Drop `generated` (TS
62+
filenames) and the Zod `validation` pointer. Replace with a neutral
63+
**Constraints** table built from field metadata that renders for ALL entities
64+
(including value objects with no storage). Keep Storage/Identity/Relationships/
65+
Used by.
66+
67+
**Files:**
68+
- Modify: `server/typescript/packages/codegen-ts/src/generators/docs-data.ts` (remove `GeneratedFileDoc` + `generated`; remove Zod `validation`; add `constraints` table shape: `{ hasConstraints, header, rows: [{ field, required, type, limits, rules }] }`)
69+
- Modify: `server/typescript/packages/codegen-ts/src/generators/docs-data-builder.ts` (delete the `generated.push(...)` block and the `validation` Zod object; build `constraints` from every field — reuse the existing `constraintsCell` logic for limits/required/enum/validators; works without storage)
70+
- Modify: `templates/docs/entity-page.md.mustache` (root) — remove `## Generated code`; replace `## Validation` with a `## Constraints` Markdown table (columns: Field | Required | Type | Limits | Rules); make `## Used by` bullets link `./<Template>.md`. Then run `scripts/sync-doc-templates.sh`.
71+
- Modify: golden `docs-file-conformance.test.ts` to the neutralized output.
72+
- Test: add a value-object fixture (no storage) with declared constraints (required, maxLength, enum, a `validator.*`) proving constraints render without a Storage section.
73+
- Test: `server/typescript/packages/codegen-ts/test/docs-neutrality.test.ts` — generated entity docs contain none of: `Zod`, a generated `.ts`/`.cs`/`.kt`/`.py` filename, TS type literals.
74+
75+
- [ ] **Step 1: Write the neutrality test** asserting the rendered entity doc (from an existing fixture) contains no `Zod`, no `.ts` filename, no `## Generated code`. Run → FAIL.
76+
- [ ] **Step 2: Write the value-object-constraints test** (a VO fixture with required/maxLength/enum/validator) asserting a `## Constraints` table with those rules and NO `## Storage`. Run → FAIL.
77+
- [ ] **Step 3: Update `docs-data.ts`** — drop `generated`/`GeneratedFileDoc`, drop Zod `validation`, add `constraints` shape.
78+
- [ ] **Step 4: Update `docs-data-builder.ts`** — remove generated + Zod-validation builders; build the `constraints` table for all fields.
79+
- [ ] **Step 5: Update + sync `entity-page.md.mustache`** (root → run sync script).
80+
- [ ] **Step 6: Regenerate/update the golden** to the neutral output; eyeball it for neutrality.
81+
- [ ] **Step 7: Run → PASS** all of: neutrality test, VO-constraints test, golden, byte-identity gate. `bun test packages/codegen-ts`.
82+
- [ ] **Step 8: Commit.** `feat(docs): neutralize entity page — constraints table, drop Zod/generated SDK sections`
83+
84+
---
85+
86+
## Task 3: New neutral `template.output` page
87+
88+
**Intent:** One Markdown page per `template.output`, render-contract-shaped,
89+
distinct from the entity page, fully neutral (no generated-helper signatures, no
90+
language types).
91+
92+
**Files:**
93+
- Create: `server/typescript/packages/codegen-ts/src/generators/template-doc-data.ts``TemplateDocData`: `{ generatedMarker, name, kind (document|email), description?, format, isEmail, parts?: [{ label, ref, format, escaped }], payload: { name, link }, referencedFields: string[], requiredTags?: string[], maxChars?: number, sourceRefs: string[], capability: string }`.
94+
- Create: `server/typescript/packages/codegen-ts/src/generators/template-doc-builder.ts``buildTemplateDocData(template, opts)` walking a `template.output` node (mirror `render-helper-file.ts` attr reads). `capability` is a fixed neutral string per kind (document → "returns the rendered string"; email → "returns subject + html body + optional text body").
95+
- Create: `templates/docs/template-page.md.mustache` (root) + sync — sections: title + kind/description; `## Output` (format; for email the parts table + multipart note + escaping); `## Input` (payload link + referenced fields/requiredTags); `## Render contract` (maxChars-fails note, requiredTags, neutral drift guarantee); `## Source` (template refs); `## Capability` (the neutral capability sentence).
96+
- Modify: `docs-file.ts` — after entity pages, iterate `loadedRoot` `template.output` nodes → emit `<Template>.md` via `templateGenerator({ ref: "docs/template-page.md", ... })`. (Or a sibling `template-docs-file.ts`; keep one emission entry from the generator list.)
97+
- Test: `template-doc-conformance.test.ts` golden — a `document` template (WelcomePage) and an `email` template (WelcomeEmail, 3 parts); assert the sections, the payload link to the entity page, and the entity page's Used-by link resolving to this page.
98+
99+
- [ ] **Step 1: Write the template-page golden test** for a document + an email template (fixtures), asserting the neutral sections, payload→entity link, and entity↔template cross-links resolve. Run → FAIL.
100+
- [ ] **Step 2: Implement `template-doc-data.ts`** (the shape).
101+
- [ ] **Step 3: Implement `template-doc-builder.ts`** (walk node → data; neutral capability string).
102+
- [ ] **Step 4: Author `templates/docs/template-page.md.mustache`** (root) + run sync.
103+
- [ ] **Step 5: Wire emission** in `docs-file.ts` to also emit template pages.
104+
- [ ] **Step 6: Run → PASS** the golden + full `bun test packages/codegen-ts`.
105+
- [ ] **Step 7: Commit.** `feat(docs): neutral template.output documentation page (render contract)`
106+
107+
---
108+
109+
## Task 4: `meta docs` standalone command
110+
111+
**Intent:** A standalone CLI command that emits neutral metadata docs (entity +
112+
template pages) from metadata ALONE — no codegen config, no Node toolchain for
113+
the adopter (ships in the compiled binary, like `migrate-ts`).
114+
115+
**Files:**
116+
- Create: `server/typescript/packages/cli/src/commands/docs.ts``meta docs <metadata> --out <dir>`: load the metadata root (mirror `migrate.ts` loading), build a minimal render context (project provider + framework templates), emit entity pages (neutral) + template pages into `--out`. No dependency on a full `gen` config.
117+
- Modify: the CLI command registry (where `gen`/`migrate`/`verify` register) to add `docs`.
118+
- Ensure the standalone `bun build --compile` binary includes the command (verify it imports cleanly — the framework-provider lazy-resolves templates; the binary has no on-disk `templates/`, so the command must surface a clear error if templates can't resolve, OR embed them — match how `gen` handles templates in the binary).
119+
- Test: `server/typescript/packages/cli/test/docs-command.test.ts` — run `docs` against a fixture metadata file → asserts `<Entity>.md` + `<Template>.md` written to `--out`, neutral content, exits 0; appears in `--help`.
120+
121+
- [ ] **Step 1: Write the command test** (emits both page types from a metadata fixture to a temp `--out`; no gen config). Run → FAIL.
122+
- [ ] **Step 2: Implement `docs.ts`** mirroring `migrate.ts`'s metadata loading; reuse the docs + template-doc builders + `render()`.
123+
- [ ] **Step 3: Register** the command; add `--help` text.
124+
- [ ] **Step 4: Run → PASS** the command test. Verify `meta docs --help` lists it.
125+
- [ ] **Step 5: Binary check** — build/locate the standalone binary path used by other CLI tests; confirm `docs` is reachable (or document the template-resolution constraint if the binary can't see on-disk templates, and handle gracefully).
126+
- [ ] **Step 6: Commit.** `feat(cli): meta docs — standalone neutral metadata-docs command`
127+
128+
---
129+
130+
## Task 5: Closeout
131+
132+
- [ ] **Step 1:** Full TS suites green: `cd server/typescript && bun test` (metadata, render, codegen-ts, cli). Record counts.
133+
- [ ] **Step 2:** Hygiene — `git diff $(git merge-base origin/main HEAD)..HEAD` shows no private names, no absolute home paths, no committed node_modules/bunfig.toml. The new `templates/` + fixtures use generic names.
134+
- [ ] **Step 3:** Whole-branch code-review + code-simplifier (the pre-merge gate); fix findings.
135+
- [ ] **Step 4:** Forward-merge to main (FF/merge onto current origin/main tip, never rewrite), push, remove worktree, delete branch. Update memory.
136+
137+
---
138+
139+
## Self-review notes
140+
141+
- **Spec coverage:** shared canonical (T1) ✓; neutral entity page incl. constraints table + drop Zod/generated (T2) ✓; neutral template page (T3) ✓; `meta docs` standalone (T4) ✓; byte-identity gate (T1) ✓; neutrality assertion (T2) ✓.
142+
- **Type consistency:** `constraints` shape introduced in T2 `docs-data.ts` is consumed by the T2 template edit; `TemplateDocData` in T3 is consumed by the T3 template + the T4 command.
143+
- **Out-of-scope guard restated:** no per-port port of the builder; no native-codegen changes; no SDK docs.

0 commit comments

Comments
 (0)