ddduck 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +125 -0
  3. package/docs/architecture.md +77 -0
  4. package/docs/cli.md +239 -0
  5. package/docs/getting-started.md +98 -0
  6. package/docs/model-reference.md +92 -0
  7. package/docs/model.md +75 -0
  8. package/package.json +76 -0
  9. package/policies/concept-owner-domain.yaml +8 -0
  10. package/policies/documentation-model-reference-resolution.yaml +8 -0
  11. package/policies/no-dangling-model-reference.yaml +8 -0
  12. package/policies/policy-spec.schema.json +23 -0
  13. package/schemas/context-pack.schema.json +83 -0
  14. package/schemas/fr-to-code-audit.schema.json +85 -0
  15. package/schemas/product/concept.schema.json +17 -0
  16. package/schemas/product/domain-interface.schema.json +18 -0
  17. package/schemas/product/domain.schema.json +24 -0
  18. package/schemas/product/evidence-anchor.schema.json +30 -0
  19. package/schemas/product/guarantee.schema.json +35 -0
  20. package/schemas/product/model.schema.json +20 -0
  21. package/schemas/product/relationship.schema.json +21 -0
  22. package/schemas/product/use-case.schema.json +27 -0
  23. package/scripts/audit-fr-to-code.mjs +162 -0
  24. package/scripts/check-generated-docs.mjs +58 -0
  25. package/scripts/check-generated-graph-svg.mjs +60 -0
  26. package/scripts/check-generated-graph.mjs +66 -0
  27. package/scripts/check-model.mjs +488 -0
  28. package/scripts/ddduck.mjs +542 -0
  29. package/scripts/generate-agent-readiness-report.mjs +23 -0
  30. package/scripts/generate-docs.mjs +205 -0
  31. package/scripts/generate-graph-svg.mjs +359 -0
  32. package/scripts/generate-graph.mjs +268 -0
  33. package/scripts/lib/agent-readiness-evals.mjs +433 -0
  34. package/scripts/lib/agent-readiness-report.mjs +79 -0
  35. package/scripts/lib/cli-contract.mjs +162 -0
  36. package/scripts/lib/context-pack.mjs +107 -0
  37. package/scripts/lib/ddduck-config.mjs +57 -0
  38. package/scripts/lib/fr-to-code-audit.mjs +144 -0
  39. package/scripts/lib/product-layout.mjs +93 -0
  40. package/scripts/lib/product-operation.mjs +431 -0
  41. package/scripts/lib/product-paths.mjs +43 -0
  42. package/scripts/lib/product-query.mjs +284 -0
  43. package/scripts/lib/product-root-resolver.mjs +167 -0
  44. package/scripts/lib/scan-ignore.mjs +8 -0
  45. package/scripts/lib/skill-installer.mjs +410 -0
  46. package/scripts/query-model.mjs +64 -0
  47. package/scripts/run-agent-readiness-evals.mjs +57 -0
  48. package/skills/update-ddduck-specs/SKILL.md +98 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 diegomarino
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,125 @@
1
+ # ddduck
2
+
3
+ ddduck defines a small, machine-readable product-spec format. The framework keeps
4
+ schemas, validators, policies, and generators separate from each consumer product.
5
+
6
+ Start with [the getting-started guide](docs/getting-started.md) for a working first product.
7
+ Then use [the model guide](docs/model.md), [the model reference](docs/model-reference.md),
8
+ [the CLI reference](docs/cli.md), and [the architecture guide](docs/architecture.md) as needed.
9
+
10
+ ## Model graph
11
+
12
+ Every product renders to a verified graph of its model — the ownership spine
13
+ (Model → Domain → members), reference edges, and a legend decoding shapes and
14
+ line styles. `ddduck generate` produces it as a deterministic SVG. This
15
+ framework's own model:
16
+
17
+ ![ddduck model graph: the framework's Model, its Domains and owned Concepts, Interfaces, Guarantees, and Use Cases, with a legend](https://raw.githubusercontent.com/diegomarino/ddduck/main/docs/ddd/generated/graph/model-graph.svg)
18
+
19
+ ## Product layout
20
+
21
+ A consumer product owns one product root. Documentation-centric repositories can use `docs/ddd/`;
22
+ small or dedicated product repositories can use `ddd/`:
23
+
24
+ ```text
25
+ docs/ddd/
26
+ product.yaml
27
+ model/
28
+ domains/
29
+ concepts/
30
+ relationships/
31
+ use-cases/
32
+ interfaces/
33
+ guarantees/
34
+ decisions/
35
+ generated/
36
+ docs/
37
+ graph/
38
+ ```
39
+
40
+ `product.yaml` and files under `model/` are canonical source. `generated/` is derived
41
+ output: never edit it by hand.
42
+
43
+ Repository-local ddduck tool metadata lives outside the product root in `.ddduck/`. For example,
44
+ this framework repository stores its own model in `docs/ddd/` and records that selection in:
45
+
46
+ ```json
47
+ {
48
+ "schemaVersion": "1",
49
+ "productRoot": "docs/ddd",
50
+ "ignore": ["vendor", "target", "build", "dist", "__pycache__"]
51
+ }
52
+ ```
53
+
54
+ `ignore` lists directory names the scanners skip on top of the always-ignored
55
+ dot-directories and `node_modules`; it is written pre-filled by `ddduck init`
56
+ and fully editable (see [the CLI reference](docs/cli.md)).
57
+
58
+ ## Authoring
59
+
60
+ Install the CLI from npm:
61
+
62
+ ```bash
63
+ npm install -g ddduck
64
+ ```
65
+
66
+ Or run it from a local checkout for contributing (`npm install`, then `npm link` or
67
+ `node <checkout>/scripts/ddduck.mjs` — see
68
+ [Install ddduck](docs/getting-started.md#install-ddduck)). Create a product root with:
69
+
70
+ ```bash
71
+ ddduck init ddd --id model:<product-id>
72
+ ```
73
+
74
+ `--root <path>` is always the explicit override; without it, ddduck resolves the enclosing
75
+ product root, then `.ddduck/config.json`, then a unique repository candidate, and fails with a
76
+ diagnostic when the choice is ambiguous. The mutation surface is deliberately narrow — `check`,
77
+ `generate`, and the `create`/`move`/`split`/`retire` Guarantee lifecycle commands — and every
78
+ successful source mutation regenerates the derived views. The canonical resolution rules and
79
+ command contracts live in [the CLI reference](docs/cli.md#product-root-resolution).
80
+
81
+ YAML remains the normal human-authored source format, with `ddduck check` as the deterministic
82
+ safety net.
83
+
84
+ ## Agent skill
85
+
86
+ Install the evidence-backed model maintenance skill in a consumer repository:
87
+
88
+ ```bash
89
+ ddduck install skill update-ddduck-specs --repo <repository-root>
90
+ ```
91
+
92
+ `--repo` defaults to the current directory. See [the CLI reference](docs/cli.md#install-an-agent-skill)
93
+ for the installed layout, host invocation, and plan-only behavior.
94
+
95
+ ## Product queries
96
+
97
+ The bounded read API — `ddduck query node|neighbors|impact|anchors|spec|context` — emits JSON
98
+ only (`--json` is optional and a no-op) and never writes source or generated output. Default
99
+ queries expose only active Guarantees; pass `--history` to read a retired or split Guarantee's
100
+ historical record instead of its lifecycle redirect. The full query table and response contract
101
+ live in [the CLI reference](docs/cli.md#queries).
102
+
103
+ ### Bounded context packs
104
+
105
+ `ddduck query context` is the agent-facing bounded read for an explicit selection: full
106
+ canonical records for the selected IDs, every direct edge that touches them, one-hop perimeter
107
+ summaries, and a SHA-256 `sourceDigest` identifying the source snapshot — authoritative only
108
+ for reads that did not race a mutation. Its boundaries and refusal rules are documented in
109
+ [the CLI reference](docs/cli.md#queries); responses conform to
110
+ [`schemas/context-pack.schema.json`](schemas/context-pack.schema.json).
111
+
112
+ ## Agent-readiness evals
113
+
114
+ Maintainer surface: see
115
+ [Agent-readiness evals in the development guide](https://github.com/diegomarino/ddduck/blob/main/docs/development.md#agent-readiness-evals).
116
+
117
+ ## Revision-scoped FR-to-code audits
118
+
119
+ Maintainer surface: see
120
+ [Revision-scoped FR-to-code audits in the development guide](https://github.com/diegomarino/ddduck/blob/main/docs/development.md#revision-scoped-fr-to-code-audits).
121
+
122
+ ## Framework contracts
123
+
124
+ Global `PolicySpec` declarations live in `policies/`, outside any product graph: see
125
+ [Framework contracts in the development guide](https://github.com/diegomarino/ddduck/blob/main/docs/development.md#framework-contracts).
@@ -0,0 +1,77 @@
1
+ # Architecture
2
+
3
+ ddduck keeps product facts separate from framework contracts. Canonical product YAML is the
4
+ source of truth. Schemas, policies, validation, generation, and query code interpret that source;
5
+ they do not become product nodes. Generated views flow outward and are never canonical input.
6
+
7
+ ```mermaid
8
+ flowchart LR
9
+ subgraph Product[Selected product root]
10
+ Source[product.yaml and model YAML]
11
+ Decisions[decisions]
12
+ Derived[generated views]
13
+ end
14
+ subgraph Framework[ddduck framework]
15
+ Schemas[Schemas and policies]
16
+ Check[Validation]
17
+ Generate[Generators]
18
+ Query[JSON query]
19
+ end
20
+ Source --> Check
21
+ Decisions --> Check
22
+ Schemas --> Check
23
+ Check --> Generate
24
+ Generate --> Derived
25
+ Source --> Query
26
+ Decisions --> Query
27
+ ```
28
+
29
+ ## Authoring and verification
30
+
31
+ After manual canonical YAML edits, authors validate source with `ddduck check --source-only`, run
32
+ `ddduck generate`, then run default `ddduck check`. Default `check` verifies source and that
33
+ required generated views are fresh, so it cannot precede generation after a source edit.
34
+
35
+ ```mermaid
36
+ flowchart LR
37
+ Edit[Author canonical YAML] --> SourceCheck[ddduck check --source-only]
38
+ SourceCheck -->|valid| Generate[ddduck generate]
39
+ SourceCheck -->|invalid| Fix[Fix diagnostics]
40
+ Generate --> FreshCheck[ddduck check]
41
+ FreshCheck --> Views[Fresh Markdown and graph views]
42
+ Fix --> Edit
43
+ ```
44
+
45
+ ## Staged lifecycle mutation
46
+
47
+ Guarantee mutations run against a contained staging copy. The CLI validates the complete staged
48
+ product and regenerated views before publication. A rejected operation publishes no intended
49
+ canonical or generated change; filesystem interruption beyond that tested boundary is a recovery
50
+ concern, not a database transaction guarantee.
51
+
52
+ ```mermaid
53
+ flowchart LR
54
+ Request[create move split or retire] --> Lock[Acquire product lock]
55
+ Lock --> Stage[Copy canonical source to staging]
56
+ Stage --> Validate[Transform, validate, generate]
57
+ Validate -->|valid| Publish[Publish canonical and generated views]
58
+ Validate -->|invalid| Cleanup[Discard staging and release lock]
59
+ Publish --> Release[Release lock and report result]
60
+ ```
61
+
62
+ ## Query boundary
63
+
64
+ Queries are read-only and require `--json`. A context query returns selected canonical records,
65
+ direct touching edges, one-hop summaries for unselected neighbors, and a source digest. It does
66
+ not recursively expand context or write canonical or generated files.
67
+
68
+ ```mermaid
69
+ sequenceDiagram
70
+ participant Caller
71
+ participant CLI as ddduck query
72
+ participant Product as Canonical product root
73
+ Caller->>CLI: query context --id ... --root ... --json
74
+ CLI->>Product: Load and resolve selected source
75
+ CLI-->>Caller: Selected records, edges, summaries, digest
76
+ Note over CLI,Caller: No source or generated output is written
77
+ ```
package/docs/cli.md ADDED
@@ -0,0 +1,239 @@
1
+ # CLI reference
2
+
3
+ `ddduck` operates on a selected product root. Run `ddduck --help`, or pass `--help` anywhere
4
+ after a command name (including `ddduck <command> <subcommand> --help`), for the built-in usage
5
+ lines. Option values may be written as `--option value` or `--option=value`; a value that begins
6
+ with `--` must use the `--option=value` form. Every command rejects unknown options, duplicate
7
+ options, missing option values, and unexpected positional arguments. Expected failures write a
8
+ concise diagnostic (multi-error validation reports keep one line per error) plus a safe next
9
+ action to standard error and exit nonzero; errors without a specific next action fall back to a
10
+ command-specific hint. Help exits zero.
11
+
12
+ ## Product root resolution
13
+
14
+ Product-facing commands accept `--root <product-root>`. When `--root` is omitted, ddduck resolves
15
+ the root in this order:
16
+
17
+ 1. An enclosing product root found by walking upward from the current directory.
18
+ 2. `.ddduck/config.json` `productRoot`, when present and the current directory is not inside a
19
+ product root.
20
+ 3. A unique primary `product.yaml` candidate under the repository boundary.
21
+ 4. A relevant example candidate only when no primary candidate exists.
22
+
23
+ Discovery admits a candidate by shape — a ddduck `product.yaml` with a sibling `model/`
24
+ directory — not by full validation, so a broken product still resolves and the command's own
25
+ validation reports its errors. Discovery excludes `.git/`, `.ddduck/`, `node_modules/`,
26
+ `generated/`, `.superpowers/`, `.worktrees/`, `.ddduck-init-stage-*` staging left by an
27
+ interrupted `init` (the next `init` of the same destination sweeps that debris; staging for
28
+ other destinations is never touched), and test fixtures. Multiple
29
+ viable primary roots
30
+ fail and ask for `--root`, listing every candidate and flagging any that fail validation; the
31
+ resolver never uses an arbitrary first match.
32
+
33
+ Use `.ddduck/config.json` for a repository default:
34
+
35
+ ```json
36
+ {
37
+ "schemaVersion": "1",
38
+ "productRoot": "docs/ddd",
39
+ "ignore": ["vendor", "target", "build", "dist", "__pycache__"]
40
+ }
41
+ ```
42
+
43
+ `ignore` lists extra directory names (basenames only, no globs) that
44
+ every ddduck scanner skips, in addition to the always-skipped dot-directories
45
+ and `node_modules`. Omit the key to accept the defaults shown above; set it to
46
+ `[]` to skip nothing beyond the built-in defaults. `ddduck init` writes this
47
+ file pre-filled when it does not already exist.
48
+
49
+ ## Install an agent skill
50
+
51
+ ```text
52
+ ddduck install skill update-ddduck-specs [--repo <repository-root>]
53
+ ```
54
+
55
+ `--repo` defaults to the current directory. The installer chooses the least intrusive host
56
+ topology from the repository's existing directories:
57
+
58
+ ```text
59
+ no .agents/ or .claude/ -> .agents/skills/update-ddduck-specs/SKILL.md
60
+ .agents/ only -> .agents/skills/update-ddduck-specs/SKILL.md
61
+ .claude/ only -> .claude/skills/update-ddduck-specs/SKILL.md
62
+ .agents/ and .claude/ -> .agents/skills/update-ddduck-specs/SKILL.md
63
+ .claude/skills/update-ddduck-specs -> ../../.agents/skills/update-ddduck-specs
64
+ ```
65
+
66
+ The installer writes `.ddduck/agent-skills.lock.json` with the selected canonical path, host
67
+ adapters, package version, and installed `SKILL.md` SHA-256. It does not create a host directory
68
+ for a host that is absent from the repository, except for the `.agents/` fallback when no host
69
+ directory exists. On success it prints one result line naming the action (`created`, `upgraded`,
70
+ or `no-op`), the repository, the canonical skill path, and the lock path. It does not accept
71
+ `--json`.
72
+
73
+ Invoke the skill from the relevant host:
74
+
75
+ ```text
76
+ Codex: $update-ddduck-specs
77
+ Claude: /update-ddduck-specs
78
+ ```
79
+
80
+ The skill defaults to plan-only; changing a product model requires explicit apply authorization.
81
+ Its workflow behavior is defined by the installed `SKILL.md` (and its packaged
82
+ [canonical source](../skills/update-ddduck-specs/SKILL.md)).
83
+
84
+ This package is published to npm as `ddduck`; install the CLI globally with `npm install -g ddduck`
85
+ (see [the getting-started guide](getting-started.md#install-ddduck)).
86
+
87
+ ## Common behavior
88
+
89
+ Product writes are `init`, `generate`, `create`, `move`, `split`, and `retire`; successful
90
+ mutations regenerate all required views. `check` and every `query` are read-only. A successful
91
+ `check` is silent. Successful product mutations print one concise result line, or one JSON result
92
+ object when `--json` is available.
93
+
94
+ ## `init`
95
+
96
+ ```text
97
+ ddduck init [destination] --id model:<product-id> [--json]
98
+ ```
99
+
100
+ | Option or argument | Required | Default | Meaning |
101
+ | ------------------ | -------- | ----------------------------- | ------------------------------------------------- |
102
+ | `destination` | no | config, then `ddd/` directory | Empty directory to create as the product root. |
103
+ | `--id` | yes | none | Root Model ID, matching `model:<lowercase-slug>`. |
104
+ | `--json` | no | false | Emit one JSON result object instead of text. |
105
+
106
+ `init` writes the canonical directory layout, `product.yaml`, and fresh generated docs and graph
107
+ views. It refuses a non-empty destination. On success it reports the Model ID, normalized root,
108
+ `product.yaml`, and all generated paths as one text line or, with `--json`, one object containing
109
+ `operation`, `root`, `affectedIds`, `canonicalPaths`, and `generatedPaths`. On failure it exits
110
+ nonzero without reporting success.
111
+
112
+ ## `check`
113
+
114
+ ```text
115
+ ddduck check [--root <product-root>] [--base <previous-product-root>] \
116
+ [--docs-root <docs-root> ...] [--source-only]
117
+ ```
118
+
119
+ | Option | Default | Meaning |
120
+ | --------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------- |
121
+ | `--root` | resolved root | Product root to validate. |
122
+ | `--base` | none | Previous product root used to check historical Guarantee retention. |
123
+ | `--docs-root` | product root | Directory scanned for documentation references; repeatable. Passing it replaces the default product-root scope. |
124
+ | `--source-only` | false | Validate canonical source only; skip derived-view freshness checks and skip documentation references inside `generated/`. |
125
+
126
+ By default, `check` validates canonical source, then requires fresh generated Markdown and graph
127
+ views. Documentation references are validated only inside the product root; pass one or more
128
+ `--docs-root` directories to widen (and replace) that scope, mirroring the framework's own
129
+ repository-wide gate. It writes nothing and is quiet on success. It exits nonzero for invalid source, stale
130
+ views, invalid roots, invalid options, a busy root (`.ddduck-operation.lock` held by a live
131
+ ddduck operation), or leftover state from an interrupted operation
132
+ (`.ddduck-operation.lock`, `.ddduck-operation.reclaim`, or `.ddduck-operation-stage-*` with no
133
+ live owning process); running any mutation, such as `ddduck generate`, reclaims that leftover
134
+ state.
135
+
136
+ ## `generate`
137
+
138
+ ```text
139
+ ddduck generate [--root <product-root>] [--json]
140
+ ```
141
+
142
+ | Option | Default | Meaning |
143
+ | -------- | ------------- | --------------------------------------------------------------------- |
144
+ | `--root` | resolved root | Product root to validate and regenerate. |
145
+ | `--json` | false | Emit one JSON mutation-result object instead of the text result line. |
146
+
147
+ `generate` validates canonical source before writing `generated/docs/model-overview.md`,
148
+ `generated/graph/model-graph.json`, and `generated/graph/model-graph.ndjson`. A successful text
149
+ result identifies the root, canonical paths (none for generate), and generated paths. It exits
150
+ nonzero without an intended product mutation if validation or contained-output checks fail.
151
+
152
+ ## Guarantee mutations
153
+
154
+ All mutation results identify the selected root, affected Guarantee IDs, canonical paths, and
155
+ fresh generated paths. Append `--json` to any command below for one JSON result object.
156
+
157
+ ### `create guarantee`
158
+
159
+ ```text
160
+ ddduck create guarantee --origin <origin> --classification <invariant|acceptance-criterion> \
161
+ --owner <domain-id> --statement <text> [--root <product-root>] [--json]
162
+ ```
163
+
164
+ `--origin`, `--classification`, `--owner`, and `--statement` are required. The root is resolved
165
+ through the common product-root rules. `create` allocates the next stable ID for the origin and
166
+ classification, writes its canonical Guarantee YAML, updates the owning Domain, and regenerates
167
+ views. It exits nonzero if the owner is unknown or any input or staged product is invalid.
168
+
169
+ ### `move guarantee`
170
+
171
+ ```text
172
+ ddduck move guarantee <guarantee-id> --to <domain-id> [--root <product-root>] [--json]
173
+ ```
174
+
175
+ `<guarantee-id>` and `--to` are required. `move` requires an active Guarantee and an existing
176
+ destination Domain. It changes ownership, records the prior owner in `ownershipHistory`, updates
177
+ both Domain records, and regenerates views. It exits nonzero without an intended mutation when
178
+ the Guarantee is inactive, missing, already owned by the destination, or the staged product fails.
179
+
180
+ ### `split guarantee`
181
+
182
+ ```text
183
+ ddduck split guarantee <guarantee-id> --into <successor-id[,successor-id ...]> \
184
+ --decision ADR-NNN [--root <product-root>] [--json]
185
+ ```
186
+
187
+ `<guarantee-id>`, `--into`, and `--decision` are required. `--into` accepts one or more distinct
188
+ active successor IDs; the decision must resolve in the product decision registry.
189
+ `split` preserves the source ID, marks it `split`, records its successors and lifecycle decision,
190
+ then regenerates views. It exits nonzero without an intended mutation if an active UseCase or
191
+ DomainInterface would retain a reference to the non-effective Guarantee.
192
+
193
+ ### `retire guarantee`
194
+
195
+ ```text
196
+ ddduck retire guarantee <guarantee-id> --decision ADR-NNN [--root <product-root>] [--json]
197
+ ```
198
+
199
+ `<guarantee-id>` and `--decision` are required. `retire` requires an active Guarantee and a
200
+ registered decision, marks the Guarantee `retired`, records `lifecycleDecision`, and regenerates
201
+ views. The same active UseCase and DomainInterface safety gate applies. Invalid input or a failed
202
+ staged validation exits nonzero without an intended mutation.
203
+
204
+ ## Queries
205
+
206
+ Every query emits exactly one JSON document and writes no source or generated output. While a
207
+ live ddduck mutation holds `.ddduck-operation.lock`, queries and `check` fail with a busy
208
+ diagnostic instead of reading a partially published snapshot. A read racing the very start of a
209
+ mutation, before the lock exists, may still observe a partial snapshot, so `sourceDigest` is
210
+ authoritative only for reads that did not race a mutation. JSON is
211
+ the only output format, so `--json` is optional and accepted as a no-op for compatibility. The
212
+ document contains `schemaVersion`, `query`, `rootModelId`, `result`, and
213
+ `diagnostics`. Non-context query roots are resolved through the common product-root rules.
214
+ `context` requires an explicit `--root`. Non-context queries accept optional `--history`; without it, a split or retired
215
+ Guarantee resolves to its lifecycle redirect rather than its historical contract.
216
+
217
+ ```mermaid
218
+ sequenceDiagram
219
+ participant Caller
220
+ participant CLI as ddduck query
221
+ participant Model as Canonical product root
222
+ Caller->>CLI: query context --id ... --root ... --json
223
+ CLI->>Model: Load and resolve selected source
224
+ CLI-->>Caller: Full selection, direct edges, summaries, digest
225
+ Note over CLI,Caller: Read-only; no source or generated output is written
226
+ ```
227
+
228
+ | Command | Required options | Result |
229
+ | -------------------------------------------------------------------------- | ---------------- | ----------------------------------------------------------------------- |
230
+ | `ddduck query node --id <id> [--root <root>] [--history] [--json]` | `--id` | Full canonical node and product-relative source path. |
231
+ | `ddduck query neighbors --id <id> [--root <root>] [--history] [--json]` | `--id` | Deterministically sorted incoming and outgoing edges. |
232
+ | `ddduck query impact --id <id> [--root <root>] [--history] [--json]` | `--id` | Reverse impact closure over ownership and behavioral references. |
233
+ | `ddduck query anchors --id <id> [--root <root>] [--history] [--json]` | `--id` | Evidence, reachable decisions, policies, and view freshness. |
234
+ | `ddduck query spec [--id <model-id>] [--root <root>] [--history] [--json]` | none | Root, domains, view freshness, and verification commands. |
235
+ | `ddduck query context --id <id> [--id <id> ...] --root <root> [--json]` | `--id`, `--root` | Selected records, touching edges, one-hop summaries, and source digest. |
236
+
237
+ `context` accepts one or more distinct, repeatable `--id` options; it rejects `--history`.
238
+ Its selected records are complete, while unselected endpoints appear only as one-hop summaries.
239
+ The command does not recursively expand the perimeter.
@@ -0,0 +1,98 @@
1
+ # Getting started
2
+
3
+ This executable journey creates a product with one Domain, one Concept, and one Guarantee.
4
+
5
+ ## Install ddduck
6
+
7
+ Install the published CLI globally from npm:
8
+
9
+ ```sh
10
+ npm install -g ddduck
11
+ ddduck --help
12
+ ```
13
+
14
+ To contribute or run an unreleased revision, work from a local checkout instead. Either put the
15
+ `ddduck` bin on `PATH` with `npm link`:
16
+
17
+ ```sh
18
+ git clone <ddduck-repository-url> ddduck
19
+ cd ddduck
20
+ npm install
21
+ npm link
22
+ ddduck --help
23
+ ```
24
+
25
+ or skip linking and invoke the CLI directly from the checkout:
26
+
27
+ ```sh
28
+ node <checkout>/scripts/ddduck.mjs --help
29
+ ```
30
+
31
+ ## Create the first product
32
+
33
+ Run the complete Bash block from an empty working directory with `ddduck` on `PATH`.
34
+
35
+ ```mermaid
36
+ flowchart LR
37
+ Source[Manual canonical YAML edit] --> SourceCheck[ddduck check --source-only]
38
+ SourceCheck -->|valid| Generate[ddduck generate]
39
+ SourceCheck -->|invalid| Diagnostic[Actionable diagnostic]
40
+ Generate --> FreshCheck[ddduck check]
41
+ FreshCheck --> Docs[Generated Markdown is fresh]
42
+ FreshCheck --> Graph[Generated graph is fresh]
43
+ ```
44
+
45
+ ```bash
46
+ ddduck init ddd --id model:library
47
+
48
+ cat > ddd/model/domains/catalog.yaml <<'YAML'
49
+ schemaVersion: "1"
50
+ kind: Domain
51
+ id: domain:catalog
52
+ model: model:library
53
+ name: Catalog
54
+ purpose: Organize the library catalog.
55
+ concepts:
56
+ - concept:book
57
+ interfaces: []
58
+ guarantees: []
59
+ YAML
60
+
61
+ cat > ddd/model/concepts/book.yaml <<'YAML'
62
+ schemaVersion: "1"
63
+ kind: Concept
64
+ id: concept:book
65
+ model: model:library
66
+ ownerDomain: domain:catalog
67
+ name: Book
68
+ purpose: Identify a catalogued book.
69
+ YAML
70
+
71
+ cat > ddd/product.yaml <<'YAML'
72
+ schemaVersion: "1"
73
+ kind: Model
74
+ id: model:library
75
+ name: library
76
+ purpose: Define the library product.
77
+ domains:
78
+ - domain:catalog
79
+ useCases: []
80
+ decisions: []
81
+ YAML
82
+
83
+ ddduck check --root ddd --source-only
84
+ ddduck generate --root ddd
85
+ ddduck check --root ddd
86
+ ddduck create guarantee --origin catalog --classification invariant \
87
+ --owner domain:catalog --statement "A Book has a stable catalog identity." --root ddd
88
+ ddduck query spec --root ddd --json
89
+ ```
90
+
91
+ Default `check` requires both valid canonical source and fresh generated views. After a manual
92
+ source edit, use `check --source-only`, run `generate`, then use default `check`. Do not edit
93
+ `generated/` by hand.
94
+
95
+ The successful `create` allocates the first catalog invariant serial, adds it to the Domain, and
96
+ refreshes all generated views. The final query emits one JSON document suitable for a tool or
97
+ agent. See the [model reference](model-reference.md) before adding other node kinds, and use the
98
+ [CLI reference](cli.md) for the complete command contracts.
@@ -0,0 +1,92 @@
1
+ # Model reference
2
+
3
+ Canonical YAML uses schema version `"1"`. IDs are lowercase, hyphenated after their structural
4
+ prefix, except stable Guarantee IDs and decision IDs such as `ADR-001`. A Guarantee ID is keyed
5
+ to its classification: `<ORIGIN>-INV-<serial>` for an `invariant`, `<ORIGIN>-AC-<serial>` for an
6
+ `acceptance-criterion`.
7
+ The checker requires exactly one Model root.
8
+
9
+ ## Model root
10
+
11
+ `product.yaml` is the only `Model` node. Unlike every child node, it has no `model` field.
12
+ Required fields are `schemaVersion`, `kind`, `id`, `name`, `purpose`, and `domains`. Optional
13
+ top-level fields include `nameStatus`, `useCases`, `relationships`, `decisions`, and `notes`.
14
+
15
+ ```yaml
16
+ schemaVersion: "1"
17
+ kind: Model
18
+ id: model:<product-slug>
19
+ name: A product name
20
+ purpose: Define the product.
21
+ domains:
22
+ - domain:<domain-slug>
23
+ useCases: []
24
+ decisions: []
25
+ ```
26
+
27
+ ## Child-node fields
28
+
29
+ All child nodes include `schemaVersion`, `kind`, `id`, and `model`. `model` must name the root
30
+ Model ID. `Domain`, `Concept`, and `DomainInterface` respectively use `domain:`, `concept:`, and
31
+ `interface:` IDs. A child owned by a Domain uses `ownerDomain`; the owning Domain must also list
32
+ the child in the matching collection.
33
+
34
+ ### Domain
35
+
36
+ Required: `name`, `purpose`. Optional owned lists: `concepts`, `excludedConcepts`, `interfaces`,
37
+ `guarantees`, and `decisions`.
38
+
39
+ ```yaml
40
+ schemaVersion: "1"
41
+ kind: Domain
42
+ id: domain:<domain-slug>
43
+ model: model:<product-slug>
44
+ name: A domain name
45
+ purpose: Describe the domain responsibility.
46
+ concepts: []
47
+ interfaces: []
48
+ guarantees: []
49
+ ```
50
+
51
+ ### Concept
52
+
53
+ Required: `ownerDomain`, `name`, `purpose`. Optional: `decisions`.
54
+
55
+ ```yaml
56
+ schemaVersion: "1"
57
+ kind: Concept
58
+ id: concept:<concept-slug>
59
+ model: model:<product-slug>
60
+ ownerDomain: domain:<domain-slug>
61
+ name: A concept name
62
+ purpose: Describe the concept responsibility.
63
+ ```
64
+
65
+ ### Relationship
66
+
67
+ Required: `from`, `to`, `relationshipType`, `mode`, and `ownedBy` (a Domain ID). Optional:
68
+ `description`, `constraints`, and `decisions`.
69
+
70
+ ### UseCase
71
+
72
+ Required: `name`, `goal`, `preconditions`, and `success`. `preconditions.requires` is required;
73
+ `success` requires `preserves` and `establishes` lists. Optional: `interfaces` and evidence
74
+ anchors.
75
+
76
+ ### DomainInterface
77
+
78
+ Required: `ownerDomain`, `name`, and `operationKind` (`command` or `query`). Optional:
79
+ `guarantees` and evidence anchors.
80
+
81
+ ### Guarantee
82
+
83
+ Required: `ownerDomain`, `classification` (`invariant` or `acceptance-criterion`), `statement`,
84
+ and `status` (`active`, `split`, or `retired`). A split or retired Guarantee also requires a
85
+ `lifecycleDecision`; a split Guarantee names active `successors`. Optional `ownershipHistory`
86
+ records former owning Domains. Evidence anchors are also supported.
87
+
88
+ Evidence anchors contain a product-relative `path`, `anchor`, and `role` (`source`, `decision`,
89
+ or `verification`). The path must resolve to a regular file inside the selected product root.
90
+
91
+ For full schema constraints, inspect the shipped files under `schemas/product/`; use
92
+ [the getting-started guide](getting-started.md) for the minimal working path.