@nurix/etna 0.20.38 → 0.20.40

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.
Files changed (29) hide show
  1. package/data/harness-index.json +1 -1
  2. package/data/harnesses/code/agents/brainstorm.md +9 -5
  3. package/data/harnesses/code/codex/agents/brainstorm.toml +9 -5
  4. package/data/harnesses/code/harness.json +2 -2
  5. package/data/harnesses/code/skills/brainstorm/README.md +18 -45
  6. package/data/harnesses/code/skills/brainstorm/SKILL.md +105 -173
  7. package/data/harnesses/code/skills/brainstorm/references/doctrine.md +70 -141
  8. package/data/harnesses/code/skills/brainstorm/references/entry.md +70 -0
  9. package/data/harnesses/code/skills/brainstorm/references/harvest.md +85 -137
  10. package/data/harnesses/code/skills/brainstorm/references/session-schema.md +98 -135
  11. package/data/harnesses/delivery/agents/brainstorm.md +9 -5
  12. package/data/harnesses/delivery/codex/agents/brainstorm.toml +9 -5
  13. package/data/harnesses/delivery/harness.json +2 -2
  14. package/data/harnesses/delivery/skills/brainstorm/README.md +18 -45
  15. package/data/harnesses/delivery/skills/brainstorm/SKILL.md +105 -173
  16. package/data/harnesses/delivery/skills/brainstorm/references/doctrine.md +70 -141
  17. package/data/harnesses/delivery/skills/brainstorm/references/entry.md +70 -0
  18. package/data/harnesses/delivery/skills/brainstorm/references/harvest.md +85 -137
  19. package/data/harnesses/delivery/skills/brainstorm/references/session-schema.md +98 -135
  20. package/data/harnesses/etna/agents/brainstorm.md +9 -5
  21. package/data/harnesses/etna/codex/agents/brainstorm.toml +9 -5
  22. package/data/harnesses/etna/harness.json +2 -2
  23. package/data/harnesses/etna/skills/brainstorm/README.md +18 -45
  24. package/data/harnesses/etna/skills/brainstorm/SKILL.md +105 -173
  25. package/data/harnesses/etna/skills/brainstorm/references/doctrine.md +70 -141
  26. package/data/harnesses/etna/skills/brainstorm/references/entry.md +70 -0
  27. package/data/harnesses/etna/skills/brainstorm/references/harvest.md +85 -137
  28. package/data/harnesses/etna/skills/brainstorm/references/session-schema.md +98 -135
  29. package/package.json +2 -2
@@ -1,142 +1,90 @@
1
1
  # Harvest — the stop pipeline
2
2
 
3
- Load when: `/brainstorm stop` is invoked (facilitator), or executing any stop-gate dispatch
4
- (twin). The pipeline's mechanical gates live in the detector (`--gate=manifest`, `--gate=move`);
5
- this reference carries the routing judgment.
6
-
7
- The pipeline, end to end:
8
-
9
- 1. Converge.
10
- 2. Final sync and compose → manifest (`Status: proposed`).
11
- 3. **One** user approval (`Status: approved`).
12
- 4. Apply, reading both sides of every destination (`Status: applied`).
13
- 5. Uselessness test — gaps open a new `Round` and return to step 3.
14
- 6. Move to `docs/history/brainstorms/{topic}/` — the completion marker.
15
- 7. Offer: delete or commit — the user decides.
16
-
17
- **Harvest fails loud, never silent.** The move happens **only** after the full apply passes the
18
- uselessness test. A partial apply — twin death, session kill, anything — leaves the folder visibly
19
- unfinished in `docs/research/`, and the user restarts the stop. The pipeline **never** resumes
20
- silently from a half-applied state, and **never** writes a canonical doc without an approved
21
- manifest, gap-round fixes included.
22
-
23
- ## The routing map
24
-
25
- Route each piece of the surface by scope. Format every artifact through the `documentation` skill;
26
- where it is unavailable, format it yourself and record in the manifest which path ran. Read **both
27
- sides** of every destination before writing — the destination's current content is a contract, not
28
- a blank page.
29
-
30
- | What | Goes to | Shape |
31
- | --- | --- | --- |
32
- | **Source of truth** | The repo's canonical home for that knowledge: `docs/features/` for a feature, `docs/architecture/` for cross-cutting doctrine, else a topic `Readme.md` | One consolidated reader-first doc distilled from the whole surface: thesis → what it is; domain fragment → how it works; ledger → present-tense rationale **without entry codes** |
33
- | **Executable work** | `docs/history/plans/` | Split by deliverable, never by pillar |
34
- | **Decision records** | One record per decision *subject* | A decision revising an already-recorded subject updates that record in place (its changelog carries the journey) rather than minting a new one; declined alternatives ride along with their re-evaluate conditions |
35
- | **Domain-model changes** | The living domain-model doc | The information-architecture contract the `boundary` skill reads at the next plan check |
36
- | **Still-open (parked) forks** | The repo's open-questions home | Each with a *resolution-lands-in* pointer |
37
- | **Backlog items** | The repo backlog | See the scope-guard trio below |
38
- | **Fragments** | Their destinations — drafted in destination format, so this is a move, not a translation | Merge per the destination's existing structure |
39
-
40
- **The scope-guard trio** disambiguates everything that isn't a commitment:
41
-
42
- - *Will build later* → **backlog**.
43
- - *Deliberately not building* → **non-goals**.
44
- - *Weighed and chose another option* → a **Declined:** line inside the deciding ledger entry,
45
- with its evidence and re-evaluate condition — carried into the harvested decision record.
46
-
47
- **Directional steering is not feature truth.** A harvested principle informs many decisions and
48
- changes slowly; a feature fact belongs to its feature doc and changes at code speed. The harvest
49
- **links** between the steering layer and feature docs — **never** duplicates prose across them, and
50
- **never** invents a new top-level home for principles; they land in the *existing* living docs.
51
-
52
- Rejection rationale and reasoning chains **must** have explicit destinations — options-considered
53
- sections, decision changelogs — or the uselessness test fails: the folder is **never** deleted into
54
- a knowledge loss.
55
-
56
- ## The uselessness test
57
-
58
- The deletion-safety gate: after the apply, the post-harvest living docs alone must be enough.
59
-
60
- - **The reader is always a freshly spawned, context-free agent** — a full-context reader cannot
61
- cold-read; it already knows every undefined term.
62
- - **Isolation is enforced, not instructed:** the cold reader's prompt contains an explicit
63
- allowed-path list (the manifest's destinations — never the session folder), and the detector
64
- independently verifies no harvested doc links back into the session folder (BS-HARVEST-01) — a
65
- link into scaffolding is itself a harvest defect.
66
- - **The task:** reconstruct the design — thesis, commitments, reasoning, declined branches — from
67
- the allowed paths only.
68
- - **Grading:** the twin diffs the reconstruction against the ledger and thesis and names every
69
- gap; the session-replay evals audit the grading itself. Anything unrecoverable is a named harvest
70
- gap, recorded in the manifest (`Result: fail`); its fixes enter a new manifest `Round`, approved
71
- like the first. Iterate until the folder is redundant.
72
-
73
- ## The move, and the offer
74
-
75
- When the detector's move gate is clean:
76
-
77
- 1. Delete `ops/` entirely — transcript-grade residue **never** enters git.
78
- 2. `git mv` the folder to `docs/history/brainstorms/{topic}/`.
79
- 3. Set `Status: harvested` in `state.md`.
80
-
81
- Update no index — none keeps a row per session. The move is the completion marker: a folder under
82
- `docs/research/` is by definition unfinished, which is exactly what the maintenance census reads.
83
-
84
- Then the offer, relayed by the facilitator: **delete the moved folder, or commit it.** The user
85
- decides; the design assumes deletion — **nothing** anywhere may depend on the folder surviving.
86
- Committing is the explicit way to keep git-history forensics; an uncommitted folder deleted here is
87
- gone, and that loss is accepted by design.
3
+ Load when: `/brainstorm stop`; any question about where session content lands. The twin reads it to build the manifest.
4
+
5
+ Stop is a fixed pipeline: converge, final sync, one approval, apply, the uselessness test, the move, the offer. You orchestrate it, because every approval belongs to the user; the twin executes each leg as a `stop` dispatch. The session's product is the mutated living docs, so the pipeline's exit condition is checkable: a context-free reader given only the harvested destinations reconstructs the design. Until that passes, the folder stays under `docs/research/`, visibly unfinished.
6
+
7
+ ## 1. Converge
8
+
9
+ Every open fork is resolved into a decision or parked with a destination, now.
10
+
11
+ - **Offer one blindspot pass first** if none has run this session: one line, yes or no. A yes dispatches it before the convergence.
12
+ - Run the convergence as converge picks: one pick per fork, recommendation first, batched. A park names where its resolution will land.
13
+ - The user may resolve or park; they may not leave a fork open. A fork the user will not decide is parked to the repository's open-questions home.
14
+
15
+ ## 2. Final sync and manifest
16
+
17
+ Dispatch the twin, scope `final sync + compose + manifest`. It reconciles, composes, runs the detector at `--gate=manifest`, and builds `ops/manifest.md` (`Status: proposed`) only when that gate is clean. While the gate fails, relay what blocks in plain words and go back to step 1.
18
+
19
+ ## 3. One approval
20
+
21
+ Show the manifest table and ask once: approve, or name the rows to change. This is the designed gate before the harvest writes into canonical documents; nothing is written until it is answered, and on silence the session stays open with the manifest proposed. Under standing approval ("don't seek any more approvals"), record the approval as standing and continue.
22
+
23
+ ## 4. Apply
24
+
25
+ Dispatch the twin, scope `apply`. It sets `Status: approved`, reads **both sides** of every destination before writing (the destination's current content is a contract, not a blank page), formats each artifact through the `documentation` skill, and sets `Status: applied`.
26
+
27
+ **The apply is all-or-nothing and loud.** If it cannot finish, the twin reports exactly what applied and stops; relay that verbatim. The folder stays under `docs/research/`, and the user restarts the stop. Never resume silently from a half-applied state: a bad harvest corrupting canonical docs is worse than a skipped one, and a loud early failure the user can fix beats damage discovered after the folder is gone.
28
+
29
+ ## 5. The uselessness test
30
+
31
+ Dispatch the twin, scope `uselessness test`. It spawns a fresh, context-free cold reader whose brief holds only the allowed-path list (the manifest's destinations, never the session folder) and the task to reconstruct the design: the thesis, the commitments, the reasoning, the declined branches. It grades the reconstruction against the ledger and the thesis and records the result in the manifest.
32
+
33
+ - **Pass** (`Result: pass`, `Gaps: none`) → step 6.
34
+ - **Gaps** → each is a named piece of knowledge the destinations lost. The fix re-enters at step 3 as a delta manifest (`Round` incremented), approved like the first, then applied and retested.
35
+
36
+ If the twin reports it cannot spawn a sub-agent, dispatch the cold reader yourself, on the **standard tier** (Sonnet on Anthropic; the flagship model at default reasoning effort on OpenAI): reconstruction from a short path list is synthesis, not frontier work. Its brief is the allowed-path list and the reconstruction task, nothing else; give the twin its reply to grade. Neither you nor the twin may be the reader: a reader that has seen the session already knows every undefined term.
37
+
38
+ ## 6. The move
39
+
40
+ Dispatch the twin, scope `move`. It runs `--gate=move`, deletes `ops/`, moves the folder to `docs/history/brainstorms/{topic}/` (with `git mv` when any file in it is tracked, plain `mv` when none is, because `git mv` refuses a never-committed folder), and sets `Status: harvested`. The location is the completion marker: a folder still under `docs/research/` is unfinished by definition. Under standing approval, hold this step and step 7 for the end-of-session message, because deleting the untracked capture cannot be undone.
41
+
42
+ ## 7. The offer
43
+
44
+ Relay the twin's offer as one question: **delete the moved folder, or commit it.** The design assumes deletion, since the uselessness test has made the folder redundant; committing keeps a git-history record the user chose. An uncommitted folder deleted at stop leaves no forensics, which the user accepts by choosing delete.
45
+
46
+ ## Where content lands
47
+
48
+ The twin routes by scope, never by surface file:
49
+
50
+ | Piece of the surface | Destination |
51
+ | --- | --- |
52
+ | The whole surface, distilled | one reader-first source-of-truth document at the repository's canonical home (`docs/features/`, `docs/architecture/`, else a topic `Readme.md`): the thesis as what it is, the domain fragment as how it works, the ledger as present-tense rationale with no `D`/`F` codes |
53
+ | Executable work | plans, split by deliverable, never by surface file |
54
+ | Decisions | one record per decision subject; a decision revising a recorded subject updates that record in place, its declined alternatives riding along |
55
+ | Domain-model changes | the living domain-model document, which the `boundary` skill reads at the next plan check |
56
+ | Parked forks | the repository's open-questions home, each pointing to where its resolution will land |
57
+ | Will-build-later | the backlog |
58
+ | Deliberately-not-building | the destination's non-goals |
59
+ | Weighed and chose another | a **Declined:** line with its re-evaluate condition, in the decision record or the source-of-truth document's rationale |
60
+
61
+ - **Rejection rationale and reasoning chains need an explicit destination**, or the uselessness test fails; they are what living docs lose first.
62
+ - **No destination links back into the session folder.** The folder is about to be deleted; a link into it is a pointer to nothing, and the detector fails the move on one.
63
+ - **Steering is not feature truth.** A harvested principle goes to the steering layer (`docs/architecture/`); a feature fact goes to its feature doc. The harvest links between them and never copies prose across them.
64
+ - **Starting or harvesting a session edits no index.** The folder's location is the record.
65
+
66
+ ## Degradations — flagged, never silent
67
+
68
+ | Missing | Then |
69
+ | --- | --- |
70
+ | The `documentation` skill | the twin formats the artifacts itself, and the manifest records which path ran |
71
+ | Nested sub-agent dispatch | you dispatch the cold reader (step 5) |
72
+ | The detector, or Node | the twin runs the schema's checks by hand and says so in its report; relay it as a flagged fact |
73
+ | Any leg failing | the twin logs `S<n> → failed` with the reason; relay it and re-run that leg |
88
74
 
89
75
  ## Field lessons — apply
90
76
 
91
- Each is a rule measured on live harvests.
92
-
93
- - **Run the move gate clean immediately before the move and treat that as the verdict** — the
94
- gate's checks read `ops/`, which the move deletes, so a post-move re-run fails by construction.
95
- Verify the post-move state by hand: `Status: harvested`, no `ops/`, `check-links` clean.
96
- - **Distil the process record into `state.md` before the move** — the sync log dies with `ops/`,
97
- and a ten-line dispatch summary separates a record that shows its workings from one that asserts
98
- its commitments from nowhere.
99
- - **Uncommitted harvest artifacts are deleted, not deprecated** — deprecate-in-place protects
100
- readers holding a pointer, and a never-committed file has none; a tombstone for a
101
- twenty-minute-old file is ceremony.
102
- - **At manifest time, read every existing AD's Decision and Open Questions against the new
103
- commitments.** A harvest routes only through the docs its commitments name, and the test is
104
- commitment-level, not textual — grep finds nothing, because the ledger never names the
105
- neighbours. Report the unimpacted verdicts with their evidence too.
106
- - **A manifest row names one site; the file you open holds more.** Fix every same-doctrine site
107
- inside a file the manifest already opens — a self-contradicting document is worse than a wider
108
- diff — but **never** wander into an unnamed file: that becomes a backlog row, because a canonical
109
- doc is not rewritten outside an approved scope. Say which you did, per row, in the application
110
- record.
111
- - **Re-run the uselessness test when the destination *set* changes**, not only when content does —
112
- a consolidation that moves referrers produces a document set no cold reader has graded. The
113
- recurring find: a truth doc stating a decided-but-unbuilt mechanism in the present tense; the
114
- fix is one clause naming the unbuilt prerequisite.
115
- - **Retirement wording beats suppression.** `doc-lint`'s heuristics block the honest retirement
116
- sentence (`superseded by`, `no longer`); rephrase with no loss of meaning — "retired by
117
- AD-00N", "is not the product's position", "lives in a package that is gone" — and reach for
118
- `doc-lint-disable` only when the banned phrase is itself the claim.
119
- - **Amending another session's draft: change the contradicting claim everywhere it is asserted,
120
- and nothing else** — a claim stated in nine places and fixed in three leaves the doc worse; a
121
- one-paragraph note saying what moved and what did not keeps the amendment legible to the doc's
122
- author.
123
- - **A suppression marker is a dated assertion about code, and it decays faster than the docs
124
- around it.** A harvest that deletes doctrine rows corrects their wrappers first — a false wrapper
125
- is a correction row in the manifest, never collateral of a delete. A phantom guard propagates by
126
- citation: grep the guard *path*, not its name, and count live docs separately from frozen ones,
127
- which record what was believed and are not edited.
128
- - **Retiring a guardrail row edits three artifacts.** The row is cited by ID from feature docs and
129
- frozen plans, wrapped in a marker asserting where its code lives, and restated in the
130
- out-of-scope register at the foot of the same file: keep the ID and mark the row retired with a
131
- pointer, correct the wrapper, and replace the register bullet with a pointer — otherwise the file
132
- contradicts itself twenty lines apart.
133
- - **Size the decision records to the repo's AD doctrine before writing them.** One decision per
134
- subject argued feels natural and produces micro-ADs where the rule is one overarching AD per
135
- architectural subject; the test at manifest time is whether a reader would ever need one record
136
- without the others. The safe shape is one AD per plane with a section per settled subject — each
137
- keeping its Decision, Why and Declined table — and a separate AD only for a genuinely different
138
- subject. Link with section anchors where a bare pointer loses precision, and verify anchors by
139
- hand: the link checker strips them before resolving.
140
- - **The per-file lint hook reads intermediate states.** It appends queue rows from mid-edit files;
141
- run the linter over the whole edited set before declaring the apply done, and leave the stale
142
- rows for the facilitator rather than draining them.
77
+ Each was measured on a live harvest; the twin applies them, and you relay where one changes what the user sees.
78
+
79
+ - **The move gate run immediately before the move is the verdict.** Its checks read `ops/`, which the move deletes, so a re-run after the move fails by construction. Verify the post-move state by hand instead: `Status: harvested`, no `ops/`, links resolving.
80
+ - **Distil the process record into `state.md` before the move.** The sync log dies with `ops/`; a ten-line dispatch summary separates a record that shows its workings from one that asserts its decisions from nowhere.
81
+ - **A never-committed harvest artifact that turns out wrong is deleted, not deprecated.** Deprecating in place protects readers holding a pointer, and a file that was never committed has none.
82
+ - **At manifest time, read every existing architecture decision's Decision and open questions against the new decisions.** A harvest routes only through the docs its decisions name, and the ledger never names the neighbours, so grep finds nothing: the test is decision against decision. Report the unaffected verdicts with their evidence too.
83
+ - **A manifest row names one site; the file it opens holds more.** Fix every site of the same doctrine inside a file the manifest already opens, since a self-contradicting document is worse than a wider diff, but never wander into a file no row names: that becomes a backlog row, because a canonical doc is not rewritten outside an approved scope. Say per row which you did.
84
+ - **Re-run the uselessness test when the destination set changes**, not only when content does: a consolidation that moves referrers produces a document set no cold reader has graded. The recurring find is a truth doc stating a decided-but-unbuilt mechanism in the present tense; the fix is one clause naming the unbuilt prerequisite.
85
+ - **Rephrase a retirement rather than suppress the linter.** `doc-lint` blocks honest retirement sentences ("superseded by", "no longer"); say "retired by" the record, "is not the product's position", "lives in a package that is gone", and reach for `doc-lint-disable` only when the banned phrase is itself the claim.
86
+ - **Amending another session's draft: change the contradicting claim everywhere it is asserted, and nothing else.** A claim stated in nine places and fixed in three leaves the doc worse; a one-paragraph note on what changed and what did not keeps the amendment legible to its author.
87
+ - **A suppression marker is a dated claim about code and decays faster than the prose around it.** A harvest deleting doctrine rows corrects their wrappers first, as a manifest row of its own, never as collateral of a delete. A phantom guard spreads by citation: grep the guard's path, not its name, and count live docs apart from frozen ones, which record what was believed and are not edited.
88
+ - **Retiring a guardrail row edits three artifacts.** The row is cited by id from feature docs and frozen plans, wrapped in a marker naming where its code lives, and restated in the out-of-scope register at the foot of the same file: keep the id and mark the row retired with a pointer, correct the wrapper, and replace the register bullet with a pointer, or the file contradicts itself twenty lines apart.
89
+ - **Size decision records to the repository's own decision doctrine before writing them.** One record per argued subject feels natural and yields micro-records where the rule is one record per architectural subject; the test is whether a reader would ever need one without the others. The safe shape is one record per plane with a section per settled subject, each keeping its Decision, Why and Declined lines, and a separate record only for a genuinely different subject. Link with section anchors where a bare pointer loses precision, and check anchors by hand: the link checker strips them.
90
+ - **A per-file lint hook reads intermediate states.** It queues rows from mid-edit files; run the linter over the whole edited set before calling the apply done, and leave its stale rows for the facilitator rather than draining them.
@@ -1,194 +1,157 @@
1
- # Session schema — the single format authority
1
+ # Session schema — the on-disk contract
2
2
 
3
- Load when: bootstrapping a session, writing any working-surface file, dispatching the twin, or
4
- interpreting detector output. The detector (`scripts/detector.mjs`) is the mechanical half of this
5
- contract: every rule below carrying a rule ID is machine-checked; everything else is the twin's
6
- semantic judgment.
3
+ Load when: bootstrap; writing a capture entry or a dispatch line you are unsure of; relaying a detector finding. The twin reads it on every dispatch.
7
4
 
8
- ## Folder layout
5
+ This is the format `scripts/detector.mjs` parses, and the twin, the replay evals and the maintenance census all key on its rule ids. A line that drifts from it fails a rule or, worse, is silently not seen, so match the shapes below exactly: field names, the em dash ` — `, the arrow ` → `, the middle dot ` · `. **Every datetime is UTC in one shape, `YYYY-MM-DDTHH:MMZ`, taken from `date -u +%Y-%m-%dT%H:%MZ`:** the detector compares stamps as strings, so a local-time or differently shaped stamp makes a fresh compose read as stale, or a stale one as fresh.
9
6
 
10
- An open session is `docs/research/{topic}-brainstorm/` (kebab-case topic slug):
7
+ ## Layout
11
8
 
12
- | Path | Holds | Writer |
13
- | --- | --- | --- |
14
- | `state.md` | anchor + aspect map | twin |
15
- | `thesis.md` | composed claim → argument → what changed | twin |
16
- | `forks.md` | open questions with close conditions | twin |
17
- | `ledger.md` | commitments | twin |
18
- | `basis/` | frozen entry material | facilitator, once, at intake |
19
- | `fragments/` | harvest-native fragments, drafted in destination format; created on first real content | twin |
20
- | `ops/` | the untracked capture layer, deleted at stop | — |
21
- | `ops/.gitignore` | `*` — `ops/` **never** enters git [BS-OPS-01/02] | facilitator |
22
- | `ops/capture.md` | the facilitator's raw append ledger | facilitator |
23
- | `ops/sync-log.md` | the paired twin-dispatch log | both (see below) |
24
- | `ops/manifest.md` | the harvest manifest | twin, in the stop pipeline |
25
-
26
- On a passed harvest the folder **moves** to `docs/history/brainstorms/{topic}/`, `ops/` deleted
27
- first. The move is the completion marker; the user then deletes or commits the folder. A folder
28
- under `docs/research/` is by definition unfinished.
29
-
30
- **Write protocol (one writer per file; the sync log is paired):** the facilitator bootstraps `ops/` at intake, appends to
31
- `ops/capture.md`, and writes the initial `basis/` copy plus the sync-log *dispatch* lines —
32
- **nothing else, ever**. The twin writes every other file, at gates. The user may hand-edit anything;
33
- the twin diffs each file against its own last compose before rewriting and folds foreign edits in
34
- as first-class user signal.
35
-
36
- ## state.md
9
+ ```
10
+ docs/research/{topic}-brainstorm/
11
+ ├── state.md twin
12
+ ├── thesis.md twin
13
+ ├── forks.md twin
14
+ ├── ledger.md twin
15
+ ├── fragments/{name}.md twin, created on first real content
16
+ ├── basis/ facilitator, at intake; frozen
17
+ └── ops/ untracked; deleted at the move
18
+ ├── .gitignore facilitator, at bootstrap: the single line *
19
+ ├── capture.md facilitator, every turn
20
+ ├── sync-log.md dispatch lines: facilitator · result lines: twin
21
+ └── manifest.md twin, at stop
22
+ ```
23
+
24
+ On a passing harvest the folder moves to `docs/history/brainstorms/{topic}/` without `ops/`, and `state.md` reads `Status: harvested`.
25
+
26
+ ## `state.md`
37
27
 
38
28
  ```markdown
39
29
  # State
40
30
 
41
- - Status: open | stopping | harvested
42
- - Posture: mid-probe on the sync-layer aspect, three forks open
31
+ - Status: open
32
+ - Posture: mid-probe on the persistence aspect, two forks open
43
33
  - Started: 2026-07-08
44
- - Sitting: single | multi
45
- - Last compose: 2026-07-08T14:30Z | never
34
+ - Sitting: single
35
+ - Last compose: 2026-07-08T14:30Z
46
36
 
47
37
  ## Aspect map
48
38
 
49
- - persistence — how session state survives restarts → F1, D3
39
+ - persistence — how cache state survives restarts → F1, D1
50
40
  - onboarding — the first-run experience → thesis
51
- - risks — failure modes and mitigations → none yet
41
+ - risks — failure modes and mitigations → F2, fragment:domain-model
52
42
  ```
53
43
 
54
- - `Status` moves **only** forward: `open → stopping → harvested` — the twin sets `stopping` when the
55
- stop pipeline begins and `harvested` at the move [BS-STATE-01].
56
- - The aspect map is derived per idea from the basis and edited by the user. Each aspect carries
57
- `→` refs to the content covering it: fork IDs (`F#`), ledger IDs (`D#`), `thesis`,
58
- `fragment:{name}`, or `none yet` (an open coverage gap — informational mid-session
59
- [BS-ASPECT-01], blocking at the manifest gate [BS-ASPECT-02]). Ref *presence* is the detector's
60
- half; whether the content actually covers the aspect is the twin's.
61
-
62
- ## thesis.md
44
+ | Field | Values |
45
+ | --- | --- |
46
+ | `Status` | `open` → `stopping` → `harvested`, forward only: the twin sets `stopping` when the stop pipeline begins and `harvested` at the move |
47
+ | `Posture` | one line a resuming reader can act on: where the conversation is and what is next; a parked session says so here |
48
+ | `Started` | ISO date |
49
+ | `Sitting` | `single` · `multi` |
50
+ | `Last compose` | the ISO datetime of the last thesis compose, equal to the thesis stamp; `never` before the first |
63
51
 
64
- ```markdown
65
- # {Topic} — thesis
52
+ Each aspect line is `- {name} — {gloss} → {refs}`, refs comma-separated: `F<n>` (a fork, open or resolved by a decision), `D<n>`, `fragment:{name}` (a file under `fragments/`), `thesis`, or `none yet`.
66
53
 
67
- Current as of: 2026-07-08T14:30Z
54
+ ## `thesis.md`
68
55
 
69
- ## Claim
70
- ## Argument
71
- ## What changed
72
- ```
56
+ A title, then `Current as of: <ISO datetime>`, then the sections `## Claim`, `## Argument`, `## What changed`, in that order.
73
57
 
74
- Composed prose, rewritten whole at every compose, **never** appended. The three sections and the
75
- stamp are mandatory [BS-THESIS-01]; the stamp must equal `state.md`'s `Last compose`
76
- [BS-COMPOSE-01]. At the manifest gate, `Last compose` must be later than the newest
77
- `ops/capture.md` entry — a compose over unsynced capture is stale [BS-COMPOSE-02].
78
-
79
- ## forks.md
58
+ ## `forks.md`
80
59
 
81
60
  ```markdown
82
- ## F3 — Should reads wait for a compose? [open]
61
+ ## F2 — What happens on catalog API timeout? [open]
83
62
 
84
- Full self-contained prose in the user's framing.
63
+ The cache can serve stale on timeout or propagate the error; the basis is silent on it.
85
64
 
86
- - Raised by: user | twin (S4) | probe | harvest
87
- - Closes when: a pick between wait-for-fresh and read-stale-with-warning
65
+ - Raised by: twin (S1)
66
+ - Closes when: an accepted failure behavior — stale-serve with a warning, or error propagation
88
67
  ```
89
68
 
90
- - IDs `F1, F2, …` unique, never reused [BS-FORK-01]. Status marker: `[open]` or
91
- `[parked → {destination}]`. Every fork carries `Closes when:` [BS-FORK-01].
92
- - `Raised by: twin (S#)` must cite a reconciled sync-log entry [BS-SYNC-02].
93
- - **The twin deletes a resolved fork's entry** — the resolving ledger entry's `Resolves:` field is
94
- the record. `forks.md` holds only open and parked forks; a ledger `Resolves: F3`
95
- coexisting with an open F3 is an inconsistency [BS-FORK-02]. Parked forks survive to the
96
- manifest, which must route each one [BS-MANIFEST-01].
97
- - The manifest gate requires zero `[open]` forks [BS-FORK-03].
69
+ The heading's bracket is `[open]` or `[parked → {destination path}]`. `Raised by:` is `user`, `facilitator`, or `twin (S<n>)` citing the reconciled sync that raised it; a blindspot fork's body opens `Blindspot:`. A fork resolved by a decision leaves the file; the decision's `Resolves:` keeps its id.
98
70
 
99
- ## ledger.md
71
+ ## `ledger.md`
100
72
 
101
73
  ```markdown
102
- ## D4 — Sessions initialize in dump or interview
103
-
104
- - Decision: every session opens in dump or interview; probe and converge are mid-session moves.
105
- - Why: a first-time user cannot be asked to pick a posture they have no vocabulary for.
106
- Declined: free initial posture — observed cold-starts stall in probe; re-evaluate if
107
- session-replay evals show experienced users fighting the default.
108
- - How to apply: the facilitator's start calibration offers only the two entry moves.
109
- - Resolves: F2
74
+ ## D1 — Cache keys are per-tenant
75
+
76
+ - Decision: every cache key embeds the tenant id; no shared entries.
77
+ - Why: cross-tenant reads are a trust break, and memory cost is acceptable at current tenant
78
+ counts. Declined: shared keys with tenant checks at read time — a single missed check leaks
79
+ data; re-evaluate if memory pressure forces it.
80
+ - How to apply: the cache module's key builder prefixes the tenant slug.
81
+ - Resolves: F3
110
82
  ```
111
83
 
112
- - IDs `D1, D2, …` unique, append-only [BS-LEDGER-01]. `Decision`, `Why`, `How to apply` are
113
- mandatory; `Resolves:` when the commitment closes forks. Amendments and reversals are
114
- annotations plus a new entry ("Reversed by D9" on the old; D9 names what it reverses) — never a
115
- rewrite. Declined options live inside `Why` per [doctrine.md](doctrine.md).
116
-
117
- ## ops/capture.md
84
+ `Decision`, `Why` and `How to apply` are required and non-empty; `Resolves` is optional. Ids are unique and never reused.
118
85
 
119
- The facilitator's per-turn append. Lowest possible bar: raw, unpolished, everything
120
- session-relevant from *both* sides (user substance and facilitator substance — diagnoses, informed
121
- rejections, definitions, reasoning chains), including residue judged not worth pillar filing.
122
- Format:
86
+ ## `ops/capture.md`
123
87
 
124
88
  ```markdown
89
+ # Capture
90
+
125
91
  ---
126
- ### T14 · 2026-07-08T14:22Z
92
+ ### T2 · 2026-07-08T14:20Z
127
93
 
128
- <raw notes for this turn>
94
+ facilitator: flagged the trust concern on shared entries — a missed tenant check at read time is
95
+ a leak, not a bug. recommended per-tenant keys; user accepted (→ D1). residue: user mentioned a
96
+ "warm-on-deploy" idea in passing, not pursued.
129
97
  ```
130
98
 
131
- Turn IDs `T#` ascend, each with an ISO timestamp — the timestamp compose-freshness checks against
132
- [BS-COMPOSE-02]. **Never** distill here; distillation is the twin's.
133
-
134
- ## ops/sync-log.md
99
+ Entries are separated by `---`, headed `### T<n> · <ISO datetime>`, numbered in order, and labelled by speaker inside (`user (dump):`, `facilitator:`). The heading's datetime is what the manifest gate compares against the last compose.
135
100
 
136
- Paired-written, one pair per twin dispatch:
101
+ ## `ops/sync-log.md`
137
102
 
138
103
  ```
139
- S4 | gate: on-demand | dispatched: 2026-07-08T14:25Z | scope: full reconcile + compose
140
- S4 → reconciled | 2026-07-08T14:29Z | 4 edits · 2 new forks · 6 open · untouched: risks
104
+ S1 | gate: start | dispatched: 2026-07-08T14:05Z | scope: bootstrap reconcile
105
+ S1 → reconciled | 2026-07-08T14:08Z | 2 edits · 1 new fork · 2 open · untouched: risks
141
106
  ```
142
107
 
143
- The **facilitator** writes the dispatch line as it dispatches; the **twin** appends the result
144
- line (`reconciled` or `failed`) on return — **never** one author for both sides. Every dispatch
145
- line must acquire a result line; only the newest entry may be unpaired (in flight) [BS-SYNC-01].
146
- A `failed` result is surfaced to the user at the next turn break and re-run at the next gate.
108
+ The facilitator writes the first line as it dispatches; the twin appends the second on return, `reconciled` or `failed | <ts> | <reason>`. Gates: `start` · `on-demand` · `pause` · `stop`. Ids run `S1, S2, …` across the session.
147
109
 
148
- ## ops/manifest.md
149
-
150
- Created by the stop pipeline; gates the harvest apply:
110
+ ## `ops/manifest.md`
151
111
 
152
112
  ```markdown
153
113
  # Harvest manifest — {topic}
154
114
 
155
115
  Round: 1
156
- Status: proposed | approved | applied
116
+ Status: proposed
157
117
 
158
118
  | # | What | Source | Destination | Action |
159
119
  |---|------|--------|-------------|--------|
160
- | 1 | consolidated source of truth | thesis + fragments + ledger | docs/features/{x}.md | create |
161
- | 2 | parked fork F7 | forks.md | docs/architecture/open-questions.md | append |
120
+ | 1 | consolidated source of truth | thesis + ledger | docs/features/widget-cache.md | create |
121
+ | 3 | parked fork F2 | forks.md | docs/architecture/open-questions.md | append |
162
122
 
163
123
  ## Uselessness test
164
124
 
165
- - Result: pass | fail
166
- - Cold-reader allowed paths: <the destination docs above>
167
- - Gaps: none | <named gaps → next Round>
125
+ - Result: pass
126
+ - Cold-reader allowed paths: docs/features/widget-cache.md, docs/architecture/open-questions.md
127
+ - Gaps: none
168
128
  ```
169
129
 
170
- Every parked fork and every fragment must have a row [BS-MANIFEST-01]. `Status: approved` is set
171
- only after the user approves; gap fixes re-enter as a new `Round` with the same approval
172
- requirement. After apply, no destination doc may link into the session folder [BS-HARVEST-01];
173
- the move to history requires a recorded passing uselessness test [BS-USELESS-01].
174
-
175
- ## Detector
130
+ `Status` runs `proposed` → `approved` → `applied`. Every parked fork's id and every fragment's file name appear in a row's What or Source. Destinations are repository-relative paths. A gap round increments `Round`.
176
131
 
177
- `node scripts/detector.mjs <session-folder> [--gate=session|manifest|move] [--json]`
132
+ ## The detector
178
133
 
179
- - `session` (default) — the always-on integrity rules; run at any gate.
180
- - `manifest` — adds the convergence gates (zero open forks, full aspect coverage, fresh compose);
181
- the twin may not construct a manifest while any of these fail.
182
- - `move` — adds the post-apply gates (manifest applied, uselessness pass recorded, no links into
183
- scaffolding); the folder may not move while any fail.
134
+ `node <skill>/scripts/detector.mjs <session-folder> [--gate=session|manifest|move] [--json]` exits `0` clean, `1` with violations listed by rule id, `2` on unusable input. Gates are cumulative: `manifest` runs the session rules too, `move` runs all. A real run always prints per-rule lines and a `clean` or `failing` summary; **empty output means the detector never ran**, which is a failed gate, never a pass.
184
135
 
185
- | Exit | Meaning |
186
- | --- | --- |
187
- | `0` | clean |
188
- | `1` | violations, listed with rule IDs |
189
- | `2` | unusable input |
190
-
191
- A run always prints output — per-rule lines plus a `clean`/`failing` summary, or a usage/error
192
- message. **Exit 0 with empty output means the detector never executed** — a failure, **never** a
193
- pass. Rules degrade gracefully: with no git context, `BS-OPS-02` reports `skipped` and never blocks.
194
- Rule IDs are stable — the twin, the evals, and the maintenance census key on them.
136
+ | Rule | Gate | Fails when |
137
+ | --- | --- | --- |
138
+ | `BS-STATE-01` | session | `state.md` missing, or a field absent or invalid |
139
+ | `BS-STATE-02` | session | no `## Aspect map`, or no parseable aspect |
140
+ | `BS-ASPECT-01` | session | an aspect ref names no such fork, decision or fragment |
141
+ | `BS-THESIS-01` | session | the thesis lacks its stamp or a mandated section |
142
+ | `BS-COMPOSE-01` | session | the thesis stamp differs from `Last compose` |
143
+ | `BS-FORK-01` | session | duplicate fork id, no `Closes when:`, or a park without destination |
144
+ | `BS-FORK-02` | session | a decision resolves a fork still open |
145
+ | `BS-LEDGER-01` | session | duplicate decision id, or Decision, Why or How to apply empty |
146
+ | `BS-OPS-01` | session | `ops/.gitignore` missing or not `*` |
147
+ | `BS-OPS-02` | session | any `ops/` file tracked by git (skipped outside git) |
148
+ | `BS-SYNC-01` | session | a dispatch other than the newest has no result line |
149
+ | `BS-SYNC-02` | session | a `twin (S<n>)` attribution cites a sync that never reconciled |
150
+ | `BS-ASPECT-02` | manifest | an aspect has no content (`none yet`) |
151
+ | `BS-COMPOSE-02` | manifest | the newest capture entry is newer than the last compose |
152
+ | `BS-FORK-03` | manifest | any fork is open |
153
+ | `BS-MANIFEST-01` | manifest | a parked fork or a fragment has no manifest row |
154
+ | `BS-HARVEST-01` | move | a destination is missing, or links into the session folder |
155
+ | `BS-USELESS-01` | move | no passing uselessness test with `Gaps: none`, or the manifest is not `applied` |
156
+
157
+ When you relay a finding, name the rule id and what it means for the user, in plain words: "the last compose predates the newest capture (`BS-COMPOSE-02`), so the twin syncs before the manifest".
@@ -28,8 +28,9 @@ as a failed gate and report it, never as a pass.
28
28
  ## The write protocol you enforce
29
29
 
30
30
  One writer per file. You write `state.md`, `thesis.md`, `forks.md`, `ledger.md`, `fragments/`,
31
- manifest, and your own sync-log **result** lines. You never write `ops/capture.md` (the
32
- facilitator's) or sync-log dispatch lines. The user may hand-edit anything: before rewriting any
31
+ manifest, and your own sync-log **result** lines. You never write the facilitator's files — the
32
+ folder, `ops/` and `ops/.gitignore` at bootstrap, `basis/` at intake, `ops/capture.md` — or
33
+ sync-log dispatch lines. The user may hand-edit anything: before rewriting any
33
34
  file, read its current state in full and treat content you did not write as **first-class user
34
35
  signal — fold it forward, never clobber it**. A hand-edit that contradicts the ledger is a design
35
36
  question: file a fork, don't "fix" the file.
@@ -116,13 +117,16 @@ Stop is facilitator-orchestrated because approval belongs to the user; you execu
116
117
  what applied and stop — the folder stays visibly unfinished and the user restarts; never
117
118
  resume silently from a half-applied state.
118
119
  3. **Uselessness test.** Spawn a **fresh, context-free cold reader** — an independent subagent
119
- that inherits none of this session's context — whose prompt contains only the allowed-path list
120
+ on the standard tier (`model: sonnet`, named on the dispatch so it never inherits yours) that
121
+ inherits none of this session's context — whose prompt contains only the allowed-path list
120
122
  (the manifest's destinations — never the session folder) and the instruction to reconstruct the
121
123
  design: thesis, commitments, reasoning, declined branches. Grade its reconstruction against the
122
124
  ledger and thesis. Gaps → record them in the manifest (`Result: fail`, named gaps), and the fixes
123
125
  re-enter as a new manifest `Round` requiring fresh approval. Pass → record it.
124
- 4. **Move.** Run `--gate=move`. When clean: delete `ops/` entirely, `git mv` the folder to
125
- `docs/history/brainstorms/{topic}/`, set state `Status: harvested` (no index row to move: the folder is
126
+ 4. **Move.** Run `--gate=move`. When clean: delete `ops/` entirely, then move the folder to
127
+ `docs/history/brainstorms/{topic}/`: `git mv` when `git ls-files <folder>` lists anything,
128
+ plain `mv` when it lists nothing — `git mv` refuses a folder git has never tracked, and a
129
+ session is often never committed before its stop. Then set state `Status: harvested` (no index row to move: the folder is
126
130
  the record). End your
127
131
  report with the offer the facilitator relays: **delete the moved folder, or commit it** — the
128
132
  user decides; the design assumes deletion.