T-87GH-new-scripts-derive-schema-bound-values
Status: closed/done · Impact: high · Complexity: large
The per-type scaffolders (new_*.ts) each hardcode or copy what schema.json
already declares and re-implement entity writing, so schemas drift (born-stale
schema_version, invalid status — the TS-port recurrence of #59,
T-ZU6V-new-scripts-derive-patterns-from-schema) and there is no single
authoring path. Replace them with one shared, parameterized
entity-authoring pipeline in lib driven by schema.json + a body-template,
and reshape entity identifiers to a uniform AA-NNNN-<optional-slug> so the
naming is consistent and the prefix/id seam is unambiguous. Touches the entity
standard (S-0005-entity-definition-contract / D-0004-entity-definition-architecture)
and the identifier ADR (D-0002-entity-identifier-shape).
| Location | Role today |
|---|---|
plugin/scripts/new_task.ts, new_milestone.ts, new_backlog.ts; plugin/skills/standard-new/new_standard.ts, epic-new/new_epic.ts | Per-type scaffolders that each copy a static template and hardcode schema-bound values (schema_version, status choices, patterns). Drift on every schema bump; new_standard.ts writes a status outside the enum. |
plugin/lib/model/entities/<type>/body-template.eta | Static body-only starting point carrying frozen frontmatter (task pinned schema_version: "3" vs schema v5). |
plugin/lib/model/entities/<type>/schema.json | Frontmatter contract (required fields, defaults, enums) — the source of truth, but not used to generate frontmatter. |
plugin/lib/model/entity.ts | Entity projection (T-0011) — reads schema/template; natural host for the shared writer. |
[D-0002-entity-identifier-shape](/planning/decisions/entity-identifier-shape/) | Canonical: filenames are AA-NNNN-<optional-slug> with a per-type numbering style (incrementing vs base-36). On disk the corpus is still the pre-reshape concatenated <prefix><id> (D0001, MML68) this task migrates. |
Proposed
Section titled “Proposed”1. Shared entity-authoring pipeline (in lib, parameterized by type)
Section titled “1. Shared entity-authoring pipeline (in lib, parameterized by type)”A single module that, given an entity type and a set of input values:
- Loads
schema.jsonand builds the frontmatter object by merging the input values over schema-derived defaults (required fields + declared defaults):schema_version= the schema’s currentversion,status∈ the schema enum, etc. — never hardcoded or copied from a frozen template. - Serializes the frontmatter object → YAML.
- Passes the frontmatter (plus any extra context values) into a templating engine over the entity’s body-template for variable substitution and render logic → body text.
- Writes
<frontmatter>+<body>to the instance path under the new identifier, minted per-type per D-0002-entity-identifier-shape: next-free incrementing number for incrementing types, collision-retry base-36 for base-36 types.
One engine, one writer, all entity types — because they adhere to the same
shape standard. The new_*.ts scripts collapse into thin callers (or the
sdlc <type> create op per T-0010 / D-0007-deterministic-op-substrate).
Templating engine: Eta (decided — TS-native, fast, supports logic, well supported). Declared the standard per P-0004-leverage-best-tool.
2. Entity-definition standard update (S-0005-entity-definition-contract / D-0004-entity-definition-architecture)
Section titled “2. Entity-definition standard update (S-0005-entity-definition-contract / D-0004-entity-definition-architecture)”Each entity ships schema.json (frontmatter contract — required + defaults
usable for auto-generation) and a body-template.<ext> (templating-engine
template) in place of the static body-template.eta. Amend S0005’s artifact set and
D0004’s operations contract accordingly.
3. Identifier reshape — implement D-0002-entity-identifier-shape
Section titled “3. Identifier reshape — implement D-0002-entity-identifier-shape”Filenames become AA-NNNN-<optional-slug>.md exactly as fixed by
D-0002-entity-identifier-shape: uppercase abbreviation, dash, 4-char id,
optional immutable slug. The id minter is per-type — next-free
incrementing number for the incrementing types (Decision is pinned; Standard,
Principle, Milestone, …) and collision-retry base-36 for the base-36 types
(Task, Backlog, …). Existing ids are preserved as-is.
D0002 owns the abbreviation registry and the numbering style per type, and
D-ORMG-data-model mirrors it in the roster Prefix column. This task
consumes that registry — it does not re-decide it.
4. Migrate existing entities
Section titled “4. Migrate existing entities”Rename every existing instance to AA-NNNN-<slug> and sweep inbound wikilinks.
Existing ids are preserved (already valid 4-char base-36), so the rename is
mechanical: insert the A- dash after the single-letter abbreviation
(D0007-… → D-0007-…, MML68 → M-ML68). Accept the break from historical
names (no git --follow preservation required). Proto-instances of planned
types (cap-1, …) reshape when their type’s abbreviation locks at ship.
Approach
Section titled “Approach”- Decisions locked (shipped corpus): engine = Eta; identifier shape =
AA-NNNN-<slug>per D-0002-entity-identifier-shape (per-type incrementing/base-36; existing ids preserved); shipped abbreviations stay single letters. Only planned-type abbreviations remain to lock when each ships — no gating decision blocks the shipped-corpus work. - Build the shared authoring pipeline in
plugin/lib/model(frontmatter from schema defaults + merge; body via the engine overbody-template); unit-test parameterized across ≥2 entity types. - Add
body-template.<ext>per entity; migratebody-template.etacontent into it; drop static frontmatter from the templates. - Amend
S0005+D0004(body-template + schema-driven frontmatter).D0002and theDORMG-data-modelroster already carry theAA-NNNNshape + abbreviation/numbering registry — consume them, don’t re-amend. - Repoint
new_*.ts(and thesdlc <type> createop perT0010) at the pipeline; delete all hardcoded schema-bound values. - Add the
project-checkguard: template↔schemaschema_versionagreement and scaffolder choice-list ⊆ schema enum. (FilenameAA-NNNNconformance is T-0003’s check, not this one.) - Corpus migration: rename instances + sweep wikilinks; run
entities-auditto confirm clean.
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
plugin/lib/model/entity.ts (+ new writer module) | modify/new | The shared schema-driven frontmatter + templated-body pipeline; per-type id minter (incrementing + base-36) |
plugin/lib/model/entities/<type>/schema.json | modify | Ensure required/default coverage for auto-generation |
plugin/lib/model/entities/<type>/body-template.<ext> | new | Templating-engine body template (replaces static body-template.eta) |
plugin/scripts/new_*.ts, plugin/skills/*/new_*.ts | modify | Thin callers of the pipeline; remove hardcoded schema-bound values |
docs/planning/standards/S0005-…; docs/planning/decisions/D0004-… | modify | Standard/ADR amendments (body-template + schema-driven frontmatter). D0002 + DORMG-data-model already carry the identifier registry. |
.claude/skills/project-check/ | new | Guard: template↔schema agreement, enum subset (filename AA-NNNN conformance is owned by T-0003) |
docs/planning/** instances + inbound wikilinks | modify | Rename to AA-NNNN-<slug>; sweep references |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1: The shared pipeline, given an entity type + input, writes a file whose
schema_versionequals that schema’sversionand whosestatusis in the schema enum — verified parameterized across ≥2 entity types (no per-type hardcoding). - AC-2: Entity bodies are produced by rendering
body-template.<ext>through the chosen engine with frontmatter/context variables (not by copying a staticbody-template.eta). - AC-3:
new_standard.ts(via the pipeline) offers every value in the standardstatusenum and writes a valid one; a scaffolded draft standard passesvalidate_frontmatter.ts. - AC-4: A
project-checkcheck fails on (a) atemplate/schemaschema_versionmismatch and (b) a scaffolder choice-list value absent from the schema enum. (FilenameAA-NNNNconformance is owned by T-0003, not this guard.) - AC-5: Every existing entity instance is renamed to
AA-NNNN-<slug>, inbound wikilinks are swept, andaudit_entities.tsreports no new drift attributable to the rename. - AC-6:
S0005/D0004are amended to define the body-template + schema-driven-frontmatter contract; theAA-NNNNidentifier shape + abbreviation/numbering registry already live in D-0002-entity-identifier-shape and D-ORMG-data-model and are consumed unchanged.
Out of scope
Section titled “Out of scope”- Which planned entity types ship now vs later — each locks its
AAwhen it ships. - This task is large and a candidate to split into an epic (pipeline / standard-amendments / identifier-reshape + corpus migration); kept as one definition here per the review request.
Dependencies
Section titled “Dependencies”- Relates to
#59(T-ZU6V-new-scripts-derive-patterns-from-schema, the regressed precedent), T-0010 (operations relocation — the pipeline is thecreateop), D-0007-deterministic-op-substrate (thelib/substrate home), S-0005-entity-definition-contract / D-0004-entity-definition-architecture (amended here), and D-0002-entity-identifier-shape / D-ORMG-data-model (consumed — the canonical identifier registry). Likely belongs under M-ML68 (the identifier-migration milestone). No hard blocker — the shipped-corpus decisions are locked; only planned-type abbreviations lock at ship.
Discovery context
Section titled “Discovery context”Holistic scope and pipeline design from the user’s #233 review comment
(2026-06-02): schema → frontmatter (defaults + merge), body-template → body via
a templating engine, all shared/parameterized lib code. Identifier reshape to
AA-NNNN-<slug> decided the same day. Promoted from the scaffolder-drift
backlog item, which generalized #59 to the TS substrate.
Depends on
Section titled “Depends on”T-FCVG-op-registry-and-module-walk