From 78e8ee5297332b1fa19ad11b7e3c0ef02c4d8452 Mon Sep 17 00:00:00 2001 From: Mateus Andrade <133387879+protonspy@users.noreply.github.com> Date: Tue, 7 Jul 2026 05:30:49 -0300 Subject: [PATCH 1/2] feat(plan): plan mode, decision records, and the glossary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Land the plan layer above specs and the two knowledge contracts that ride on it. Plan mode (substrate): docs/plans// decomposes an initiative into feats, each becoming exactly one spec. Adds the plan grammar (parse/validate), the approval hash gate, the sequencer, deterministic briefs, the autonomous runner and its sandbox, the /prd + quick-prd authoring skills, plan/feat graph nodes, and the web read model. Decision records (docs/adr/): a decision passing the triple gate — hard to reverse, surprising without context, a real trade-off — becomes an ADR at docs/adr/NNNN-.md. Feats cite it as adr:, a third ref token beside stack: and [[wiki]]. `csdd plan validate` reports broken/ambiguous/malformed and cites-superseded citations plus docs/adr well-formedness; `csdd plan brief` inlines cited records in full with the open-decision forbidden line; the graph emits adr nodes with cites/superseded_by edges and a broken/orphan-decision lint. The prd skill grills gate-positive decisions one at a time (recording each ADR inline), sweeps assumptions at Present, and funnels run deviations through supersession; quick-prd carries the light gate. Dogfood: ADRs 0001-0003. The glossary (docs/glossary.md): one canonical term per domain concept with an _Avoid_ synonym list. A shared internal/glossary package parses, normalizes, and whole-token matches identifiers. `csdd plan validate` reports an avoided term in a feat/plan slug; `csdd graph analyze` / `csdd wiki lint` catch spec dirs and wiki page names; the graph emits term nodes and references edges (orphan-term lint). The glossary skill (challenge/sharpen/stress-test/record, the tombstone rule) and /glossary command own the discipline; prd/quick-prd/wiki gain invocation hooks. Dogfood: docs/glossary.md. --- docs/adr/0001-decision-records-storage.md | 3 + docs/adr/0002-two-tier-interview.md | 3 + docs/adr/0003-glossary-deferred.md | 3 + docs/glossary.md | 52 + docs/plans/PLAN-decision-records.md | 472 +++++++ docs/plans/PLAN-glossary.md | 419 +++++++ docs/plans/PLAN-knowledge-base.md | 1093 +++++++++++++++++ docs/plans/PLAN-plan-mode.md | 667 ++++++++++ internal/cli/cli.go | 6 + internal/cli/glossary_cli_test.go | 128 ++ internal/cli/plan.go | 543 ++++++++ internal/cli/plan_adr_test.go | 129 ++ internal/cli/plan_bridge_cli_test.go | 151 +++ internal/cli/plan_cli_test.go | 130 ++ internal/cli/plan_e2e_test.go | 168 +++ internal/cli/plan_skill_test.go | 45 + internal/cli/sandbox.go | 110 ++ internal/cli/sandbox_cli_test.go | 58 + internal/cli/spec.go | 7 +- internal/glossary/glossary.go | 266 ++++ internal/glossary/glossary_test.go | 136 ++ internal/graph/analyze.go | 170 ++- internal/graph/extract.go | 3 + internal/graph/extract_adr.go | 131 ++ internal/graph/extract_adr_test.go | 114 ++ internal/graph/extract_glossary.go | 102 ++ internal/graph/extract_glossary_test.go | 129 ++ internal/graph/extract_plan.go | 281 +++++ internal/graph/extract_plan_test.go | 135 ++ internal/graph/extract_spec.go | 15 +- internal/graph/incremental.go | 2 + internal/graph/model.go | 13 +- internal/paths/paths.go | 19 + internal/plan/adr.go | 267 ++++ internal/plan/adr_test.go | 259 ++++ internal/plan/approve.go | 51 + internal/plan/brief.go | 247 ++++ internal/plan/brief_test.go | 108 ++ internal/plan/load.go | 115 ++ internal/plan/model.go | 140 +++ internal/plan/parse.go | 258 ++++ internal/plan/parse_test.go | 250 ++++ internal/plan/planjson.go | 42 + internal/plan/runner.go | 437 +++++++ internal/plan/runner_exec.go | 210 ++++ internal/plan/runner_test.go | 296 +++++ internal/plan/sandbox.go | 269 ++++ internal/plan/sandbox_test.go | 150 +++ internal/plan/seq.go | 260 ++++ internal/plan/seq_test.go | 157 +++ internal/plan/status.go | 192 +++ internal/plan/status_test.go | 179 +++ internal/plan/validate.go | 436 +++++++ internal/plan/validate_test.go | 201 +++ .../templates/commands/csdd-plan-run.md.tmpl | 23 + .../commands/csdd-plan-status.md.tmpl | 13 + .../commands/csdd-plan-validate.md.tmpl | 11 + .../templates/commands/glossary.md.tmpl | 22 + .../templater/templates/commands/prd.md.tmpl | 29 + .../templater/templates/plan/plan.md.tmpl | 64 + .../templates/root/knowledge-section.md.tmpl | 40 + .../templates/sandbox/Dockerfile.tmpl | 36 + .../sandbox/allowed-domains.txt.tmpl | 36 + .../templates/sandbox/devcontainer.json.tmpl | 25 + .../templates/sandbox/init-firewall.sh.tmpl | 62 + .../templates/skills/glossary/SKILL.md.tmpl | 109 ++ .../templates/skills/prd/SKILL.md.tmpl | 177 +++ .../templates/skills/quick-prd/SKILL.md.tmpl | 25 + .../templates/skills/wiki/SKILL.md.tmpl | 3 + internal/web/frontend/src/App.tsx | 6 +- internal/web/frontend/src/api.ts | 12 +- .../web/frontend/src/components/PlansView.tsx | 181 +++ internal/web/frontend/src/styles.css | 49 + internal/web/frontend/src/types.ts | 42 + internal/web/handlers.go | 16 + internal/web/plans.go | 142 +++ internal/web/plans_test.go | 105 ++ 77 files changed, 11441 insertions(+), 14 deletions(-) create mode 100644 docs/adr/0001-decision-records-storage.md create mode 100644 docs/adr/0002-two-tier-interview.md create mode 100644 docs/adr/0003-glossary-deferred.md create mode 100644 docs/glossary.md create mode 100644 docs/plans/PLAN-decision-records.md create mode 100644 docs/plans/PLAN-glossary.md create mode 100644 docs/plans/PLAN-knowledge-base.md create mode 100644 docs/plans/PLAN-plan-mode.md create mode 100644 internal/cli/glossary_cli_test.go create mode 100644 internal/cli/plan.go create mode 100644 internal/cli/plan_adr_test.go create mode 100644 internal/cli/plan_bridge_cli_test.go create mode 100644 internal/cli/plan_cli_test.go create mode 100644 internal/cli/plan_e2e_test.go create mode 100644 internal/cli/plan_skill_test.go create mode 100644 internal/cli/sandbox.go create mode 100644 internal/cli/sandbox_cli_test.go create mode 100644 internal/glossary/glossary.go create mode 100644 internal/glossary/glossary_test.go create mode 100644 internal/graph/extract_adr.go create mode 100644 internal/graph/extract_adr_test.go create mode 100644 internal/graph/extract_glossary.go create mode 100644 internal/graph/extract_glossary_test.go create mode 100644 internal/graph/extract_plan.go create mode 100644 internal/graph/extract_plan_test.go create mode 100644 internal/plan/adr.go create mode 100644 internal/plan/adr_test.go create mode 100644 internal/plan/approve.go create mode 100644 internal/plan/brief.go create mode 100644 internal/plan/brief_test.go create mode 100644 internal/plan/load.go create mode 100644 internal/plan/model.go create mode 100644 internal/plan/parse.go create mode 100644 internal/plan/parse_test.go create mode 100644 internal/plan/planjson.go create mode 100644 internal/plan/runner.go create mode 100644 internal/plan/runner_exec.go create mode 100644 internal/plan/runner_test.go create mode 100644 internal/plan/sandbox.go create mode 100644 internal/plan/sandbox_test.go create mode 100644 internal/plan/seq.go create mode 100644 internal/plan/seq_test.go create mode 100644 internal/plan/status.go create mode 100644 internal/plan/status_test.go create mode 100644 internal/plan/validate.go create mode 100644 internal/plan/validate_test.go create mode 100644 internal/templater/templates/commands/csdd-plan-run.md.tmpl create mode 100644 internal/templater/templates/commands/csdd-plan-status.md.tmpl create mode 100644 internal/templater/templates/commands/csdd-plan-validate.md.tmpl create mode 100644 internal/templater/templates/commands/glossary.md.tmpl create mode 100644 internal/templater/templates/commands/prd.md.tmpl create mode 100644 internal/templater/templates/plan/plan.md.tmpl create mode 100644 internal/templater/templates/sandbox/Dockerfile.tmpl create mode 100644 internal/templater/templates/sandbox/allowed-domains.txt.tmpl create mode 100644 internal/templater/templates/sandbox/devcontainer.json.tmpl create mode 100644 internal/templater/templates/sandbox/init-firewall.sh.tmpl create mode 100644 internal/templater/templates/skills/glossary/SKILL.md.tmpl create mode 100644 internal/templater/templates/skills/prd/SKILL.md.tmpl create mode 100644 internal/web/frontend/src/components/PlansView.tsx create mode 100644 internal/web/plans.go create mode 100644 internal/web/plans_test.go diff --git a/docs/adr/0001-decision-records-storage.md b/docs/adr/0001-decision-records-storage.md new file mode 100644 index 0000000..3bd9438 --- /dev/null +++ b/docs/adr/0001-decision-records-storage.md @@ -0,0 +1,3 @@ +# Store decision records under docs/adr/ with an adr: citation token + +**Context.** Every load-bearing decision except technology had three destinations, all of which rot: "Context and vision" prose the parser ignores, `[ASSUMPTION]` markers nothing forces resolving, or nowhere at all — so the *why* never travelled with the *what* into specs and runner sessions. **Decision.** Decision records live in project-scoped `docs/adr/NNNN-.md` (append-only, one flat sequence, like `docs/stack.md`), and feats cite them with a third ref token, `adr:`, tokenized and linted beside `stack:` and `[[wiki]]`. **Why.** Reusing the proven stack-ref machinery (tokenize → validate → inline into the brief) makes hand-written ADRs first-class before any skill ships, and a lintable citation is what a plain `NNNN-slug.md` file alone lacks; the rejected alternatives — a wiki page (prose, not a contract) and a plan-scoped record (invisible to sibling plans) — both recreate the drift this feature removes. diff --git a/docs/adr/0002-two-tier-interview.md b/docs/adr/0002-two-tier-interview.md new file mode 100644 index 0000000..ee93dcb --- /dev/null +++ b/docs/adr/0002-two-tier-interview.md @@ -0,0 +1,3 @@ +# Draft interviews in two tiers — batch scope facts, grill decisions + +**Context.** The prd skill's Draft used one batched multiple-choice interview ("1B, 2A, 3C") optimized for speed, which bundles load-bearing decisions in with scope facts so they pass undiscussed; pure one-at-a-time grilling (the studied grilling skill) is the opposite failure — it makes cheap scope facts as expensive as real decisions. **Decision.** Draft runs two tiers: the existing batched lettered multiple-choice for scope facts, then a sequential Decision grill (one decision per exchange, recommendation first, dependency order, ADR written inline) for every candidate that passes the triple gate. **Why.** csdd's batch already beats grilling for facts and grilling already beats batch for decisions, so splitting on the triple gate takes the strength of each; the grill applies only to the 2–5 gate-positive decisions a typical initiative carries, bounding the interview cost that killed pure grilling. diff --git a/docs/adr/0003-glossary-deferred.md b/docs/adr/0003-glossary-deferred.md new file mode 100644 index 0000000..59cfab6 --- /dev/null +++ b/docs/adr/0003-glossary-deferred.md @@ -0,0 +1,3 @@ +# Defer the glossary / ubiquitous language to its own phase + +**Context.** domain-modeling bundles a `CONTEXT.md` glossary (ubiquitous language, canonical entity aliases) with its ADR discipline, and it was tempting to ship both under the decision-records feature. **Decision.** The glossary is deferred to its own phase (`docs/plans/PLAN-glossary.md`) rather than folded into decision-records. **Why.** The glossary's real value is the canonical/alias entity table feeding the knowledge-base graph extractor, so it must be designed *with* the graph — a different seam than the plan-grammar/validate/brief seams this feature touches; conflating the two would widen this feature's blast radius for no shared machinery. This is the explicit "no" — the deferral is a decision, not an omission — and PLAN-glossary is the phase that resolves it. diff --git a/docs/glossary.md b/docs/glossary.md new file mode 100644 index 0000000..85532c6 --- /dev/null +++ b/docs/glossary.md @@ -0,0 +1,52 @@ +# Glossary — csdd's ubiquitous language + +This is the project's **ubiquitous-language contract**: one canonical term per +domain concept, defined as what it **is**, with an `_Avoid_` list of the synonyms +it bans. Identifiers (feat slugs, spec directories, wiki page names) are minted +from canonical terms; `csdd plan validate`, `csdd graph analyze`, and +`csdd wiki lint` report an avoided term used as a whole token. Prose outside the +`## Language` section is ignored by the parser. + +## Language + +### Planning + +**Plan**: The structured document above specs (`docs/plans//`) that +decomposes an initiative into feats; each feat becomes exactly one spec. +_Avoid_: prd, epic + +**Feat**: One row of a plan's Feats table — a spec-sized chunk of work with an +explicit objective, dependencies, and refs; it becomes exactly one spec. +_Avoid_: feature, story, ticket + +**Spec**: The per-feature contract under `specs//` (requirements, design, +tasks) that a feat is realized as. +_Avoid_: specification-doc + +**Seed**: A pre-authored artifact under a plan's `seeds//` that hands the +eventual spec a head start. + +**Brief**: The deterministic context pack `csdd plan brief` assembles for one run +step — the feat, its refs, decisions, and the step contract. + +### Contracts + +**Quality Gate**: A `-