@pilotspace/add 1.12.0 → 1.14.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 +90 -0
- package/bin/cli.js +203 -15
- package/docs/03-step-1-specify.md +1 -1
- package/docs/04-step-2-scenarios.md +1 -1
- package/docs/08-step-6-verify.md +4 -2
- package/docs/09-the-loop.md +4 -0
- package/docs/11-governance.md +1 -1
- package/docs/16-releasing.md +1 -1
- package/docs/17-components.md +23 -5
- package/docs/appendix-c-glossary.md +6 -4
- package/docs/appendix-d-worked-example.md +79 -0
- package/package.json +1 -1
- package/skill/add/SKILL.md +5 -1
- package/skill/add/advisor.md +8 -1
- package/skill/add/components.md +21 -23
- package/skill/add/phases/5-build.md +1 -1
- package/skill/add/phases/6-verify.md +13 -14
- package/skill/add/phases/7-observe.md +11 -10
- package/skill/add/release.md +1 -1
- package/skill/add/run.md +20 -20
- package/skill/add/scope.md +1 -1
- package/skill/add/streams.md +7 -0
- package/tooling/add.py +689 -93
- package/tooling/add_engine/constants.py +1 -1
- package/tooling/add_engine/release.py +3 -3
- package/tooling/templates/TASK.fast.md.tmpl +3 -1
- package/tooling/templates/TASK.md.tmpl +15 -1
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
|
|
17
17
|
**Co-specification** — how a spec is made in ADD: the AI and the human **brainstorm the shape together** (diverge), the AI **drafts** it, and the human **validates with the AI's advice** (validate). The AI's decisive advice is the *lowest-confidence flag*. It replaces dictation-by-one-side — the human owns the decision, the AI owns surfacing what it does not yet know. See [03 Specify](./03-step-1-specify.md).
|
|
18
18
|
|
|
19
|
-
**Component** — a declared part of a multi-part codebase that owns a source `root` and its own `green-bar` (suite + checks), named in `.add/components.toml` under `[component.<name>]`. A task binds to one with a `component:` header line, which adds that root to its §5 Scope and holds it to that component's green bar at verify. Declared, never inferred; a project with no components is byte-identical to a single-codebase project. See [17 Components](./17-components.md).
|
|
19
|
+
**Component** — a declared part of a multi-part codebase that owns a source `root` and its own `green-bar` (suite + checks), named in `.add/components.toml` under `[component.<name>]`. A task binds to one with a `component:` header line, which adds that root to its §5 Scope and holds it to that component's green bar at verify. At the gate the engine also **surfaces** the component's `verify` command (the literal suite to run, e.g. `pytest -q`) and records it — NO-EXEC, the operator runs it; the fast lane carries the same `component:` affordance. Declared, never inferred; a project with no components is byte-identical to a single-codebase project. See [17 Components](./17-components.md).
|
|
20
20
|
|
|
21
|
-
**Cross-component contract** — the frozen, machine-checkable interface between a producer component and its consumers, declared under `[contract.<id>]` (producer + consumers). A task names its role with a `produces: <id>` or `consumes: <id>` header. On the producer's freeze the engine writes an immutable snapshot at `.add/contracts/<id>.json`; a consumer pins its hash and is flagged `contract_consumer_stale` if the producer later re-freezes a changed shape. Inside one milestone a `consumes:` task is HELD from writing its §3 until the producer's snapshot exists — the intra-milestone BE→FE ordering. See [17 Components](./17-components.md).
|
|
21
|
+
**Cross-component contract** — the frozen, machine-checkable interface between a producer component and its consumers, declared under `[contract.<id>]` (producer + consumers). A task names its role with a `produces: <id>` or `consumes: <id>` header. On the producer's freeze the engine writes an immutable snapshot at `.add/contracts/<id>.json`; a consumer pins its hash and is flagged `contract_consumer_stale` if the producer later re-freezes a changed shape. Inside one milestone a `consumes:` task is HELD from writing its §3 until the producer's snapshot exists — the intra-milestone BE→FE ordering. Freeze-recency: the consumer is also held `producer_contract_stale` if a *live* producer task has re-opened or drifted its §3 (the snapshot no longer matches a frozen producer); `add.py check` surfaces the softer `contract_producer_stale` and `contract_snapshot_hashless` (a snapshot with no hash to verify) as never-red warnings. See [17 Components](./17-components.md).
|
|
22
22
|
|
|
23
|
-
**Federation (multi-repo)** — the transport that carries a frozen cross-component contract between separate repositories. A consumer repo declares `[federation.<id>]` with a `source` (and optional `pin`); `add.py federate pull <id>` validates the producer repo's published snapshot and lands a byte-for-byte copy locally, where it behaves exactly as in a monorepo. Fail-loud: an unknown id, unreadable source, invalid snapshot, or version mismatch HARD-STOPS and lands nothing. Each repo keeps its own git-native `state.json`; only the immutable snapshot crosses. See [17 Components](./17-components.md).
|
|
23
|
+
**Federation (multi-repo)** — the transport that carries a frozen cross-component contract between separate repositories. A consumer repo declares `[federation.<id>]` with a `source` (and optional `pin`); `add.py federate pull <id>` validates the producer repo's published snapshot and lands a byte-for-byte copy locally, where it behaves exactly as in a monorepo. Fail-loud: an unknown id, unreadable source, a `source` that escapes the repo's allowlist (`federation_source_escapes` — the path is confined to a sibling of the repo root), invalid snapshot, or version mismatch HARD-STOPS and lands nothing. Each repo keeps its own git-native `state.json`; only the immutable snapshot crosses. See [17 Components](./17-components.md).
|
|
24
24
|
|
|
25
25
|
**Disposable code** — the view that code is one regenerable implementation of the artifacts, not a durable asset to be preserved.
|
|
26
26
|
|
|
@@ -46,6 +46,8 @@
|
|
|
46
46
|
|
|
47
47
|
**Onboarding** (formerly "on-ramp") — the path a new user walks from install to their first milestone: install → `/add` → describe the goal → the agent runs intake (sizing the request into a milestone the human confirms) → the specification bundle → the self-driving run. The AI-first entry to the method; the human talks to the agent rather than hand-typing `add.py`.
|
|
48
48
|
|
|
49
|
+
**Decisions (ADR)** — the engine-harvested record in a task's §7 OBSERVE: one actor-tagged line per key decision, gathered at the gate from the stamps already in the task — §1 framing `[AI]` (the choice + the rejected alternatives), §3 freeze `[human]`, §5 strategy-actually-used `[AI]`, §6 gate `[human|AI]`. *Harvested, never authored* — the engine invents no decision content, only mirrors what the task recorded — and scoped to the §7 OBSERVE placeholder alone. The durable who-decided-what trail that separates human direction from AI building; `add.py audit` flags a done task whose block never harvested (`adr_record_missing`).
|
|
50
|
+
|
|
49
51
|
**Decision point** (formerly "seam") — a place where the flow stops for human judgment: the contract-freeze approval (the one approval), an escalated verify gate, intake confirmation, milestone close. The machine layer keeps the legacy name: the `--json` owner enum `seam`, the decide-digest key `seam`, and the `seam-audit` CI job.
|
|
50
52
|
|
|
51
53
|
**The decision arc** — the three engine-sourced lines a gate report opens with at every **decision point**: `goal:` the milestone goal the work serves · `done:` the achievement, the proven progress toward it (the gate reports render this line as `done`) · `plan:` what comes next. What `done` reports adapts per gate (verify: tests + evidence · milestone close: exit-criteria met · intake: the request sized) while the three-part shape stays constant. Rendered first, above the report's summary, so the human confirms with sight of the whole trajectory, not a local snapshot. Engine-sourced like all evidence — goal · done · plan are pulled from `add.py` output, never re-typed. Presentation only: it never adds a gate or changes a `PASS` / `RISK-ACCEPTED` / `HARD-STOP` / freeze outcome. The report it opens is the chat report a person reads at a decision point — distinct from the three Test/Quality/Risk reports a verify gate produces ([11 Governance](./11-governance.md)). See the `add` skill's `report-template.md`.
|
|
@@ -100,7 +102,7 @@
|
|
|
100
102
|
|
|
101
103
|
**Release steps** — the AI-defined, per-milestone ordered hints to ship a closed milestone, of which `merge` is one small step (a pull request, an exported hand-off document, a tag or a publish are others). Defined at close and **fed** into the release scope (see **Release**), never a second flow.
|
|
102
104
|
|
|
103
|
-
**Readiness floor** — the engine-enforced pre-cut gate `add.py release` applies before it records anything: a green suite, zero open security `HARD-STOP`, a closed-and-unreleased milestone to bundle, and every riding `RISK-ACCEPTED` waiver disclosed in the notes. Its four rejects are `release_security_open` (un-forceable) · `
|
|
105
|
+
**Readiness floor** — the engine-enforced pre-cut gate `add.py release` applies before it records anything: a green suite, zero open security `HARD-STOP`, a closed-and-unreleased milestone to bundle, and every riding `RISK-ACCEPTED` waiver disclosed in the notes. Its four rejects are `release_security_open` (un-forceable) · `release_build_in_flight` · `release_no_closed_milestone` · `release_undisclosed_waiver`; `--force` may override every reject except the security stop.
|
|
104
106
|
|
|
105
107
|
**RELEASES.md ledger** — the append-only, newest-first trail of release rows at the project root (date · version · milestones · waivers shipped · evidence). Like the §Key Decisions log it is never rewritten; a superseded or yanked version is recorded as a new row. The ledger is the attribution source — a milestone is "released" because a row says so — which is why the `→ releasable` cue never has to read a milestone file.
|
|
106
108
|
|
|
@@ -150,3 +150,82 @@ A week later, telemetry shows an unexpectedly high `forbidden` rate. The `6_obse
|
|
|
150
150
|
---
|
|
151
151
|
|
|
152
152
|
This is the whole method in one feature: four artifacts written in order, an AI build bounded by them, a verification grounded in evidence plus the one check tests miss, and a loop that turns production reality into the next specification.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Multi-component, end to end
|
|
157
|
+
|
|
158
|
+
The example above is a single codebase with one green bar. Real slices often cross components — a backend endpoint and the frontend that calls it. ADD ships that slice *inside one milestone* using the component pillar (chapter 17). Here is the same flow, now spanning two components: a `gateway` backend that **produces** an `orders` contract, and a `web` frontend that **consumes** it.
|
|
159
|
+
|
|
160
|
+
### Declare the components
|
|
161
|
+
|
|
162
|
+
The two parts and the boundary between them are declared in `.add/components.toml` — never inferred:
|
|
163
|
+
|
|
164
|
+
```toml
|
|
165
|
+
[component.gateway]
|
|
166
|
+
root = "apps/gateway"
|
|
167
|
+
green_bar = "pytest + pyright"
|
|
168
|
+
verify = "pytest -q apps/gateway"
|
|
169
|
+
|
|
170
|
+
[component.web]
|
|
171
|
+
root = "apps/web"
|
|
172
|
+
green_bar = "vitest + a11y"
|
|
173
|
+
verify = "pnpm -C apps/web test"
|
|
174
|
+
|
|
175
|
+
[contract.orders]
|
|
176
|
+
producer = "gateway"
|
|
177
|
+
consumers = ["web"]
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
One milestone, **list-orders slice**, holds two tasks: `orders-api` (the BE, `produces: orders`) and `orders-list` (the FE, `consumes: orders`).
|
|
181
|
+
|
|
182
|
+
### The backend freezes first → an immutable snapshot
|
|
183
|
+
|
|
184
|
+
`orders-api` carries a `component: gateway` and a `produces: orders` header. It runs the normal flow — specify, scenarios, contract — and the human freezes its §3:
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
GET /orders?status= -> 200 { orders: [{ id, status, total, placedAt }], nextCursor }
|
|
188
|
+
400 { error: "bad_status" }
|
|
189
|
+
Status: FROZEN @ v1 — approved by the tech lead
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
The moment that contract freezes and the task crosses contract→tests, the engine writes an immutable snapshot — `.add/contracts/orders.json` — recording the id, producer, version, frozen date, and a hash over the frozen §3 shape. That file *is* the published interface.
|
|
193
|
+
|
|
194
|
+
### The frontend is held until the backend freezes
|
|
195
|
+
|
|
196
|
+
`orders-list` (`component: web`, `consumes: orders`) was started in the same milestone, but it must not commit to a shape the backend has not frozen. When it tries to advance scenarios→contract before the snapshot exists, the engine refuses:
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
$ python3 .add/tooling/add.py advance
|
|
200
|
+
add: error: producer_contract_unfrozen: orders-list consumes 'orders' but no frozen producer snapshot exists yet — the FE is held until gateway freezes
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Once `orders.json` exists, the same `advance` succeeds: the FE writes its §3 against the frozen shape and **pins that snapshot's hash**. The slice is ordered by the contract, not by splitting BE and FE across two milestones.
|
|
204
|
+
|
|
205
|
+
If the backend later *re-opens* its §3 to change the shape, the engine holds the consumer `producer_contract_stale` rather than letting it pin a shape that is mid-change — and `add.py check` separately surfaces `contract_producer_stale` / `contract_snapshot_hashless` as never-red warnings. Freeze-recency, not just existence.
|
|
206
|
+
|
|
207
|
+
### Each task verifies against its own green bar
|
|
208
|
+
|
|
209
|
+
At the gate, the engine holds each task to *its* component. `orders-api` must cite `pytest + pyright` in its §6 evidence; `orders-list` must cite `vitest + a11y` — cite the wrong bar (or none) and the gate refuses `component_green_bar_uncited`. The engine never runs either suite; it **surfaces** the component's `verify` command so the operator sees exactly what to run:
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
$ python3 .add/tooling/add.py gate PASS
|
|
213
|
+
task 'orders-api' gate -> PASS
|
|
214
|
+
component: gateway · expected green-bar: pytest + pyright · verify: pytest -q apps/gateway # run this suite — the engine does not (NO-EXEC)
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Two tasks, one milestone, two green bars — each held to its own, each suite run by you.
|
|
218
|
+
|
|
219
|
+
### Across repositories — federation
|
|
220
|
+
|
|
221
|
+
When `gateway` and `web` live in *separate* repos, only the snapshot transport changes. The `web` repo declares where the producer publishes:
|
|
222
|
+
|
|
223
|
+
```toml
|
|
224
|
+
[federation.orders]
|
|
225
|
+
source = "../gateway/.add/contracts/orders.json"
|
|
226
|
+
pin = "v1"
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
`add.py federate pull orders` validates the producer repo's published snapshot (valid JSON, matching id, a hash, matching version) and lands a byte-for-byte copy locally — from there the FE holds and pins exactly as in a monorepo. The pull is fail-loud: an unknown id, an unreadable source, a `source` that escapes the repo's allowlist (`federation_source_escapes`), an invalid snapshot, or a version mismatch each HARD-STOPS and lands nothing. Federation never builds the FE against a guessed, out-of-tree, or stale endpoint.
|
|
230
|
+
|
|
231
|
+
That is the component pillar in one slice: declare the parts, freeze the boundary, hold the consumer behind the producer, verify each part on its own bar, and carry the frozen contract across repos — all within the same six-step flow and its single contract-freeze approval.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pilotspace/add",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"description": "ADD (AI-Driven Development). One skill. Eight steps. Five disciplines. Every feature ships through the loop — a minimal, state-tracked Claude Code skill that ships the AIDD book as its trust layer.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"add": "bin/cli.js"
|
package/skill/add/SKILL.md
CHANGED
|
@@ -15,7 +15,7 @@ user-invocable: true
|
|
|
15
15
|
when_to_use: "Invoke in any repo with a `.add/` directory, or when the user wants spec/tests-first feature work, resumes ADD work, or asks to start/advance a task."
|
|
16
16
|
category: workflows
|
|
17
17
|
keywords: [add, aidd, ai-driven-development, spec-first, tdd, contract, scenarios, verify, milestone, task-orchestration]
|
|
18
|
-
argument-hint: "status | init | continue | [describe new short goals or expectation]"
|
|
18
|
+
argument-hint: "status | init | continue | --todo <text> | [describe new short goals or expectation]"
|
|
19
19
|
license: MIT
|
|
20
20
|
metadata:
|
|
21
21
|
author: add
|
|
@@ -32,6 +32,10 @@ result through passing evidence rather than a plausible-looking diff.
|
|
|
32
32
|
preamble plus seven step sections, filled top to bottom. The Python tool tracks where you
|
|
33
33
|
are so context never rots across sessions.
|
|
34
34
|
|
|
35
|
+
**The `--todo` fast-path.** When the skill ARGUMENTS begin with `--todo`, skip orienting: route to
|
|
36
|
+
`add.py todo` and print its output — `--todo <text>` captures · `--todo` lists open todos ·
|
|
37
|
+
`--todo --done <id>` closes (engine errors surfaced verbatim) — then STOP.
|
|
38
|
+
|
|
35
39
|
## Always start here (orient — do not skip)
|
|
36
40
|
|
|
37
41
|
Engine: `.add/tooling/add.py` · book: `.add/docs/`. Ensure the engine is in the project first:
|
package/skill/add/advisor.md
CHANGED
|
@@ -24,7 +24,7 @@ independent enough to earn it. When in doubt, do it in-context.
|
|
|
24
24
|
|
|
25
25
|
Give the subagent the *piece of your plan it owns* and a fixed return shape. This reuses
|
|
26
26
|
`streams.md`'s worker-contract tags for a single advisory subagent — the contract is identical
|
|
27
|
-
on any runner; only the spawn adapter (see `streams.md`) changes.
|
|
27
|
+
on any runner; only the spawn adapter (see `streams.md`) changes. The `<strategy>` block mirrors the task's §5 (Strategy + Known-problem fixes) as the subagent's PREFERRED path — it self-improves on that plan and reports the strategy it actually used.
|
|
28
28
|
|
|
29
29
|
```xml
|
|
30
30
|
<objective>
|
|
@@ -40,6 +40,13 @@ Work step by step, following the plan:
|
|
|
40
40
|
3. Self-score your result with confidence.md; if any dimension < 0.9, refine before returning.
|
|
41
41
|
</persona>
|
|
42
42
|
|
|
43
|
+
<strategy>
|
|
44
|
+
The task's §5 plan — the Strategy (ordered batches) order and the Known-problem fixes — is
|
|
45
|
+
your PREFERRED starting path, not a hard rule. Improve on it when a better strategy emerges
|
|
46
|
+
as you build; on done, report the strategy you ACTUALLY used so the orchestrator can update
|
|
47
|
+
§5 for the audit trail.
|
|
48
|
+
</strategy>
|
|
49
|
+
|
|
43
50
|
<context_files>
|
|
44
51
|
the plan / task files the piece needs (read-only unless the piece says otherwise)
|
|
45
52
|
</context_files>
|
package/skill/add/components.md
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
# Components — monorepo and multi-repo slices
|
|
2
2
|
|
|
3
|
-
Opt-in pillar for a milestone
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
for this only when one milestone genuinely crosses components. Full narrative:
|
|
7
|
-
book chapter `17-components.md`.
|
|
3
|
+
Opt-in pillar for a milestone spanning **more than one green bar** — a BE + its
|
|
4
|
+
FE, a shared lib + two apps, services across repos. No components declared =
|
|
5
|
+
byte-identical to a single-codebase project. Full narrative: `17-components.md`.
|
|
8
6
|
|
|
9
7
|
## Declare (never inferred)
|
|
10
8
|
|
|
@@ -13,21 +11,21 @@ book chapter `17-components.md`.
|
|
|
13
11
|
```toml
|
|
14
12
|
[component.gateway]
|
|
15
13
|
root = "apps/gateway"
|
|
16
|
-
|
|
14
|
+
green_bar = "pytest + pyright"
|
|
17
15
|
[component.dashboard]
|
|
18
16
|
root = "apps/web"
|
|
19
|
-
|
|
17
|
+
green_bar = "vitest + a11y"
|
|
20
18
|
```
|
|
21
19
|
|
|
22
|
-
A task binds with a `component: <name>` header
|
|
23
|
-
|
|
20
|
+
A task binds with a `component: <name>` header → that root joins its §5 Scope,
|
|
21
|
+
and verify holds it to that component's green-bar.
|
|
24
22
|
|
|
25
23
|
## The loop
|
|
26
24
|
|
|
27
|
-
1. **Per-component verify.** A bound task must CITE its
|
|
28
|
-
the
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
1. **Per-component verify.** A bound task must CITE its green-bar in §6 evidence
|
|
26
|
+
or the gate refuses `component_green_bar_uncited`. The engine never runs the
|
|
27
|
+
suite — it **surfaces** the component's `verify` command (and records it in §6);
|
|
28
|
+
you run it (NO-EXEC). The fast lane carries the same `component:` affordance.
|
|
31
29
|
2. **Freeze a cross-component contract.** Declare `[contract.<id>]`
|
|
32
30
|
(producer + consumers). A task names its role `produces: <id>` / `consumes: <id>`.
|
|
33
31
|
The producer's freeze (contract→tests) writes the immutable snapshot
|
|
@@ -35,20 +33,20 @@ Scope, and verify holds it to that component's green-bar.
|
|
|
35
33
|
flags consumers `contract_consumer_stale`; a missing/malformed snapshot
|
|
36
34
|
HARD-STOPS — never build against an unfrozen shape.
|
|
37
35
|
3. **One milestone, full slice.** A `consumes:` task is HELD from advancing
|
|
38
|
-
scenarios→contract (`producer_contract_unfrozen`) until the producer's
|
|
39
|
-
|
|
40
|
-
milestone.
|
|
36
|
+
scenarios→contract (`producer_contract_unfrozen`) until the producer's snapshot
|
|
37
|
+
exists — and `producer_contract_stale` if a live producer re-opened/drifted its
|
|
38
|
+
§3 (freeze-recency). The FE stays downstream of the frozen BE, in one milestone.
|
|
41
39
|
4. **Across repos — federate.** A consumer repo declares `[federation.<id>]`
|
|
42
40
|
(`source` + optional `pin`); `add.py federate pull <id>` validates and lands a
|
|
43
|
-
byte-for-byte copy of the producer
|
|
44
|
-
|
|
41
|
+
byte-for-byte copy of the producer's snapshot locally. Fail-loud:
|
|
42
|
+
unknown id / unreadable source / a `source` escaping the repo's allowlist
|
|
43
|
+
(`federation_source_escapes`, confined to a repo-root sibling) / invalid
|
|
45
44
|
snapshot / version mismatch each HARD-STOPS and lands nothing.
|
|
46
45
|
|
|
47
46
|
## Hold the line
|
|
48
47
|
|
|
49
48
|
- **Declared, not inferred** — no scanning `apps/*`.
|
|
50
|
-
- **No central server / no shared mutable state** — federation copies an
|
|
51
|
-
|
|
52
|
-
- **No new approval** —
|
|
53
|
-
|
|
54
|
-
identity story (`streams.md`, governance), layered on this graph.
|
|
49
|
+
- **No central server / no shared mutable state** — federation copies an immutable
|
|
50
|
+
snapshot; each repo keeps its own `state.json`.
|
|
51
|
+
- **No new approval** — engine-enforced gates on the six-step flow, not extra human
|
|
52
|
+
checkpoints. Per-component ownership/autonomy is the identity story (`streams.md`).
|
|
@@ -16,7 +16,7 @@ tests, iterate to green. Keep each batch small enough to review in full.
|
|
|
16
16
|
- **Scope (may touch)** — the allowlist of every file the build may write (backticked tokens). Needing a file outside the declared Scope is a **STOP → change request** back to Specify, never improvisation.
|
|
17
17
|
- **Strategy (ordered batches)** — the planned build order. Guidance, not enforced.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Enforced: a completing verify gate refuses an out-of-scope build (`scope_violation` → self-heal); `add.py check` surfaces it.
|
|
20
20
|
|
|
21
21
|
## The cardinal rule
|
|
22
22
|
|
|
@@ -3,16 +3,15 @@
|
|
|
3
3
|
Goal: establish trust and record an outcome. Passing tests are necessary, not
|
|
4
4
|
sufficient. Fill **§6** in TASK.md including the GATE RECORD.
|
|
5
5
|
|
|
6
|
-
> **Who resolves this gate depends on the `autonomy:` header
|
|
7
|
-
>
|
|
8
|
-
>
|
|
9
|
-
>
|
|
10
|
-
>
|
|
11
|
-
> whenever residue is found, this phase is **human-led**.
|
|
6
|
+
> **Who resolves this gate depends on the `autonomy:` header.** Under `autonomy: auto` (the default)
|
|
7
|
+
> a run auto-PASSes on complete evidence with **no residue** (security · concurrency · architecture),
|
|
8
|
+
> recorded *auto-resolved* with the named run as owner;
|
|
9
|
+
> **security is always a HARD-STOP and is never auto-passed**. Under `conservative`, or whenever
|
|
10
|
+
> residue is found, this phase is **human-led** (auto-PASS conditions: `run.md`).
|
|
12
11
|
|
|
13
12
|
## Before you build — declare the build expectations
|
|
14
13
|
|
|
15
|
-
Fill the §6 **Build expectations** block BEFORE Build: OBSERVABLE outcomes derived from §2
|
|
14
|
+
Fill the §6 **Build expectations** block BEFORE Build: OBSERVABLE outcomes derived from §2 + §3. At this gate, confirm each against real evidence (the `confirmed by` column) — one with no evidence is not yet verified.
|
|
16
15
|
|
|
17
16
|
## Part one — confirm the evidence
|
|
18
17
|
|
|
@@ -26,22 +25,22 @@ If any is false, stop and return to Build.
|
|
|
26
25
|
## Part two — check what tests miss
|
|
27
26
|
|
|
28
27
|
- **Concurrency/timing** — correct when two run at once? (Tests run serially and miss races.)
|
|
29
|
-
- **Security** — exposed secrets, injection openings, unexpected dependencies. A security finding is always `HARD-STOP`, never a waiver. ANY note here escalates to the human — start it with `NOTE` or `⚠` so `add.py audit` can see it (`unescalated_security_note`).
|
|
28
|
+
- **Security** — exposed secrets, injection openings, unexpected dependencies. A security finding is always `HARD-STOP`, never a waiver. ANY note here escalates to the human — start it with `NOTE` or `⚠` so `add.py audit` can see it (`unescalated_security_note`). **But that check sees only what you wrote down:** it fires on a *marked* note that slipped through as an auto-gate PASS — a finding you never marked is **invisible** to the engine, escalated to no one. Honest disclosure, not false cover: under `auto`, a human **spot-audit** (reading the diff) is the only backstop for a *missed* security finding.
|
|
30
29
|
- **Architecture** — respects layering/dependency rules in CONVENTIONS.md?
|
|
31
30
|
|
|
32
31
|
## Part three — the deep check (do not skim)
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
If the task produced code, record that every new symbol is referenced (wiring) and that no new dead/unused code was introduced. If it produced prose or non-code, record a semantic read — what you read in full and what it confirmed. The resolver judges which path; the engine never classifies.
|
|
35
34
|
|
|
36
|
-
Record it in the §6 **Deep checks** block
|
|
35
|
+
Record it in the §6 **Deep checks** block — an unfilled one is a **shallow verify**, not a PASS.
|
|
37
36
|
|
|
38
37
|
## Part four — was the green earned?
|
|
39
38
|
|
|
40
|
-
A green suite proves tests pass — not that the build EARNED them. Three judgment cheats pass the unchanged suite: src overfit to the test fixtures (special-cased to literal inputs), vacuous asserts (
|
|
39
|
+
A green suite proves tests pass — not that the build EARNED them. Three judgment cheats pass the unchanged suite: src overfit to the test fixtures (special-cased to literal inputs), vacuous asserts (green against an empty implementation), and real logic stubbed away — all invisible to the mechanical tamper tripwire. Score them with an adversarial refute-read: an independent reviewer — the engine never spawns one — prompted to argue the green was NOT earned. A confirmed earned-green failure is HARD-STOP-class: never auto-passed, never RISK-ACCEPTED — a first cheat enters the bounded self-heal loop (run.md). Under `auto`, **record the verdict** in §6's `### Refute-read verdict` block — `add.py audit` flags an unrecorded `refute_unrecorded`, one of three measure-not-block shape lints it surfaces (also `shallow_deep_check` + `risk_unset`).
|
|
41
40
|
|
|
42
41
|
## Record exactly one outcome (no silent pass)
|
|
43
42
|
|
|
44
|
-
|
|
43
|
+
Present this gate via `report-template.md`'s ARC, render DECISION as a guided choice, and reconcile FLAGS with `add.py report --decide`'s open-item count first.
|
|
45
44
|
|
|
46
45
|
| Outcome | When |
|
|
47
46
|
|---------|------|
|
|
@@ -53,10 +52,10 @@ When you present this gate, open with the ARC per `report-template.md`, render t
|
|
|
53
52
|
|
|
54
53
|
<exit_gate>
|
|
55
54
|
- [ ] Evidence confirmed, non-functional risks checked, outcome recorded — a person approved, or
|
|
56
|
-
(under `autonomy: auto
|
|
55
|
+
(under `autonomy: auto`, no residue) the run auto-resolved as accountable owner.
|
|
57
56
|
</exit_gate>
|
|
58
57
|
|
|
59
|
-
> **Advisor · Confidence** — the earned-green refute-read is the canonical adversarial spawn (advisor.md); score
|
|
58
|
+
> **Advisor · Confidence** — the earned-green refute-read is the canonical adversarial spawn (advisor.md); score it before recording the gate (confidence.md).
|
|
60
59
|
|
|
61
60
|
```bash
|
|
62
61
|
python3 .add/tooling/add.py gate PASS # marks the task done
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
# Phase 7 — Observe (feed the next loop)
|
|
2
2
|
|
|
3
|
-
Goal: release deliberately, watch reality,
|
|
3
|
+
Goal: release deliberately, watch reality, turn what you learn into the next spec. Fill **§7** in TASK.md.
|
|
4
4
|
|
|
5
5
|
## Do
|
|
6
6
|
|
|
7
|
-
1. **Release behind a scope-of-impact limit** —
|
|
7
|
+
1. **Release behind a scope-of-impact limit** — a flag and/or gradual rollout.
|
|
8
8
|
2. **Reuse scenarios as monitors** — the §2 scenarios that defined "correct" now
|
|
9
|
-
define what you alert on: overall error rate, each rejection's rate (a spike
|
|
10
|
-
|
|
9
|
+
define what you alert on: overall error rate, each rejection's rate (a spike is a
|
|
10
|
+
signal), latency of the risky op under load.
|
|
11
11
|
3. **Draft the next spec delta** — every defect, surprise, or new need becomes a
|
|
12
|
-
|
|
13
|
-
4. **Propose a voice delta** —
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
only
|
|
17
|
-
|
|
12
|
+
change that re-enters the flow at Specify (a new task).
|
|
13
|
+
4. **Propose a voice delta** — note where your voice diverged from the human's (wordings +
|
|
14
|
+
flow); propose a confirmable **voice delta** tuning `SOUL.md`, emitted `open`. The human
|
|
15
|
+
confirms, then you rewrite the routed section. Read `soul.md` (grammar, routing,
|
|
16
|
+
human-is-only-writer).
|
|
17
|
+
|
|
18
|
+
> **Decisions (ADR)** — at the gate the engine harvests §7's ADR block (§1/§3/§5/§6); `add.py audit` flags one never harvested.
|
|
18
19
|
|
|
19
20
|
## AI prompt
|
|
20
21
|
|
package/skill/add/release.md
CHANGED
|
@@ -35,7 +35,7 @@ One arc, seven steps: **cue → gather → draft notes → readiness floor → h
|
|
|
35
35
|
|
|
36
36
|
<reject_codes>
|
|
37
37
|
- `release_security_open` — open security HARD-STOP exists. Never shipped. `--force` does NOT override this.
|
|
38
|
-
- `
|
|
38
|
+
- `release_build_in_flight` — a build is in flight, ungated.
|
|
39
39
|
- `release_no_closed_milestone` — nothing new since last release.
|
|
40
40
|
- `release_undisclosed_waiver` — a RISK-ACCEPTED waiver rides into the release but is absent from the notes.
|
|
41
41
|
</reject_codes>
|
package/skill/add/run.md
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
# The dynamic run — executing a locked scope
|
|
2
2
|
|
|
3
|
-
Once a task's CONTRACT is frozen (phase 3), the scope is *locked
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
**single human approval at the decision point** — the AI drafts the whole bundle, a human approves
|
|
8
|
-
it once. The engine stays judgment-free: this is a rubric, not `add.py`.
|
|
3
|
+
Once a task's CONTRACT is frozen (phase 3), the scope is *locked* — ADD's autonomy decision point:
|
|
4
|
+
below it code is disposable; above it nothing breaks. This rubric covers the **build->verify half,
|
|
5
|
+
executed as a dynamic, self-improving run**. The human-led **specification bundle** (Specify ·
|
|
6
|
+
Scenarios · Contract) still owns *direction*. The engine stays judgment-free: this is a rubric, not `add.py`.
|
|
9
7
|
|
|
10
8
|
## The specification bundle (v7)
|
|
11
9
|
|
|
@@ -14,19 +12,18 @@ bundle in one pass** — Spec, Scenarios, Contract, and failing Tests — and pr
|
|
|
14
12
|
The human gives **one approval, at the frozen contract** (the decision point).
|
|
15
13
|
|
|
16
14
|
Why one and not zero: the decision point **stays human**. The AI *drafts* the contract but never
|
|
17
|
-
*freezes its own* — a person approves the frozen shape before any auto-run touches code
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
*freezes its own* — a person approves the frozen shape before any auto-run touches code: that the
|
|
16
|
+
Spec captures real intent, the Scenarios cover the cases that matter, and the Contract shape is the
|
|
17
|
+
one to freeze. Reject any part → back to draft (backward-correction, principle 4, not failure). The
|
|
18
|
+
decision-point guide (`phases/3-contract.md`) carries the **freeze review checklist** — seven lines,
|
|
19
|
+
⚠-first.
|
|
22
20
|
|
|
23
21
|
**The lowest-confidence flag.** The AI presents the bundle **lowest-confidence first**: the
|
|
24
22
|
**1–2 points most likely to be wrong**, tagged by part
|
|
25
|
-
(`⚠ [spec|scenario|contract|test] … — because …; if wrong: …`)
|
|
26
|
-
assumption
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
gap is a CI checker's job, not prose.
|
|
23
|
+
(`⚠ [spec|scenario|contract|test] … — because …; if wrong: …`) — `because` names the §1
|
|
24
|
+
assumption behind the doubt, `if wrong` its cost. If nothing is materially uncertain, the AI still
|
|
25
|
+
names the single biggest risk — never a blank "none". This flag is honor-system: the lint cannot
|
|
26
|
+
force engagement — closing that gap is a CI checker's job, not prose.
|
|
30
27
|
|
|
31
28
|
## When the run begins — the scope-lock trigger
|
|
32
29
|
|
|
@@ -71,6 +68,7 @@ recorded pass is an explicit pass, not a skip).
|
|
|
71
68
|
- **Auto-PASS requires ALL of:** every test green; coverage not decreased; no test weakened and no
|
|
72
69
|
contract edited; loops dry; completeness-critic clean; and the deep check below.
|
|
73
70
|
- **The deep check (every gate, do not skim).** If the task produced code, record that every new symbol is referenced (wiring) and that no new dead/unused code was introduced. If it produced prose or non-code, record a semantic read. An unfilled deep check is a **shallow verify**, not an auto-PASS.
|
|
71
|
+
- **The recorded refute-read (under `auto`).** The earned-green refute-read (`6-verify.md`) is not just run — its **verdict is recorded** in §6 (`EARNED | NOT-EARNED`); `add.py audit` surfaces an unrecorded one as `refute_unrecorded` — one of three shape lints it lists (with `shallow_deep_check` + `risk_unset`) — and a human spot-audit is the backstop. NOT-EARNED routes to `add.py heal`, never an auto-PASS.
|
|
74
72
|
- **Always escalates to a human (never auto-passed):** any **security** finding (HARD-STOP, always);
|
|
75
73
|
a **concurrency**/timing risk the tests cannot exercise; an **architecture**/layering violation;
|
|
76
74
|
any failing test.
|
|
@@ -118,7 +116,9 @@ autonomy: manual | conservative | auto
|
|
|
118
116
|
```
|
|
119
117
|
|
|
120
118
|
- **auto (the default)** — the run may auto-PASS when evidence + residue checks are satisfied.
|
|
121
|
-
Security still always escalates
|
|
119
|
+
Security still always escalates — but only a finding the AI *surfaces*: a security issue the
|
|
120
|
+
reviewer misses is **invisible** to the engine, so under `auto` a human **spot-audit** is the
|
|
121
|
+
only backstop for a missed finding.
|
|
122
122
|
- **conservative** — the deliberate *lowering*: the run converges but STOPS at the verify gate.
|
|
123
123
|
- **manual** — the strict floor: the human owns the verify gate; the engine never auto-resolves.
|
|
124
124
|
|
|
@@ -138,7 +138,7 @@ in its header is not blocked by the v14 mechanical guard.
|
|
|
138
138
|
|
|
139
139
|
**Autonomy is earned by goal-clarity — the auto-ready goal.** A milestone goal is auto-ready
|
|
140
140
|
when **every exit criterion cites a verifier** — `(verify: <test | command | metric>)`.
|
|
141
|
-
`add.py check` raises
|
|
142
|
-
|
|
143
|
-
|
|
141
|
+
`add.py check` raises `goal_not_auto_ready` while criteria are uncited; `status` prints a
|
|
142
|
+
`goal-ready:` line. It **measures, never blocks** — the lint cannot prove the citation honest
|
|
143
|
+
(`(verify: it works)` passes); that judgment stays the human's.
|
|
144
144
|
</constraints>
|
package/skill/add/scope.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
| `change-request` | route to SPECIFY/CONTRACT of the affected task | 0 milestones |
|
|
12
12
|
| `split_required` | draft ALL N items as a batch in ONE pass | N milestones/tasks |
|
|
13
13
|
|
|
14
|
-
**Confirm before create is the
|
|
14
|
+
**Confirm before create is the convention.** "One pass" means one drafting pass, NOT auto-creation — nothing is written until the human confirms; enforced only by the opt-in `--await-confirm` (below).
|
|
15
15
|
|
|
16
16
|
**Confirm the milestone before detailing tasks.** `new-milestone <slug> --await-confirm` seeds it *unconfirmed* — `new-task` is HELD (`milestone_unconfirmed`) until you show the filled `MILESTONE.md`, get the human's go, and run `milestone-confirm <slug>`. Keeps you from digging into task §0–§5 before the parent is agreed. (Omit the flag: no gate.)
|
|
17
17
|
|
package/skill/add/streams.md
CHANGED
|
@@ -179,6 +179,13 @@ Score confidence (0-1) on Completeness · Clarity · Practicality · Optimizatio
|
|
|
179
179
|
Self-Eval; if any < 0.9, refine before returning.
|
|
180
180
|
</persona>
|
|
181
181
|
|
|
182
|
+
<strategy>
|
|
183
|
+
The task's §5 plan — the Strategy (ordered batches) order and the Known-problem fixes — is
|
|
184
|
+
your PREFERRED starting path, not a hard rule. Improve on it when a better strategy emerges
|
|
185
|
+
as you build; on done, report the strategy you ACTUALLY used so the orchestrator can update
|
|
186
|
+
§5 for the audit trail.
|
|
187
|
+
</strategy>
|
|
188
|
+
|
|
182
189
|
<touch_boundary> <!-- from run.md; the worker's contract, identical on every runner -->
|
|
183
190
|
MAY: rewrite code in src/ · drive tests green WITHOUT weakening them · gather verify evidence.
|
|
184
191
|
MUST NOT: edit the frozen CONTRACT or locked scope · weaken/delete/skip any test ·
|