@rasensio/aidlc-content 1.50.0 → 1.52.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.
@@ -0,0 +1,115 @@
1
+ # Manifest for the explanation pages in packages/content/docs/ — the single
2
+ # declaration site. They ship inside @rasensio/aidlc-content and are read from the
3
+ # installed package by `aidlc explain`; no project ever holds a copy
4
+ # (docs-unreachable-from-installed-projects).
5
+ #
6
+ # Four claims live here as data rather than as prose, because a test can compare
7
+ # data and cannot read prose: which pages exist, what code each one is about,
8
+ # which CLI commands each one covers, and which broken-looking things are
9
+ # deliberate. Guards are in packages/cli/test/docs-topics.test.ts.
10
+ #
11
+ # Schema (capability-docs/design.md, "Interfaces"):
12
+ # boundary prose stating the pages-versus-knowledge-graph split
13
+ # entries[] one per file in this directory
14
+ # id short slug, unique
15
+ # kind index | topic
16
+ # file filename in this directory, must exist
17
+ # title topic only
18
+ # source topic only; the code this page is about, must exist on disk
19
+ # commands topic only; top-level CLI commands this page covers
20
+ # undocumented[] commands deliberately covered by no page, each with a reason
21
+ # historical_paths[] paths named on purpose that do not resolve, each with a reason
22
+
23
+ boundary: >-
24
+ These pages and the knowledge graph are split by QUESTION, not by audience — both
25
+ serve agents as well as people. The knowledge graph (.aidlc/knowledge/, surfaced into
26
+ CLAUDE.md by `aidlc knowledge context`) answers where a thing is and what shape it
27
+ has: terse, indexed, loaded into every prompt. These pages (packages/content/docs/,
28
+ read with `aidlc explain`) answer why a thing
29
+ exists, what breaks without it, and how to use it: prose, read on demand. If a page
30
+ here restates a fact the knowledge graph already carries, that is the duplication this
31
+ split exists to prevent — link to the code instead. No page documents the contents of
32
+ the knowledge graph itself, which is why no topic's `source` points into
33
+ .aidlc/knowledge/.
34
+
35
+ entries:
36
+ - id: readme
37
+ kind: index
38
+ file: README.md
39
+
40
+ - id: lifecycle
41
+ kind: topic
42
+ title: The lifecycle
43
+ file: lifecycle.md
44
+ source: packages/cli/src/core
45
+ commands: [init, start, continue, status, transition, gate, menu, amend, templates, spec, cross-check]
46
+
47
+ - id: state-and-concurrency
48
+ kind: topic
49
+ title: State, claims and concurrent work
50
+ file: state-and-concurrency.md
51
+ source: packages/cli/src/concurrency
52
+ commands: [claim, release]
53
+
54
+ - id: roadmap
55
+ kind: topic
56
+ title: The roadmap
57
+ file: roadmap.md
58
+ source: packages/content/skills/04-roadmap.md
59
+ commands: [roadmap, autopilot]
60
+
61
+ - id: reviews-and-guidance
62
+ kind: topic
63
+ title: Reviews, guidance and the constitution
64
+ file: reviews-and-guidance.md
65
+ source: packages/cli/src/review
66
+ commands: [review, constitution]
67
+
68
+ - id: cost-tracking
69
+ kind: topic
70
+ title: Cost tracking
71
+ file: cost-tracking.md
72
+ source: packages/cli/src/cost
73
+ commands: [cost]
74
+
75
+ - id: metrics
76
+ kind: topic
77
+ title: Metrics
78
+ file: metrics.md
79
+ source: packages/cli/src/metrics
80
+ commands: [metrics]
81
+
82
+ - id: knowledge-graph
83
+ kind: topic
84
+ title: The knowledge graph
85
+ file: knowledge-graph.md
86
+ source: packages/cli/src/knowledge
87
+ commands: [knowledge, discover]
88
+
89
+ - id: skills-and-platforms
90
+ kind: topic
91
+ title: Skills and platforms
92
+ file: skills-and-platforms.md
93
+ source: packages/cli/src/compile
94
+ commands: [add, update, docs, explain]
95
+
96
+ - id: hygiene-and-compliance
97
+ kind: topic
98
+ title: Repo hygiene and compliance
99
+ file: hygiene-and-compliance.md
100
+ source: packages/cli/src/doctor
101
+ commands: [doctor, compliance]
102
+
103
+ # Empty on purpose: every top-level command is claimed by a page above. The
104
+ # checker's allowlist branch is exercised on synthetic input in the test rather
105
+ # than by leaving a real command undocumented to keep a code path warm.
106
+ undocumented: []
107
+
108
+ historical_paths:
109
+ - path: packages/web
110
+ reason: >-
111
+ Deleted at the website cutover (nextjs-website-revamp, T27). Named in
112
+ knowledge-graph.md and hygiene-and-compliance.md as the worked example behind the
113
+ `knowledge-stale-sources` check: 15 graph entities described it for 17 days, and
114
+ neither page can make that point without writing the path that no longer resolves.
115
+ The entries were removed by stale-graph-entries; the story is what stays.
@@ -0,0 +1,121 @@
1
+ # The knowledge graph
2
+
3
+ ## Why this exists
4
+
5
+ An agent starting a session knows nothing about your codebase. Left to itself it will re-explore —
6
+ grepping, opening files, reconstructing the same picture the last session built and discarded. That is
7
+ slow, and it is charged per token.
8
+
9
+ The knowledge graph is persistent memory for that problem. Entities (modules, decisions, conventions,
10
+ dependencies, debt, endpoints) with relationships between them, stored as YAML and indexed for
11
+ full-text search. `aidlc knowledge context` compiles a summary of it into `CLAUDE.md`, so the facts
12
+ arrive in the prompt without anyone querying for them.
13
+
14
+ It is deliberately **terse**. Each entry is a compressed paragraph, because it competes for prompt
15
+ space with the actual task. That compression is also its limit, and the reason the pages in this folder
16
+ exist alongside it — see the boundary below.
17
+
18
+ **What breaks without it:** every session pays the discovery cost again, and two sessions reach
19
+ different conclusions about the same code.
20
+
21
+ ## How to use it
22
+
23
+ ```
24
+ aidlc discover
25
+ aidlc knowledge query cost
26
+ aidlc knowledge get <id>
27
+ aidlc knowledge graph <id>
28
+ aidlc knowledge add --type decision --id <slug> --name "<title>" --description "<why>"
29
+ aidlc knowledge relate <from> <to> --type <kind>
30
+ aidlc knowledge context --scope phase --phase design
31
+ ```
32
+
33
+ `discover` scans a codebase and seeds the graph — that is how a brownfield project starts. After that,
34
+ record findings as you make them rather than at the end.
35
+
36
+ To add several entities at once, pipe YAML documents (separated by `---`) to
37
+ `aidlc knowledge add --stdin`. A `tags:` string there means what `--tags` means: comma-separated.
38
+ **Every document is checked before any is written**, and a run that fails writes nothing. That rule
39
+ exists because, before 1.40.1, the YAML was written before the index looked at it. A `tags: a,b,c`
40
+ string was saved, then the command crashed with `entity.tags.join is not a function`. The natural
41
+ retry merged into the saved record and turned the string into one tag per character. Four entities in
42
+ this repo's own graph carried 11 to 17 single-letter tags each before anyone noticed.
43
+
44
+ **Query before exploring.** That is the whole point: `aidlc knowledge query <term>` costs one command,
45
+ and re-deriving the same fact costs a session.
46
+
47
+ **Then check what it told you against the source.** This is the rule that matters most on this page.
48
+ The graph is an index into the code, not an authority over it. An entry naming a component, a function
49
+ or a registry is a pointer to open, and an entry written by an earlier instance may name something a
50
+ later one renamed or deleted. A design built on a symbol that is not there produces code against an API
51
+ nobody has, and nothing downstream catches it until implementation.
52
+
53
+ `aidlc knowledge verify <id>` records that you checked. `aidlc knowledge update <id>` corrects an entry
54
+ that no longer matches.
55
+
56
+ That rule is not hypothetical here. For 17 days this graph carried **15 entities describing
57
+ `@rasensio/aidlc-web`, a package deleted at the website cutover** — eight module entries plus seven
58
+ dependencies sourced to its manifest. Its directory, `packages/web`, does not exist; the repo has
59
+ `packages/cli`, `packages/content` and `packages/website`. `aidlc knowledge query "web"` answered
60
+ with the deleted package before it answered with the real one. Nothing reported it, because a stale
61
+ entry and a correct one are the same shape.
62
+
63
+ They are no longer the same shape to `aidlc doctor`. The `knowledge-stale-sources` check resolves
64
+ every entity's `source` against the disk and every relationship endpoint against the entity set, and
65
+ names what does not resolve. It is **report tier**: it applies nothing, under any tier or flag. Of
66
+ those 15 entities, 12 wanted deleting and 3 wanted their path corrected to a different manifest —
67
+ indistinguishable from the data alone, so the remedy is a decision and `doctor` may not make it. See
68
+ [Repo hygiene and compliance](hygiene-and-compliance.md).
69
+
70
+ Two things that episode is worth remembering for. First, the two staleness signals that existed
71
+ could not see it: `lastVerified` age flags most of a real graph, correct entries included, and the
72
+ git-diff change signal goes quiet exactly when a directory is deleted, because a path that no longer
73
+ exists stops appearing in diffs. Second, the entries were **auto-discovered at confidence 0.6**, so
74
+ they lost the `CLAUDE.md` context budget to the hand-written 0.9 entries and never reached a prompt.
75
+ That is the confidence ranking working — and it is also why nobody noticed for 17 days. A low-value
76
+ fact that is wrong is still wrong; it just costs less per day.
77
+
78
+ ## The boundary against these pages
79
+
80
+ Both surfaces are read by agents, so the split is by **question**, not audience:
81
+
82
+ | | Answers | Shape | When it is read |
83
+ |---|---|---|---|
84
+ | Knowledge graph | Where is it? What shape is it? | Terse, indexed | Every prompt |
85
+ | These pages | Why does it exist? What breaks without it? How do I use it? | Prose | On demand |
86
+
87
+ A worked example of the difference. The graph records that `resolveSource` returns a `ResolveResult` of
88
+ `ok` or `reason` rather than `null`. True, and useful for finding it. What it cannot afford to carry is
89
+ *why*: a null could not distinguish "no transcript on disk" from "transcript found but no matching
90
+ turns", and the bugfix instance `cost-claim-attribution` bought that distinction. An agent holding only
91
+ the fact will simplify the type back to `null` and re-introduce the bug. An agent that read
92
+ [cost-tracking.md](cost-tracking.md) will not.
93
+
94
+ So: if something belongs in one line and answers *where*, it goes in the graph. If it needs a paragraph
95
+ and answers *why*, it goes here. A page that restates a graph fact is the duplication the split exists
96
+ to prevent — which is why no page here documents the graph's contents, and no topic's `source`
97
+ points into `.aidlc/knowledge/`.
98
+
99
+ ## Where the code lives
100
+
101
+ - `packages/cli/src/knowledge` — the engine. YAML files are the source of truth; a SQLite full-text
102
+ index sits behind a `KnowledgeIndex` interface for search. The index is derived and can be rebuilt.
103
+ - `.aidlc/knowledge` — this project's own graph: `modules.yaml`, `decisions.yaml`,
104
+ `conventions.yaml`, `dependencies.yaml`, `debt.yaml`, `endpoints.yaml`, `relationships.yaml`, plus
105
+ the index database. Newer records sit one per file in a directory named for the type —
106
+ `decisions/<id>.yaml`, `relationships/<from>-<type>-<to>-<hash>.yaml` — and both layouts are read.
107
+
108
+ Why one file per record: every instance used to append its decision to the end of `decisions.yaml`.
109
+ Two branches that both append at the end conflict, so once one pull request merged, every other open
110
+ one conflicted — and GitHub never runs the custom merge driver, so none of them could merge. On
111
+ 2026-10-02 that stalled a three-item autopilot run for two hours. Separate files make the conflict
112
+ impossible rather than recoverable. The existing records were left where they are on purpose: moving
113
+ them in one commit would itself conflict with every open branch. `aidlc knowledge compact` folds the
114
+ record files back into the per-type files when one file is wanted.
115
+ - `packages/cli/src/operational/knowledge.ts` — the operational hooks around it.
116
+ - `packages/cli/src/discover` — the codebase scan behind `aidlc discover`.
117
+
118
+ One implementation lesson worth carrying: a "preserve this unchanged" path that round-trips through a
119
+ serializer does not preserve anything. Rebuilding the index must copy bytes, not re-emit parsed
120
+ structures, or comment formatting and key order drift on every rebuild — 829 lines of diff versus 108
121
+ on real data.
@@ -0,0 +1,198 @@
1
+ # The lifecycle
2
+
3
+ ## Why this exists
4
+
5
+ Working with an AI agent on real software has a specific failure mode: the agent writes code
6
+ immediately, the code is plausible, and nobody can tell afterwards what it was supposed to do. There
7
+ is no record of the decision, so the next session re-decides it, differently.
8
+
9
+ The lifecycle exists to put a paper trail in front of the code. An **instance** is one unit of work
10
+ with its own folder under `.aidlc/state/`. It moves through **phases**, and each phase must produce a
11
+ named document before the next one starts. Requirements before design, design before code, tests
12
+ before release. That ordering is not ceremony — it is the only thing that makes a later question
13
+ like "why is it built this way?" answerable at all.
14
+
15
+ **What breaks without it:** the work still gets done, but each session starts from scratch. This
16
+ project's own numbers make the case: every instance has left a folder of requirements, designs and
17
+ retrospectives — 47 of them at the time of writing — and the reason anything in this repo can be
18
+ traced back to a decision is that the document existed before the code did. Where the trail is missing — the knowledge graph's stale
19
+ entries, for instance — nobody can tell whether a thing is wrong or merely old.
20
+
21
+ The second reason is subtler. Phases give an agent a place to *stop*. Without a phase boundary, an
22
+ agent asked to fix a typo will refactor the module, because there is no structural moment at which
23
+ "that is enough" is the correct answer.
24
+
25
+ ## How to use it
26
+
27
+ Set up a project once:
28
+
29
+ ```
30
+ aidlc init
31
+ ```
32
+
33
+ Then, per piece of work:
34
+
35
+ ```
36
+ aidlc start quick-feature --name my-thing
37
+ aidlc status
38
+ aidlc continue
39
+ aidlc transition my-thing
40
+ ```
41
+
42
+ `start` creates the folder and a branch. `continue` resumes from the next incomplete step, loading
43
+ only the context that step needs. `transition` evaluates the gates and advances the phase — it
44
+ refuses if the phase's documents are not done, which is the point.
45
+
46
+ **Templates** decide which phases apply. There are five, in `packages/content/templates`:
47
+
48
+ | Template | Phases | Use it for |
49
+ |---|---|---|
50
+ | `micro-task` | implementation, testing | a typo, a version bump |
51
+ | `bugfix` | reproduction first, then the usual | something is broken |
52
+ | `quick-feature` | requirements → deployment | most features |
53
+ | `full-feature` | adds ideation | you do not yet know what you are building |
54
+ | `spike` | research question, no release | finding out whether something is possible |
55
+
56
+ `aidlc templates` lists them; `aidlc templates show <name> --scope <scope>` prints each phase with
57
+ the artifacts it requires. Use it before creating an instance by hand — an instance seeded with
58
+ artifacts its template never asked for fails its gates on files nobody needs, and until this command
59
+ existed the artifact names lived only inside `node_modules`.
60
+
61
+ **Scope** is the other dial, and it is the one people get wrong. Scope is not how big or ambitious
62
+ the work is — it is which phases run. `micro` starts at implementation, `standard` starts at
63
+ requirements, `full` starts at ideation. A large change with a settled design is `standard`; a small
64
+ change nobody has thought about is `full`.
65
+
66
+ **Gates** are the checks between phases. `aidlc gate <instance> <phase>` runs one without advancing,
67
+ which is what CI calls. It fails on any phase not yet marked complete, and `aidlc transition` is the
68
+ step that marks it — so a gate run before the transition fails by design. When either command fails,
69
+ its output ends with a numbered **Next steps** block: one action per kind of failure, with the real
70
+ instance, phase and artifact names filled in. When the `CI` environment variable is set, `aidlc gate`
71
+ words that block for a pipeline and names no command that changes lifecycle state. `--json` output
72
+ carries no such block.
73
+
74
+ Two gates are worth knowing because they block real work:
75
+
76
+ - The **traceability gate** requires every active acceptance criterion in `requirements.md` to be
77
+ referenced by some test. Criteria are written `- AC-1: <text>`, and tests refer to them as
78
+ `<instance>/AC-1`. It has no override flag, deliberately — the one time a gate here had no bypass,
79
+ it forced the discovery that five "criteria" were release process steps rather than properties of
80
+ the software. The requirements skill asks for behaviours in one of four shapes —
81
+ `WHEN …, THE SYSTEM SHALL …`, `WHILE …`, `IF …, THEN …`, `WHERE …` — because each one names its
82
+ own test. The gate does not check the shape, on purpose: a performance budget or a docs change is
83
+ not a behaviour, and a check would force it into one. A bugfix's `requirements.md` also lists
84
+ *unchanged* behaviour as criteria, so the fix cannot quietly break its neighbour.
85
+ - The **ownership gate** checks that the session transitioning a phase is the one that claimed it.
86
+ This one has an override, and the honest observation from the retrospectives is that having the
87
+ override meant it got waved through by reflex on every phase.
88
+
89
+ `aidlc menu`, or bare `aidlc`, opens a picker of the common commands if you would rather not
90
+ remember them.
91
+
92
+ **When requirements move after their phase closed**, `aidlc amend <instance>` is the way back. The
93
+ gates check that artifacts exist, not that they still agree with each other, so editing
94
+ `requirements.md` after its phase completed leaves the phase `complete`, the design describing the old
95
+ criterion, and every gate passing — silent drift.
96
+
97
+ The protocol is: retire the criterion in place, issue its replacement with a fresh ID, then append an
98
+ amendment section naming what changed and which phases it invalidated.
99
+
100
+ ```markdown
101
+ ## Amendment 1 — 2026-09-07, after the design review
102
+ - **Retires:** AC-4, AC-9
103
+ - **Issues:** AC-31
104
+ - **Reopens:** design
105
+ - **Reason:** the customer integration needs JSON as well as CSV
106
+ ```
107
+
108
+ `aidlc amend <instance> --impact` is read-only and lists every task, test and artifact that still cites
109
+ the retired criteria. It is deliberately advisory: it *suggests* phases and never chooses them, because
110
+ the first design derived the reopen set from that walk and the result was degenerate —
111
+ `requirements.md` always cites every retired criterion, so every amendment reopened the requirements
112
+ phase. A destructive state write should not depend on a prose-scanning heuristic.
113
+
114
+ Running `aidlc amend <instance>` reopens the phase named in `Reopens:` and every phase between it and
115
+ the current one, setting each back to `in-progress`. That re-arms the gates that already exist — this
116
+ added no new gate — and appends a `type: reopen` record so churn is visible in history rather than
117
+ reading as a normal forward pass. It needs a live claim, prints every change before making it, requires
118
+ `--confirm` from testing onwards, applies amendments in order, and is a stated no-op on a second run.
119
+ A completed instance is refused outright: its change is new work.
120
+
121
+ A correction confined to the current phase does not have to reopen anything. Write `Reopens: none`, or
122
+ name the current phase: the amendment is recorded and no phase moves. That is checked, not taken on
123
+ trust. The walk is the one input a refusal may read: `aidlc amend` refuses any reopen — `none` included —
124
+ that would leave a completed phase still citing a retired criterion, names each such phase, and prints the
125
+ `Reopens:` it would accept. `--impact` ends with the same verdict in one line. The walk still never
126
+ chooses what is reopened; it can only stop a write, never cause one.
127
+
128
+ **What the system does today** lives in `.aidlc/specs/`, one file per capability. Each instance's
129
+ `requirements.md` describes a change; after enough of them, nobody can say what the system does without
130
+ replaying all of them. The corpus is that replay, done once per instance instead of by every reader.
131
+
132
+ A requirements author writes the change as a `## Spec delta` section — `ADDED`, `MODIFIED` and `REMOVED`
133
+ blocks against named capabilities. A `MODIFIED` or `REMOVED` block carries `Base: <revision>`, the
134
+ 8-character hash `aidlc spec show <capability>` prints for the requirement it was written against.
135
+
136
+ ```markdown
137
+ ## Spec delta
138
+
139
+ ### MODIFIED cost-tracking: Phase windows
140
+ Base: 3f2a9c1e
141
+ The system attributes each usage record to the phase and turn open at its timestamp.
142
+ ```
143
+
144
+ At the completion moment `aidlc transition` folds the delta in, stamps each requirement with the
145
+ instance and date, and files the delta under `.aidlc/specs/archive/<date>-<instance>.md`. If another
146
+ instance changed the same requirement first, its revision no longer matches the base: the fold stops,
147
+ completion is not recorded, and nothing is written. That is the whole conflict rule — a requirement is
148
+ never silently overwritten. `aidlc spec fold <instance> --dry-run` runs the same check any time before.
149
+ An instance with no delta completes exactly as before; nothing was back-filled, so the corpus starts
150
+ empty and grows.
151
+
152
+ **Before code is written**, `aidlc cross-check <instance>` reads `requirements.md`, `design.md` and
153
+ `tasks.md` side by side. `aidlc review` reads one artifact at a time, so a criterion design forgot, or a
154
+ task nobody asked for, passes every review and turns up in the code. The check prints one line per gap,
155
+ naming both artifacts and the criterion or task:
156
+
157
+ ```
158
+ requirements.md AC-4 → tasks.md: no open or done task cites it
159
+ tasks.md T7 → requirements.md: cites no criterion
160
+ requirements.md AC-2 → design.md: not mentioned
161
+ ```
162
+
163
+ It reads criteria and tasks with the parsers the gates use, so the two can never disagree about what a
164
+ file says, and it prints the lines those parsers could not read. It writes nothing, changes no phase,
165
+ exits 0 whatever it finds, and no gate runs it — the implementation skill offers it before the first
166
+ task, and acting on a gap is a person's call: fix the open artifact, or amend a completed one.
167
+
168
+ **One agent per task** is the other way to run implementation, where the platform has sub-agents
169
+ (Claude Code today). Each task goes to an agent that starts fresh, so task 8 does not inherit tasks 1–7;
170
+ a second agent that edits nothing reviews it, and the box is ticked only after that review passes. The
171
+ reviewer is handed one fixed `git diff` listing every test or spec file that existed before the task
172
+ and was modified, deleted or renamed — and fails each one the task did not ask to change. The listing
173
+ is mechanical on purpose: the agent that wrote the code also used to be the one deciding the tests that
174
+ define done were fine, and a loosened assertion looks like a pass from inside. It is asked once per
175
+ instance and off by default, because it roughly doubles the agents. Tasks that may run at the same time
176
+ carry `(wave: <n>)` in `tasks.md`; a wave must be a run of consecutive tasks, and a bad marker keeps
177
+ the task and warns rather than dropping it from gate coverage. The whole loop is one rule file,
178
+ `.aidlc/resources/rules/task-agents.md`, so a session that runs its tasks itself never reads it.
179
+
180
+ ## Where the code lives
181
+
182
+ - `packages/cli/src/core` — templates, scope resolution, and the gate engine.
183
+ `template-resolver.ts` handles `extends:`; `gate.ts` evaluates phase criteria.
184
+ - `packages/cli/src/state` — reading and writing the instance folders and `transitions.log`.
185
+ - `packages/cli/src/traceability` — the acceptance-criteria parser and the test scanner behind the
186
+ traceability gate. The AC grammar is closed on purpose; near-misses warn rather than vanish.
187
+ - `packages/cli/src/tasks` — the `tasks.md` breakdown parser, including the `(wave: <n>)` marker.
188
+ - `packages/cli/src/change` — the amendment grammar, the read-only impact walk, and the `reopen`
189
+ transition. `parser.ts` is fence-aware and treats a wrapped bullet as one bullet, because the first
190
+ version truncated a wrapped `Retires:` list to half its ids and dropped three fields silently.
191
+ - `packages/cli/src/spec` — the spec corpus: the capability-file parser, the delta parser, and the
192
+ fold. `planFold` computes every file before `applyFold` writes any, which is what makes a conflict
193
+ leave the corpus untouched.
194
+ - `packages/cli/src/crosscheck` — `aidlc cross-check`, a pure comparison of one instance's three
195
+ planning artifacts. Nothing but its own command imports it, and a test keeps it that way.
196
+ - `packages/cli/src/menu` — the interactive picker. It reads no lifecycle state by design, because
197
+ "what should I do next?" belongs to the skill, not the menu.
198
+ - `packages/content/templates` — the five templates, as data.
@@ -0,0 +1,67 @@
1
+ # Metrics
2
+
3
+ ## Why this exists
4
+
5
+ The lifecycle already records everything needed to answer whether the process is working: when each
6
+ phase started and ended, which instances were bugfixes, which earlier instance each bugfix blames, and
7
+ what each one cost. Metrics is the read-only roll-up over that, so nobody has to open 42 folders and
8
+ count.
9
+
10
+ The one number that justifies the module is **true cost**. A feature's own cost is what its sessions
11
+ burned. Its true cost adds the bugfixes it caused. Read own cost and meta-features look cheap; read true
12
+ cost and they do not. Cost tracking: $153.65 own, $219.78 true. The gap is a third, and it is exactly the
13
+ gap that hides whether finishing work is generating more work than it retires.
14
+
15
+ The second is **change failure rate** per template — the share of completed instances that some later
16
+ bugfix names as its cause. It is computed from `caused_by` links that a human confirmed, never guessed,
17
+ which is why the number means something.
18
+
19
+ **What breaks without it:** you optimise the thing you can see. This project shipped eleven features in
20
+ nine days and then spent five days on seven bugfixes, and the ratio flipped because most of what shipped
21
+ were features that watch the lifecycle rather than serve a user. That pattern was invisible until it was
22
+ counted.
23
+
24
+ ## How to use it
25
+
26
+ ```
27
+ aidlc metrics
28
+ aidlc metrics --json
29
+ ```
30
+
31
+ Read-only and pure — it computes from existing state and writes nothing.
32
+
33
+ Four families come out:
34
+
35
+ **Completion moment.** Scope-aware, which is fiddlier than it sounds: for most templates an instance
36
+ completes when its last applicable phase completes, but maintenance-terminal templates complete on
37
+ maintenance *entry*, because maintenance is open-ended and would otherwise never finish.
38
+
39
+ **Change failure rate per template.** Distinct completed instances named in some bugfix's `caused_by`,
40
+ divided by completed instances.
41
+
42
+ **Lead times**, per phase and per instance. Phase lead time pairs each `to: X` in `transitions.log`
43
+ with the next `from: X`, summing re-entries, and falls back to the phase file when the log is
44
+ incomplete. The fallback matters — a phase that was never transitioned through the CLI would otherwise
45
+ read as zero, which is a bug this project shipped and then fixed.
46
+
47
+ **True cost**, one level deep. Own cost plus the cost of bugfixes that blame this instance. One level,
48
+ not transitive, because a bugfix caused by a bugfix is a chain whose attribution nobody can defend.
49
+ Null when there is no ledger data — never zero-filled, for the reason given in
50
+ [cost-tracking.md](cost-tracking.md).
51
+
52
+ Two cautions when reading the output. The generated release posts snapshot these figures into their
53
+ frontmatter at generation time, so a post's numbers are historical, not live. And `own_cost` is never
54
+ written as `true_cost` — they are separate fields precisely because conflating them is the error the
55
+ module exists to prevent.
56
+
57
+ ## Where the code lives
58
+
59
+ - `packages/cli/src/metrics/report.ts` — `computeMetrics(projectRoot, config)`, the whole module. One
60
+ pure function, no writes, no network.
61
+ - `packages/cli/src/commands/metrics.ts` — the command, including `--json`.
62
+ - `packages/cli/src/state` — `transitions.log` and the phase files it reads.
63
+ - `packages/cli/src/cost` — where the money half comes from.
64
+
65
+ The inputs are the instance folders under `.aidlc/state/`, and `caused_by` in `instance.yaml` is the
66
+ link that makes change failure rate and true cost possible. It is written only after a human confirms
67
+ the candidate — an unconfirmed guess is left absent, and absent means unknown rather than none.
@@ -0,0 +1,144 @@
1
+ # Reviews, guidance and the constitution
2
+
3
+ ## Why this exists
4
+
5
+ An agent that reviews its own work finds nothing. Not because it is dishonest — because the same
6
+ reasoning that produced the artifact produces the review, so the blind spots are identical. Every
7
+ mechanism on this page is a way of getting a second opinion into the process without a second human.
8
+
9
+ Three of them, at three timescales:
10
+
11
+ **Adversarial review** is per artifact. A separate session reads `requirements.md` or `design.md`
12
+ cold and attacks it: ambiguities, contradictions, missing edge cases, untestable criteria, hidden
13
+ assumptions, security gaps, scope creep. Findings land in `<artifact>.md.review.md` — the artifact's
14
+ own extension, then the suffix — and a `critical` finding blocks the phase.
15
+
16
+ The value is not theoretical. On one design here the review found that a guard intended to catch
17
+ stale file paths would fail on the very page explaining stale file paths — the page has to name the
18
+ deleted path in order to discuss it. That defect would have shipped and then been "fixed" by deleting
19
+ the guard.
20
+
21
+ **Guidance layers** are per project, and they accumulate. Each is a markdown file in
22
+ `.aidlc/guidance/` registered in `index.yaml`. A layer added today applies to the next phase
23
+ immediately — phases read the index at runtime rather than having guidance baked into them, so
24
+ nothing needs recompiling.
25
+
26
+ They split two ways, and the split is the answer to "they accumulate":
27
+
28
+ - **Always-read** — every layer whose index entry does *not* say `on_demand: true`. A phase reads
29
+ these on entry, without being asked.
30
+ - **On-demand** — a layer whose entry carries `on_demand: true`. Registered, active, current; read
31
+ only when a phase has a stated reason to.
32
+
33
+ `lessons.md` is the on-demand one, and it is the reason the split exists. Appended at each
34
+ retrospective, up to three entries per instance, it reached **88KB — 85% of every byte a session read
35
+ before touching task work**, while the consolidation trigger sat at 25 sections and 90 days. At 23
36
+ sections, 12 days after a consolidation, both triggers were still in the future and the file was
37
+ already the largest thing resident. A third trigger now fires on **20KB**, which is the dimension that
38
+ costs money.
39
+
40
+ Its always-read counterpart is **`lessons-digest.md`**: a distillation, under 4KB, regenerated by the
41
+ retrospective at consolidation, with what it *omits* confirmed edit by edit. The full corpus stays at
42
+ `.aidlc/guidance/lessons.md` and the digest names that path, because distilling a safety mechanism is
43
+ fine and silently dropping it is not.
44
+
45
+ **The constitution** is per repo and rarely changes. It states what this repo is for and what it must
46
+ never become, derived from a product vision document. Triage checks items against it, and an item
47
+ that crosses a prohibition is the clearest `hold/` there is — naming the prohibition turns "not for
48
+ us" into a reason the submitter can read.
49
+
50
+ **What breaks without them:** work passes review because the reviewer was the author, the same defect
51
+ recurs every few weeks with nobody noticing it is the same defect, and scope drifts one reasonable
52
+ item at a time.
53
+
54
+ ## How to use it
55
+
56
+ ```
57
+ aidlc review my-thing requirements.md
58
+ aidlc constitution
59
+ ```
60
+
61
+ `review` scaffolds the findings file with a placeholder; an agent then performs the actual review and
62
+ overwrites it. Findings carry a severity (`critical`, `major`, `minor`), the section, the issue, a
63
+ concrete suggestion, and a status. A finding without a suggestion is not actionable and should not be
64
+ written.
65
+
66
+ **The findings filename carries the artifact's extension twice, and that is deliberate.** The file
67
+ for `requirements.md` is `requirements.md.review.md`. It looks like a typo. The gate looks artifacts
68
+ up by the name the template declares, so `requirements.review.md` is a file the gate cannot see — and
69
+ for three weeks that is exactly what happened: the command built its filename from the argument as
70
+ typed, so typing `requirements` (the phase name, and what the review skill's own prose called the
71
+ artifact) produced a file that was written, parsed, counted and summarised correctly and then reported
72
+ as absent by the transition. Eleven findings files across six completed instances were sitting on disk
73
+ having never counted toward the gate they were run for.
74
+
75
+ Both spellings of the *argument* now work — `aidlc review my-thing requirements` and
76
+ `aidlc review my-thing requirements.md` write the same file — because one module,
77
+ `review/findings-naming.ts`, owns the mapping in both directions. Prefer the command over naming the
78
+ file by hand. `aidlc doctor` renames any legacy file it finds.
79
+
80
+ The reason both directions live in one module rather than the writer being "fixed": fixing only the
81
+ writer leaves the already-written files dead, and fixing only the reader leaves two valid spellings
82
+ forever. The reader resolves both because it strips the suffix and then canonicalizes, so the two
83
+ spellings converge on one key and no call site has to know which it is looking at.
84
+
85
+ Two further conventions worth copying:
86
+
87
+ **Review `design.md` and `tasks.md` as separate findings files.** The skill can be read as folding
88
+ task findings into the design's file, and doing that once blurred two real defects together — splitting
89
+ by artifact forced findings about the breakdown apart from findings about the design.
90
+
91
+ **State the dimensions you found nothing in.** A review that lists four findings and stops is
92
+ indistinguishable from a review that only looked at four things. Writing "security: no issues, and
93
+ here is why the section does not apply" is what makes the absence evidence.
94
+
95
+ Guidance needs no command — drop a file in `.aidlc/guidance/` and add it to `index.yaml`. There is one
96
+ rule that matters: **guidance is never inlined into a compiled skill.** Skills reference the layer;
97
+ they do not copy it. A copy is a thing that drifts, and a drifted copy of a security rule is worse
98
+ than no rule.
99
+
100
+ That rule has a trap worth knowing before you register a small layer. A layer under 2KB *is* inlined
101
+ when a skill names it in a `{{guidance:<name>}}` placeholder — the threshold exists so a multi-KB
102
+ document becomes a pointer instead of bloating eighteen skill bodies. Set `always_pointer: true` on
103
+ the entry to opt out whatever the size. `lessons-digest.md` does exactly that, and the flag is
104
+ load-bearing rather than decorative: without it, the file the whole change exists to keep small would
105
+ be copied into every emitted skill.
106
+
107
+ `always_pointer` and `on_demand` answer different questions and are independent. `always_pointer` is
108
+ about *rendering* — how a named layer is delivered into a skill body. `on_demand` is about *reading* —
109
+ whether a phase opens the layer at all on entry. A layer may set either, both, or neither.
110
+
111
+ The lessons file is capped at three new entries per retrospective, and follow-ups default to
112
+ `dropped` — keeping one requires a stated reason. Both caps exist because finishing work reliably
113
+ generates more work than it retires.
114
+
115
+ ## Where the code lives
116
+
117
+ - `packages/cli/src/review` — `findings-parser.ts` parses the findings format that the phase gate
118
+ reads. The gate looks only at `*.review.md`, which is what lets compliance findings live in a
119
+ separate `*.compliance.md` file and stay advisory. `findings-naming.ts` is the single declaration
120
+ site for how an artifact name and a findings filename map to each other, in both directions; two
121
+ independent derivations of that key is the defect it exists to prevent, so its test asserts the
122
+ inverse property rather than a table of literals.
123
+ - `packages/cli/src/commands/review.ts` — the scaffold generator, and the placeholder detection that
124
+ stops an unreviewed scaffold from counting as a review. Also the artifact allowlist: an argument the
125
+ instance's template does not declare is refused, because a typo used to scaffold a findings file no
126
+ gate would ever read.
127
+ - `packages/cli/src/doctor/migrations/findings-filename.ts` — renames legacy findings files. Safe
128
+ tier, and it never opens the file. A collision (both spellings present for one artifact) is
129
+ *reported*, never resolved: renaming would clobber a real review to tidy a name.
130
+ - `packages/content/guidance` — the layers shipped with the framework: `secure-defaults.md`,
131
+ `accessibility.md`, `api-conventions.md`, `lessons-digest.md`, `content-operations.md`, plus
132
+ `index.yaml`. The shipped digest is a **stub**, deliberately: lessons are project data, and a
133
+ framework package must not hand one project's observations to every consumer.
134
+ - `packages/cli/src/compile/guidance-budget.ts` — `alwaysReadLayers` and the two 20KB constants. One
135
+ module so the skill prose, the `aidlc status` notice and the tests cite one declaration.
136
+ - `packages/cli/src/doctor/migrations/lessons-digest-layer.ts` — moves an existing project onto the
137
+ digest. `confirm` tier, because it changes what every future session reads. Runs directly after
138
+ `install-guidance`, and that order is load-bearing: it registers the digest only when the body is
139
+ already on disk, and reversed it would leave `lessons` on-demand with nothing always-read in its
140
+ place.
141
+ - `.aidlc/guidance/lessons.md` — this project's own lessons, now on-demand. Worth reading before
142
+ writing any guard: it already contains the failure modes of the guard you are about to write.
143
+ - `packages/content/skills/80-review.md` and `05-constitution.md` — the review protocol and the
144
+ constitution protocol.