Skip to content

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).

LocationRole today
plugin/scripts/new_task.ts, new_milestone.ts, new_backlog.ts; plugin/skills/standard-new/new_standard.ts, epic-new/new_epic.tsPer-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.etaStatic body-only starting point carrying frozen frontmatter (task pinned schema_version: "3" vs schema v5).
plugin/lib/model/entities/<type>/schema.jsonFrontmatter contract (required fields, defaults, enums) — the source of truth, but not used to generate frontmatter.
plugin/lib/model/entity.tsEntity 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.

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:

  1. Loads schema.json and builds the frontmatter object by merging the input values over schema-derived defaults (required fields + declared defaults): schema_version = the schema’s current version, status ∈ the schema enum, etc. — never hardcoded or copied from a frozen template.
  2. Serializes the frontmatter object → YAML.
  3. 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.
  4. 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.

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.

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.

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-…, MML68M-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.

  1. 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.
  2. Build the shared authoring pipeline in plugin/lib/model (frontmatter from schema defaults + merge; body via the engine over body-template); unit-test parameterized across ≥2 entity types.
  3. Add body-template.<ext> per entity; migrate body-template.eta content into it; drop static frontmatter from the templates.
  4. Amend S0005 + D0004 (body-template + schema-driven frontmatter). D0002 and the DORMG-data-model roster already carry the AA-NNNN shape + abbreviation/numbering registry — consume them, don’t re-amend.
  5. Repoint new_*.ts (and the sdlc <type> create op per T0010) at the pipeline; delete all hardcoded schema-bound values.
  6. Add the project-check guard: template↔schema schema_version agreement and scaffolder choice-list ⊆ schema enum. (Filename AA-NNNN conformance is T-0003’s check, not this one.)
  7. Corpus migration: rename instances + sweep wikilinks; run entities-audit to confirm clean.
LocationKindChange
plugin/lib/model/entity.ts (+ new writer module)modify/newThe shared schema-driven frontmatter + templated-body pipeline; per-type id minter (incrementing + base-36)
plugin/lib/model/entities/<type>/schema.jsonmodifyEnsure required/default coverage for auto-generation
plugin/lib/model/entities/<type>/body-template.<ext>newTemplating-engine body template (replaces static body-template.eta)
plugin/scripts/new_*.ts, plugin/skills/*/new_*.tsmodifyThin callers of the pipeline; remove hardcoded schema-bound values
docs/planning/standards/S0005-…; docs/planning/decisions/D0004-…modifyStandard/ADR amendments (body-template + schema-driven frontmatter). D0002 + DORMG-data-model already carry the identifier registry.
.claude/skills/project-check/newGuard: template↔schema agreement, enum subset (filename AA-NNNN conformance is owned by T-0003)
docs/planning/** instances + inbound wikilinksmodifyRename to AA-NNNN-<slug>; sweep references
  • AC-1: The shared pipeline, given an entity type + input, writes a file whose schema_version equals that schema’s version and whose status is 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 static body-template.eta).
  • AC-3: new_standard.ts (via the pipeline) offers every value in the standard status enum and writes a valid one; a scaffolded draft standard passes validate_frontmatter.ts.
  • AC-4: A project-check check fails on (a) a template/schema schema_version mismatch and (b) a scaffolder choice-list value absent from the schema enum. (Filename AA-NNNN conformance is owned by T-0003, not this guard.)
  • AC-5: Every existing entity instance is renamed to AA-NNNN-<slug>, inbound wikilinks are swept, and audit_entities.ts reports no new drift attributable to the rename.
  • AC-6: S0005/D0004 are amended to define the body-template + schema-driven-frontmatter contract; the AA-NNNN identifier shape + abbreviation/numbering registry already live in D-0002-entity-identifier-shape and D-ORMG-data-model and are consumed unchanged.
  • Which planned entity types ship now vs later — each locks its AA when 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.

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.

T-FCVG-op-registry-and-module-walk


← Back to Tasks