@pilotspace/add 1.8.0 → 1.10.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/CHANGELOG.md +109 -0
- package/bin/cli.js +137 -2
- package/docs/16-releasing.md +2 -2
- package/docs/17-components.md +125 -0
- package/docs/appendix-c-glossary.md +8 -0
- package/package.json +2 -2
- package/skill/add/SKILL.md +90 -116
- package/skill/add/adopt.md +13 -34
- package/skill/add/advisor.md +9 -10
- package/skill/add/compact-foundation.md +21 -34
- package/skill/add/components.md +54 -0
- package/skill/add/confidence.md +9 -25
- package/skill/add/deltas.md +12 -28
- package/skill/add/design.md +26 -32
- package/skill/add/fold.md +26 -51
- package/skill/add/graduate.md +18 -54
- package/skill/add/intake.md +30 -34
- package/skill/add/loop.md +30 -34
- package/skill/add/phases/0-ground.md +6 -14
- package/skill/add/phases/0-setup.md +30 -81
- package/skill/add/phases/1-specify.md +7 -22
- package/skill/add/phases/2-scenarios.md +1 -3
- package/skill/add/phases/3-contract.md +8 -22
- package/skill/add/phases/4-tests.md +3 -6
- package/skill/add/phases/5-build.md +8 -22
- package/skill/add/phases/6-verify.md +14 -49
- package/skill/add/phases/7-observe.md +1 -3
- package/skill/add/phases/fast-lane.md +31 -0
- package/skill/add/release.md +36 -90
- package/skill/add/report-template.md +41 -126
- package/skill/add/run.md +89 -159
- package/skill/add/scope.md +40 -89
- package/skill/add/setup-review.md +10 -27
- package/skill/add/soul.md +17 -36
- package/skill/add/streams.md +90 -149
- package/tooling/add.py +804 -14
- package/tooling/templates/TASK.fast.md.tmpl +72 -0
- package/tooling/templates/TASK.md.tmpl +1 -1
package/skill/add/deltas.md
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
# Lessons learned — how each loop sharpens the foundation
|
|
2
2
|
|
|
3
|
-
A **lesson learned** is a single learning a task produces, tagged by which of ADD's five
|
|
4
|
-
competencies it improves. You write deltas in a task's **OBSERVE** phase; later, the
|
|
5
|
-
`foundation-update-loop` gathers the confirmed ones and consolidates them into a versioned `PROJECT.md`.
|
|
6
|
-
This is how `DDD · SDD · UDD · TDD · ADD` stop being write-once and start converging.
|
|
3
|
+
A **lesson learned** is a single learning a task produces, tagged by which of ADD's five competencies it improves. Write deltas in a task's **OBSERVE** phase; later, `fold.md` gathers confirmed ones and consolidates them into a versioned `PROJECT.md`. This is how `DDD · SDD · UDD · TDD · ADD` stop being write-once and start converging.
|
|
7
4
|
|
|
8
|
-
You
|
|
9
|
-
(consolidating into the foundation is judgment — see the verify/observe decision point). You never self-approve a consolidation.
|
|
5
|
+
You **emit** deltas as `open`. Only the **human** moves a delta to `folded` or `rejected`. You never self-approve a consolidation.
|
|
10
6
|
|
|
11
7
|
## The grammar (frozen)
|
|
12
8
|
|
|
13
|
-
Each delta begins on its own **tag line**; the learning may wrap
|
|
9
|
+
Each delta begins on its own **tag line**; the learning may wrap:
|
|
14
10
|
|
|
15
11
|
```
|
|
16
12
|
- [<COMPETENCY> · <status>] <learning> (evidence: <pointer>)
|
|
@@ -18,14 +14,10 @@ Each delta begins on its own **tag line**; the learning may wrap onto continuati
|
|
|
18
14
|
|
|
19
15
|
- `<COMPETENCY>` — exactly one of the five (below).
|
|
20
16
|
- `<status>` — `open` | `folded` | `rejected`. A **newly emitted delta is `open`**.
|
|
21
|
-
- `<learning>` — the insight
|
|
22
|
-
|
|
23
|
-
**close** the delta (on its last line).
|
|
24
|
-
- `(evidence: …)` — **required**, non-empty: a failing scenario, a production signal, a review
|
|
25
|
-
note. No evidence → it is an opinion, not a delta.
|
|
17
|
+
- `<learning>` — the insight. The `- [COMPETENCY · status]` tag line comes **first**; `(evidence: …)` **closes** the delta.
|
|
18
|
+
- `(evidence: …)` — **required**, non-empty: a failing scenario, a production signal, a review note. No evidence → it is an opinion, not a delta.
|
|
26
19
|
|
|
27
|
-
A long learning may wrap —
|
|
28
|
-
delta, not two:
|
|
20
|
+
A long learning may wrap — `add.py check` joins continuation lines, so this is **one** delta:
|
|
29
21
|
|
|
30
22
|
```
|
|
31
23
|
- [SDD · open] the export endpoint must reject a tenant-scoped token used cross-tenant,
|
|
@@ -42,23 +34,19 @@ delta, not two:
|
|
|
42
34
|
| `TDD` | Test | how we prove correctness — a missing scenario, a flaky or hollow test |
|
|
43
35
|
| `ADD` | AI/build | how the AI builds — a harness, prompt, or convention that helped or hurt |
|
|
44
36
|
|
|
45
|
-
If a learning
|
|
46
|
-
That is its home. Split genuinely separate learnings into separate deltas; never tag one twice.
|
|
37
|
+
If a learning touches two, ask "which competency, once updated, would have PREVENTED this?" — that is its home. Split separate learnings into separate deltas; never tag one twice.
|
|
47
38
|
|
|
48
39
|
## Status lifecycle
|
|
49
40
|
|
|
50
41
|
```
|
|
51
42
|
emit (OBSERVE) human review (foundation-update-loop)
|
|
52
|
-
open ───────────▶ folded (
|
|
53
|
-
└──────────▶ rejected (considered and deliberately NOT consolidated —
|
|
43
|
+
open ───────────▶ folded (learning merged into PROJECT.md; version bumps)
|
|
44
|
+
└──────────▶ rejected (considered and deliberately NOT consolidated — trail kept)
|
|
54
45
|
```
|
|
55
46
|
|
|
56
|
-
|
|
57
|
-
delta is left in place (not deleted) so "we saw this and chose not to act" stays auditable.
|
|
47
|
+
A `rejected` delta is left in place (not deleted) so "we saw this and chose not to act" stays auditable.
|
|
58
48
|
|
|
59
|
-
## Reject codes
|
|
60
|
-
|
|
61
|
-
There is no engine validator yet, so before you record a delta, self-check it:
|
|
49
|
+
## Reject codes
|
|
62
50
|
|
|
63
51
|
<reject_codes>
|
|
64
52
|
- `unknown_competency` — the tag is missing or not one of `DDD · SDD · UDD · TDD · ADD`. Fix the tag.
|
|
@@ -68,14 +56,10 @@ There is no engine validator yet, so before you record a delta, self-check it:
|
|
|
68
56
|
|
|
69
57
|
## Worked example
|
|
70
58
|
|
|
71
|
-
A task that built a tenancy feature finished its OBSERVE phase with:
|
|
72
|
-
|
|
73
59
|
```
|
|
74
60
|
- [DDD · open] the account model conflated org and workspace (evidence: scenario_cross_tenant_read failed)
|
|
75
61
|
- [TDD · open] no scenario covered a deleted tenant's dangling sessions (evidence: review note, PR thread)
|
|
76
62
|
- [ADD · open] the scaffold's allow-list missed the tenancy lib, slowing build (evidence: build log retry)
|
|
77
63
|
```
|
|
78
64
|
|
|
79
|
-
|
|
80
|
-
consolidated the DDD and TDD deltas into `PROJECT.md` (→ `folded`) and rejected the ADD one as a one-off
|
|
81
|
-
(→ `rejected`). The foundation got sharper; nothing was silently lost.
|
|
65
|
+
At the next foundation update the human consolidated the DDD and TDD deltas (→ `folded`) and rejected the ADD one (→ `rejected`). The foundation got sharper; nothing was silently lost.
|
package/skill/add/design.md
CHANGED
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
When a **UI feature** reaches specify, design it before you build it. This loop takes the
|
|
4
4
|
feature from the **domain** to a screen the human has **seen and confirmed** — a real captured
|
|
5
|
-
image — *before* any implementation
|
|
6
|
-
|
|
7
|
-
runs it for you.
|
|
5
|
+
image — *before* any implementation. It is loaded on demand (like `advisor.md` / `confidence.md`);
|
|
6
|
+
the engine never runs it for you.
|
|
8
7
|
|
|
9
8
|
Design before code is the UDD half of the method. The token + component foundation a UI project
|
|
10
9
|
draws from already exists — `tokens.json` (the compact-DTCG dialect, `udd-tokens.md`),
|
|
11
|
-
`catalog.json` + `prototypes/<name>.json` (`udd-catalog.md`). This loop
|
|
12
|
-
|
|
10
|
+
`catalog.json` + `prototypes/<name>.json` (`udd-catalog.md`). This loop fills that foundation
|
|
11
|
+
for a feature and earns the human's sign-off on the look before build.
|
|
13
12
|
|
|
14
13
|
## The loop — four beats
|
|
15
14
|
|
|
@@ -20,52 +19,47 @@ review-domain → research-components → wireframe → render-capture-con
|
|
|
20
19
|
Run the beats in order. Each feeds the next; the last ends at a human design-confirm.
|
|
21
20
|
|
|
22
21
|
### 1 · review-domain
|
|
23
|
-
Start from the **domain**, not
|
|
22
|
+
Start from the **domain**, not a blank canvas. Read the domain model — entities, flows, the
|
|
24
23
|
ubiquitous language in `PROJECT.md` / `GLOSSARY.md` — and derive **which screens** the feature
|
|
25
24
|
needs and the **regions** each screen holds. Map each domain entity to a *presentational*
|
|
26
25
|
component (it shows state; it does not own a domain decision). The screen list + per-screen
|
|
27
|
-
regions are this beat's output,
|
|
26
|
+
regions are this beat's output, grounded in the domain you just read.
|
|
28
27
|
|
|
29
28
|
### 2 · research-components (reuse before you invent)
|
|
30
|
-
Check `catalog.json` **first** and **reuse** the components already there — that
|
|
31
|
-
|
|
32
|
-
libraries for this kind of screen) only to fill a **genuine gap**, and propose a **new** catalog
|
|
29
|
+
Check `catalog.json` **first** and **reuse** the components already there — that keeps screens
|
|
30
|
+
consistent. Research a reference UI only to fill a **genuine gap**, and propose a **new** catalog
|
|
33
31
|
component for that gap with a **cited** reference. Reuse before invention; a new component is the
|
|
34
|
-
exception,
|
|
32
|
+
exception, not the default.
|
|
35
33
|
|
|
36
34
|
### 3 · wireframe
|
|
37
35
|
Draw a **low-fi**, **structural** layout for each screen — regions and component slots, no
|
|
38
|
-
styling, no color. This is the cheapest
|
|
39
|
-
|
|
36
|
+
styling, no color. This is the cheapest artifact that shows the *expected layout*, so the human
|
|
37
|
+
can correct structure before a pixel is styled. Confirm the wireframe, then move on.
|
|
40
38
|
|
|
41
39
|
### 4 · render-capture-confirm
|
|
42
40
|
Render the screen as a **self-contained HTML mock** — the project's component library via CDN,
|
|
43
41
|
bound to `tokens.json` (resolved to CSS variables), composed from the **reusable per-component
|
|
44
42
|
kit** (one token-bound partial per catalog component), populated with realistic **mock** data.
|
|
45
|
-
**Capture** a real image
|
|
43
|
+
**Capture** a real image (a headless screenshot) and present that image to the human for
|
|
46
44
|
**design-confirm** — show-before-ask, **before build**. On confirm, record the layout back to
|
|
47
45
|
`prototypes/<name>.json` + `catalog.json`, save the captured image to
|
|
48
|
-
`.add/design/captures/<name>.<ext>`, and **attach or mention it in the feature's `TASK.md`**
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
*machine-checkable* record of the same screen.
|
|
46
|
+
`.add/design/captures/<name>.<ext>`, and **attach or mention it in the feature's `TASK.md`** —
|
|
47
|
+
so the screen the human approved is traceable from the task that builds it. The HTML mock is the
|
|
48
|
+
*visible evidence*; the json-render tree is the *machine-checkable* record.
|
|
52
49
|
|
|
53
50
|
## Tool-agnostic capture
|
|
54
51
|
|
|
55
|
-
How you render and capture is **your** choice
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
attached/mentioned in the feature's `TASK.md`. `add.py check` raises a never-red
|
|
67
|
-
`missing_capture` WARN for any prototype under `.add/design/prototypes/` that still lacks a
|
|
68
|
-
capture — a nudge to render + confirm it, never a blocker.
|
|
52
|
+
How you render and capture is **your** choice: a headless browser (Playwright / Puppeteer), an
|
|
53
|
+
`html2image`-style renderer, a browser-automation skill, a design tool, or a hosted screenshot
|
|
54
|
+
service. The recommended default is the self-contained HTML mock above, captured headless,
|
|
55
|
+
because it needs no app build yet still wears the project's real tokens and component vocabulary.
|
|
56
|
+
For a project that renders json-render, the recommended default is **`@json-render/image`**
|
|
57
|
+
(Satori → PNG/SVG, no browser). The captured image is **design-confirm evidence** the human
|
|
58
|
+
approves; the engine never renders. This keeps the loop tool-agnostic and the method renderer-free.
|
|
59
|
+
|
|
60
|
+
Captures live at **`.add/design/captures/<name>.<ext>`** and are attached/mentioned in the
|
|
61
|
+
feature's `TASK.md`. `add.py check` raises a never-red `missing_capture` WARN for any prototype
|
|
62
|
+
under `.add/design/prototypes/` that still lacks a capture — a nudge to render + confirm it.
|
|
69
63
|
|
|
70
64
|
The loop **binds** the existing UDD contracts **read-only**: `tokens.json`, `catalog.json`, and
|
|
71
65
|
`prototypes/<name>.json` are read and composed, never reshaped — the `prototypes/<name>.json`
|
package/skill/add/fold.md
CHANGED
|
@@ -1,86 +1,61 @@
|
|
|
1
1
|
# Consolidating lessons — how the foundation self-improves
|
|
2
2
|
|
|
3
|
-
This **closes the loop**. `deltas.md` lets a task EMIT lessons (`open` lessons learned in
|
|
4
|
-
OBSERVE phase); the retrospective consolidation gathers the confirmed ones and writes them into a
|
|
5
|
-
**versioned foundation**, so `DDD · SDD · UDD · TDD · ADD` sharpen across milestones instead of drifting.
|
|
3
|
+
This **closes the loop**. `deltas.md` lets a task EMIT lessons (`open` lessons learned in OBSERVE); retrospective consolidation gathers the confirmed ones and writes them into a **versioned foundation**, so `DDD · SDD · UDD · TDD · ADD` sharpen across milestones.
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
it only ever TRANSCRIBES each lesson's OWN captured text into its routed home and bumps the version.
|
|
9
|
-
It NEVER composes or merges prose, and it never **self-approves** a consolidation — running the
|
|
10
|
-
command records the human's confirmation, it does not replace their judgment. Deciding WHICH lessons
|
|
11
|
-
to keep, and later polishing the raw transcribed bullets into lean one-screen prose, remain the
|
|
12
|
-
human's work — the latter via the **compaction door** (`compact-foundation.md`).
|
|
5
|
+
`add.py fold` is **judgment-free**: it only TRANSCRIBES each lesson's own captured text into its routed home and bumps the version. It NEVER composes or merges prose, and it **never self-approves** a consolidation — running the command records the human's confirmation. Deciding WHICH lessons to keep, and polishing raw transcribed bullets into lean one-screen prose, remain the human's work — the latter via the **compaction door** (`compact-foundation.md`).
|
|
13
6
|
|
|
14
7
|
## When to consolidate
|
|
15
8
|
|
|
16
|
-
At **milestone close** (the natural
|
|
17
|
-
lessons have piled up. One run of `add.py fold` is ONE consolidation session: it bumps
|
|
18
|
-
`foundation-version` exactly once and stamps every lesson it resolves with that one new version.
|
|
9
|
+
At **milestone close** (the natural version bump), or **on demand** when open lessons pile up. One run of `add.py fold` = ONE consolidation session: bumps `foundation-version` exactly once and stamps every resolved lesson with that version.
|
|
19
10
|
|
|
20
11
|
## The ritual
|
|
21
12
|
|
|
22
|
-
1. **Gather** — `add.py deltas` reads every task's OBSERVE block for lessons still `open
|
|
23
|
-
2. **Confirm** — decide which to keep; a lesson you do NOT want is marked `rejected` and left in place
|
|
24
|
-
(see below). Running `add.py fold` over the rest IS your confirmation — the command needs no separate flag.
|
|
13
|
+
1. **Gather** — `add.py deltas` reads every task's OBSERVE block for lessons still `open`.
|
|
14
|
+
2. **Confirm** — decide which to keep; a lesson you do NOT want is marked `rejected` and left in place. Running `add.py fold` over the rest IS your confirmation.
|
|
25
15
|
3. **Write** — `add.py fold [--task <slug>] [--comp <TAG>]` performs the mechanical write atomically:
|
|
26
16
|
- flips each selected `open` lesson to `folded` and stamps it `[folded foundation-version N]`;
|
|
27
|
-
- transcribes each lesson VERBATIM as one bullet at the TOP (newest-first) of its routed section
|
|
17
|
+
- transcribes each lesson VERBATIM as one bullet at the TOP (newest-first) of its routed section;
|
|
28
18
|
- prepends one row to §Key Decisions (date · what · why · outcome);
|
|
29
19
|
- bumps `foundation-version` by one.
|
|
30
|
-
Validate-all-then-write: if any precondition fails the command writes NOTHING
|
|
31
|
-
4. **Propose & polish** —
|
|
32
|
-
lean prose (append-only, newest-first) via the compaction door. The engine never does this editorial step.
|
|
20
|
+
Validate-all-then-write: if any precondition fails the command writes NOTHING.
|
|
21
|
+
4. **Propose & polish** — transcribed bullets are RAW; afterward consolidate/merge into lean prose (append-only, newest-first) via the compaction door.
|
|
33
22
|
|
|
34
|
-
## Consolidation routing
|
|
23
|
+
## Consolidation routing
|
|
35
24
|
|
|
36
25
|
| competency | consolidates into | how |
|
|
37
26
|
|------------|-----------|-----|
|
|
38
|
-
| `DDD` | `PROJECT.md` §Domain |
|
|
39
|
-
| `SDD` | `PROJECT.md` §Spec |
|
|
40
|
-
| `UDD` | `PROJECT.md` §Users |
|
|
41
|
-
| `TDD` | `CONVENTIONS.md` §Method learnings |
|
|
42
|
-
| `ADD` | `CONVENTIONS.md` §Method learnings |
|
|
27
|
+
| `DDD` | `PROJECT.md` §Domain | transcribed bullet at the top (newest-first) |
|
|
28
|
+
| `SDD` | `PROJECT.md` §Spec | transcribed bullet at the top |
|
|
29
|
+
| `UDD` | `PROJECT.md` §Users | transcribed bullet at the top |
|
|
30
|
+
| `TDD` | `CONVENTIONS.md` §Method learnings | transcribed bullet |
|
|
31
|
+
| `ADD` | `CONVENTIONS.md` §Method learnings | transcribed bullet |
|
|
43
32
|
|
|
44
|
-
|
|
45
|
-
**§Key Decisions** (newest-first) (date · decision · why · outcome): the universal, auditable trail of
|
|
46
|
-
what the foundation learned.
|
|
33
|
+
Every consolidation ALSO prepends one row at the TOP of `PROJECT.md` §Key Decisions: date · decision · why · outcome.
|
|
47
34
|
|
|
48
35
|
## Status transitions & version
|
|
49
36
|
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
|
|
53
|
-
-
|
|
54
|
-
silently rewrites existing foundation text — EXCEPT via the recorded **compaction door** (`compact-foundation.md`):
|
|
55
|
-
eligible (shipped + zero open residues) stable entries collapse upward into a rolled-up settled line at the tail.
|
|
56
|
-
- each `add.py fold` run **bumps** the `foundation-version:` marker in `PROJECT.md` by one (monotonic int).
|
|
37
|
+
- **confirm**: `open` → `folded` (text transcribed at top of routed target, newest-first).
|
|
38
|
+
- **decline**: `open` → `rejected`, left in place — "we considered and chose not to act" stays auditable.
|
|
39
|
+
- Consolidation is **append-only (newest-first)**: PREPENDS new bullets/rows, never silently rewrites — EXCEPT via the recorded compaction door.
|
|
40
|
+
- Each `add.py fold` run **bumps** `foundation-version:` in `PROJECT.md` by one (monotonic int).
|
|
57
41
|
|
|
58
|
-
## Reject codes
|
|
42
|
+
## Reject codes
|
|
59
43
|
|
|
60
44
|
<reject_codes>
|
|
61
|
-
- `no_open_deltas` — nothing is `open` in the selected scope.
|
|
62
|
-
- `missing_route_section` — a lesson routes to a foundation section that does not exist
|
|
63
|
-
lesson with no `## Users` section). Fail-closed: add the section header, then re-run. Nothing is written.
|
|
45
|
+
- `no_open_deltas` — nothing is `open` in the selected scope. Version is NOT bumped.
|
|
46
|
+
- `missing_route_section` — a lesson routes to a foundation section that does not exist. Add the section header, then re-run. Nothing is written.
|
|
64
47
|
- `no_foundation_version` — `PROJECT.md` carries no parseable `foundation-version:` marker to bump.
|
|
65
48
|
</reject_codes>
|
|
66
49
|
|
|
67
|
-
|
|
68
|
-
silently dropped): invoking `add.py fold` IS the confirmation, so `unconfirmed_fold` no longer applies;
|
|
69
|
-
and routing is total over the five competencies, so a missing destination surfaces as the more precise
|
|
70
|
-
`missing_route_section` rather than `unroutable_delta`.
|
|
50
|
+
Convention-era codes `unconfirmed_fold` and `unroutable_delta` are **retired**: invoking `add.py fold` IS the confirmation; a missing destination surfaces as `missing_route_section`.
|
|
71
51
|
|
|
72
|
-
## Worked example
|
|
52
|
+
## Worked example
|
|
73
53
|
|
|
74
|
-
The `competency-deltas` task closed its OBSERVE with two lessons
|
|
75
|
-
which have no PROJECT.md section:
|
|
54
|
+
The `competency-deltas` task closed its OBSERVE with two lessons:
|
|
76
55
|
|
|
77
56
|
```
|
|
78
57
|
- [ADD · open] dogfood .add/tooling template can silently diverge from canonical (evidence: md5 mismatch this build)
|
|
79
58
|
- [TDD · open] structural tests guard canonical artifacts but not their dogfood twins (evidence: scope-loop note + this build)
|
|
80
59
|
```
|
|
81
60
|
|
|
82
|
-
|
|
83
|
-
`CONVENTIONS.md` §Method learnings, prepends a §Key Decisions row, flips them to `folded` with a
|
|
84
|
-
`[folded foundation-version N]` stamp, and bumps `foundation-version` 1 → 2 — all in one atomic write.
|
|
85
|
-
The two competencies the foundation never tracked before now have a home — which is exactly why v5
|
|
86
|
-
routes `TDD`/`ADD` to `CONVENTIONS.md`.
|
|
61
|
+
The human keeps both and runs `add.py fold`. Routing transcribes each into `CONVENTIONS.md` §Method learnings, prepends a §Key Decisions row, flips them to `folded` with `[folded foundation-version N]`, and bumps `foundation-version` 1 → 2 — all in one atomic write.
|
package/skill/add/graduate.md
CHANGED
|
@@ -1,75 +1,39 @@
|
|
|
1
1
|
# Stage graduation — propose the move to production as a roadmap, never a flip
|
|
2
2
|
|
|
3
|
-
A project
|
|
4
|
-
the MVP is genuinely covered AND a human-confirmed roadmap of production work exists. This guide
|
|
5
|
-
is the **4th scope level** — after setup (`phases/0-setup.md`), intake (`intake.md` / `scope.md`),
|
|
6
|
-
and the milestone loop (`loop.md`). It turns the bare `add.py stage` flip into the **final step** of
|
|
7
|
-
an analytics-driven, interview-led orchestration.
|
|
3
|
+
A project graduates when the MVP is genuinely covered AND a human-confirmed roadmap of production work exists. This is the **4th scope level** — after setup, intake/scope, and the milestone loop. It turns the bare `add.py stage` flip into the **final step** of an analytics-driven, interview-led orchestration.
|
|
8
4
|
|
|
9
|
-
You
|
|
10
|
-
tallies and enforces the floor. The engine never decides that the project is "ready" — that is
|
|
11
|
-
judgment, and it belongs to the interview.
|
|
5
|
+
You **gather and propose**; the **human confirms and judges**; the engine only counts tallies and enforces the floor. The engine never decides "ready" — that is judgment, and it belongs to the interview.
|
|
12
6
|
|
|
13
|
-
## The cue
|
|
7
|
+
## The cue
|
|
14
8
|
|
|
15
|
-
When every milestone is `done` AND the human's stage-goal-criteria in `PROJECT.md` are all `[x]`,
|
|
16
|
-
`add.py status` prints:
|
|
9
|
+
When every milestone is `done` AND the human's stage-goal-criteria in `PROJECT.md` are all `[x]`, `add.py status` prints:
|
|
17
10
|
|
|
18
11
|
```
|
|
19
12
|
→ MVP covered → propose graduation
|
|
20
13
|
```
|
|
21
14
|
|
|
22
|
-
|
|
23
|
-
(a project with no stage-goal-criteria block behaves exactly as today — grandfathered, zero change).
|
|
15
|
+
Before both tallies complete, status is silent. A project with no stage-goal-criteria block is grandfathered — zero change.
|
|
24
16
|
|
|
25
17
|
## The flow
|
|
26
18
|
|
|
27
|
-
1. **Gather
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
2. **Co-specify interview** — synthesize *"what production means HERE"* WITH the human, using the
|
|
33
|
-
gathered records as the agenda (the residue to harden, the coverage gaps to monitor, the open
|
|
34
|
-
deltas to consolidate). This synthesis is the judgment the engine refuses to make. Interview to real confidence —
|
|
35
|
-
do not guess what "production-ready" means for this project.
|
|
36
|
-
3. **Draft the roadmap** — for each production outcome the interview surfaces, draft a production
|
|
37
|
-
milestone with the EXISTING command and goal-gate criteria:
|
|
38
|
-
`add.py new-milestone <slug> --stage production --goal "…"`, then write its exit criteria. The
|
|
39
|
-
roadmap is **≥1** milestone — the hardening work itself (SLOs, rollback tests, incident runbooks)
|
|
40
|
-
is what these milestones *contain*; this guide proposes them, it does not do them.
|
|
41
|
-
4. **Human confirms** — present the roadmap via `report-template.md`, opening with the ARC
|
|
42
|
-
(goal · done · plan): the stage-graduation goal, the MVP coverage that earns the move, and the
|
|
43
|
-
plan the production milestones lay out. Render the roadmap as a guided choice — the recommended path
|
|
44
|
-
+ its described alternatives (per `report-template.md`). The human accepts, edits, or declines each drafted
|
|
45
|
-
milestone. No milestone is created without this; nothing advances on a draft the human has not confirmed.
|
|
46
|
-
5. **Flip — the final step** — only now run `add.py stage production`. Because ≥1 production milestone
|
|
47
|
-
now exists, the guard passes and the transition is recorded. This is the orchestration's last act.
|
|
19
|
+
1. **Gather** — run `add.py graduation-report` (`--json` to branch on it). Clusters the MVP loop's evidence: open deltas by competency · open RISK-ACCEPTED waivers · RETRO records · verify residue · observe-loop coverage gaps. Gathers, never judges.
|
|
20
|
+
2. **Co-specify interview** — synthesize *"what production means HERE"* WITH the human, using the gathered records as the agenda. Interview to real confidence — do not guess what "production-ready" means for this project.
|
|
21
|
+
3. **Draft the roadmap** — for each production outcome the interview surfaces, draft a production milestone: `add.py new-milestone <slug> --stage production --goal "…"`, then write its exit criteria. The roadmap is **≥1** milestone containing the hardening work (SLOs, rollback tests, incident runbooks).
|
|
22
|
+
4. **Human confirms** — present the roadmap via `report-template.md`, opening with the ARC (goal · done · plan). Render as a guided choice (per `report-template.md`). Nothing advances on an unconfirmed draft.
|
|
23
|
+
5. **Flip — the final step** — only now run `add.py stage production`. Because ≥1 production milestone now exists, the guard passes and the transition is recorded.
|
|
48
24
|
|
|
49
|
-
## The floor
|
|
25
|
+
## The floor
|
|
50
26
|
|
|
51
|
-
`add.py stage production` is **guarded**:
|
|
52
|
-
byte-unchanged) when zero milestones have `stage: production`. The check is a **tally** — "does a
|
|
53
|
-
production-roadmap record exist?" — never a readiness judgment (gather-not-judge at stage level;
|
|
54
|
-
it mirrors the milestone goal-gate's `milestone_goal_unmet`). `--force` overrides it, preserving human
|
|
55
|
-
authority for grandfathered/edge cases; use it deliberately, not as the normal path.
|
|
27
|
+
`add.py stage production` is **guarded**: refuses with `stage_no_roadmap` when zero milestones have `stage: production`. The check is a tally, never a readiness judgment. `--force` overrides for grandfathered/edge cases.
|
|
56
28
|
|
|
57
|
-
|
|
58
|
-
existing bare flip, unchanged. `add.py init --stage production` is an explicit at-creation declaration
|
|
59
|
-
(the same authority as `--force`), not a transition — it is out of scope of the guard by design.
|
|
29
|
+
Guard is on the `→production` transition only. Flips to prototype/poc/mvp are unchanged. `add.py init --stage production` is an explicit at-creation declaration — out of scope of the guard.
|
|
60
30
|
|
|
61
|
-
## Invariants
|
|
31
|
+
## Invariants
|
|
62
32
|
|
|
63
|
-
- **The flip is the final step**, never called outside this confirmed-roadmap path.
|
|
64
|
-
|
|
65
|
-
- **The
|
|
66
|
-
enforces the floor — it does not advance the stage on its own.
|
|
67
|
-
- **The flow is continuous, not cue-reentrant.** The moment you draft the first production milestone,
|
|
68
|
-
`status` stops printing the cue (the "every milestone done" tally breaks). That is expected — do NOT
|
|
69
|
-
re-await the cue after drafting; carry the flow straight through to confirm and flip.
|
|
33
|
+
- **The flip is the final step**, never called outside this confirmed-roadmap path.
|
|
34
|
+
- **No auto-flip.** Every step is human-confirmed; the engine gathers, counts, and enforces the floor — it does not advance the stage on its own.
|
|
35
|
+
- **The flow is continuous, not cue-reentrant.** Once you draft the first production milestone, `status` stops printing the cue. Do NOT re-await the cue; carry straight through to confirm and flip.
|
|
70
36
|
|
|
71
37
|
## Depth and reuse
|
|
72
38
|
|
|
73
|
-
The same orchestration serves prototype→poc and poc→mvp; **mvp→production** is the rigorous proof
|
|
74
|
-
case (every step at full depth + the observe loop). At lower stages, run it light — the shape is the
|
|
75
|
-
same, the depth is less.
|
|
39
|
+
The same orchestration serves prototype→poc and poc→mvp; **mvp→production** is the rigorous proof case. At lower stages, run it light — same shape, less depth.
|
package/skill/add/intake.md
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
# Intake — size a request into versioned scope
|
|
2
2
|
|
|
3
|
-
Before a task exists, ADD turns a raw request into correctly-sized, versioned scope
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
**confirms**. Never create scope without a confirmed proposal.
|
|
3
|
+
Before a task exists, ADD turns a raw request into correctly-sized, versioned scope — the
|
|
4
|
+
**intake level** (the per-task flow is phases 0–7; intake is the step *before* a task). You
|
|
5
|
+
(the AI) **propose**; the human **confirms**. Never create scope without a confirmed proposal.
|
|
7
6
|
|
|
8
7
|
## Interview before you size
|
|
9
8
|
|
|
10
|
-
When the request arrives as a question, or its intent is not
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
reject — never guess a bucket.
|
|
9
|
+
When the request arrives as a question, or its intent is not sharp enough to place in one bucket:
|
|
10
|
+
explore it WITH the user before classifying. Reflect the intent you heard, name what seems in and
|
|
11
|
+
out of scope, and offer 2–3 sized options with your own recommendation. Only then emit
|
|
12
|
+
`{ bucket, rationale, command }`. `ask_human` stays the floor: when interviewing cannot sharpen the
|
|
13
|
+
request, reject — never guess a bucket.
|
|
16
14
|
|
|
17
15
|
## The four buckets
|
|
18
16
|
|
|
@@ -25,40 +23,38 @@ Classify every request into exactly ONE bucket:
|
|
|
25
23
|
| `task` | fits within the ACTIVE milestone's stated scope | `add.py new-task <slug>` |
|
|
26
24
|
| `change-request` | modifies ALREADY-FROZEN scope (a frozen contract or a shipped promise) | `add.py phase specify\|contract <affected>` |
|
|
27
25
|
|
|
28
|
-
**Tie-break order: the frozen-scope test runs FIRST, before the size test.**
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
→ `task`.
|
|
26
|
+
**Tie-break order: the frozen-scope test runs FIRST, before the size test.** Ask "does this change
|
|
27
|
+
already-frozen scope?" → if yes it is a `change-request` (never re-size frozen work as new scope).
|
|
28
|
+
Only if no, apply the size test: a new theme → `new-major`; a slice of a live theme → `sub-milestone`;
|
|
29
|
+
fits the active milestone → `task`.
|
|
33
30
|
|
|
34
|
-
**One-task gap rule.** If the request is ONE task but does NOT fit the active milestone's
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
**One-task gap rule.** If the request is ONE task but does NOT fit the active milestone's stated
|
|
32
|
+
scope, do not force it into `sub-milestone` (which requires "too big for one task"): create a new
|
|
33
|
+
micro-milestone to house it (`new-milestone` + `new-task`) — that gives the task ledger attribution
|
|
34
|
+
and clear exit criteria without inflating scope.
|
|
38
35
|
|
|
39
36
|
## What you emit (the proposal)
|
|
40
37
|
|
|
41
|
-
Present the proposal
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
Present the proposal via `report-template.md` — open with the ARC (goal · done · plan): the goal this
|
|
39
|
+
request serves, what is already covered, and the plan the chosen bucket sets up. Render it as a guided
|
|
40
|
+
choice — the recommended bucket + its described alternatives (per `report-template.md`). For every
|
|
41
|
+
request, emit ONE of:
|
|
44
42
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
`add.py …` from the table. The human confirms or overrides before you run it.
|
|
50
|
-
- **a rejection** — `{ reject, rationale }` — and you create nothing, emitting one of the closed set:
|
|
43
|
+
- **a classification** — `{ bucket, rationale, command }` — `rationale` names WHY (the theme, the
|
|
44
|
+
slice, the fit, or the frozen scope touched) and `command` is the exact `add.py …` from the table.
|
|
45
|
+
The human confirms or overrides before you run it.
|
|
46
|
+
- **a rejection** — `{ reject, rationale }` — create nothing, from this closed set:
|
|
51
47
|
|
|
52
48
|
<reject_codes>
|
|
53
49
|
- `ask_human` — too ambiguous/underspecified to size. Ask the human; never guess a bucket.
|
|
54
|
-
- `frozen_scope` — it changes frozen scope; route it as a `change-request` back to
|
|
55
|
-
|
|
56
|
-
- `split_required` — it spans more than one bucket; propose the SMALLEST set of correctly-sized
|
|
57
|
-
|
|
50
|
+
- `frozen_scope` — it changes frozen scope; route it as a `change-request` back to SPECIFY/CONTRACT of
|
|
51
|
+
the affected task — never spawn a parallel milestone that forks the truth.
|
|
52
|
+
- `split_required` — it spans more than one bucket; propose the SMALLEST set of correctly-sized items,
|
|
53
|
+
each with its own rationale; never force it into one milestone.
|
|
58
54
|
</reject_codes>
|
|
59
55
|
|
|
60
|
-
When confirmed, record the `rationale` in the artifact you create or affect — the new
|
|
61
|
-
|
|
56
|
+
When confirmed, record the `rationale` in the artifact you create or affect — the new MILESTONE.md
|
|
57
|
+
goal/body, the new TASK.md, or a note in the affected TASK.md — never in state.json.
|
|
62
58
|
|
|
63
59
|
## Worked examples (from this project's own history)
|
|
64
60
|
|
package/skill/add/loop.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# The dynamic loop — open deltas and extras become the next tasks
|
|
2
2
|
|
|
3
3
|
A milestone is not done when its tasks are done — it is done when its **GOAL** is met.
|
|
4
|
-
This guide
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
This guide drives a milestone toward that goal: turn what each task leaves behind (open lessons,
|
|
5
|
+
and work discovered but out of scope) into the next tasks, and keep going until the exit criteria
|
|
6
|
+
are all met.
|
|
7
7
|
|
|
8
|
-
You
|
|
8
|
+
You **gather and propose**; the **human confirms**; the existing `add.py new-task`
|
|
9
9
|
creates each one. The engine never decides what the next task is — that is judgment.
|
|
10
10
|
|
|
11
11
|
## The goal-gate (what holds the loop open)
|
|
@@ -13,19 +13,19 @@ creates each one. The engine never decides what the next task is — that is jud
|
|
|
13
13
|
`add.py milestone-done <slug>` REFUSES to close a milestone while its exit criteria are not
|
|
14
14
|
all met — it stops with `milestone_goal_unmet` and the milestone stays active. The exit-criteria
|
|
15
15
|
checkboxes in `MILESTONE.md` ARE the human's goal-met affirmation: the engine reads the
|
|
16
|
-
`- [x]`/`- [ ]` tally, it never judges whether the goal is met
|
|
17
|
-
|
|
16
|
+
`- [x]`/`- [ ]` tally, it never judges whether the goal is met. Checking the last box is the
|
|
17
|
+
deliberate act that releases the gate.
|
|
18
18
|
|
|
19
19
|
The gate fires only when criteria exist. A milestone with no exit-criteria checkboxes closes as
|
|
20
20
|
before — write criteria into `MILESTONE.md` if you want the goal-gate to hold the milestone open.
|
|
21
21
|
|
|
22
22
|
`milestone-done` is the only way a milestone reaches `done`; `archive-milestone` and `compact`
|
|
23
|
-
both refuse a milestone that is not done.
|
|
23
|
+
both refuse a milestone that is not done. The one gate is enough — there is no quiet way around it.
|
|
24
24
|
|
|
25
25
|
## The loop
|
|
26
26
|
|
|
27
27
|
When every task is done but the goal is not, `add.py status` shows
|
|
28
|
-
`goal not met (m/n exit criteria)
|
|
28
|
+
`goal not met (m/n exit criteria)`. That is the cue:
|
|
29
29
|
|
|
30
30
|
1. **Gather** the carried inventory:
|
|
31
31
|
- open lessons — `add.py deltas` (the §7 OBSERVE deltas still `open`);
|
|
@@ -38,36 +38,32 @@ When every task is done but the goal is not, `add.py status` shows
|
|
|
38
38
|
the normal flow (specify → … → verify).
|
|
39
39
|
5. **Repeat** until the work the goal needs is done.
|
|
40
40
|
6. **Close** — when the goal is genuinely met, run the **ship review** before you close:
|
|
41
|
-
- **Fill the ship review first** — write the milestone's `## Close — ship review` section
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
it is evidence, **not a new gate**.
|
|
41
|
+
- **Fill the ship review first** — write the milestone's `## Close — ship review` section:
|
|
42
|
+
**Ship by domain** — what changed per bounded context (`tooling` · `skill` · `book`, or
|
|
43
|
+
"untouched"); **Cross-task evidence** — one row per task (`gate` · `tests` · `residue`);
|
|
44
|
+
and the **Goal met?** map — each exit criterion tied to the evidence that satisfies it.
|
|
45
|
+
This is the whole-milestone cross-task evidence the human READS; it is evidence, not a gate.
|
|
47
46
|
- **Check the boxes** — read that evidence, then check the exit-criteria boxes in `MILESTONE.md`
|
|
48
|
-
(the single affirmation
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
- **Define the release steps** — write the milestone's `## Release steps` (merge is one small
|
|
52
|
-
among them; PR, asset export, tag/publish are others
|
|
53
|
-
|
|
54
|
-
Present the close via `report-template.md` — open with the ARC (goal · done · plan)
|
|
55
|
-
|
|
56
|
-
close. Render the close as a guided choice — the recommended next move + its described alternatives
|
|
57
|
-
(per `report-template.md`).
|
|
47
|
+
(the single affirmation), and `add.py milestone-done <slug>` succeeds (then consolidate open
|
|
48
|
+
deltas and archive — the `milestone-done → fold → compact → archive` lifecycle, per
|
|
49
|
+
`fold.md` · `compact-foundation.md`).
|
|
50
|
+
- **Define the release steps** — write the milestone's `## Release steps` (merge is one small
|
|
51
|
+
step among them; PR, asset export, tag/publish are others). These **feed** the release scope —
|
|
52
|
+
read `release.md` for the cut; loop.md never re-specifies it.
|
|
53
|
+
Present the close via `report-template.md` — open with the ARC (goal · done · plan) and
|
|
54
|
+
render as a guided choice (recommended next move + described alternatives).
|
|
58
55
|
|
|
59
56
|
## Reopen is the verb; this loop is the trigger
|
|
60
57
|
|
|
61
|
-
When a deepened verify
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
When a deepened verify finds a criterion unmet on a task already marked done,
|
|
59
|
+
`add.py reopen <task> --to <phase> --reason "..."` returns it to the flow with a recorded
|
|
60
|
+
reason and a reset gate. Deciding WHEN to fire it — because a goal criterion is unmet — is this
|
|
61
|
+
loop's job.
|
|
65
62
|
|
|
66
63
|
## The reactivation residual (deferred)
|
|
67
64
|
|
|
68
|
-
A reopen fired inside the loop happens while the milestone is still **active** — the goal-gate
|
|
69
|
-
it open, so it never reached done
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
milestone reactivation first-class.
|
|
65
|
+
A reopen fired inside the loop happens while the milestone is still **active** — the goal-gate
|
|
66
|
+
held it open, so it never reached done. The one residual — reopening a task inside a milestone
|
|
67
|
+
that was already closed — is surfaced by `add.py check` (a done milestone with a live task reads
|
|
68
|
+
as incoherent). Re-activating a closed milestone is **deferred**: resolve it by hand for now,
|
|
69
|
+
until a later task makes milestone reactivation first-class.
|