@pilotspace/add 2.0.0 → 2.1.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 +49 -0
- package/README.md +104 -196
- package/agents/add-advisor.md +76 -0
- package/agents/add-worker.md +102 -0
- package/bin/cli.js +3 -1
- package/package.json +1 -1
- package/skill/add/SKILL.md +60 -70
- package/skill/add/beyond.md +5 -4
- package/skill/add/persona-author/SKILL.md +116 -0
- package/skill/add/persona-author/assets/example-design-persona.md +55 -0
- package/skill/add/persona-author/assets/example-persona.md +57 -0
- package/skill/add/persona-author/references/contract.md +69 -0
- package/skill/add/persona-author/references/patterns.md +122 -0
- package/skill/add/persona-author/references/seeding.md +79 -0
- package/skill/add/phases/build.md +6 -5
- package/skill/add/phases/direction.md +9 -2
- package/skill/add/phases/verify.md +7 -6
- package/skill/add/run.md +5 -0
- package/tooling/add.py +43 -2
- package/tooling/add_engine/constants.py +18 -17
- package/tooling/add_engine/guidelines.py +5 -4
- package/tooling/add_engine/io_state.py +3 -3
- package/tooling/templates/PLAN.md.tmpl +4 -3
- package/agents/add.md +0 -68
- package/tooling/templates/personas/_template.md.tmpl +0 -86
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# The ADD persona contract
|
|
2
|
+
|
|
3
|
+
What the ADD engine reads and validates. Miss the required parts and the persona fails
|
|
4
|
+
`add.py check`; miss the recommended frontmatter and no apply-surface loads it. This is the
|
|
5
|
+
hard schema — `references/patterns.md` is the judgment that fills it well.
|
|
6
|
+
|
|
7
|
+
## File
|
|
8
|
+
|
|
9
|
+
- Path: `.add/personas/<slug>.md` — `<slug>` is kebab-case (e.g. `payments-api-engineer`).
|
|
10
|
+
- **Never overwrite** an existing persona file; author a new slug or fold into the named one.
|
|
11
|
+
- **Never** name a persona `_`-prefixed — the engine treats `_`-prefixed files as scaffolds and
|
|
12
|
+
skips them (they are excluded from the roster, emptiness checks, and quality WARNs).
|
|
13
|
+
|
|
14
|
+
## Frontmatter
|
|
15
|
+
|
|
16
|
+
```yaml
|
|
17
|
+
---
|
|
18
|
+
name: <persona name — e.g. Payments API Engineer> # REQUIRED
|
|
19
|
+
vibe: <one-line essence — what this persona keeps true> # REQUIRED
|
|
20
|
+
flow: <design | build | advisor | verify> # RECOMMENDED — comma-separate if >1
|
|
21
|
+
task-kinds: <from the closed taxonomy, comma-separated> # RECOMMENDED
|
|
22
|
+
use-when: <pushy should-select line — enumerate triggers> # RECOMMENDED
|
|
23
|
+
not-when: <the near-miss that belongs to a named sibling> # RECOMMENDED
|
|
24
|
+
folded: <consolidation history, newest first> # OPTIONAL
|
|
25
|
+
source: <teacher file(s) distilled from> # OPTIONAL
|
|
26
|
+
---
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- **`name` · `vibe`** — REQUIRED. Absence fails the schema check.
|
|
30
|
+
- **`flow`** — the apply-surfaces this lens loads at. The ONLY valid values are
|
|
31
|
+
`design` · `build` · `advisor` · `verify` (single-sourced as `constants.PERSONA_FLOW_VALUES`).
|
|
32
|
+
Any other value is a typo that no surface loads — `add.py check` emits a `persona_quality` WARN
|
|
33
|
+
naming it. Surfaces: **design** = the UDD requirements lens · **build** = the domain-identity
|
|
34
|
+
overlay on SOUL.md · **advisor** = the subagent/streams delegation lens · **verify** = the
|
|
35
|
+
evidence-judging lens (earned-green refute-read + gate record).
|
|
36
|
+
- **`task-kinds`** — the persona's SCOREBOARD KEY, from the closed taxonomy:
|
|
37
|
+
`feature · refactor · test · docs · ui · security · data · infra · release · integration`.
|
|
38
|
+
Route-outcome traces join a task's `kind:` header to this claim, so performance is measurable
|
|
39
|
+
per kind. A value outside the taxonomy scores as nothing.
|
|
40
|
+
- **`use-when` / `not-when`** — the selection boundary. Selectors under-trigger on essence lines,
|
|
41
|
+
so `use-when` ENUMERATES the concrete contexts that should pick THIS persona; `not-when` names
|
|
42
|
+
the sibling that owns the near-miss (e.g. `CI permissions → security-gatekeeper`).
|
|
43
|
+
|
|
44
|
+
## Sections
|
|
45
|
+
|
|
46
|
+
**REQUIRED (engine-checked, presence-based):**
|
|
47
|
+
|
|
48
|
+
- `## Identity`
|
|
49
|
+
- `## Critical Rules`
|
|
50
|
+
- `## Default Requirement`
|
|
51
|
+
- `## Success Metrics`
|
|
52
|
+
|
|
53
|
+
**RECOMMENDED (a surface can't fully use the lens without them):**
|
|
54
|
+
|
|
55
|
+
- `## Abilities`
|
|
56
|
+
|
|
57
|
+
**OPTIONAL (absence is conformant):**
|
|
58
|
+
|
|
59
|
+
- `## Anti-patterns`
|
|
60
|
+
- `## Playbook`
|
|
61
|
+
|
|
62
|
+
## Quality WARNs `add.py check` surfaces (non-blocking, measure-not-block)
|
|
63
|
+
|
|
64
|
+
- **flow typo** — a `flow:` value outside the four is named in the finding (loaded by no surface).
|
|
65
|
+
- **bare placeholder** — a `<…>` token left outside backtick spans and HTML comments (a half-filled
|
|
66
|
+
copy). Backticked (`` `<slug>` ``) and commented (`<!-- <x> -->`) angle brackets are content, not
|
|
67
|
+
placeholders. Sweep every real `<…>` before you finish.
|
|
68
|
+
|
|
69
|
+
These are WARNs, never failures — but a roster-ready persona clears all of them.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# The judgment layer — distilled from strong subagent design
|
|
2
|
+
|
|
3
|
+
Eleven patterns that separate an expert lens from an undifferentiated keyword list. Each is drawn
|
|
4
|
+
from an apple-to-apple read of strong agent files (senior-rust/-java engineers, python-expert,
|
|
5
|
+
module-doc-generator, component-tracer, ux-design-architect, and peers) plus a diagnosis of the
|
|
6
|
+
vendored teacher corpus, and cast for an ADD persona. Contract (which section) →
|
|
7
|
+
`references/contract.md`; this file is *how to fill it well*.
|
|
8
|
+
|
|
9
|
+
## Contents
|
|
10
|
+
1. Earned-perspective Identity
|
|
11
|
+
2. Bold-lead Critical Rules
|
|
12
|
+
3. The qualification gate
|
|
13
|
+
4. Read-before-you-assert
|
|
14
|
+
5. Failure-mode-aware Success Metrics
|
|
15
|
+
6. ORIENT-first Abilities
|
|
16
|
+
7. Design-for-failure (conditional)
|
|
17
|
+
8. Guilty-until-proven Anti-patterns
|
|
18
|
+
9. Numbers you'd defend
|
|
19
|
+
10. Per-flow stance
|
|
20
|
+
11. Deliberate exclusions — what NOT to put in a persona
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 1. Earned-perspective Identity
|
|
25
|
+
Every strong agent opens not with a title but with *what it has seen*. State the domain depth AND
|
|
26
|
+
the scar that shapes its judgement.
|
|
27
|
+
- ✗ "You are a senior payments engineer with expertise in APIs."
|
|
28
|
+
- ✓ "…has shipped reconciliation systems where a single un-idempotent retry double-charged a
|
|
29
|
+
customer, so it treats every write as replayable until proven otherwise."
|
|
30
|
+
The scar is what makes the later Anti-patterns feel inevitable rather than arbitrary.
|
|
31
|
+
|
|
32
|
+
## 2. Bold-lead Critical Rules
|
|
33
|
+
Lead each rule with a **bold clause**, then the why. Scannable beats prose. Keep it to what the
|
|
34
|
+
persona would actually *refuse to wave through* — not a wish list.
|
|
35
|
+
- ✗ "Always make sure to handle errors properly and think about idempotency."
|
|
36
|
+
- ✓ "**Every write is idempotent** — a retried request must not double-apply; key it or reject it."
|
|
37
|
+
When a rule is subtle, one ✗/✓ contrast pair teaches more than a paragraph — "follow best
|
|
38
|
+
practices" is useless; "wrap MobX components in `observer()` (see `RoleSkillCard.tsx:15`)" acts.
|
|
39
|
+
|
|
40
|
+
## 3. The qualification gate
|
|
41
|
+
The single sharpest transferable stance. Before elaborating, name the simplest baseline that meets
|
|
42
|
+
the contract; if it wins, take it and STOP. Cleverness is a tax the project pays forever.
|
|
43
|
+
- ✓ Critical Rule: "**Simplest baseline first** — if a plain table + unique index meets the
|
|
44
|
+
contract, ship that; an event-sourced ledger earns its keep or it's a tax."
|
|
45
|
+
Its sibling move covers contradictory requirements ("minimal but feature-rich"): name the tension
|
|
46
|
+
and propose the balance with its cost — never silently satisfy one half. And perspective proves
|
|
47
|
+
itself by naming the losing option: *why this, not that — and why that loses*.
|
|
48
|
+
|
|
49
|
+
## 4. Read-before-you-assert
|
|
50
|
+
The reporting agents (module-doc, component-tracer) make this a hard rule: never cite a file,
|
|
51
|
+
symbol, or line you have not opened. In an ADD persona it is an Anti-pattern:
|
|
52
|
+
- ✓ "a claim resting on a file/symbol not opened → open it or cut the claim."
|
|
53
|
+
It binds outputs too: every path or example the persona's own deliverable cites must exist at the
|
|
54
|
+
named place — a placeholder that survives into the deliverable is the same defect. This mirrors
|
|
55
|
+
the add-worker floor ("never invent a file you have not opened") as a domain instinct.
|
|
56
|
+
|
|
57
|
+
## 5. Failure-mode-aware Success Metrics
|
|
58
|
+
A metric is only expertise if it names the way of being wrong it catches. State each as an
|
|
59
|
+
INVARIANT (true as the project grows), paired with its failure mode.
|
|
60
|
+
- ✗ "High test coverage; good performance."
|
|
61
|
+
- ✓ "**No double-post under retry** — a replayed request leaves the ledger byte-identical (catches
|
|
62
|
+
the un-idempotent write); **p95 < 150 ms at 100 rps** (catches the N+1 that only shows under load)."
|
|
63
|
+
Each bar must be checkable IN-SESSION by the agent holding the lens — a behaviour it can observe
|
|
64
|
+
or a test it can run. An invented outcome statistic ("engagement +40%") sounds measured and never
|
|
65
|
+
was; it is the signature rot of weak persona corpora.
|
|
66
|
+
|
|
67
|
+
## 6. ORIENT-first Abilities
|
|
68
|
+
Lead the ability list with the 1–3 commands the lens RUNS on load before acting — `add.py status`,
|
|
69
|
+
the domain's suite, the diff to judge. Acting on ground truth beats re-deriving it. State every
|
|
70
|
+
other ability as something doable *now*, anchored to a real file/tool/command — not an aspiration.
|
|
71
|
+
- ✓ "can diff two response fixtures byte-for-byte to prove passthrough" (checkable)
|
|
72
|
+
- ✗ "understands API design deeply" (unfalsifiable)
|
|
73
|
+
|
|
74
|
+
## 7. Design-for-failure (conditional)
|
|
75
|
+
Any persona that owns I/O, network, or infra carries a design-for-failure ability: it can name the
|
|
76
|
+
**timeout · retry · circuit-breaker · rollback** for every external call. An unbounded await or a
|
|
77
|
+
silent half-write is a defect, never "expected". Omit this for pure design/docs lenses — forcing it
|
|
78
|
+
on a lens that touches no I/O is noise. Match the pattern to the persona's real surface.
|
|
79
|
+
|
|
80
|
+
## 8. Guilty-until-proven Anti-patterns
|
|
81
|
+
Distinct from Critical Rules (always-do): these are the smells the lens treats as *guilty until
|
|
82
|
+
proven innocent*, each with its default reaction. The sharpest are the instincts the Identity's
|
|
83
|
+
scars produced — and the strongest attach the COST to the smell:
|
|
84
|
+
- ✓ "'0 issues found' on a first pass → look harder."
|
|
85
|
+
- ✓ "an abstraction with no second caller → cut it."
|
|
86
|
+
- ✓ "PIL in production preprocessing → 3× slower than cv2; reach for cv2 first."
|
|
87
|
+
A smell with its price is an argument; a bare smell is a style opinion.
|
|
88
|
+
|
|
89
|
+
## 9. Numbers you'd defend
|
|
90
|
+
The cheapest bytes-per-judgment in strong agents: a named budget beats an adjective. "Optimize
|
|
91
|
+
performance" buys nothing; "p95 < 200 ms at the declared load", "44×44 px touch targets", "batch
|
|
92
|
+
wait ≤ 10 ms" anchor the lens to a bar it can hold a build to. Two conditions, or the number is
|
|
93
|
+
cosplay: the expert could defend WHY that number (name what breaks past it), and the lens can
|
|
94
|
+
check it in-session (see 5). Fake precision reads as measured and teaches the agent to invent —
|
|
95
|
+
worse than no number at all.
|
|
96
|
+
|
|
97
|
+
## 10. Per-flow stance
|
|
98
|
+
The strongest agents split behaviour by mode and bind a bookend to each — *reviewing opens with
|
|
99
|
+
the defect sweep; reimplementing opens with the qualification gate; explaining closes with failure
|
|
100
|
+
modes*. A persona claiming more than one `flow:` does the same in one or two lines: what it LEADS
|
|
101
|
+
with at build, what it REFUSES at verify. A verify stance carries the default verdict — NEEDS-WORK
|
|
102
|
+
until the evidence cites the actual run — plus its automatic-fail triggers. A lens whose rules
|
|
103
|
+
read identically at every flow hasn't decided what each surface is for.
|
|
104
|
+
|
|
105
|
+
## 11. Deliberate exclusions — what NOT to put in a persona
|
|
106
|
+
A persona is a layer in a stack; keep the other layers' work OUT of it.
|
|
107
|
+
- **No tone/voice** — that is SOUL.md's. A persona that prescribes phrasing is duplicating it.
|
|
108
|
+
- **No self-score / confidence rubric** — the agent (add-worker) owns the six-dimension score.
|
|
109
|
+
- **No output skeleton** — the deliverable's shape is the agent's Return contract, not the lens's.
|
|
110
|
+
- **No stakes/CoT priming** ("take a deep breath", "$500 tip") — motivation is the agent's; the
|
|
111
|
+
persona supplies judgment, not pep talk.
|
|
112
|
+
- **No keyword taxonomy** — a page of noun-phrase bullets ("saga pattern, composite indexes, …")
|
|
113
|
+
buys no behaviour; the model knows the words. Every bullet carries an opinion or it goes.
|
|
114
|
+
- **No tutorial code dumps** — framework boilerplate rots fast; a snippet earns its place only
|
|
115
|
+
when it encodes a rule the prose can't.
|
|
116
|
+
- **No invented metrics or fabricated telemetry** — "+40% engagement", "47 pipelines deployed":
|
|
117
|
+
numbers that sound measured train the lens to hallucinate finished-ness.
|
|
118
|
+
- **No adverb-padded checklists** — "documented thoroughly", "monitored comprehensively" are
|
|
119
|
+
unverifiable filler wearing a checklist's clothes.
|
|
120
|
+
- **No other project's paths** — a persona anchors to THIS project's real files and commands;
|
|
121
|
+
an inherited path from a seed source is contamination, not context.
|
|
122
|
+
Every line you cut from these categories makes the judgment that remains sharper.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Seeding a persona from an existing source
|
|
2
|
+
|
|
3
|
+
Authoring from a blank page is the slowest path and the one most likely to miss the judgment
|
|
4
|
+
layer. When a near-fit source exists, **seed from it, then distil** — never copy it wholesale. Two
|
|
5
|
+
sources are always worth checking first, in this order:
|
|
6
|
+
|
|
7
|
+
1. **The teacher library** — `.add/personas-teacher/**/*.md`, grouped by division folder
|
|
8
|
+
(`design/`, `sales/`, `paid-media/`, …). A vetted, domain-organised corpus. Prefer this.
|
|
9
|
+
2. **A sample subagent** — a `~/.claude/agents/*.md` file (e.g. `senior-rust-engineer.md`) when the
|
|
10
|
+
teacher library has no near-fit for a technical domain.
|
|
11
|
+
|
|
12
|
+
A source is a **head-start on structure**, not a finished lens. The mechanical parts map straight
|
|
13
|
+
across; the judgment parts you must *distil* (compress a verbose body into a few sharp clauses);
|
|
14
|
+
and a few parts the source will **never** carry — you add those yourself. That last column is the
|
|
15
|
+
whole point: a seed that skips it is just a reformatted résumé.
|
|
16
|
+
|
|
17
|
+
## Teacher file → ADD persona
|
|
18
|
+
|
|
19
|
+
A teacher file: frontmatter `name · vibe · description · color · emoji`, division from its folder,
|
|
20
|
+
and a verbose motivational body (`## 🧠 Identity & Memory`, `## 🎯 Core Mission`, …).
|
|
21
|
+
|
|
22
|
+
| ADD schema | Seed from the teacher | Action |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| `name:` | frontmatter `name` | carry across |
|
|
25
|
+
| `vibe:` | frontmatter `vibe` | carry across (tighten to one line) |
|
|
26
|
+
| `flow:` | the division folder — `design/` → `design`; a review/audit persona → `verify`/`advisor` | **infer, then confirm** against the closed values |
|
|
27
|
+
| `task-kinds:` | the domain (a `design/` lens → `ui`; a data persona → `data`) | **you pick** from the closed taxonomy |
|
|
28
|
+
| `use-when:` / `not-when:` | frontmatter `description` seeds `use-when`; the sibling it's most confused with seeds `not-when` | distil + **add `not-when`** (the source has none) |
|
|
29
|
+
| `## Identity` | the body's identity/experience paragraph ("You've seen developers struggle with…") | **distil to earned perspective** — scars, not the résumé |
|
|
30
|
+
| `## Critical Rules` | any `**Default requirement**:` / non-negotiable lines in the body | distil to bold-lead rules; **add** the two default stances (surface-tradeoffs · qualification-gate) |
|
|
31
|
+
| `## Default Requirement` | the one `Default requirement:` line if present | carry or write |
|
|
32
|
+
| `## Success Metrics` | *(the teacher rarely has measurable metrics)* | **ADD — this is the judgment.** MEASURABLE invariants, each sharpened by the failure it guards |
|
|
33
|
+
| `## Abilities` | the `Core Mission` bullets | distil to concrete, anchored, checkable actions; lead with the ORIENT commands |
|
|
34
|
+
| `## Anti-patterns` | the instincts implied by the "you've seen X fail" lines | name them guilty-until-proven; **always add** read-before-you-assert |
|
|
35
|
+
|
|
36
|
+
## Subagent md (`~/.claude/agents/*.md`) → ADD persona
|
|
37
|
+
|
|
38
|
+
A subagent file: frontmatter `name · description · model · color`, the `description` embeds a
|
|
39
|
+
`Use when: …` clause and `<example>` blocks, and the body leads with `## Core Principles
|
|
40
|
+
(Non-Negotiable)`.
|
|
41
|
+
|
|
42
|
+
| ADD schema | Seed from the subagent | Action |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `name:` / `vibe:` | frontmatter `name`; **vibe has no source** | carry name; **write a one-line vibe** |
|
|
45
|
+
| `flow:` / `task-kinds:` | the `<example>` Contexts name the work (review → `verify`; build → `build`) | infer flow + kinds, confirm against the closed sets |
|
|
46
|
+
| `use-when:` / `not-when:` | the `Use when: …` clause in `description`; each `<commentary>` names a core capability | carry `use-when`; **add `not-when`** |
|
|
47
|
+
| `## Identity` | the opening `You are a **…**` paragraph | distil to earned perspective |
|
|
48
|
+
| `## Critical Rules` | the `## Core Principles (Non-Negotiable)` list | distil to bold-lead rules (keep 1–2 signatures); **add** the two default stances |
|
|
49
|
+
| `## Abilities` | the capabilities in the `<commentary>` tags + the body's numbered principles | make each doable *now*, anchored to a file/tool/command; an I/O lens **adds** design-for-failure |
|
|
50
|
+
| `## Success Metrics` | *(subagents state principles, not measurable bars)* | **ADD — measurable, failure-aware invariants** |
|
|
51
|
+
| `## Anti-patterns` | the "only when genuinely required" / "avoid" hedges | name them guilty-until-proven; **always add** read-before-you-assert |
|
|
52
|
+
|
|
53
|
+
## What to mine, what to refuse
|
|
54
|
+
|
|
55
|
+
Both source families carry gold the mapping tables can't express — and a signature rot that must
|
|
56
|
+
not survive the seed:
|
|
57
|
+
|
|
58
|
+
- **Teacher gold** — the one-line `Default requirement:` floor · the "You've seen…" scar sentence
|
|
59
|
+
(feeds Identity) · behaviour-paired metric rows ("100% warm transfers — never a cold handoff")
|
|
60
|
+
· a named methodology with its verbatim moves and why-they-work (feeds a Playbook) · the rare
|
|
61
|
+
"when NOT to use" lines (feed `not-when:` as *symptom → sibling*) · a reviewer's default-verdict
|
|
62
|
+
stance with automatic-fail triggers (feeds a verify-flow stance).
|
|
63
|
+
- **Teacher rot — refuse** — deliverable code dumps (CSS/config skeletons), emoji-header chrome,
|
|
64
|
+
invented outcome statistics ("+40% engagement" no one measured), motivational closers and
|
|
65
|
+
"instructions reference" footers that point at nothing.
|
|
66
|
+
- **Subagent gold** — review-mode checklists (feed the verify side of a per-flow stance) ·
|
|
67
|
+
pitfalls with the cost attached ("PIL in prod preprocessing → 3× slower than cv2" — feeds
|
|
68
|
+
Anti-patterns) · budgets the author would defend ("p95 < 200 ms", "44×44 px" — feed
|
|
69
|
+
Rules/Metrics) · mode bookends ("reviewing opens with the defect sweep").
|
|
70
|
+
- **Subagent rot — refuse** — keyword-taxonomy pages (nouns buy no behaviour), tip bribes and
|
|
71
|
+
self-score rubrics, tutorial code blocks, and another project's hard-coded paths — a persona
|
|
72
|
+
anchors to THIS project's real files only.
|
|
73
|
+
|
|
74
|
+
## After the seed
|
|
75
|
+
|
|
76
|
+
Record provenance honestly: add a `source:` frontmatter line naming the seed — the teacher slug,
|
|
77
|
+
or `agents/<file>` — (the contract lists `source` as an optional field). Then run the **Workflow** in `SKILL.md` over the
|
|
78
|
+
seeded draft — every section still faces its judgment bar — and `add.py check` until green. A seed
|
|
79
|
+
that never had the Success-Metrics and Anti-patterns columns filled is not done.
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# Build — AI writes the code (the beat you drive to green)
|
|
2
2
|
|
|
3
|
-
Objective: implement the feature so EVERY failing test
|
|
4
|
-
test or the contract. This is the only phase the
|
|
5
|
-
ambiguity. Write code into `.add/tasks/<slug>/src
|
|
3
|
+
Objective: implement the feature so EVERY failing test — or, for a non-coding task, every §4
|
|
4
|
+
acceptance check — passes, without changing any test or the contract. This is the only phase the
|
|
5
|
+
AI leads; §1–§4 removed all ambiguity. Write code into `.add/tasks/<slug>/src/` (a non-coding
|
|
6
|
+
task writes its artifact to the path its §5 Scope declares).
|
|
6
7
|
|
|
7
8
|
## Work in small batches
|
|
8
9
|
|
|
@@ -15,7 +16,7 @@ each batch small enough to review in full.
|
|
|
15
16
|
|
|
16
17
|
- **Scope (may touch)** — the allowlist the build may write (backticked tokens); a file outside it is a **STOP → change request** back to Specify.
|
|
17
18
|
- **Strategy (ordered batches)** — the planned build order; guidance, not enforced.
|
|
18
|
-
- **Strategy facets** — Approach (domain strategy) · Data strategy · Pattern · Optimization stance: the domain HOW, anchored upstream (§1 Framings · §3 Schema · CONVENTIONS.md Honors), drafted at tests->build in the Persona's domain vocabulary; ⚠-mark the facet you trust least (risk: high →
|
|
19
|
+
- **Strategy facets** — Approach (domain strategy) · Data strategy · Pattern · Optimization stance: the domain HOW, anchored upstream (§1 Framings · §3 Schema · CONVENTIONS.md Honors), drafted at tests->build in the Persona's domain vocabulary; ⚠-mark the facet you trust least (risk: high → spawn `add-advisor`, advise-midflight mode). Advisory, never a gate.
|
|
19
20
|
|
|
20
21
|
Enforced: a completing verify gate refuses an out-of-scope build (`scope_violation` → self-heal).
|
|
21
22
|
|
|
@@ -39,7 +40,7 @@ contract.** A genuine need to change either is a change request back to Specify.
|
|
|
39
40
|
## Exit gate
|
|
40
41
|
|
|
41
42
|
<exit_gate>
|
|
42
|
-
- [ ] All tests pass.
|
|
43
|
+
- [ ] All tests (or §4 acceptance checks) pass.
|
|
43
44
|
- [ ] Coverage did not decrease.
|
|
44
45
|
- [ ] No test and no contract modified by the AI.
|
|
45
46
|
- [ ] No dependency outside the allow-list.
|
|
@@ -81,7 +81,7 @@ stamp its §3 `Status: FROZEN @ v1`, build is open.
|
|
|
81
81
|
<exit_gate>
|
|
82
82
|
- [ ] `.add/state.json` exists; setup seeded unlocked (`--await-lock`) then locked.
|
|
83
83
|
- [ ] Seed lines filled; untouched sections carry the living marker (brownfield: evidence-grounded from code).
|
|
84
|
-
- [ ] First task created; §1–§4 drafted — the red suite runs RED before build opens; `.add/SETUP-REVIEW.md` written lowest-confidence-first.
|
|
84
|
+
- [ ] First task created; §1–§4 drafted — the red suite (or §4 acceptance checks) runs RED before build opens; `.add/SETUP-REVIEW.md` written lowest-confidence-first.
|
|
85
85
|
- [ ] Human confirmed the baseline approval and `add.py lock --by` ran with their name.
|
|
86
86
|
</exit_gate>
|
|
87
87
|
|
|
@@ -236,6 +236,13 @@ scenario asserting **behavior, not internals** · contract-conformance tests (sh
|
|
|
236
236
|
responses) · side-effect assertions on rejection paths (`assert balance unchanged`) · a recorded
|
|
237
237
|
coverage target.
|
|
238
238
|
|
|
239
|
+
**Non-coding task?** For `kind: docs · release · infra` (or a wholly non-coding project) the
|
|
240
|
+
check need not be a script: §4 is a failing-first **acceptance check** — verifiable pass/fail
|
|
241
|
+
evidence (renders · every internal link resolves · `§X covers A/B/C` · a command exits 0), red
|
|
242
|
+
before the artifact exists and green after. Declare `Tests live in: evidence`. Red→green still
|
|
243
|
+
binds; only the must-be-executable-code requirement is lifted (the human may declare acceptance
|
|
244
|
+
mode on any task). Coding kinds keep the executable red suite above.
|
|
245
|
+
|
|
239
246
|
## Declaring where tests live
|
|
240
247
|
|
|
241
248
|
§4's `Tests live in:` line is machine-read — declare paths as backticked tokens on that line: with
|
|
@@ -254,7 +261,7 @@ moves. Ground §3 on each parent edge's frozen §3 — the PLAN.md itself, never
|
|
|
254
261
|
built code.
|
|
255
262
|
|
|
256
263
|
<exit_gate>
|
|
257
|
-
- [ ] One test per scenario, red for the right reason, asserting observable behavior; coverage target recorded.
|
|
264
|
+
- [ ] One test (or acceptance check, for a non-coding kind) per scenario, red for the right reason, asserting observable behavior; coverage target recorded.
|
|
258
265
|
</exit_gate>
|
|
259
266
|
|
|
260
267
|
> **Persona / Advisor / Confidence** — load the domain-fit `.add/personas/<slug>.md` (its Critical
|
|
@@ -11,7 +11,7 @@ sufficient. Fill **§6** in PLAN.md including the GATE RECORD.
|
|
|
11
11
|
|
|
12
12
|
## Part one — confirm the evidence
|
|
13
13
|
|
|
14
|
-
- [ ] All tests pass.
|
|
14
|
+
- [ ] All tests pass — or, for a non-coding task, every §4 acceptance check is green (the evidence it names is real).
|
|
15
15
|
- [ ] Coverage did not decrease.
|
|
16
16
|
- [ ] No test or contract was altered during build.
|
|
17
17
|
- [ ] The §3 Target (measurable) is hit — including any declared outcome tests can't show, confirmed by real evidence.
|
|
@@ -50,7 +50,7 @@ tasks use the compact form — banner → SUMMARY → EVIDENCE → APPROVE; `sec
|
|
|
50
50
|
|---------|------|
|
|
51
51
|
| `PASS` | all checks met |
|
|
52
52
|
| `RISK-ACCEPTED` | a **non-security** gap, with signed owner + ticket + expiry |
|
|
53
|
-
| `HARD-STOP` | any failing test or any security finding |
|
|
53
|
+
| `HARD-STOP` | any failing test or acceptance check, or any security finding |
|
|
54
54
|
|
|
55
55
|
## Exit gate / Next
|
|
56
56
|
|
|
@@ -95,10 +95,11 @@ Spawn a *single* subagent for one well-scoped piece of your plan (many-task pipe
|
|
|
95
95
|
stream-orchestrator persona); the engine never spawns — your call per step. Spawn when the piece
|
|
96
96
|
is separable and worth the round-trip: a broad sweep, an independent adversarial review (the
|
|
97
97
|
refute-read — fresh context, never author-graded), a batch, a context-offload; not for narrow
|
|
98
|
-
cheap work — in doubt, do it in-context. **Prefer the named roster**:
|
|
99
|
-
spawn names the mode
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
cheap work — in doubt, do it in-context. **Prefer the named roster**: `add-worker` for an execution
|
|
99
|
+
piece (the spawn names the mode: direction · build · verify · persona) and `add-advisor` for an
|
|
100
|
+
advisory one (propose-plan · refute · advise-midflight) — over an ad-hoc spawn; each carries its
|
|
101
|
+
roster contract and loads the beat guide + best-fit persona itself. Tier: **mid** ordinary, **top**
|
|
102
|
+
complex/cross-cutting (the roster contract in `agents/*.md` maps tiers to
|
|
102
103
|
models); a stronger model never buys back a gate. **Refute-read persona** — a **Code-Reviewer**;
|
|
103
104
|
findings carry severity: 🔴 blocker · 🟡 concern · 💭 note. A persona is advisory: it never
|
|
104
105
|
lowers a gate (a security finding still HARD-STOPs).
|
package/skill/add/run.md
CHANGED
|
@@ -89,6 +89,11 @@ Two findings enter the loop:
|
|
|
89
89
|
|
|
90
90
|
Either way: ≤3 honest redos, then escalate. A gamed green never ships.
|
|
91
91
|
|
|
92
|
+
**Every return trip is a visible round** (round-visible-runs): any verify→build return —
|
|
93
|
+
a plain `add.py phase build [--note "finding"]` or a heal — increments the task's
|
|
94
|
+
uncapped, observational `rounds` record; `status` names `round N` and the route trace
|
|
95
|
+
carries it. Heal stays the cheat-classed, capped subset; rounds are the honest whole.
|
|
96
|
+
|
|
92
97
|
## Emitting deltas — feeding the foundation back
|
|
93
98
|
|
|
94
99
|
Every gap the completeness-critic finds becomes an **`open` lesson learned** in the task's OBSERVE
|
package/tooling/add.py
CHANGED
|
@@ -593,6 +593,11 @@ def cmd_init(args: argparse.Namespace) -> None:
|
|
|
593
593
|
continue
|
|
594
594
|
_atomic_write(dest, rendered)
|
|
595
595
|
|
|
596
|
+
# persona-skill: personas are AUTHORED via the persona-author skill (not seeded from a
|
|
597
|
+
# template) — but the location must exist so the first authored persona has a home and the
|
|
598
|
+
# unseeded nudge has a directory to check. Create it empty; the skill fills it.
|
|
599
|
+
(root / "personas").mkdir(parents=True, exist_ok=True)
|
|
600
|
+
|
|
596
601
|
# specs-5dd (ADD 2.0 M3): the five living 5-DD specs — same survivor idiom as
|
|
597
602
|
# SETUP_FILES (never clobber, never write blank), ONE template rendered five ways.
|
|
598
603
|
for dd in SPEC_DDS:
|
|
@@ -779,6 +784,8 @@ def cmd_new_task(args: argparse.Namespace) -> None:
|
|
|
779
784
|
# was HARD-STOP escalated) could launder the cap (HEAL_CAP) to zero by re-creating itself —
|
|
780
785
|
# a zero-human cap bypass (the same invariant _heal_or_escalate guards: "never auto-resets").
|
|
781
786
|
prior_heal = state["tasks"].get(slug, {}).get("heal") if args.force else None
|
|
787
|
+
# round-visible-runs: the round record is monotonic the same way — survives a --force re-create.
|
|
788
|
+
prior_rounds = state["tasks"].get(slug, {}).get("rounds") if args.force else None
|
|
782
789
|
state["tasks"][slug] = {
|
|
783
790
|
"title": title,
|
|
784
791
|
"phase": "direction",
|
|
@@ -796,6 +803,8 @@ def cmd_new_task(args: argparse.Namespace) -> None:
|
|
|
796
803
|
state["tasks"][slug]["relates_to"] = relates_to
|
|
797
804
|
if prior_heal is not None:
|
|
798
805
|
state["tasks"][slug]["heal"] = prior_heal # monotonic — survives the --force re-create
|
|
806
|
+
if prior_rounds is not None:
|
|
807
|
+
state["tasks"][slug]["rounds"] = prior_rounds # same monotonic contract as heal
|
|
799
808
|
if from_delta:
|
|
800
809
|
state["tasks"][slug]["from_delta"] = from_delta # lineage: seeded from <prior>
|
|
801
810
|
if sensitivity:
|
|
@@ -1686,8 +1695,21 @@ def cmd_phase(args: argparse.Namespace) -> None:
|
|
|
1686
1695
|
# scope snapshot), so verify's _tamper_guard is armed and a freeze-gated DRAFT §3 is refused.
|
|
1687
1696
|
# validate-then-write: a refusal raises BEFORE the phase is set, so nothing moves. The heal
|
|
1688
1697
|
# loop sets phase=build directly (never via cmd_phase) and so stays exempt.
|
|
1698
|
+
# round-visible-runs: --note annotates a verify->build ROUND — refuse it anywhere else,
|
|
1699
|
+
# BEFORE any write (validate-then-write; a refused entry leaves state byte-unchanged).
|
|
1700
|
+
# The refusal keys on the FLAG being passed (whitespace included) and the note is stored
|
|
1701
|
+
# VERBATIM (§1 Boundary); the contract's refusal exit code is 2.
|
|
1702
|
+
note = getattr(args, "note", None)
|
|
1703
|
+
if note is not None and args.phase != "build":
|
|
1704
|
+
_die("phase_note_build_only: --note annotates the verify->build round this return "
|
|
1705
|
+
"records — it is only valid with target build", code=2)
|
|
1706
|
+
prior = state["tasks"][slug].get("phase")
|
|
1689
1707
|
if args.phase == "build":
|
|
1690
1708
|
_build_entry(root, state, slug, skip_freeze=getattr(args, "skip_freeze", False))
|
|
1709
|
+
# round-visible-runs: a verify->build return trip IS a round — record it in the SAME
|
|
1710
|
+
# save as the phase write (atomic; no round without the return, no return without it).
|
|
1711
|
+
if args.phase == "build" and prior == "verify":
|
|
1712
|
+
_record_round(state["tasks"][slug], source="phase", note=note)
|
|
1691
1713
|
state["tasks"][slug]["phase"] = args.phase
|
|
1692
1714
|
state["tasks"][slug]["updated"] = _now()
|
|
1693
1715
|
save_state(root, state) # F12: durable state FIRST (source of truth) — may _die
|
|
@@ -2293,6 +2315,7 @@ def _append_route_trace(root: Path, state: dict, slug: str, outcome: str) -> Non
|
|
|
2293
2315
|
"kind": kind, "lane": lane, "routed_by": by,
|
|
2294
2316
|
"persona": m.group(1) if m else None, "outcome": outcome,
|
|
2295
2317
|
"heals": (t.get("heal") or {}).get("attempts", 0),
|
|
2318
|
+
"rounds": (t.get("rounds") or {}).get("count", 0), # visible verify->build return trips
|
|
2296
2319
|
"recross": bool(t.get("recross")), "age_hours": age,
|
|
2297
2320
|
"target_hit": t.get("target_hit"), # the §3 Target judgment (plan-core)
|
|
2298
2321
|
"actor": (t.get("gate_actor") or {}).get("name"),
|
|
@@ -2925,7 +2948,10 @@ def cmd_status(args: argparse.Namespace) -> None:
|
|
|
2925
2948
|
_now_active = _active_task(state)
|
|
2926
2949
|
if _now_active and _now_active in (state.get("tasks") or {}):
|
|
2927
2950
|
_now_ph = (state["tasks"][_now_active] or {}).get("phase", "?")
|
|
2928
|
-
|
|
2951
|
+
# round-visible-runs: a bounced task names its return-trip count; silent at 0.
|
|
2952
|
+
_now_r = ((state["tasks"][_now_active] or {}).get("rounds") or {}).get("count", 0)
|
|
2953
|
+
_now_rr = f" · round {_now_r}" if _now_r else ""
|
|
2954
|
+
print(f"now : '{_now_active}' · phase={_now_ph}{_now_rr} · {_next_footer(root, state)}")
|
|
2929
2955
|
print(f" PLAN.md: .add/tasks/{_now_active}/PLAN.md · re-orient: add.py status --brief")
|
|
2930
2956
|
print(f"project : {state.get('project', '(unknown)')}")
|
|
2931
2957
|
# project autonomy default (task init-auto-default): the posture new tasks INHERIT,
|
|
@@ -3957,7 +3983,7 @@ def cmd_check(args: argparse.Namespace) -> None:
|
|
|
3957
3983
|
infos.append((f"persona '{slug}'", "schema-conformant"))
|
|
3958
3984
|
# persona-schema-hardening: quality findings the presence check can't see
|
|
3959
3985
|
# (typo'd flow: value · bare <…> placeholder) — WARN-only (measure-not-block),
|
|
3960
|
-
# REAL personas only:
|
|
3986
|
+
# REAL personas only: any `_`-prefixed scaffold is placeholders by design.
|
|
3961
3987
|
if not slug.startswith("_"):
|
|
3962
3988
|
try:
|
|
3963
3989
|
text = pf.read_text(encoding="utf-8")
|
|
@@ -4914,6 +4940,18 @@ def _scope_guard(root: Path, state: dict, slug: str) -> None:
|
|
|
4914
4940
|
f"declared §5 Scope — {shown} ({len(out)} total)"))
|
|
4915
4941
|
|
|
4916
4942
|
|
|
4943
|
+
def _record_round(task: dict, *, source: str, note: str | None = None) -> None:
|
|
4944
|
+
"""Record ONE verify->build return trip — a visible 'round' (round-visible-runs).
|
|
4945
|
+
|
|
4946
|
+
Uncapped and OBSERVATIONAL: rounds never gate, never cap, never move a phase — they
|
|
4947
|
+
make a dynamic verify->fix workflow legible in status and the route traces. Distinct
|
|
4948
|
+
from the heal counter (the CHEAT-classed, capped subset); a heal return records BOTH.
|
|
4949
|
+
Caller owns the save — the increment rides the same atomic write as the phase move."""
|
|
4950
|
+
r = task.setdefault("rounds", {"count": 0, "history": []})
|
|
4951
|
+
r["count"] = r.get("count", 0) + 1
|
|
4952
|
+
r.setdefault("history", []).append({"at": _now(), "source": source, "note": note})
|
|
4953
|
+
|
|
4954
|
+
|
|
4917
4955
|
def _heal_or_escalate(root: Path, state: dict, slug: str, *, reason: str, source: str) -> None:
|
|
4918
4956
|
"""The bounded self-heal router (verify-integrity, heal-then-escalate). Called ONLY when
|
|
4919
4957
|
a cheat is CONFIRMED at this point — mechanical (tripwire divergence, source "tamper") or
|
|
@@ -4941,6 +4979,7 @@ def _heal_or_escalate(root: Path, state: dict, slug: str, *, reason: str, source
|
|
|
4941
4979
|
"spec (change-request -> re-freeze) or abandon. A gamed green is never auto-passed.")
|
|
4942
4980
|
heal["attempts"] = heal.get("attempts", 0) + 1
|
|
4943
4981
|
heal.setdefault("history", []).append(entry)
|
|
4982
|
+
_record_round(t, source=source) # a heal return is ALSO a visible round (uncapped view)
|
|
4944
4983
|
t["phase"] = "build" # DIRECT — never via advance (no re-snapshot)
|
|
4945
4984
|
t["updated"] = _now()
|
|
4946
4985
|
_sync_task_marker(root, slug, "build")
|
|
@@ -6682,6 +6721,8 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
6682
6721
|
# cmd_phase) so pre-collapse scripts keep working; the stored value is always canonical.
|
|
6683
6722
|
pp.add_argument("phase", choices=PHASES + tuple(LEGACY_PHASES))
|
|
6684
6723
|
pp.add_argument("slug", nargs="?", default=None)
|
|
6724
|
+
pp.add_argument("--note", default=None,
|
|
6725
|
+
help="annotate the verify->build round this return records (build target only)")
|
|
6685
6726
|
pp.add_argument("--skip-freeze", action="store_true",
|
|
6686
6727
|
help="cross direction->build on a DRAFT §3, recording an auditable freeze_skipped "
|
|
6687
6728
|
"marker (the universal freeze gate's only bypass; never auto-freezes §3)")
|
|
@@ -115,18 +115,18 @@ PHASE_GROUPS = {
|
|
|
115
115
|
"VERIFY": ("verify",),
|
|
116
116
|
}
|
|
117
117
|
# phase-bundles: the roster agent PREFERRED for each phase (per-PHASE, not per-bundle —
|
|
118
|
-
#
|
|
119
|
-
#
|
|
120
|
-
#
|
|
121
|
-
#
|
|
122
|
-
#
|
|
123
|
-
# unmapped/corrupted phase token, not this map
|
|
118
|
+
# advisor-split: `add-worker` is the execution shell for every phase; the spawn prompt names
|
|
119
|
+
# the mode (direction·build·verify·persona) and the agent loads that beat's guide + the fitting
|
|
120
|
+
# persona (personas carry the expertise, the agent carries the discipline). `add-advisor` is
|
|
121
|
+
# spawned on demand to propose/pressure-test/decide — it is not a per-phase default, so it is
|
|
122
|
+
# absent here. A phase missing here is a bug (PHASE_GROUPS' own union covers every key);
|
|
123
|
+
# `_phase_bundle` is the fail-closed resolver for an unmapped/corrupted phase token, not this map.
|
|
124
124
|
PHASE_AGENT = {
|
|
125
|
-
"direction": "add",
|
|
126
|
-
"build": "add",
|
|
127
|
-
"verify": "add",
|
|
125
|
+
"direction": "add-worker",
|
|
126
|
+
"build": "add-worker",
|
|
127
|
+
"verify": "add-worker",
|
|
128
128
|
}
|
|
129
|
-
SETUP_FILES = ("PROJECT.md", "CONVENTIONS.md", "GLOSSARY.md", "MODEL_REGISTRY.md", "dependencies.allowlist", "DESIGN.md", "SOUL.md"
|
|
129
|
+
SETUP_FILES = ("PROJECT.md", "CONVENTIONS.md", "GLOSSARY.md", "MODEL_REGISTRY.md", "dependencies.allowlist", "DESIGN.md", "SOUL.md")
|
|
130
130
|
|
|
131
131
|
# persona-setup: a PERSONA living doc (`.add/personas/<slug>.md`) is a frozen-schema file
|
|
132
132
|
# distilled from the vendored teacher library to its critical-rules + default-requirement +
|
|
@@ -168,18 +168,19 @@ SPEC_DDS = {
|
|
|
168
168
|
# THIS constant (not their own copy) so the wording can never drift across the three surfaces.
|
|
169
169
|
# Project-scoped (not "this milestone's domain") per the confirmed v2 amendment: the AI should
|
|
170
170
|
# catch up ALL of a project's missing personas, not draft a single milestone-fit one.
|
|
171
|
-
PERSONA_HINT = ("no project-fit persona seeded yet under .add/personas/ —
|
|
172
|
-
"
|
|
173
|
-
"from PROJECT.md's domain
|
|
171
|
+
PERSONA_HINT = ("no project-fit persona seeded yet under .add/personas/ — use the persona-author "
|
|
172
|
+
"skill (or read docs/18-personas.md) to author the project's persona(s) "
|
|
173
|
+
"from PROJECT.md's domain")
|
|
174
174
|
|
|
175
175
|
# persona-fit-nudge: the OPPOSITE-branch, mutually-exclusive sibling of PERSONA_HINT — fires only
|
|
176
176
|
# when ≥1 real persona ALREADY exists, so a brand-new milestone doesn't silently assume one of
|
|
177
177
|
# them fits its domain. Existence-only (names the persona slugs already seeded); the AI still
|
|
178
|
-
# owns the actual fit judgment (
|
|
179
|
-
# similarity. {slugs} is filled at call time from
|
|
178
|
+
# owns the actual fit judgment (add-worker's persona mode, guided by the persona-author skill) —
|
|
179
|
+
# the engine never scores content similarity. {slugs} is filled at call time from
|
|
180
|
+
# `.add/personas/*.md` (excluding any `_`-prefixed scaffold).
|
|
180
181
|
PERSONA_FIT_HINT_TEMPLATE = (
|
|
181
|
-
"existing persona(s) seeded — {slugs} — confirm one fits this milestone's domain, or
|
|
182
|
-
"
|
|
182
|
+
"existing persona(s) seeded — {slugs} — confirm one fits this milestone's domain, or use the "
|
|
183
|
+
"persona-author skill (or read docs/18-personas.md) to author a better-fit one"
|
|
183
184
|
)
|
|
184
185
|
|
|
185
186
|
# Scaffolded into .add/.gitignore at init so the engine's transient LOCAL artifacts
|
|
@@ -46,10 +46,11 @@ def _guideline_block() -> str:
|
|
|
46
46
|
"PROJECT.md `invariants:` (run/entry contracts) bind EVERY task: the artifact must hold under\n"
|
|
47
47
|
"the BARE declared runtime — a dependency that breaks it is a defect, never \"expected\".\n"
|
|
48
48
|
"\n"
|
|
49
|
-
"Roster (from `add-method/agents
|
|
50
|
-
"(direction · build · verify ·
|
|
51
|
-
"
|
|
52
|
-
"
|
|
49
|
+
"Roster (from `add-method/agents/*.md`): TWO agents — `add-worker` runs each EXECUTION beat\n"
|
|
50
|
+
"(the spawn names it: direction · build · verify · persona), and `add-advisor` is the second\n"
|
|
51
|
+
"mind it spawns to propose a plan, pressure-test a draft, or decide a delegable ambiguity so\n"
|
|
52
|
+
"the beat never stalls. Each loads that beat's phase guide plus the best-fit `.add/personas/`\n"
|
|
53
|
+
"persona (personas carry the expertise, the agent carries the discipline; the floor binds both).\n"
|
|
53
54
|
"\n"
|
|
54
55
|
"On Claude Code the `add` skill drives this loop; other agents follow the three steps. Book: https://pilotspace.github.io/ADD/. This block is generated by `add.py sync-guidelines` — edit outside the markers.\n"
|
|
55
56
|
f"{_GUIDE_END}"
|
|
@@ -270,9 +270,9 @@ def _md5_file(p: Path) -> str | None:
|
|
|
270
270
|
|
|
271
271
|
def _personas_unseeded(root: Path) -> bool:
|
|
272
272
|
"""True when `.add/personas/` has no REAL (non-template) authored persona: the
|
|
273
|
-
directory is absent, empty, or holds only
|
|
274
|
-
|
|
275
|
-
rather than raising — this feeds a `note:`/INFO hint, never a gate."""
|
|
273
|
+
directory is absent, empty, or holds only a `_template.md` scaffold (personas are
|
|
274
|
+
authored via the persona-author skill, not seeded). Fail-soft: an unreadable directory
|
|
275
|
+
counts as unseeded rather than raising — this feeds a `note:`/INFO hint, never a gate."""
|
|
276
276
|
d = root / "personas"
|
|
277
277
|
if not d.is_dir():
|
|
278
278
|
return True
|
|
@@ -71,7 +71,7 @@ Verified by: <agent-id> · at: <ISO-8601 UTC timestamp>
|
|
|
71
71
|
|
|
72
72
|
---
|
|
73
73
|
|
|
74
|
-
## 4 · TESTS — failing-first suite (red) ▸ docs/06-step-4-tests.md
|
|
74
|
+
## 4 · TESTS — failing-first suite or acceptance checks (red) ▸ docs/06-step-4-tests.md
|
|
75
75
|
|
|
76
76
|
<test_plan>
|
|
77
77
|
- test_<name>: arrange / act / assert behavior not internals · covers: <M#, R:code>
|
|
@@ -79,6 +79,7 @@ Verified by: <agent-id> · at: <ISO-8601 UTC timestamp>
|
|
|
79
79
|
|
|
80
80
|
Tests live in: `./tests/` · MUST run red (missing implementation) before Build.
|
|
81
81
|
<!-- declare paths as backticked tokens on this line: `./…` = this task dir · a token with "/" = the project root · a bare name = a sibling of the previous token's dir · a directory counts its *.py files (non-recursive) · declared counts marked † · outside the project root counts 0. The test_plan bullets' `covers:` tails are machine-read too: `add.py locate path::test_name` resolves a failing test to the frozen §3 clause it proves -->
|
|
82
|
+
<!-- NON-CODING task (kind: docs · release · infra, or a non-coding project)? §4 is a failing-first ACCEPTANCE CHECK, not a script — verifiable pass/fail evidence (mkdocs build succeeds · §X covers A/B/C · every internal link resolves), red before the artifact exists and green after. Set `Tests live in: evidence` (no `./tests/`). The red→green discipline holds; only the must-be-executable-code requirement is lifted. -->
|
|
82
83
|
|
|
83
84
|
---
|
|
84
85
|
|
|
@@ -86,14 +87,14 @@ Tests live in: `./tests/` · MUST run red (missing implementation) before Build.
|
|
|
86
87
|
|
|
87
88
|
Strategy actually used: <fill at VERIFY — what you ACTUALLY did (or "as planned"); harvested into §7 Decisions (ADR)>
|
|
88
89
|
Code lives in: `./src/`
|
|
89
|
-
Spawn (multi-agent): build/verify subagent spawns default `isolation: worktree`; cross-agent advisor — spawn
|
|
90
|
+
Spawn (multi-agent): build/verify subagent spawns default `isolation: worktree`; cross-agent advisor — spawn `add-advisor` (an agent OTHER than the builder) for the freeze `--cross` and the §6 refute-read; `self` only when solo.
|
|
90
91
|
Constraints: do NOT change any test or the frozen §3 contract; stay inside §3 Scope (an out-of-scope build fails the gate: scope_violation); keep the §3 Regression floor green; allow-list packages only; ask if unclear.
|
|
91
92
|
|
|
92
93
|
---
|
|
93
94
|
|
|
94
95
|
## 6 · VERIFY — evidence + non-functional review ▸ docs/08-step-6-verify.md
|
|
95
96
|
|
|
96
|
-
- [ ] all tests pass — including the §3 Regression floor (host suite)
|
|
97
|
+
- [ ] all tests (or §4 acceptance checks) pass — including the §3 Regression floor (host suite)
|
|
97
98
|
- [ ] coverage did not decrease
|
|
98
99
|
- [ ] no test or contract was altered during build
|
|
99
100
|
- [ ] the green was EARNED, not gamed — no overfit to fixtures, vacuous asserts, or stubbed-away logic (a confirmed cheat is HARD-STOP)
|