@pilotspace/add 1.5.0 → 1.7.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 +91 -0
- package/README.md +34 -1
- package/bin/cli.js +449 -58
- package/docs/02-the-flow.md +1 -1
- package/docs/04-step-2-scenarios.md +6 -0
- package/docs/09-the-loop.md +2 -0
- package/docs/16-releasing.md +182 -0
- package/docs/README.md +3 -0
- package/docs/appendix-c-glossary.md +19 -1
- package/package.json +4 -1
- package/skill/add/SKILL.md +33 -0
- package/skill/add/fold.md +53 -35
- package/skill/add/graduate.md +2 -1
- package/skill/add/intake.md +1 -0
- package/skill/add/loop.md +18 -4
- package/skill/add/phases/0-setup.md +1 -1
- package/skill/add/phases/2-scenarios.md +2 -0
- package/skill/add/phases/3-contract.md +1 -1
- package/skill/add/phases/6-verify.md +1 -1
- package/skill/add/release.md +115 -0
- package/skill/add/report-template.md +42 -6
- package/skill/add/scope.md +1 -0
- package/tooling/add.py +862 -91
- package/tooling/templates/GLOSSARY.md.tmpl +2 -0
- package/tooling/templates/MILESTONE.md.tmpl +23 -0
- package/tooling/templates/TASK.md.tmpl +5 -1
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Release — cut a versioned ship, never an unwatched flip
|
|
2
|
+
|
|
3
|
+
A project does not "release" because someone bumped a number. It releases when one or more
|
|
4
|
+
**closed milestones** are bundled into a versioned, user-facing cut whose notes are evidence-backed,
|
|
5
|
+
whose risk is disclosed, and whose behaviour is then watched. This guide is the **5th scope level** —
|
|
6
|
+
after setup (`phases/0-setup.md`), intake (`intake.md` / `scope.md`), the milestone loop (`loop.md`),
|
|
7
|
+
and stage graduation (`graduate.md`). It is a different verb from each of them:
|
|
8
|
+
|
|
9
|
+
- a **milestone** is *feature-complete and consolidated*; a **release** is *shipped + watched*.
|
|
10
|
+
- **graduation** changes the project's *rigor* (mvp→production); a **release** ships a *version*.
|
|
11
|
+
The axes are orthogonal — you cut releases at every stage (prototype preview · mvp beta · prod GA).
|
|
12
|
+
|
|
13
|
+
So a release is its own scope level: it bundles **≥1** closed milestone, and it may bundle several.
|
|
14
|
+
You (the AI) **gather and propose**; the **human confirms and judges**; the engine records the cut
|
|
15
|
+
and enforces a floor — it **never tags, publishes, or deploys** (the same stance as "the engine never
|
|
16
|
+
renders" in `design.md` and "never spawns" in `advisor.md`). The outward act is the human's.
|
|
17
|
+
|
|
18
|
+
## The cue (what starts this)
|
|
19
|
+
|
|
20
|
+
When ≥1 milestone is `done` AND archived AND not yet attributed to a release, `add.py status` prints:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
→ releasable: N milestone(s) closed since last release
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
That line is the trigger. It is a **tally** over unreleased-but-archived milestones — never a
|
|
27
|
+
readiness judgment. It is silent until the first such milestone exists (a project that has never
|
|
28
|
+
released, or has released everything, sees nothing here — grandfathered, zero change).
|
|
29
|
+
|
|
30
|
+
## The flow
|
|
31
|
+
|
|
32
|
+
One arc, seven steps: **cue → gather → draft notes → readiness floor → human confirms → cut → watch.**
|
|
33
|
+
|
|
34
|
+
1. **Gather the release inventory** — run `add.py release-report` (add `--json` to branch on it). It
|
|
35
|
+
clusters the cut's evidence into labeled record-sets: the closed milestones since the last release ·
|
|
36
|
+
their **consolidated deltas** (the "what changed" record) · open RISK-ACCEPTED waivers riding into
|
|
37
|
+
the release · any open **security HARD-STOP** (a blocker) · the §2 scenarios to take live as monitors.
|
|
38
|
+
It **gathers, never judges** — there is no readiness verdict to read; the records are what you reason from.
|
|
39
|
+
2. **Draft the release notes** — write a [Keep a Changelog](https://keepachangelog.com/) entry **from the
|
|
40
|
+
consolidated deltas + each milestone's goal** (reuse — those consolidated deltas ARE the changelog source;
|
|
41
|
+
you are not inventing the story, you are surfacing what the foundation already recorded). Group Added / Changed /
|
|
42
|
+
Fixed; name the headline capabilities concretely. Propose the **semver bump** — breaking→MAJOR,
|
|
43
|
+
feature→MINOR, fix-only→PATCH — and let the human confirm it (the version is a decision, not a default).
|
|
44
|
+
3. **Meet the readiness floor** — before the cut the engine enforces a floor (see below): the suite is
|
|
45
|
+
green, **zero** open security HARD-STOP, and every RISK-ACCEPTED waiver shipping in this release is
|
|
46
|
+
signed AND disclosed in the notes. A security finding is a HARD-STOP here exactly as in verify —
|
|
47
|
+
never auto-passed, never shipped silent.
|
|
48
|
+
4. **Human confirms the cut** — present via `report-template.md`, opening with the ARC (goal · done · plan):
|
|
49
|
+
the version you are shipping, the milestones + evidence that earn it, and the rollout + watch plan that
|
|
50
|
+
follows. Render the cut as a guided choice — the recommended version + its described alternatives
|
|
51
|
+
(per `report-template.md`). Show the drafted notes, the version, and the waivers being shipped. The human approves once
|
|
52
|
+
(the decision point) — never pre-stamped; you surface a summary to decide on, not the artifact itself.
|
|
53
|
+
5. **Cut — record the marker** — only now run `add.py release <version> --notes <file>`. The engine
|
|
54
|
+
**records**: it prepends the CHANGELOG entry, stamps one append-only row (newest-first) in
|
|
55
|
+
`RELEASES.md` (date · version · milestones · waivers shipped · evidence), and attributes the bundled
|
|
56
|
+
milestones to this version (so the cue stops firing for them).
|
|
57
|
+
6. **Ship — the human's outward act** — the engine has recorded the cut; the **human runs the tag /
|
|
58
|
+
publish / deploy** (`git tag`, `npm publish`, the deploy pipeline — tool-agnostic, whatever this project
|
|
59
|
+
ships through). The tag is the human-gated trigger, exactly the dogfooded recipe today. The engine never
|
|
60
|
+
performs it: design-for-failure lives in the pipeline the human owns, not in the method tool.
|
|
61
|
+
7. **Watch — re-enter observe at the release scope level** — the §2 scenarios become live monitors for the
|
|
62
|
+
*released* version; live-registry / deploy confirmation is post-cut **evidence**, not a unit test. A
|
|
63
|
+
regression found in the wild re-enters at Specify as a **change request** → a narrowed **PATCH hotfix
|
|
64
|
+
release** (this same flow, scoped to the fix). Release is not the finish line — it is where the most
|
|
65
|
+
reliable information appears (`phases/7-observe.md`).
|
|
66
|
+
|
|
67
|
+
## The floor (what the engine enforces)
|
|
68
|
+
|
|
69
|
+
`add.py release <version>` is **guarded** — it refuses (non-zero exit, state byte-unchanged) on:
|
|
70
|
+
|
|
71
|
+
<reject_codes>
|
|
72
|
+
- `release_security_open` — an open security HARD-STOP exists. The non-negotiable; a security finding is
|
|
73
|
+
never shipped. Resolve it (a change request back to Specify) before the cut. `--force` does NOT override this.
|
|
74
|
+
- `release_tests_red` — the suite is not green. Evidence, not a plausible diff, is what a release ships on.
|
|
75
|
+
- `release_no_closed_milestone` — nothing new since the last release. The cut is a no-op; do **not** bump.
|
|
76
|
+
- `release_undisclosed_waiver` — a RISK-ACCEPTED waiver rides into the release but is absent from the notes.
|
|
77
|
+
Disclosure is the floor: a shipped risk the user can't read about is a hidden risk. Add it to the notes.
|
|
78
|
+
</reject_codes>
|
|
79
|
+
|
|
80
|
+
`--force` preserves human authority for grandfathered / edge cases (e.g. a first release of a brownfield
|
|
81
|
+
adopt), mirroring `stage --force` — but it never overrides `release_security_open`. Use it deliberately,
|
|
82
|
+
not as the normal path.
|
|
83
|
+
|
|
84
|
+
## Invariants (never break these)
|
|
85
|
+
|
|
86
|
+
- **The engine records; the human ships.** `add.py release` writes the CHANGELOG + ledger + attribution;
|
|
87
|
+
it never tags, publishes, or deploys. The outward act stays human-owned and tool-agnostic.
|
|
88
|
+
- **Security is a HARD-STOP at the cut**, not just at verify. No `--force`, no waiver, no exception.
|
|
89
|
+
- **Notes draw from consolidated deltas** — release after `fold.md` has run, so the changelog surfaces
|
|
90
|
+
consolidated learnings, not raw open lessons. The lifecycle order is one line:
|
|
91
|
+
`milestone-done → fold → compact → archive → (repeat ≥1×) → release → watch`.
|
|
92
|
+
- **The ledger is append-only (newest-first)** — like §Key Decisions, a release row is never rewritten;
|
|
93
|
+
a superseded or yanked version is recorded with a new row, never edited away.
|
|
94
|
+
- **A release bundles, it does not equal.** One version may attribute several milestones; never force a
|
|
95
|
+
release per milestone.
|
|
96
|
+
|
|
97
|
+
## Depth and reuse
|
|
98
|
+
|
|
99
|
+
The shape is constant; the depth follows the stage (read it from `add.py status`):
|
|
100
|
+
|
|
101
|
+
- **prototype / poc** — a one-line preview note + a tag; no deploy ceremony. The point is feedback, not GA.
|
|
102
|
+
- **mvp** — full notes + tag + a guarded publish; watch the headline scenarios.
|
|
103
|
+
- **production** — every step at full rigor: notes + tag + deploy behind a rollback-tested pipeline +
|
|
104
|
+
live scenario monitors + error-budget watch. The hotfix path (step 7) is first-class here.
|
|
105
|
+
|
|
106
|
+
## Worked example (this method's own 1.5.0)
|
|
107
|
+
|
|
108
|
+
The repo already runs this by hand. The `udd-design-loop` milestone closed (4/4) and consolidated into
|
|
109
|
+
`foundation-version 33`; the human then drafted the `## [1.5.0]` CHANGELOG entry from those deltas,
|
|
110
|
+
bumped the three version sources in lockstep, and the forward-pinned `test_release_1_5_0.py` asserted
|
|
111
|
+
in-repo readiness (versions agree · changelog lineage survives · feature anchors named · engine
|
|
112
|
+
untouched). The cut itself — the `git tag` that triggers the npm/PyPI publish — stayed human-gated, and
|
|
113
|
+
the live-registry confirmation was gathered *after* the tag as verify evidence, never a unit test. This
|
|
114
|
+
guide makes that ritual first-class: `release-report` gathers it, the floor enforces it, `add.py release`
|
|
115
|
+
records it, and the human still owns the tag.
|
|
@@ -61,9 +61,12 @@ NEXT the single next action + what it unlocks
|
|
|
61
61
|
1. **SUMMARY** — one line carrying intent + target + position, e.g.
|
|
62
62
|
"v13 task 2/3 — tests-declared-fallback is green, gate PASS." The reader
|
|
63
63
|
knows where they are before they read anything else.
|
|
64
|
-
2. **DECISION** — the question the human must answer,
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
2. **DECISION** — the question the human must answer, presented as a **guided
|
|
65
|
+
decision**: lead with the one **recommended pick** marked `▶ … (recommended)`,
|
|
66
|
+
then its **1–3** described alternatives, every option carrying a one-line
|
|
67
|
+
description (see "guided choice" below). Exactly one decision per report, or an
|
|
68
|
+
explicit "none — FYI". If a decision exists, ask it after everything below has
|
|
69
|
+
been shown (show-before-ask).
|
|
67
70
|
3. **⚠ FLAGS** — lowest-confidence first, each with *why* confidence is lowest and the
|
|
68
71
|
*cost if wrong*. Where TASK.md markers exist (`⚠` / `- [~]` / `- [ ]`),
|
|
69
72
|
quote them verbatim and keep their document order — extraction ≠ judgment.
|
|
@@ -74,9 +77,38 @@ NEXT the single next action + what it unlocks
|
|
|
74
77
|
line when it is right; overrule it only with a stated reason (e.g. planned
|
|
75
78
|
tasks the state file cannot see yet).
|
|
76
79
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
+
### The DECISION block as a guided choice
|
|
81
|
+
|
|
82
|
+
When the human must choose, render block 2 as a **guided decision** — never a bare next step:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
DECISION <the question>
|
|
86
|
+
|
|
87
|
+
▶ <recommended option> (recommended)
|
|
88
|
+
<one-line description — what it means · what it unlocks or costs>
|
|
89
|
+
<alternative option>
|
|
90
|
+
<one-line description>
|
|
91
|
+
<alternative option>
|
|
92
|
+
<one-line description>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
- **Recommended pick** — exactly one option carries the `▶ … (recommended)` marker; never zero,
|
|
96
|
+
never two. Your `confidence.md` self-score informs which to recommend; the human overrides freely
|
|
97
|
+
(a recommendation, not a default that auto-proceeds).
|
|
98
|
+
- **1–3 described alternatives** — only real, takeable options (no strawmen). If there is genuinely
|
|
99
|
+
one path, show the single recommended step + its description — never invent filler to reach three.
|
|
100
|
+
- **Every option is described** — the pick and each alternative carry a one-line description (what
|
|
101
|
+
it means + what it unlocks or costs); ≤1 line, no bare labels.
|
|
102
|
+
- **Human gates only** — render the guided choice at `[human gate]` decision points; at a
|
|
103
|
+
`[you drive]` autonomous step there is no human to choose, so render none. Show-before-ask still
|
|
104
|
+
holds — the described choice is the ASK, rendered after EVIDENCE.
|
|
105
|
+
|
|
106
|
+
**The ask itself** — when block 2's decision becomes a literal question component (an
|
|
107
|
+
`AskUserQuestion` picker or a numbered menu), compose it as the guided choice above: the
|
|
108
|
+
**recommended option goes first, with a `(Recommended)` suffix**, and each option's `description`
|
|
109
|
+
carries its one-line description. On a tool without `AskUserQuestion`, render the same shape as a
|
|
110
|
+
numbered/`▶` menu in chat — the convention is tool-agnostic. The question text stays a summary —
|
|
111
|
+
intent + what "yes" means + the flag count — pointing at the report above.
|
|
80
112
|
|
|
81
113
|
## Hard rules
|
|
82
114
|
|
|
@@ -84,6 +116,10 @@ report above, the question carries intent + what "yes" means + the flag count.
|
|
|
84
116
|
- **Summary-first.** Never bury the decision under a task list or a diff.
|
|
85
117
|
- **Show before ask.** Render the artifact (digest · diff · report) before any
|
|
86
118
|
approval question; the human decides on what they can see.
|
|
119
|
+
- **Guided decision.** At a `[human gate]`, present block 2 as a guided choice — one highlighted
|
|
120
|
+
**recommended pick** (`▶ … (recommended)`, exactly one) + its 1–3 described alternatives, every
|
|
121
|
+
option carrying a one-line description; never a bare next step. `confidence.md` informs the pick;
|
|
122
|
+
the human overrides freely. Not at `[you drive]` autonomous steps.
|
|
87
123
|
- **Reconcile the count.** Before the ask, your ⚠ FLAGS must reconcile with
|
|
88
124
|
`add.py report --decide`'s open-item count. If your prose calls an item
|
|
89
125
|
resolved while the digest still counts it open, the engine wins — fix the data
|
package/skill/add/scope.md
CHANGED
|
@@ -39,6 +39,7 @@ Rank assumptions lowest-confidence first; the top 1–2 get the flag the human r
|
|
|
39
39
|
`⚠ <assumption> — lowest confidence because <why>; if wrong: <cost>`. Present the draft via
|
|
40
40
|
`report-template.md` — open with the ARC (goal · done · plan): the goal this milestone serves,
|
|
41
41
|
what is already covered, and the plan its task list lays out.
|
|
42
|
+
Render the draft as a guided choice — the recommended scope + its described alternatives (per `report-template.md`).
|
|
42
43
|
|
|
43
44
|
## Drafting a good MILESTONE.md (section by section)
|
|
44
45
|
|