ddduck 0.1.2 → 0.3.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.
- package/README.md +12 -5
- package/docs/cli.md +106 -17
- package/docs/definition-workflow.md +130 -0
- package/docs/getting-started.md +15 -45
- package/docs/templates/change-brief.md +48 -0
- package/package.json +4 -2
- package/schemas/model-diff.schema.json +107 -0
- package/scripts/ddduck.mjs +111 -30
- package/scripts/generate-docs.mjs +1 -1
- package/scripts/lib/cli-contract.mjs +29 -9
- package/scripts/lib/fr-to-code-audit.mjs +6 -0
- package/scripts/lib/product-authoring.mjs +52 -0
- package/scripts/lib/product-diff.mjs +155 -0
- package/scripts/lib/product-operation.mjs +9 -1
- package/scripts/lib/skill-delegation.mjs +129 -0
- package/skills/update-ddduck-specs/SKILL.md +26 -83
- package/skills/update-ddduck-specs/references/authoring-and-verification.md +62 -0
- package/skills/update-ddduck-specs/references/executable-resolution.md +39 -0
- package/skills/update-ddduck-specs/references/modeling-and-evidence.md +56 -0
- package/skills/update-ddduck-specs/references/reviewing-changes.md +45 -0
- package/scripts/lib/skill-installer.mjs +0 -463
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@ ddduck defines a small, machine-readable product-spec format. The framework keep
|
|
|
4
4
|
schemas, validators, policies, and generators separate from each consumer product.
|
|
5
5
|
|
|
6
6
|
Start with [the getting-started guide](docs/getting-started.md) for a working first product.
|
|
7
|
+
For an unsettled product question or a proposed change, use the optional
|
|
8
|
+
[definition-to-planning workflow](docs/definition-workflow.md) and reuse your existing brief.
|
|
7
9
|
Then use [the model guide](docs/model.md), [the model reference](docs/model-reference.md),
|
|
8
10
|
[the CLI reference](docs/cli.md), and [the architecture guide](docs/architecture.md) as needed.
|
|
9
11
|
|
|
@@ -76,8 +78,8 @@ ddduck init ddd --id model:<product-id>
|
|
|
76
78
|
`--root <path>` is always the explicit override; without it, ddduck resolves the enclosing
|
|
77
79
|
product root, then `.ddduck/config.json`, then a unique repository candidate (see
|
|
78
80
|
[the CLI reference](docs/cli.md#product-root-resolution) for the full order, including the
|
|
79
|
-
example-candidate fallback), and fails with a diagnostic when the choice is ambiguous. The mutation surface is deliberately narrow —
|
|
80
|
-
`generate`, and the `create`/`move`/`split`/`retire` Guarantee lifecycle commands — and every
|
|
81
|
+
example-candidate fallback), and fails with a diagnostic when the choice is ambiguous. The mutation surface is deliberately narrow —
|
|
82
|
+
`generate`, domain/concept/use-case creation, and the `create`/`move`/`split`/`retire` Guarantee lifecycle commands — and every
|
|
81
83
|
successful source mutation regenerates the derived views. The canonical resolution rules and
|
|
82
84
|
command contracts live in [the CLI reference](docs/cli.md#product-root-resolution).
|
|
83
85
|
|
|
@@ -89,11 +91,16 @@ safety net.
|
|
|
89
91
|
Install the evidence-backed model maintenance skill in a consumer repository:
|
|
90
92
|
|
|
91
93
|
```bash
|
|
92
|
-
ddduck install skill
|
|
94
|
+
ddduck install skill --repo <repository-root>
|
|
93
95
|
```
|
|
94
96
|
|
|
95
|
-
`--repo` defaults to the current directory.
|
|
96
|
-
|
|
97
|
+
`--repo` defaults to the current directory. ddduck installs nothing itself: it prints the exact
|
|
98
|
+
`npx --yes '--package=skills@^1.7.0' -- skills add <ddduck-package>/skills --skill '*' -y`
|
|
99
|
+
command it will run, asks `[y/n]`, and
|
|
100
|
+
delegates the installation to the [`skills`](https://www.npmjs.com/package/skills) CLI, which
|
|
101
|
+
supports 79 agent hosts. Pass `--yes` to skip the confirmation in CI or when an agent runs the
|
|
102
|
+
command. See [the CLI reference](docs/cli.md#install-an-agent-skill) for the delegated flags,
|
|
103
|
+
exit statuses, host invocation, and plan-only behavior.
|
|
97
104
|
|
|
98
105
|
## Product queries
|
|
99
106
|
|
package/docs/cli.md
CHANGED
|
@@ -14,6 +14,25 @@ retry logic never has to string-match standard error; every other failure exits
|
|
|
14
14
|
This package is published to npm as `ddduck`; install the CLI globally with `npm install -g ddduck`
|
|
15
15
|
(see [the getting-started guide](getting-started.md#install-ddduck)).
|
|
16
16
|
|
|
17
|
+
## `--version`
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
ddduck --version [--json]
|
|
21
|
+
ddduck -v [--json]
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
| Option | Default | Meaning |
|
|
25
|
+
| -------- | ------- | ---------------------------------------------- |
|
|
26
|
+
| `--json` | false | Emit one JSON object instead of the text line. |
|
|
27
|
+
|
|
28
|
+
`--version` (alias `-v`) prints the installed package name and version taken from the package's
|
|
29
|
+
own `package.json`, as one text line — `ddduck <version>` — or, with `--json`, one object:
|
|
30
|
+
`{"name":"ddduck","version":"<version>"}`. It resolves no product root and reads no product, so
|
|
31
|
+
it is the cheapest way to confirm that a candidate executable really is ddduck and which version
|
|
32
|
+
is installed. `ddduck --version --help` prints the flag's contract like every other command.
|
|
33
|
+
Exit status: 0 on success or help; 1 on invalid input (an unknown option, for example). The
|
|
34
|
+
retryable busy exit 2 cannot occur, because no product root is touched.
|
|
35
|
+
|
|
17
36
|
## Product root resolution
|
|
18
37
|
|
|
19
38
|
Product-facing commands accept `--root <product-root>`. When `--root` is omitted, ddduck resolves
|
|
@@ -59,7 +78,7 @@ standard-error note that the repository default still selects that other root.
|
|
|
59
78
|
## Common behavior
|
|
60
79
|
|
|
61
80
|
Product writes are `init`, `generate`, `create`, `move`, `split`, and `retire`; successful
|
|
62
|
-
mutations regenerate all required views. `check` and every `query` are read-only. A successful
|
|
81
|
+
mutations regenerate all required views. `check`, `diff`, and every `query` are read-only. A successful
|
|
63
82
|
`check` writes nothing to standard output; when `--root` was omitted, it prints one standard-error
|
|
64
83
|
note naming the validated root so an implicitly resolved (for example config-pinned) root is never
|
|
65
84
|
validated invisibly. Successful product mutations print one concise result line, or one JSON result
|
|
@@ -129,6 +148,65 @@ ddduck generate [--root <product-root>] [--json]
|
|
|
129
148
|
result identifies the root, canonical paths (none for generate), and generated paths. It exits
|
|
130
149
|
nonzero without an intended product mutation if validation or contained-output checks fail.
|
|
131
150
|
|
|
151
|
+
## `diff`
|
|
152
|
+
|
|
153
|
+
```text
|
|
154
|
+
ddduck diff --base <previous-product-root> [--root <product-root>] [--json]
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Compare two independently valid versions of the same Model by stable node ID. `--base` is
|
|
158
|
+
required and `--root` uses normal root resolution. Generated output may be absent or stale.
|
|
159
|
+
The command does not apply historical retention validation first: removing a Guarantee must
|
|
160
|
+
remain visible in the comparison even when a subsequent `check --base` rejects that removal.
|
|
161
|
+
|
|
162
|
+
The text report shows IDs, field changes, and path relocations. `--json` emits one
|
|
163
|
+
`ModelDiff` version `"1"` document conforming to `schemas/model-diff.schema.json`:
|
|
164
|
+
|
|
165
|
+
- `before` and `after` contain `modelId` and canonical `sourceDigest`.
|
|
166
|
+
- `added` and `removed` contain full records with their product-relative source paths.
|
|
167
|
+
- `changed` contains field changes keyed by escaped JSON Pointer paths. `beforePresent` and
|
|
168
|
+
`afterPresent` distinguish absent fields from explicit null values.
|
|
169
|
+
- `relocated` records path changes without treating the same ID as a new record.
|
|
170
|
+
- `scope` is `canonical-yaml-only`; `excludedScopes` names decision content, evidence content,
|
|
171
|
+
delivery artifacts, and runtime.
|
|
172
|
+
|
|
173
|
+
Object-key order, comments, and YAML formatting are not record differences. Array order is
|
|
174
|
+
preserved, so a reordered list is reported. Raw canonical-file changes still affect digests.
|
|
175
|
+
Neither the digests nor an empty comparison establish ADR/evidence freshness or semantic
|
|
176
|
+
equivalence. Source reads are not atomic snapshots; run comparisons while neither root is
|
|
177
|
+
being edited. Busy and interrupted roots are refused.
|
|
178
|
+
|
|
179
|
+
Exit 0 means comparison completed, including when changes exist; it is not an approval.
|
|
180
|
+
Exit 2 means busy, and exit 1 covers invalid or incompatible inputs. Use existing `impact`
|
|
181
|
+
and `neighbors` queries on both roots to inspect changed/removed context, then review meaning
|
|
182
|
+
and run historical retention checking separately.
|
|
183
|
+
|
|
184
|
+
## Creating domains, concepts, and use cases
|
|
185
|
+
|
|
186
|
+
```text
|
|
187
|
+
ddduck create domain --id domain:<slug> --name <text> --purpose <text> [--root <product-root>] [--json]
|
|
188
|
+
ddduck create concept --id concept:<slug> --owner domain:<slug> --name <text> --purpose <text> [--root <product-root>] [--json]
|
|
189
|
+
ddduck create use-case --file <yaml-file> [--root <product-root>] [--json]
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Domain creation writes the node and adds its ID to the Model's `domains` list. Concept creation
|
|
193
|
+
writes the node and adds its ID to the owning Domain's `concepts` list. These forms require
|
|
194
|
+
every displayed field; they take model identity from the selected product.
|
|
195
|
+
|
|
196
|
+
Use-case creation reads a complete canonical `UseCase` YAML mapping. Its `model` must match
|
|
197
|
+
the selected product and all Guarantee/interface references must already resolve. It writes
|
|
198
|
+
the new node and adds its ID to the Model's `useCases` list without changing the input file.
|
|
199
|
+
An empty prerequisite or outcome list is allowed; the tool does not invent obligations.
|
|
200
|
+
|
|
201
|
+
All three forms derive the destination filename from the validated ID. Duplicate IDs,
|
|
202
|
+
occupied canonical paths, unknown fields, invalid references, or validation/generation
|
|
203
|
+
failures reject the operation without intended publication. Successful operations update
|
|
204
|
+
the owning collection and generate all views through the existing staged mutation runner.
|
|
205
|
+
There is no overwrite mode. Existing YAML comments and unrelated parent fields are retained.
|
|
206
|
+
The result has `operation`, `root`, `affectedIds` (new node and parent), `canonicalPaths`, and
|
|
207
|
+
`generatedPaths`; append `--json` for one JSON document. Publication has the filesystem
|
|
208
|
+
interruption limitations described in the [architecture guide](architecture.md#staged-lifecycle-mutation).
|
|
209
|
+
|
|
132
210
|
## Guarantee mutations
|
|
133
211
|
|
|
134
212
|
All mutation results identify the selected root, affected Guarantee IDs, canonical paths, and
|
|
@@ -227,26 +305,37 @@ The command does not recursively expand the perimeter.
|
|
|
227
305
|
## Install an agent skill
|
|
228
306
|
|
|
229
307
|
```text
|
|
230
|
-
ddduck install skill
|
|
308
|
+
ddduck install skill [--repo <repository-root>] [--yes]
|
|
231
309
|
```
|
|
232
310
|
|
|
233
|
-
`--repo` defaults to the current directory.
|
|
234
|
-
|
|
311
|
+
`--repo` defaults to the current directory. ddduck installs nothing itself: it delegates to the
|
|
312
|
+
[`skills`](https://www.npmjs.com/package/skills) CLI, which supports 79 agent hosts and owns the
|
|
313
|
+
installed layout and its own state. The command prints the exact command it will run, on its own
|
|
314
|
+
line, and then runs it in `--repo`:
|
|
235
315
|
|
|
236
316
|
```text
|
|
237
|
-
|
|
238
|
-
.agents/ only -> .agents/skills/update-ddduck-specs/SKILL.md
|
|
239
|
-
.claude/ only -> .claude/skills/update-ddduck-specs/SKILL.md
|
|
240
|
-
.agents/ and .claude/ -> .agents/skills/update-ddduck-specs/SKILL.md
|
|
241
|
-
.claude/skills/update-ddduck-specs -> ../../.agents/skills/update-ddduck-specs
|
|
317
|
+
npx --yes '--package=skills@^1.7.0' -- skills add <ddduck-package>/skills --skill '*' -y
|
|
242
318
|
```
|
|
243
319
|
|
|
244
|
-
The
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
320
|
+
The bundled skills directory is resolved inside the installed ddduck package
|
|
321
|
+
(`./node_modules/ddduck/skills` from a consumer repository, or the repository's own `skills/`
|
|
322
|
+
when the repository under analysis is ddduck itself). `--skill '*'` installs every bundled skill,
|
|
323
|
+
the absent `-g` keeps the install project-scoped, and `-y` answers the delegated CLI's own
|
|
324
|
+
prompts, because the command it applies has already been shown and confirmed here. `skills`
|
|
325
|
+
writes one canonical copy (by default `.agents/skills/<skill-name>/`) and symlinks it into the
|
|
326
|
+
agent directories that exist in the project.
|
|
327
|
+
|
|
328
|
+
`--package=` pins the delegated package so npx resolves it from the registry. Without it, npx
|
|
329
|
+
resolves the bare name `skills` against `--repo`'s own `node_modules/.bin` first, so an unrelated
|
|
330
|
+
binary under that generic name — a sibling package hoisted to a monorepo root, for example —
|
|
331
|
+
would run instead of the CLI the printed command names. The `--` separator keeps npx from
|
|
332
|
+
reading the command word as a second package specifier.
|
|
333
|
+
|
|
334
|
+
Before running it, ddduck asks `[y/n]` on standard input. Only `y` or `Y` proceeds; any other
|
|
335
|
+
answer — including an empty line and a closed standard input — aborts, installs nothing, and
|
|
336
|
+
exits 1. `--yes` skips that confirmation and keeps the command usable in CI and by agents; the
|
|
337
|
+
command is still printed. The delegated command's output streams through unchanged and its exit
|
|
338
|
+
status is propagated. `--json` is not accepted.
|
|
250
339
|
|
|
251
340
|
Invoke the skill from the relevant host:
|
|
252
341
|
|
|
@@ -256,5 +345,5 @@ Claude: /update-ddduck-specs
|
|
|
256
345
|
```
|
|
257
346
|
|
|
258
347
|
The skill defaults to plan-only; changing a product model requires explicit apply authorization.
|
|
259
|
-
Its workflow behavior is defined by the installed
|
|
260
|
-
[canonical
|
|
348
|
+
Its workflow behavior is defined by the installed skill bundle (see its packaged
|
|
349
|
+
[canonical entrypoint](../skills/update-ddduck-specs/SKILL.md)).
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# From a product question to a planning brief
|
|
2
|
+
|
|
3
|
+
Start with the question, not a YAML record. Reuse an existing proposal or design brief;
|
|
4
|
+
the [optional change brief](templates/change-brief.md) is a checklist for missing context,
|
|
5
|
+
not a required document. A short note can be enough.
|
|
6
|
+
|
|
7
|
+
## Explore, decide, then model
|
|
8
|
+
|
|
9
|
+
1. Identify the actor and problem with concrete success and refusal examples.
|
|
10
|
+
2. Separate observed evidence from accepted intent and open questions. Record alternatives
|
|
11
|
+
and contradictory evidence with provenance.
|
|
12
|
+
3. Make the semantic decision explicit. Record the decision and rationale in the brief;
|
|
13
|
+
create an ADR only for a consequential, durable choice that needs its own history.
|
|
14
|
+
4. Update canonical YAML only where accepted meaning changed. Preserve stable IDs and use
|
|
15
|
+
lifecycle commands for Guarantee transitions. A partial update can encode independent
|
|
16
|
+
accepted obligations while an unresolved question stays in prose. Zero model change is
|
|
17
|
+
correct when the existing model suffices, the change is implementation-only, or no
|
|
18
|
+
decision has been reached.
|
|
19
|
+
5. Validate structure and refresh derived views, then hand selected context to the planner
|
|
20
|
+
with delivery intent, scope, exclusions, dependencies, and acceptance examples.
|
|
21
|
+
|
|
22
|
+
**Observed** means evidence was inspected, not endorsed. **Open** means undecided.
|
|
23
|
+
**Accepted** means intended behavior, possibly not implemented. **Rejected** records an
|
|
24
|
+
alternative and rationale. These are prose labels, not new schema fields or Guarantee
|
|
25
|
+
statuses. A passing checker settles none of these semantic decisions.
|
|
26
|
+
|
|
27
|
+
For example, an admin capability need not be a member role. Existing code that grants one
|
|
28
|
+
from the other establishes observed behavior; whether that coupling is intended remains a
|
|
29
|
+
decision. Likewise, delivering a relay directive does not establish that the recipient
|
|
30
|
+
enacted it. Leave an unanswered question about who may authorize it open rather than
|
|
31
|
+
inventing an authority boundary.
|
|
32
|
+
|
|
33
|
+
## Model only what helps a decision
|
|
34
|
+
|
|
35
|
+
| Kind | Useful meaning | Counterexample to avoid |
|
|
36
|
+
| ------------ | -------------------------------------------------------------------------- | -------------------------------------------------- |
|
|
37
|
+
| Domain | A distinct product responsibility | A domain for each package or screen |
|
|
38
|
+
| Concept | Vocabulary needed to reason about behavior | A concept for every class, queue, or button |
|
|
39
|
+
| Guarantee | An observable obligation or invariant | “Best effort delivery” with no concrete commitment |
|
|
40
|
+
| Use case | An actor's goal and the obligations it requires, preserves, or establishes | An implementation task list |
|
|
41
|
+
| Relationship | A connection worth reviewing, with its meaning stated | Treating every connection as a causal dependency |
|
|
42
|
+
|
|
43
|
+
Interfaces are optional. A useful behavioral model can have none. Empty prerequisite lists
|
|
44
|
+
are not inherently wrong; add a reference when it expresses a real prerequisite, not to
|
|
45
|
+
make the diagram look complete.
|
|
46
|
+
|
|
47
|
+
For a small relay, introducing separate UI, transport, and receipt domains and
|
|
48
|
+
concepts would obscure the one responsibility under discussion. Three cohesive obligations
|
|
49
|
+
can distinguish authorization/refusal, the limit of delivery, and honest reporting. Do not
|
|
50
|
+
split every clause: split when meaning, change, or verification is independent. Remove an
|
|
51
|
+
extra Guarantee, domain, brief section, or review step when it answers no additional question.
|
|
52
|
+
Consumer practice is inspiration, not proof that its artifact count or boundaries are right.
|
|
53
|
+
|
|
54
|
+
The [relay walkthrough](https://github.com/diegomarino/ddduck/tree/main/examples/control-relay)
|
|
55
|
+
is a fictional educational scenario. The
|
|
56
|
+
[reminders scenario](https://github.com/diegomarino/ddduck/tree/main/examples/reminders)
|
|
57
|
+
illustrates refusal. Neither specifies a real product or runs an application.
|
|
58
|
+
|
|
59
|
+
## Author and review with existing tools
|
|
60
|
+
|
|
61
|
+
After hand edits, `generate` validates the staged source and generated outputs before
|
|
62
|
+
publishing derived views. It is the normal refresh action. Run operations serially against a root.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
ddduck generate --root <root>
|
|
66
|
+
ddduck check --root <root>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
An optional `ddduck check --root <root> --source-only` diagnoses canonical edits before
|
|
70
|
+
generation; `query spec` can inspect individual view freshness when needed.
|
|
71
|
+
`check` is read-only and suitable for CI/final readback. Fresh generated views establish
|
|
72
|
+
consistency with source, not product acceptance or runtime correctness.
|
|
73
|
+
|
|
74
|
+
For each selected ID, compose the existing reads:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
ddduck query impact --id <id> --root <root> --json
|
|
78
|
+
ddduck query neighbors --id <id> --root <root> --json
|
|
79
|
+
ddduck query node --id <relationship-id> --root <root> --json
|
|
80
|
+
ddduck query context --id <id> --root <root> --json
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Impact follows reverse owns/requires/preserves/establishes/uses/guarantees edges.
|
|
84
|
+
Neighbors exposes direct incoming/outgoing edges, including explicit relationships. Read
|
|
85
|
+
the relationship record for its type, description, and constraints when needed. These are
|
|
86
|
+
review candidates requiring judgment; an empty result does not establish absence of risk.
|
|
87
|
+
To select explicit relationships, filter both edge lists by `edge.kind === 'relationship'`
|
|
88
|
+
and deduplicate by `edge.id`; a self-relationship appears in both lists. If the changed ID
|
|
89
|
+
is itself a Relationship, query its record and inspect its `from` and `to` endpoints:
|
|
90
|
+
neighbors matches endpoint IDs, not the relationship record's ID.
|
|
91
|
+
There is no separate review query. Do not infer transitive effects from relationship names.
|
|
92
|
+
Separate query calls are not an atomic snapshot: keep the source stable during review and
|
|
93
|
+
re-read if it changes. A source digest identifies the read source only when it did not race
|
|
94
|
+
a mutation; it does not make multiple reads transactionally consistent.
|
|
95
|
+
|
|
96
|
+
Inspect before and after roots when something moves or disappears. In the fictional
|
|
97
|
+
ownership fixture, the same Guarantee moves from Members to Reminders within the small
|
|
98
|
+
reference corpus:
|
|
99
|
+
review its owner, both domains' lists, wording, and use-case references without inventing a
|
|
100
|
+
new ID. Read-only current-root queries alone cannot recover removed context. External feature
|
|
101
|
+
references remain the consumer bridge's responsibility.
|
|
102
|
+
|
|
103
|
+
The comparison command is:
|
|
104
|
+
|
|
105
|
+
```text
|
|
106
|
+
ddduck diff --base <root> [--root <root>] [--json]
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Its scope is canonical YAML records by stable identity, not decision/evidence
|
|
110
|
+
content, delivery artifacts, or runtime. Keep semantic review separate from structural
|
|
111
|
+
comparison and historical retention checking.
|
|
112
|
+
|
|
113
|
+
Use the implemented [domain, concept, and use-case creation commands](cli.md#creating-domains-concepts-and-use-cases)
|
|
114
|
+
to create records and update their parent lists coherently. Use-case creation consumes a
|
|
115
|
+
complete canonical YAML mapping; it does not invent obligations or decisions. See that
|
|
116
|
+
reference for syntax and refusal behavior. Schema-guided hand edits remain useful for
|
|
117
|
+
changes outside these helpers; update ownership/reference lists together before generation.
|
|
118
|
+
|
|
119
|
+
## Hand off intent, not just a graph
|
|
120
|
+
|
|
121
|
+
Select canonical context explicitly and link it from the receiving plan. Add why the work
|
|
122
|
+
is needed, scope and non-goals, success/refusal examples, dependencies, exclusions, open
|
|
123
|
+
decisions, and the next verification required. Reuse the exploration brief if it already
|
|
124
|
+
answers those questions; do not maintain duplicate requirement prose or a second backlog.
|
|
125
|
+
|
|
126
|
+
State evidence levels precisely: inspected implementation, declared evidence anchors,
|
|
127
|
+
structural checks, tests actually executed, and observed runtime are different claims.
|
|
128
|
+
An audit verdict is a declared assessment whose anchor integrity is checked; readiness
|
|
129
|
+
roles and valid links do not prove behavioral coverage. Keep anchors inside the supported
|
|
130
|
+
product root, and never create fake executable evidence or bridge documents to fill gaps.
|
package/docs/getting-started.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Getting started
|
|
2
2
|
|
|
3
3
|
This executable journey creates a product with one Domain, one Concept, and one Guarantee.
|
|
4
|
+
For help deciding what belongs in that model, start with the
|
|
5
|
+
[definition workflow](definition-workflow.md).
|
|
4
6
|
|
|
5
7
|
## Install ddduck
|
|
6
8
|
|
|
@@ -37,9 +39,9 @@ repository root, and without one writes it inside the new product root instead (
|
|
|
37
39
|
|
|
38
40
|
```mermaid
|
|
39
41
|
flowchart LR
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
Create[ddduck create] --> FreshCheck[ddduck check]
|
|
43
|
+
Source[Manual canonical YAML edit] --> Generate[ddduck generate]
|
|
44
|
+
Generate -->|invalid source| Diagnostic[Actionable diagnostic]
|
|
43
45
|
Generate --> FreshCheck[ddduck check]
|
|
44
46
|
FreshCheck --> Docs[Generated Markdown is fresh]
|
|
45
47
|
FreshCheck --> Graph[Generated graph is fresh]
|
|
@@ -48,54 +50,22 @@ flowchart LR
|
|
|
48
50
|
```bash
|
|
49
51
|
ddduck init ddd --id model:library
|
|
50
52
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
model: model:library
|
|
56
|
-
name: Catalog
|
|
57
|
-
purpose: Organize the library catalog.
|
|
58
|
-
concepts:
|
|
59
|
-
- concept:book
|
|
60
|
-
interfaces: []
|
|
61
|
-
guarantees: []
|
|
62
|
-
YAML
|
|
63
|
-
|
|
64
|
-
cat > ddd/model/concepts/book.yaml <<'YAML'
|
|
65
|
-
schemaVersion: "1"
|
|
66
|
-
kind: Concept
|
|
67
|
-
id: concept:book
|
|
68
|
-
model: model:library
|
|
69
|
-
ownerDomain: domain:catalog
|
|
70
|
-
name: Book
|
|
71
|
-
purpose: Identify a catalogued book.
|
|
72
|
-
YAML
|
|
73
|
-
|
|
74
|
-
cat > ddd/product.yaml <<'YAML'
|
|
75
|
-
schemaVersion: "1"
|
|
76
|
-
kind: Model
|
|
77
|
-
id: model:library
|
|
78
|
-
name: library
|
|
79
|
-
purpose: Define the library product.
|
|
80
|
-
domains:
|
|
81
|
-
- domain:catalog
|
|
82
|
-
useCases: []
|
|
83
|
-
decisions: []
|
|
84
|
-
YAML
|
|
85
|
-
|
|
86
|
-
ddduck check --root ddd --source-only
|
|
87
|
-
ddduck generate --root ddd
|
|
88
|
-
ddduck check --root ddd
|
|
53
|
+
ddduck create domain --id domain:catalog --name Catalog \
|
|
54
|
+
--purpose "Organize the library catalog." --root ddd
|
|
55
|
+
ddduck create concept --id concept:book --owner domain:catalog --name Book \
|
|
56
|
+
--purpose "Identify a catalogued book." --root ddd
|
|
89
57
|
ddduck create guarantee --origin catalog --classification invariant \
|
|
90
58
|
--owner domain:catalog --statement "A Book has a stable catalog identity." --root ddd
|
|
59
|
+
ddduck check --root ddd
|
|
91
60
|
ddduck query spec --root ddd --json
|
|
92
61
|
```
|
|
93
62
|
|
|
94
63
|
Default `check` requires both valid canonical source and fresh generated views. After a manual
|
|
95
|
-
source edit,
|
|
96
|
-
`
|
|
64
|
+
source edit, `ddduck generate --root ddd` validates the source and refreshes the views;
|
|
65
|
+
use `ddduck check --root ddd` for final readback or CI. To diagnose source without writing
|
|
66
|
+
anything, run `ddduck check --root ddd --source-only`. Do not edit `generated/` by hand.
|
|
97
67
|
|
|
98
|
-
|
|
99
|
-
|
|
68
|
+
Each successful `create` updates the owning collection and refreshes all generated views.
|
|
69
|
+
Guarantee creation allocates the first catalog invariant serial. The final query emits one JSON document suitable for a tool or
|
|
100
70
|
agent. See the [model reference](model-reference.md) before adding other node kinds, and use the
|
|
101
71
|
[CLI reference](cli.md) for the complete command contracts.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Optional change brief
|
|
2
|
+
|
|
3
|
+
Reuse an existing proposal, issue, or design brief first. Keep only sections that help a
|
|
4
|
+
decision; a few paragraphs may suffice. This file is not a canonical schema or a second backlog.
|
|
5
|
+
Use Observed, Open, Accepted, and Rejected as prose labels, never YAML lifecycle states.
|
|
6
|
+
|
|
7
|
+
## Problem and actor
|
|
8
|
+
|
|
9
|
+
Who needs what outcome, and why now?
|
|
10
|
+
|
|
11
|
+
## Examples and refusal cases
|
|
12
|
+
|
|
13
|
+
Describe concrete success, refusal, and uncertainty cases. Label expected behavior separately
|
|
14
|
+
from results actually observed.
|
|
15
|
+
|
|
16
|
+
## Observed evidence
|
|
17
|
+
|
|
18
|
+
Cite paths and headings, symbols, or tests; state provenance, inspected scope, and gaps.
|
|
19
|
+
Observed implementation may be a bug rather than intended behavior.
|
|
20
|
+
|
|
21
|
+
## Accepted constraints
|
|
22
|
+
|
|
23
|
+
Record accepted intent and its authority. Accepted does not mean implemented.
|
|
24
|
+
|
|
25
|
+
## Alternatives
|
|
26
|
+
|
|
27
|
+
Include doing nothing or reusing existing obligations, with tradeoffs and rejected choices.
|
|
28
|
+
|
|
29
|
+
## Open questions and conflicts
|
|
30
|
+
|
|
31
|
+
What still needs a decision? Which work depends on it? Keep unresolved assertions out of YAML.
|
|
32
|
+
|
|
33
|
+
## Affected canonical IDs
|
|
34
|
+
|
|
35
|
+
Select existing records explicitly; label proposed additions as proposals. Use fenced code
|
|
36
|
+
for IDs from another product when the repository scans documentation references.
|
|
37
|
+
Record partial or zero-model-change outcomes with a reason.
|
|
38
|
+
|
|
39
|
+
## Decision and rationale
|
|
40
|
+
|
|
41
|
+
Record who accepted what and why, plus what remains open. Link an ADR only if the durable
|
|
42
|
+
decision warrants a separate artifact.
|
|
43
|
+
|
|
44
|
+
## Planning handoff
|
|
45
|
+
|
|
46
|
+
Link the receiving plan and provide intent, scope, non-goals, acceptance/refusal examples,
|
|
47
|
+
dependencies, exclusions, unresolved decisions, and selected canonical context. State what
|
|
48
|
+
was verified, by which commands, and what has not been executed. A graph is not a delivery plan.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ddduck",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "An opinionated DDD framework for authoring, validating, and visualizing machine-readable product-spec models.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ddd",
|
|
@@ -32,6 +32,8 @@
|
|
|
32
32
|
"policies/",
|
|
33
33
|
"skills/",
|
|
34
34
|
"docs/architecture.md",
|
|
35
|
+
"docs/definition-workflow.md",
|
|
36
|
+
"docs/templates/change-brief.md",
|
|
35
37
|
"docs/getting-started.md",
|
|
36
38
|
"docs/model.md",
|
|
37
39
|
"docs/model-reference.md",
|
|
@@ -72,6 +74,6 @@
|
|
|
72
74
|
"prettier": "^3.9.6"
|
|
73
75
|
},
|
|
74
76
|
"overrides": {
|
|
75
|
-
"fast-uri": "^3.1.
|
|
77
|
+
"fast-uri": "^3.1.7"
|
|
76
78
|
}
|
|
77
79
|
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://ddduck.local/schemas/model-diff.schema.json",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"additionalProperties": false,
|
|
6
|
+
"required": [
|
|
7
|
+
"schemaVersion",
|
|
8
|
+
"kind",
|
|
9
|
+
"before",
|
|
10
|
+
"after",
|
|
11
|
+
"scope",
|
|
12
|
+
"excludedScopes",
|
|
13
|
+
"added",
|
|
14
|
+
"removed",
|
|
15
|
+
"changed",
|
|
16
|
+
"relocated"
|
|
17
|
+
],
|
|
18
|
+
"properties": {
|
|
19
|
+
"schemaVersion": { "const": "1" },
|
|
20
|
+
"kind": { "const": "ModelDiff" },
|
|
21
|
+
"before": { "$ref": "#/$defs/identity" },
|
|
22
|
+
"after": { "$ref": "#/$defs/identity" },
|
|
23
|
+
"scope": { "const": "canonical-yaml-only" },
|
|
24
|
+
"excludedScopes": { "const": ["decision-content", "evidence-content", "delivery-artifacts", "runtime"] },
|
|
25
|
+
"added": { "type": "array", "items": { "$ref": "#/$defs/record" } },
|
|
26
|
+
"removed": { "type": "array", "items": { "$ref": "#/$defs/record" } },
|
|
27
|
+
"changed": {
|
|
28
|
+
"type": "array",
|
|
29
|
+
"items": {
|
|
30
|
+
"type": "object",
|
|
31
|
+
"additionalProperties": false,
|
|
32
|
+
"required": ["id", "kind", "changes"],
|
|
33
|
+
"properties": {
|
|
34
|
+
"id": { "type": "string" },
|
|
35
|
+
"kind": { "type": "string" },
|
|
36
|
+
"changes": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/change" } }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"relocated": {
|
|
41
|
+
"type": "array",
|
|
42
|
+
"items": {
|
|
43
|
+
"type": "object",
|
|
44
|
+
"additionalProperties": false,
|
|
45
|
+
"required": ["id", "kind", "beforePath", "afterPath"],
|
|
46
|
+
"properties": {
|
|
47
|
+
"id": { "type": "string" },
|
|
48
|
+
"kind": { "type": "string" },
|
|
49
|
+
"beforePath": { "type": "string" },
|
|
50
|
+
"afterPath": { "type": "string" }
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"$defs": {
|
|
56
|
+
"identity": {
|
|
57
|
+
"type": "object",
|
|
58
|
+
"additionalProperties": false,
|
|
59
|
+
"required": ["modelId", "sourceDigest"],
|
|
60
|
+
"properties": {
|
|
61
|
+
"modelId": { "type": "string", "pattern": "^model:" },
|
|
62
|
+
"sourceDigest": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"record": {
|
|
66
|
+
"type": "object",
|
|
67
|
+
"additionalProperties": false,
|
|
68
|
+
"required": ["id", "kind", "sourcePath", "node"],
|
|
69
|
+
"properties": {
|
|
70
|
+
"id": { "type": "string" },
|
|
71
|
+
"kind": { "type": "string" },
|
|
72
|
+
"sourcePath": { "type": "string" },
|
|
73
|
+
"node": { "type": "object" }
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"change": {
|
|
77
|
+
"type": "object",
|
|
78
|
+
"additionalProperties": false,
|
|
79
|
+
"required": ["path", "beforePresent", "afterPresent"],
|
|
80
|
+
"properties": {
|
|
81
|
+
"path": { "type": "string", "pattern": "^(?:/(?:[^~/]|~[01])*)+$" },
|
|
82
|
+
"beforePresent": { "type": "boolean" },
|
|
83
|
+
"afterPresent": { "type": "boolean" },
|
|
84
|
+
"before": {},
|
|
85
|
+
"after": {}
|
|
86
|
+
},
|
|
87
|
+
"allOf": [
|
|
88
|
+
{
|
|
89
|
+
"if": { "properties": { "beforePresent": { "const": true } } },
|
|
90
|
+
"then": { "required": ["before"] },
|
|
91
|
+
"else": { "not": { "required": ["before"] } }
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"if": { "properties": { "afterPresent": { "const": true } } },
|
|
95
|
+
"then": { "required": ["after"] },
|
|
96
|
+
"else": { "not": { "required": ["after"] } }
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"anyOf": [
|
|
100
|
+
{ "properties": { "beforePresent": { "const": true } } },
|
|
101
|
+
{ "properties": { "afterPresent": { "const": true } } }
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|