@pilotspace/add 1.7.3 → 1.9.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 +82 -0
- package/docs/appendix-c-glossary.md +2 -0
- package/package.json +1 -1
- package/skill/add/SKILL.md +86 -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/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 +1075 -152
- package/tooling/templates/TASK.fast.md.tmpl +72 -0
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.
|
|
@@ -12,23 +12,15 @@ the work — gathering them IS the job, not a detour.
|
|
|
12
12
|
## Gather (in TASK.md §0)
|
|
13
13
|
|
|
14
14
|
- **Touches** — the real files · symbols · signatures the task will read or change,
|
|
15
|
-
named from the actual code (use
|
|
16
|
-
|
|
17
|
-
- **Context (working folder)** —
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
· CI) · data/fixtures (samples · fixtures · schemas). Gather only the TASK-SPECIFIC
|
|
21
|
-
delta — never index the whole repo.
|
|
22
|
-
- **Honors** — the patterns and conventions the work must respect, cited from
|
|
23
|
-
`PROJECT.md` / `CONVENTIONS.md`. Gather only the TASK-SPECIFIC delta — never
|
|
24
|
-
re-derive the architecture or re-run the setup brownfield scan.
|
|
25
|
-
- **Anchors the contract cites** — the specific symbols §3 CONTRACT will name. The
|
|
26
|
-
contract may cite only anchors that appear here.
|
|
15
|
+
named from the actual code (use code-navigation tools — grep / symbol search, never memory).
|
|
16
|
+
Each as `path:symbol — what it is / how it is keyed`.
|
|
17
|
+
- **Context (working folder)** — NON-code artifacts the task touches: docs/textbase (README · `*.md` · design notes) · TODOs (`TODO.md` · `FIXME`/`TODO`/`HACK` comments) · config/manifests (configs · `.env.example` · `pyproject`/`package` · CI) · data/fixtures. Task-specific delta only — never index the whole repo.
|
|
18
|
+
- **Honors** — the patterns and conventions the work must respect, cited from `PROJECT.md` / `CONVENTIONS.md`. Task-specific delta only — never re-derive the architecture.
|
|
19
|
+
- **Anchors the contract cites** — the specific symbols §3 CONTRACT will name. The contract may cite only anchors that appear here.
|
|
27
20
|
|
|
28
21
|
**How — gather efficiently:** for the BROAD sweep, prefer a small-model subagent / fast
|
|
29
22
|
index / skim (offload to a cheap context, return a compact map); then DEEPEN on what THIS
|
|
30
|
-
task specifically needs — never lock a shallow first pass.
|
|
31
|
-
never spawns a subagent (tool-agnostic), so the orchestrating agent chooses.
|
|
23
|
+
task specifically needs — never lock a shallow first pass.
|
|
32
24
|
|
|
33
25
|
## Greenfield / first task
|
|
34
26
|
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
# Phase 0 — Setup (autonomous draft → one human baseline approval)
|
|
2
2
|
|
|
3
|
-
Goal: point ADD at a repo and **you** draft the whole foundation — domain, first-milestone scope,
|
|
4
|
-
and the first task's contract — then hand the human exactly one decision: the **baseline approval**. Brownfield
|
|
5
|
-
is silent (the code answers the questions); greenfield keeps a short interview. Either way, the human's
|
|
6
|
-
only gate is `add.py lock`. This is the setup-level analog of a task's one-approval contract freeze.
|
|
3
|
+
Goal: point ADD at a repo and **you** draft the whole foundation — domain, first-milestone scope, and the first task's contract — then hand the human one decision: the **baseline approval**. Brownfield is silent; greenfield keeps a short interview. Either way, the human's only gate is `add.py lock`.
|
|
7
4
|
|
|
8
5
|
## 1 · Zero-touch entry — you run init yourself
|
|
9
6
|
|
|
@@ -14,29 +11,21 @@ project name and stage from the repo, and **arm the baseline-approval gate** wit
|
|
|
14
11
|
python3 .add/tooling/add.py init --name "<inferred from repo/dir>" --stage <prototype|poc|mvp|production> --await-lock
|
|
15
12
|
```
|
|
16
13
|
|
|
17
|
-
- `--await-lock`
|
|
18
|
-
|
|
19
|
-
grandfathered-locked — its gate never arms, and the closing `lock` would error `already_locked`.
|
|
20
|
-
- name + stage are **your judgment** (read them from the dir name, README, manifests); the engine stays
|
|
21
|
-
mechanical. Pick the stage from the ambition you hear: throwaway → `prototype`, one risky slice → `poc`,
|
|
22
|
-
narrow-but-real → `mvp`, full rigor → `production`.
|
|
14
|
+
- `--await-lock` seeds an *unlocked* setup — the engine refuses crossing into build or calling `gate` until you `lock`. A plain `init` is grandfathered-locked; its closing `lock` would error `already_locked`.
|
|
15
|
+
- name + stage are **your judgment** (read from the dir name, README, manifests): throwaway → `prototype`, risky slice → `poc`, narrow-but-real → `mvp`, full rigor → `production`.
|
|
23
16
|
|
|
24
17
|
`init` prints one of two things — **that is your branch**:
|
|
25
|
-
-
|
|
26
|
-
-
|
|
18
|
+
- `brownfield:` → existing code (go to **2a**);
|
|
19
|
+
- no `brownfield:` → empty repo (go to **2b**).
|
|
27
20
|
|
|
28
21
|
## 2a · Brownfield — map it silently
|
|
29
22
|
|
|
30
|
-
The code answers the questions a greenfield interview would ask
|
|
31
|
-
`adopt.md` and follow it: fill each living-doc file from the code, never clobber an existing one, and tag
|
|
32
|
-
every decision `evidence-grounded` (cite the file) or `guessed`. Ask the human **nothing** at this step.
|
|
23
|
+
The code answers the questions a greenfield interview would ask — **read it instead of asking**. Open `adopt.md` and follow it: fill each living-doc file from the code, never clobber an existing one, tag every decision `evidence-grounded` or `guessed`. Ask the human **nothing** at this step.
|
|
33
24
|
|
|
34
25
|
## 2b · Greenfield — the 4-lens interview (kept): co-specify at foundation level
|
|
35
26
|
|
|
36
27
|
An empty repo has no code to read, so run the short interview. This is the **co-specify at foundation
|
|
37
|
-
level** move —
|
|
38
|
-
lifted to the foundation. Ask the one load-bearing question per lens (diverge), draft the foundation
|
|
39
|
-
(converge), then rank where your confidence is lowest and show the top flag first (validate):
|
|
28
|
+
level** move — diverge → converge → validate, as a task's §1 uses (`phases/1-specify.md`), lifted to the foundation. Ask the one load-bearing question per lens, draft, then rank lowest-confidence-first and show the top flag:
|
|
40
29
|
|
|
41
30
|
| Lens | The one question that unblocks the section |
|
|
42
31
|
|------|--------------------------------------------|
|
|
@@ -45,98 +34,59 @@ lifted to the foundation. Ask the one load-bearing question per lens (diverge),
|
|
|
45
34
|
| Users (UDD) | The primary user and the one job they hire this for? (or "no UI — surface is X") |
|
|
46
35
|
| Decisions | What's already decided that you'd regret re-litigating? (first Key Decision row) |
|
|
47
36
|
|
|
48
|
-
Ask only the live ones
|
|
49
|
-
one notation every scope level shares — `⚠ <assumption> — lowest confidence because <why>; if wrong: <cost>` — and
|
|
50
|
-
tag thin or inferred answers `guessed`.
|
|
37
|
+
Ask only the live ones. Rank: `⚠ <assumption> — lowest confidence because <why>; if wrong: <cost>` — tag thin answers `guessed`.
|
|
51
38
|
|
|
52
39
|
## 2c · Domain deep-dive — per-drive, across multiple turns (deepens §2b)
|
|
53
40
|
|
|
54
|
-
§2b gets a foundation from one question per lens; this step DEEPENS it across **multiple
|
|
55
|
-
turns**, one deep-dive per **drive** — naming all four, including the one §2b's lens list omitted:
|
|
56
|
-
|
|
57
41
|
| Drive | Deepen |
|
|
58
42
|
|-------|--------|
|
|
59
|
-
| **DDD** (domain) | core nouns → model:
|
|
60
|
-
| **SDD** (spec) |
|
|
61
|
-
| **UDD** (users) |
|
|
62
|
-
| **TDD** (trust) | what "done & trusted" means:
|
|
43
|
+
| **DDD** (domain) | core nouns → model: entities, invariants, bounded edges |
|
|
44
|
+
| **SDD** (spec) | milestone outcome → behaviors and explicit non-goals |
|
|
45
|
+
| **UDD** (users) | primary user → jobs, surface, the one flow that must feel right |
|
|
46
|
+
| **TDD** (trust) | what "done & trusted" means: risks to prove, evidence that closes them |
|
|
63
47
|
|
|
64
|
-
Capture each surfaced decision as an **ADR**
|
|
65
|
-
**Key Decisions** as it lands — the Decisions lens becomes explicit ADR capture (the *why*, not just the *what*).
|
|
48
|
+
Capture each surfaced decision as an **ADR** into `PROJECT.md` **Key Decisions** as it lands.
|
|
66
49
|
|
|
67
|
-
**Under `autonomy: auto` with full context, auto-complete all four drives in one pass** —
|
|
68
|
-
each without stopping to interview, still lowest-confidence-first, surfacing the top **flag**. Ask
|
|
69
|
-
only the live drives; skip what the request already answered. This deepens **drafting**, never the
|
|
70
|
-
gate: auto-complete NEVER skips the human baseline approval — the `lock` (§4) stays the one decision.
|
|
50
|
+
**Under `autonomy: auto` with full context, auto-complete all four drives in one pass** — lowest-confidence-first, surfacing the top flag. This deepens **drafting**, never the gate: auto-complete NEVER skips the human baseline approval — the `lock` stays the one decision.
|
|
71
51
|
|
|
72
52
|
## 3 · Draft to the lock (both paths)
|
|
73
53
|
|
|
74
|
-
1. **Fill the living documentation
|
|
75
|
-
|
|
76
|
-
`dependencies.allowlist`, and — for a UI project — `DESIGN.md` (the design source of truth: identity ·
|
|
77
|
-
principles · screens · the named-set foundation pointers + render recipe; delete it if there's no UI;
|
|
78
|
-
the design-definition loop that fills it — domain → components → wireframe → a captured screen confirmed before build — is `design.md`).
|
|
79
|
-
Brownfield: from the code. Greenfield: from the interview, gaps flagged `guessed`.
|
|
80
|
-
2. **Propose, then size it.** You just read the codebase (brownfield) or interviewed (greenfield) — so
|
|
81
|
-
don't silently draft. First float a **kickoff suggestion** for the first milestone the human reacts to:
|
|
82
|
-
a **goal** (one outcome sentence), a **flow** (the breadth-first task order that gets there), and
|
|
83
|
-
**scenarios** (concrete examples of what the user can DO once it ships). Keep it a lightweight react-to
|
|
84
|
-
sketch — a few bullets, NOT the frozen `MILESTONE.md` or per-task §2 suites. This is show-before-ask:
|
|
85
|
-
the human reacts (confirm / adjust / redirect); you do not auto-create. On their reaction, draft its
|
|
86
|
-
`MILESTONE.md` (read `scope.md`) — goal · scope · exit criteria · breadth-first tasks.
|
|
54
|
+
1. **Fill the living documentation**: `.add/PROJECT.md` (Domain · Spec/active milestone · UI/UX · Key Decisions), `CONVENTIONS.md`, `GLOSSARY.md`, `MODEL_REGISTRY.md`, `dependencies.allowlist`, and — for a UI project — `DESIGN.md` (delete if no UI; design loop: `design.md`). Brownfield: from code. Greenfield: from interview, gaps flagged `guessed`.
|
|
55
|
+
2. **Propose, then size it.** Float a **kickoff suggestion** for the first milestone: a **goal** (one outcome sentence), a **flow** (task order), and **scenarios** (concrete examples of what ships). Not the frozen `MILESTONE.md`. On their reaction, draft `MILESTONE.md` (read `scope.md`).
|
|
87
56
|
3. **Create the first task and draft its candidate specification bundle.** `new-task` is allowed pre-lock:
|
|
88
57
|
```bash
|
|
89
58
|
python3 .add/tooling/add.py new-task <slug> --title "<first feature>"
|
|
90
59
|
```
|
|
91
|
-
Draft §1
|
|
92
|
-
|
|
93
|
-
engine **refuses crossing into build** until you `lock` (`setup_unlocked`). Sequence: bundle → lock → build.
|
|
94
|
-
4. **Write `.add/SETUP-REVIEW.md`** per `setup-review.md`: every decision you drafted (foundation, scope,
|
|
95
|
-
first contract), **lowest-confidence-first**, each tagged `guessed` | `evidence-grounded`.
|
|
60
|
+
Draft §1 · §2 · §3. **Leave §3 `Status: DRAFT`** — the lock is its approval. You MAY `advance` pre-lock, but the engine **refuses crossing into build** until you `lock` (`setup_unlocked`). Sequence: bundle → lock → build.
|
|
61
|
+
4. **Write `.add/SETUP-REVIEW.md`** per `setup-review.md`: every drafted decision, **lowest-confidence-first**, tagged `guessed` | `evidence-grounded`.
|
|
96
62
|
|
|
97
63
|
## Run mode — how the build will be driven (propose parallel + auto; confirm to keep)
|
|
98
64
|
|
|
99
|
-
Before the lock, surface
|
|
100
|
-
the **run mode**. Two settings compose it — the **autonomy** level (`add.py autonomy`, run.md: who owns
|
|
101
|
-
the verify gate) and **streams** (`add.py waves` + `streams.md`: whether independent tasks pipeline).
|
|
102
|
-
Show this table so the human sees the flow behavior of each, then PROPOSE the default:
|
|
65
|
+
Before the lock, surface the **run mode** — **autonomy** (`add.py autonomy`, run.md) and **streams** (`add.py waves` + `streams.md`):
|
|
103
66
|
|
|
104
|
-
| Run mode | Human gates
|
|
105
|
-
|
|
106
|
-
| **sequential · manual/conservative** |
|
|
107
|
-
| **parallel · auto** *(proposed default)* |
|
|
67
|
+
| Run mode | Human gates | Concurrency |
|
|
68
|
+
|----------|-------------|-------------|
|
|
69
|
+
| **sequential · manual/conservative** | contract freeze **and** every Verify | one task at a time; safest, slowest |
|
|
70
|
+
| **parallel · auto** *(proposed default)* | contract freeze **only** — Verify auto-PASSes on complete evidence | `add.py waves` schedules independent tasks; builds overlap behind frozen contracts |
|
|
108
71
|
|
|
109
|
-
**Propose `parallel + auto
|
|
110
|
-
one step — `add.py autonomy set conservative --project`, or just run tasks one at a time). This is a
|
|
111
|
-
confirm, never a silent flip. Record the chosen mode in **`PROJECT.md` Key Decisions** (e.g. "run mode:
|
|
112
|
-
parallel + auto (opt-out), confirmed by <name>") so every later session inherits it.
|
|
72
|
+
**Propose `parallel + auto`, ask the human to confirm-to-keep** (or downgrade: `add.py autonomy set conservative --project`). Record the chosen mode in **`PROJECT.md` Key Decisions**.
|
|
113
73
|
|
|
114
|
-
|
|
115
|
-
contract** fires no matter the mode. `auto` + `parallel` change the *order and throttle* of the build
|
|
116
|
-
(which tasks run when, and who gates Verify), never *whether* the contract decision point fires. A
|
|
117
|
-
high-risk task still refuses `auto` and forces a lowered rung (run.md guard).
|
|
74
|
+
The irreducible floor: **one human approval per contract** fires no matter the mode.
|
|
118
75
|
|
|
119
76
|
## 4 · The one human gate — the baseline approval
|
|
120
77
|
|
|
121
|
-
Open the report with the ARC
|
|
122
|
-
`SETUP-REVIEW.md` lowest-confidence-first (the `guessed` rows are what the human must actually check). They
|
|
123
|
-
confirm **once** — an explicit yes to the baseline approval itself, in conversation; ambient agreement mid-stream is
|
|
124
|
-
not a confirmation. On that recorded confirmation, you run the lock with their name:
|
|
78
|
+
Open the report with the ARC per `report-template.md`, render the DECISION as a guided choice, then present `SETUP-REVIEW.md` lowest-confidence-first. They confirm **once** — an explicit yes to the baseline approval itself; ambient mid-stream agreement is not a confirmation. On that recorded confirmation, you run the lock:
|
|
125
79
|
|
|
126
80
|
```bash
|
|
127
81
|
python3 .add/tooling/add.py lock --by "<name>"
|
|
128
82
|
```
|
|
129
83
|
|
|
130
|
-
Typing
|
|
131
|
-
execute it. `lock` records the lock layers (foundation · scope · contract) in one atomic write and opens the
|
|
132
|
-
build. It is judgment-free — it does **not** parse `SETUP-REVIEW.md`; the human *reading* it is the review.
|
|
84
|
+
Typing it themselves stays the **escape hatch** — the decision is always the human's; you just execute it. `lock` records the lock layers in one atomic write and opens the build.
|
|
133
85
|
|
|
134
86
|
## 5 · After the lock
|
|
135
87
|
|
|
136
|
-
- The lock **is** the first task's contract approval —
|
|
137
|
-
|
|
138
|
-
- Stamp the first task's §3 `Status: FROZEN @ v1` (lock-authorized), then read `phases/5-build.md` — build is
|
|
139
|
-
now open. Everything before this signature, you drafted.
|
|
88
|
+
- The lock **is** the first task's contract approval — do **not** ask for a separate contract-freeze sign-off.
|
|
89
|
+
- Stamp the first task's §3 `Status: FROZEN @ v1`, then read `phases/5-build.md`.
|
|
140
90
|
|
|
141
91
|
## Exit gate
|
|
142
92
|
|
|
@@ -149,5 +99,4 @@ build. It is judgment-free — it does **not** parse `SETUP-REVIEW.md`; the huma
|
|
|
149
99
|
|
|
150
100
|
## Next
|
|
151
101
|
|
|
152
|
-
After the lock, read `phases/5-build.md` (build is open).
|
|
153
|
-
*(note: book chapters 10 / 13 / 14 still describe the older human-led setup until `book-align` lands).*
|
|
102
|
+
After the lock, read `phases/5-build.md` (build is open). Book: `docs/10-setup-and-stages.md`.
|
|
@@ -3,44 +3,29 @@
|
|
|
3
3
|
Goal: state what the feature MUST do and what it must REJECT, with zero ambiguity
|
|
4
4
|
for the AI to resolve by guessing. Fill **§1 SPECIFY** in TASK.md.
|
|
5
5
|
|
|
6
|
-
Specify is **co-specification**: brainstorm the shape WITH the user, draft it, then
|
|
7
|
-
the user validate with your advice. If you cannot write the spec, you do not yet
|
|
8
|
-
understand the feature — that is information, not an obstacle. Stop and ask.
|
|
6
|
+
Specify is **co-specification**: brainstorm the shape WITH the user, draft it, then validate. If you cannot write the spec, you do not yet understand the feature — stop and ask.
|
|
9
7
|
|
|
10
8
|
## Co-specify in three moves
|
|
11
9
|
|
|
12
|
-
1. **Diverge** —
|
|
13
|
-
feature + the open questions you would otherwise guess. Invite the user to add, kill,
|
|
14
|
-
redirect. (Conversational — no new file. At prototype/poc this shortens to one sentence.)
|
|
10
|
+
1. **Diverge** — surface the decision space: the 2–3 genuine framings of the feature + the open questions you would otherwise guess. Invite the user to add, kill, redirect. (Conversational — no new file. At prototype/poc this shortens to one sentence.)
|
|
15
11
|
2. **Converge** — draft §1, then RANK where your confidence is lowest (below).
|
|
16
12
|
3. **Validate** — present the ranked uncertainty first; the user confirms, corrects, or sends back.
|
|
17
13
|
|
|
18
|
-
**Identity is direction, not default (UDD).**
|
|
19
|
-
color, the core palette, the typeface — are human-owned. Surface them for discussion during
|
|
20
|
-
Diverge; never assume a brand value. The UDD token dialect checks a token's *shape*; its *value*
|
|
21
|
-
is the user's call (`udd-tokens.md`). For a UI feature with a screen, run the design-definition
|
|
22
|
-
loop in `design.md` — domain → research and reuse components → wireframe → a real captured screen
|
|
23
|
-
the human confirms before build — and carry the confirmed layout into the contract.
|
|
14
|
+
**Identity is direction, not default (UDD).** Brand color, palette, typeface are human-owned — surface them during Diverge, never assume. For a UI feature with a screen, run the design-definition loop in `design.md`.
|
|
24
15
|
|
|
25
16
|
## Produce (in TASK.md §1)
|
|
26
17
|
|
|
27
18
|
<output_format>
|
|
28
|
-
- **Framings weighed** —
|
|
19
|
+
- **Framings weighed** — one-line trace: `X (chosen) · Y · Z`.
|
|
29
20
|
- **Must** — each required behavior.
|
|
30
|
-
- **Reject** — each refused input/situation, paired with a **named error code**
|
|
31
|
-
(`amount <= 0 -> "amount_invalid"`, never "handle bad input").
|
|
21
|
+
- **Reject** — each refused input/situation, paired with a **named error code** (`amount <= 0 -> "amount_invalid"`, never "handle bad input").
|
|
32
22
|
- **After** — the state that is true once it succeeds.
|
|
33
|
-
- **Assumptions — lowest-confidence first** — ranked most-likely-wrong → least. The top 1–2 carry a
|
|
34
|
-
`⚠` flag: `⚠ <assumption> — lowest confidence because <why>; if wrong: <cost>`. The rest are the
|
|
35
|
-
low-stakes `[x]` tail. Keep the ranking visible — a flat list of equal `[x]` ticks gets approved without reading.
|
|
23
|
+
- **Assumptions — lowest-confidence first** — ranked most-likely-wrong → least. The top 1–2 carry a `⚠` flag: `⚠ <assumption> — lowest confidence because <why>; if wrong: <cost>`. Keep the ranking visible — a flat list of equal `[x]` ticks gets approved without reading.
|
|
36
24
|
</output_format>
|
|
37
25
|
|
|
38
26
|
## The lowest-confidence flag is bundle-wide
|
|
39
27
|
|
|
40
|
-
The single human approval happens
|
|
41
|
-
§1 ranking is the first input into a bundle-level flag the user reads at the decision point (`run.md`):
|
|
42
|
-
*"of everything I'm asking you to freeze, these 1–2 are most likely wrong."* A flag may point at
|
|
43
|
-
a §1 assumption, an uncovered scenario, or the contract shape.
|
|
28
|
+
The single human approval happens at the contract freeze, over the whole bundle. So your §1 ranking feeds a bundle-level flag the user reads at the decision point (`run.md`): *"of everything I'm asking you to freeze, these 1–2 are most likely wrong."*
|
|
44
29
|
|
|
45
30
|
## AI prompt
|
|
46
31
|
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# Phase 2 — Scenarios (pass/fail cases)
|
|
2
2
|
|
|
3
|
-
Goal: rewrite each rule as a concrete Given/When/Then that is readable by people
|
|
4
|
-
and checkable by machines. This is the highest-leverage artifact — the tests are
|
|
5
|
-
generated from it. Fill **§2 SCENARIOS** in TASK.md.
|
|
3
|
+
Goal: rewrite each rule as a concrete Given/When/Then that is readable by people and checkable by machines. Fill **§2 SCENARIOS** in TASK.md.
|
|
6
4
|
|
|
7
5
|
## Produce (in TASK.md §2)
|
|
8
6
|
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
# Phase 3 — Contract (freeze the shape)
|
|
2
2
|
|
|
3
|
-
Goal: fix the external shape — interfaces, data, names, error cases — and FREEZE
|
|
4
|
-
it. This is the decision point that makes the AI-led build safe: below it code is
|
|
5
|
-
disposable; above it nothing breaks because the shape does not move. Fill
|
|
6
|
-
**§3 CONTRACT** in TASK.md.
|
|
3
|
+
Goal: fix the external shape — interfaces, data, names, error cases — and FREEZE it. The decision point that makes the AI-led build safe: below it code is disposable; above it the shape does not move. Fill **§3 CONTRACT** in TASK.md.
|
|
7
4
|
|
|
8
5
|
## Produce (in TASK.md §3)
|
|
9
6
|
|
|
@@ -17,32 +14,21 @@ Then mark `Status: FROZEN @ v1`. Generate a mock + contract tests so dependent
|
|
|
17
14
|
work can start before the real code exists.
|
|
18
15
|
</output_format>
|
|
19
16
|
|
|
20
|
-
**The freeze is the one approval.**
|
|
21
|
-
whole bundle (§1–§4). Before asking for it, present the bundle **lowest-confidence first**: the 1–2 points
|
|
22
|
-
most likely wrong (`⚠ [spec|scenario|contract|test] … — because …; if wrong: …`) — aim the human's
|
|
23
|
-
eye before they freeze. Open that report with the ARC (goal · done · plan) per `report-template.md`, rendering the freeze DECISION as a guided choice (the recommended pick + described alternatives), so the
|
|
24
|
-
human sees the goal this freeze serves and the plan beyond it, not just the bundle. See `run.md`.
|
|
25
|
-
The approval also freezes the §5 Scope (may touch) + Strategy declarations — the bundle covers them.
|
|
17
|
+
**The freeze is the one approval.** Present the bundle **lowest-confidence first**: the 1–2 points most likely wrong (`⚠ [spec|scenario|contract|test] … — because …; if wrong: …`). Open with the ARC per `report-template.md`, rendering the freeze DECISION as a guided choice (recommended pick + described alternatives). See `run.md`. The approval also freezes the §5 **Scope (may touch)** allowlist + Strategy declarations.
|
|
26
18
|
|
|
27
19
|
## The freeze review checklist
|
|
28
20
|
|
|
29
21
|
The human's one minute, aimed. Walk these seven before saying yes:
|
|
30
22
|
|
|
31
|
-
- **⚠ flags first** — read the lowest-confidence flags; accept each knowing its cost if wrong.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
record that crossed.
|
|
35
|
-
- **Intent** — does §1 say what you actually want built (and is anything you expected missing)?
|
|
36
|
-
- **Cases** — does every Must and Reject have an observable §2 scenario you care about?
|
|
23
|
+
- **⚠ flags first** — read the lowest-confidence flags; accept each knowing its cost if wrong. The engine refuses an unflagged freeze before build (`unflagged_freeze`); `audit` re-checks it on every record that crossed.
|
|
24
|
+
- **Intent** — does §1 say what you actually want built?
|
|
25
|
+
- **Cases** — does every Must and Reject have an observable §2 scenario?
|
|
37
26
|
- **Shape** — glossary names, error codes, additive vs breaking: is THIS the shape to freeze?
|
|
38
|
-
- **Grounded** — does §3 cite anchors that exist in the §0 GROUND map
|
|
39
|
-
- **Risk** —
|
|
40
|
-
`risk: high · autonomy: conservative` in the TASK.md header — the engine refuses an unguarded completion.
|
|
27
|
+
- **Grounded** — does §3 cite anchors that exist in the §0 GROUND map? `status`/`check` surface this.
|
|
28
|
+
- **Risk** — high-risk or method-defining? Require `risk: high · autonomy: conservative` in the TASK.md header.
|
|
41
29
|
- **Tests** — will §4 go red for the right reason, asserting behavior rather than internals?
|
|
42
30
|
|
|
43
|
-
|
|
44
|
-
extra documents. Reject any line and the bundle goes back to draft; that is
|
|
45
|
-
backward-correction, not failure.
|
|
31
|
+
Reject any line and the bundle goes back to draft; the freeze stays the only gate.
|
|
46
32
|
|
|
47
33
|
## AI prompt
|
|
48
34
|
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# Phase 4 — Tests (failing-first suite)
|
|
2
2
|
|
|
3
|
-
Goal: turn scenarios + contract into automated tests and confirm they FAIL before
|
|
4
|
-
any code exists. This operationalizes red/green TDD: red now, green only after
|
|
5
|
-
Build. Fill **§4 TESTS** and write the suite into `.add/tasks/<slug>/tests/`.
|
|
3
|
+
Goal: turn scenarios + contract into automated tests and confirm they FAIL before any code exists — red now, green only after Build. Fill **§4 TESTS** and write the suite into `.add/tasks/<slug>/tests/`.
|
|
6
4
|
|
|
7
5
|
## The must-fail principle
|
|
8
6
|
|
|
@@ -28,9 +26,8 @@ Resolution: `./…` → this task's dir · a token containing `/` → the projec
|
|
|
28
26
|
(the parent of `.add/`) · a bare name → a sibling of the previous token's
|
|
29
27
|
directory (else the task dir). A directory token counts the `*.py` files directly
|
|
30
28
|
inside it (non-recursive); a `.py` file token counts itself; anything else is
|
|
31
|
-
ignored. Resolved files are deduped
|
|
32
|
-
Paths are confined: anything resolving
|
|
33
|
-
outside the project root counts 0 — `..` traversal, absolute paths, and
|
|
29
|
+
ignored. Resolved files are deduped; reports mark declared counts with `†`.
|
|
30
|
+
Paths are confined: anything resolving outside the project root counts 0 — `..` traversal, absolute paths, and
|
|
34
31
|
symlink escapes are never read.
|
|
35
32
|
|
|
36
33
|
## AI prompt
|
|
@@ -7,30 +7,21 @@ removed all ambiguity. Write code into `.add/tasks/<slug>/src/`.
|
|
|
7
7
|
## Work in small batches
|
|
8
8
|
|
|
9
9
|
Pick ONE task-sized slice, restate the tests it must satisfy, implement, run
|
|
10
|
-
tests, iterate to green. Keep each batch small enough to review in full
|
|
11
|
-
cannot move faster than you can verify.
|
|
10
|
+
tests, iterate to green. Keep each batch small enough to review in full.
|
|
12
11
|
|
|
13
12
|
## Declaring the scope of impact (Scope + Strategy)
|
|
14
13
|
|
|
15
|
-
§5 of TASK.md opens with two declarations, drafted WITH the specification bundle
|
|
16
|
-
and frozen by the one §3 approval — never invented mid-build:
|
|
14
|
+
§5 of TASK.md opens with two declarations, drafted WITH the specification bundle and frozen by the §3 approval — never invented mid-build:
|
|
17
15
|
|
|
18
|
-
- **Scope (may touch)** — the allowlist of every file the build may write
|
|
19
|
-
|
|
20
|
-
file outside the declared Scope is a **STOP → change request** back to Specify,
|
|
21
|
-
never improvisation.
|
|
22
|
-
- **Strategy (ordered batches)** — the planned build order. Guidance, not
|
|
23
|
-
enforced: it aims the small-batches loop, it does not gate it.
|
|
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
|
+
- **Strategy (ordered batches)** — the planned build order. Guidance, not enforced.
|
|
24
18
|
|
|
25
|
-
Deferral, named: the engine gate (touched ⊆ declared) lands in the
|
|
26
|
-
`scope-gate-enforce` task — until it ships this section is prose discipline.
|
|
19
|
+
Deferral, named: the engine gate (touched ⊆ declared) lands in the `scope-gate-enforce` task — until it ships this section is prose discipline.
|
|
27
20
|
|
|
28
21
|
## The cardinal rule
|
|
29
22
|
|
|
30
23
|
**Never weaken or delete a test to make it pass, and never edit the frozen
|
|
31
|
-
contract.**
|
|
32
|
-
change request back to Specify. Honor the feature-specific safety rule named in §5
|
|
33
|
-
(e.g. atomic balance update) — the one property tests alone may not force.
|
|
24
|
+
contract.** A genuine need to change either is a change request back to Specify. Honor the feature-specific safety rule named in §5 (e.g. atomic balance update).
|
|
34
25
|
|
|
35
26
|
## AI prompt
|
|
36
27
|
|
|
@@ -62,11 +53,6 @@ Never: change a test or the contract; use a package off the allow-list; or push
|
|
|
62
53
|
`python3 .add/tooling/add.py advance` → read `phases/6-verify.md`.
|
|
63
54
|
Book: `docs/07-step-5-build.md`.
|
|
64
55
|
|
|
65
|
-
> Under `autonomy: auto`
|
|
66
|
-
> evidence-auto-gated run — not two manual stops. See `run.md`.
|
|
56
|
+
> Under `autonomy: auto` Build and Verify run together as one evidence-auto-gated run. See `run.md`.
|
|
67
57
|
>
|
|
68
|
-
> **Honest redo.**
|
|
69
|
-
> earned-green failure), the task returns HERE for an honest redo — revert the tampered
|
|
70
|
-
> file or de-overfit src, then advance again. This is the bounded self-heal loop (`run.md`),
|
|
71
|
-
> capped: after the cap a confirmed cheat HARD-STOPs to the human. Never weaken a test or
|
|
72
|
-
> edit the frozen contract to pass.
|
|
58
|
+
> **Honest redo.** A confirmed cheat returns the task HERE — revert the tampered file or de-overfit src, then advance again. This is the bounded self-heal loop (`run.md`), capped: after the cap it HARD-STOPs to the human. Never weaken a test or edit the frozen contract to pass.
|
|
@@ -4,21 +4,15 @@ 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
6
|
> **Who resolves this gate depends on the `autonomy:` header (see `run.md`).**
|
|
7
|
-
> Under `autonomy: auto` (the default) a run auto-PASSes once
|
|
8
|
-
>
|
|
9
|
-
>
|
|
10
|
-
>
|
|
11
|
-
>
|
|
12
|
-
> or whenever residue is found, this phase is **human-led** and the checks below
|
|
13
|
-
> are the human's.
|
|
7
|
+
> Under `autonomy: auto` (the default) a run auto-PASSes once evidence is complete —
|
|
8
|
+
> every test green, convergence loops dry, and **no residue** (security · concurrency · architecture) —
|
|
9
|
+
> recorded as *auto-resolved* with the named run as accountable owner. **Security is
|
|
10
|
+
> always a HARD-STOP and is never auto-passed.** Under `autonomy: conservative`, or
|
|
11
|
+
> whenever residue is found, this phase is **human-led**.
|
|
14
12
|
|
|
15
13
|
## Before you build — declare the build expectations
|
|
16
14
|
|
|
17
|
-
Fill the §6 **Build expectations** block BEFORE
|
|
18
|
-
correct build must produce, derived from §2 SCENARIOS + §3 CONTRACT. At this gate, confirm each
|
|
19
|
-
one against real evidence (the `confirmed by` column) — so verify proves the build is *correct*,
|
|
20
|
-
not merely that the suite is green. An expectation with no evidence is not yet verified; passing
|
|
21
|
-
tests on inputs you thought of never substitute for the outcome you promised.
|
|
15
|
+
Fill the §6 **Build expectations** block BEFORE Build: OBSERVABLE outcomes derived from §2 SCENARIOS + §3 CONTRACT. At this gate, confirm each against real evidence (the `confirmed by` column). An expectation with no evidence is not yet verified.
|
|
22
16
|
|
|
23
17
|
## Part one — confirm the evidence
|
|
24
18
|
|
|
@@ -27,56 +21,27 @@ tests on inputs you thought of never substitute for the outcome you promised.
|
|
|
27
21
|
- [ ] No test or contract was altered during build.
|
|
28
22
|
- [ ] Every §6 Build expectation is confirmed by real evidence (not just a green test).
|
|
29
23
|
|
|
30
|
-
If any is false, stop and return to Build
|
|
24
|
+
If any is false, stop and return to Build.
|
|
31
25
|
|
|
32
26
|
## Part two — check what tests miss
|
|
33
27
|
|
|
34
|
-
- **Concurrency/timing** —
|
|
35
|
-
|
|
36
|
-
- **
|
|
37
|
-
dependencies. A security finding is always `HARD-STOP`, never a waiver.
|
|
38
|
-
Writing ANY note on this line means the gate escalates to the human — and
|
|
39
|
-
start it with `NOTE` or `⚠` so `add.py audit` can see it: a marked security
|
|
40
|
-
note reviewed by the auto-gate is an audit finding (`unescalated_security_note`).
|
|
41
|
-
- **Architecture** — does it respect layering/dependency rules in CONVENTIONS.md?
|
|
28
|
+
- **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`).
|
|
30
|
+
- **Architecture** — respects layering/dependency rules in CONVENTIONS.md?
|
|
42
31
|
|
|
43
32
|
## Part three — the deep check (do not skim)
|
|
44
33
|
|
|
45
|
-
|
|
46
|
-
is *wired in*, nor that you did not leave a dead end behind — and for a non-coding change
|
|
47
|
-
they prove nothing about whether you actually *read* the thing you signed off. So one more
|
|
48
|
-
requirement, every gate:
|
|
34
|
+
Deep check — 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 — what you read in full and what it confirmed. Which path applies is the resolver's judgement; the engine never classifies.
|
|
49
35
|
|
|
50
|
-
|
|
51
|
-
referenced (wiring) and that no new dead/unused code was introduced. If it produced prose
|
|
52
|
-
or non-code, record a semantic read — what you read in full and what it confirmed. Which
|
|
53
|
-
path applies is the resolver's judgement; the engine never classifies.
|
|
54
|
-
|
|
55
|
-
Record it in the §6 **Deep checks** block — where each new symbol is called (a reference
|
|
56
|
-
search), the dead-code scan result, or the prose you read in full and what it confirmed.
|
|
57
|
-
An unfilled Deep checks block is a **shallow verify**, not a PASS.
|
|
36
|
+
Record it in the §6 **Deep checks** block. An unfilled Deep checks block is a **shallow verify**, not a PASS.
|
|
58
37
|
|
|
59
38
|
## Part four — was the green earned?
|
|
60
39
|
|
|
61
|
-
A green suite proves
|
|
62
|
-
pass the unchanged suite without earning it: src overfit to the test fixtures (special-cased
|
|
63
|
-
to the literal inputs, not the general behavior §1 asked for), vacuous asserts (tautological —
|
|
64
|
-
green even against an empty implementation), and real logic stubbed away (the function returns
|
|
65
|
-
a constant the tests happen to accept). These cheats are invisible to the mechanical tamper
|
|
66
|
-
tripwire, which only sees edited files. Score them with an adversarial refute-read: an
|
|
67
|
-
independent reviewer — a subagent under `autonomy: auto` is recommended, the engine never
|
|
68
|
-
spawns one — prompted to argue the green was NOT earned from outside the build context. This
|
|
69
|
-
is the verify-gate, whole-suite specialization of run.md's adversarial verify (see run.md), not
|
|
70
|
-
a new discipline. A confirmed earned-green failure is HARD-STOP-class: never auto-passed, never
|
|
71
|
-
RISK-ACCEPTED — but a first cheat is a chance to redo: a confirmed cheat (mechanical tamper or a
|
|
72
|
-
reported earned-green failure) enters the bounded self-heal loop — it returns to build for an honest
|
|
73
|
-
redo, and only after the loop's cap does it HARD-STOP to the human (the loop lives in run.md).
|
|
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 (tautological — green against an empty implementation), and real logic stubbed away. These are 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).
|
|
74
41
|
|
|
75
42
|
## Record exactly one outcome (no silent pass)
|
|
76
43
|
|
|
77
|
-
When you present this gate
|
|
78
|
-
`report-template.md`, render the gate DECISION as a guided choice (the recommended pick + described alternatives), and reconcile its FLAGS with `add.py report --decide`'s open-item count
|
|
79
|
-
before the ask — per that file's reconcile rule (verify is where a flag-vs-digest mismatch bites).
|
|
44
|
+
When you present this gate, open with the ARC per `report-template.md`, render the DECISION as a guided choice, and reconcile FLAGS with `add.py report --decide`'s open-item count before the ask.
|
|
80
45
|
|
|
81
46
|
| Outcome | When |
|
|
82
47
|
|---------|------|
|