diff --git a/docs/workpad/reports/dirigent/2026-10-01-lean-process-report.md b/docs/workpad/reports/dirigent/2026-10-01-lean-process-report.md new file mode 100644 index 0000000..f1730f1 --- /dev/null +++ b/docs/workpad/reports/dirigent/2026-10-01-lean-process-report.md @@ -0,0 +1,482 @@ +# Lean process experiment, 2026-10-01: report + +Date: 2026-10-01. Author: Opus 5.5 (`claude-opus-5-5`), read-only analysis, no source changes. + +This report compares two ways of running implementation work that were both used on 2026-10-01: +- the **baseline**: the step-by-step flow used for the subagent linkage fix (tasks T1–T9); +- the **lean run**: the "lean process" experiment, used for the live message history work (H0–H3). + +Sources: +- the Igor session journal `docs/workpad/journals/2026-10-01-11-bugfixing-on-main.md`; +- the linkage plan `plans/2026-10-01-subagent-linkage-reload.md` and its three review reports (`reports/2026-10-01-13-…`, `-17-…`, `-20-…`); +- the two lean plans, the plan comparison `reports/2026-10-01-24-lean-plan-comparison.md`, the run log `reports/2026-10-01-live-history-run.md`, the athanor end review `reports/2026-10-01-live-history-review.md` and the independent review `reports/2026-10-01-live-history-independent-review.md`; +- `git log` commit times (CEST, +0200) and diff stats; +- the memory notes `feedback_review_by_risk`, `feedback_sonnet_first_draft` and `feedback_planner_agents`. + +**A warning about time data.** The Igor journal's clock does not match real time. Its last entry says 05:05, but that commit was made at 22:21, and `date` showed 22:22 when this report was written. The gap is not a constant offset. During the linkage work, the journal's times stretch about 2.5× compared with git: the journal shows 11h55m from the T1 commit to the last T9 commit, git shows 4h42m. All wall-clock numbers in this report therefore come from git commit times, unless stated otherwise. The "~12 h baseline" figure in the journal, the run log and the memory note came from the journal clock. Git does not support it (see section 2). + +--- + +## 1. What the lean process is, and why the user wanted it + +**The baseline (step-by-step flow).** This is how the linkage work T1–T9 ran. +- Igor (the session coordinator agent) dispatched one implementer per task. Implementers were Sonnet, following the Sonnet-first-draft experiment. +- An Opus review followed every one or two tasks. +- Each review was followed by a fix round. The implementer who wrote the code made the fixes. +- Every Critical or Important finding got a fresh, scoped re-review. A scoped re-review checks only the fixes for the named findings. +- Then a last round fixed the Minor findings. +- Test suites ran in each task and in each review. +- The user made design decisions in the middle of the run, for example how archived children nest and how T8 labels runs with no recorded result. + +**The lean process.** This is how H0–H3 ran. +- One plan for the whole job. An Opus 5.5 planner wrote it, and a short comparison review checked it before execution. +- The plan was split into 6 **blocks**. A block is one implementer's share of the work, cut by crate or layer and handed on through commits. +- Each block got a **fresh implementer** (Sonnet in this run). Each implementer appended a **handoff note** to the run log: what it did, where it deviated from the plan, and what it left for later blocks. +- The only check between blocks was a **compile gate**: `cargo check` on the crates that block owned. The workspace was allowed to stay broken between blocks 1 and 5. Test suites ran only once, in block 6. +- **No review between blocks.** One end review covered the whole diff. Then came one fix pass for everything found, and one scoped re-check. After that, no further loops; remaining Minor items were logged. +- **Athanor** ran the blocks and the end review. Athanor is the spire orchestration agent ("the oven") and is pinned to Opus 4.6. + +**Why the user wanted it.** The user said one dev day for the linkage work was too slow ("a 4.6 would do it in an hour"). They want to understand over the coming months where the time goes. Their direction was: +- review less often; +- collect findings and fix critical or architectural ones first; +- do one review at the end, then one longer pass over the collected bugs; +- run fewer tests; the loop is "write code → detect bugs → write code", not a gate per task. + +The user marked this as an **experiment**, measured against the plan's estimate and against the baseline. They later corrected one point: "longer implementation before review" does not mean one implementer, because Sonnet implementers ran out of context on long passes (500k–750k tokens). So the plan switched to several fresh implementers in sequence. + +--- + +## 2. Timeline and measurements + +Legend: **measured** = from git commit times or the run log's token counters. **Journal** = taken from the journal's agent-duration remarks, which are plausible for single agents but not clock-checked. **Est.** = my estimate. + +### 2.1 Lean run (H0–H3) + +| Phase | What happened | Wall clock | Tokens | Source | +|---|---|---|---|---| +| Plan A | Athanor (Opus 4.6) wrote a blind lean plan. | agent ~3 min; committed 18:51 | not recorded | journal; git | +| Plan B | Opus 5.5 wrote a blind lean plan, without reading plan A. | ~9 min (18:51→19:00); agent ~6.5 min | not recorded | git; journal | +| Plan comparison | Opus compared A and B against the code. | ~6 min (19:00→19:06) | not recorded | git | +| Plan amendment | Opus folded the comparison's blockers into plan B and cut it into 6 blocks. | ~4 min (19:06→19:10) | not recorded | git | +| Block 1 | Protocol + core: the event sequence number (`seq`), the `ListMessages` reply channel, deletion of the `MessagesListed` event, and the H0 repro test. | 12 min | 186k | measured | +| Block 2 | Archive format: the `revision` field, the revision fold on read, a new fixture. | 13 min | 207k | measured | +| Block 3 | Accumulator: keeping messages after writing them, and the `LiveHistory` read interface. | 11 min | 221k | measured | +| Block 4 | Event handler: one `persist` helper for all write paths, exclusion of archiving-off sessions, seq handling. | 22 min | 344k | measured | +| Block 5 | API + web + server: the merged history read, the SSE `id:` field, reply wiring. | 22 min | 318k | measured | +| Block 6 | Docs, the first full test run (5,793 passed), 2 fallout fixes. | 36 min | 243k | measured | +| **Implementation subtotal** | | **1h56m** | **1,519k** | measured | +| Athanor end review | One review inside athanor, model unverified. Verdict: pass, zero findings. | 14 min | 156k | measured | +| Independent review | Igor dispatched a fresh Opus 5.5 review. Verdict: not ready; 6 Important, 11 Minor. | ~20 min (21:22→21:42) | not recorded | git | +| Fix pass | One Opus 5.5 implementer fixed I1–I6 and 9 of 11 Minor items. | 33 min (21:42→22:14) | ~300k (context counter) | measured | +| Scoped re-check | A fresh Opus 5.5 reviewer checked the fixes: I1–I6 fixed, 4 Minor left open (R1–R4). | ~7 min (22:14→22:21) | not recorded | git | +| **Execution total** | From the amended plan to the closed re-check. | **3h11m** (19:10→22:21) | ≥2.0M recorded | measured | +| **Total incl. planning** | From the plan A dispatch (after 18:34) to the re-check. | **≤3h47m** | — | measured (upper bound) | + +Two corrections to the run log: +- The block headers in the run log were written by the implementers themselves. Some contradict git: block 3 claims "19:47–20:25 (0:38)", but git shows 11 min. The run log's summary table is the one that matches git, and this report uses it. +- The run log's "Fix pass: 0 min, not needed (clean review)" and "Total 2h10m" describe the state before the independent review. The real execution total is 3h11m. + +**Against the estimates.** + +| Yardstick | Value | Lean actual | +|---|---|---| +| Plan A's estimate | 5–8 agent-h | — | +| Plan B's estimate | 5–7 h + 1–1.5 h review | — | +| Comparison reviewer's estimate (the one the run measured against) | 8–10 h + review | 3h11m execution, 1h56m implementation | +| Changed lines (plan B's estimate) | 1,200–1,600 | first pass +3,574 / −963 (76 files; +2,584 in `.rs`); fix pass +1,417 / −553 | + +The plan estimates are in human-style hours. Both the baseline and the lean run beat them by a wide margin, so the estimates are a poor yardstick for the process itself. They show only that agent work runs faster than planners assume. + +### 2.2 Baseline (subagent linkage, T1, T2, T5–T9) + +T3 was not a separate task, and T4 (late tool updates kept as revisions) was folded into the live-history work, where it became H0. The commits run from 94acb9da to 4c82d936. + +| Phase | Commits (time) | Reviews | Notes | +|---|---|---|---| +| Research, plan, user decisions | before 13:35 | — | Not in git. Est. 0.5–1 h. WASM hang-prevention work ran in parallel. | +| T1 + T2 | T1 13:35, T2 13:58; fixes 14:20, 14:42 | 1 review + 1 scoped re-review | 2 fix rounds. | +| T5 + T6 | T5 14:44, T6 14:52; fixes 15:25, 15:28, 15:33, 15:48 | 1 review + 1 scoped re-review | 4 fix commits (T5 fixes, T5 test, T6 M1, T5 minors). | +| T7 | 16:05 | none | Tests and a manual checklist only; low risk. | +| T8 + T9 | T8 16:14, T9 16:47; fixes 17:19, 17:31, 17:49, 18:17 | 1 review + 2 scoped re-reviews | An OAuth expiry killed the T9 implementer mid-task. The first T9 fix introduced a new Important finding. | +| **Total** | 13:35 → 18:17 = **4h42m measured**; **~5–5.7 h** with planning (est.) | **7 reviews** (3 full + 4 scoped) | **10 fix commits** after 7 first-draft commits. User decision waits are included. | + +Size: the first drafts added +3,483 lines and the fix rounds +3,439. The fix rounds rewrote about as much code as the first drafts wrote. Baseline tokens were not recorded. The memory note says Sonnet implementers reached 500k–750k tokens per task context. + +**The baseline figure corrected.** The "~12 agent-h for 7 tasks" baseline comes from the journal clock. Git shows about 4h42m for implementation, reviews and fixes, plus an estimated 0.5–1 h before the first commit. Some agents ran in parallel (a re-review next to an implementer, WASM work next to T1/T2). So agent-hours somewhat exceed wall clock, but not by a factor of 2.5. A fair statement is **about 5–6 h** for the baseline. + +### 2.3 Comparison in one table + +| | Baseline (linkage) | Lean (H0–H3) | +|---|---|---| +| Wall clock, plan to done | ~5–5.7 h (4h42m measured + est. planning) | ≤3h47m measured | +| Wall clock, implementation to done | 4h42m | 3h11m | +| First-draft lines | +3,483 | +3,574 | +| Fix lines | +3,439 (10 commits) | +1,417 (1 commit) | +| Reviews | 7 | 2 + 1 re-check (one of the 2 was void) | +| Test-suite runs | every task and every review | block 6, the independent review, the fix pass, the re-check | + +**Measured effect.** The lean run was about **35–40% faster** in wall clock for a similar first-draft size. It also produced far less fix churn. The "2h10m vs ~12 h" (5×) figure reported at 21:22 is wrong on both sides: the lean total missed the fix loop, and the baseline was taken from the drifting clock. + +--- + +## 3. Quality + +### 3.1 Findings by phase (lean run) + +| Phase | Critical | Important | Minor | Notes | +|---|---|---|---|---| +| Plan comparison (before code) | — | 4 blockers in plan B | 3 items taken from plan A | Plan A had 5 design errors that would have shown up as review findings. The worst would have broken archive compatibility (§4.3). | +| Block 6 test run | — | — | 2 fallout fixes | A count assertion based on a wrong plan instruction, and a stale constant left after the `MessagesListed` deletion. Both were real signals, found by the one test run. | +| Athanor end review | 0 | 0 | 0 | Verdict "Pass". It worked through the plan comparison's 7-item risk checklist and added nothing beyond it. | +| Independent review (Opus 5.5) | 0 | **6** | **11** | "Not ready as is." None of the 6 Important items was caught by any test suite. | +| Fix pass | — | 6 fixed | 9 fixed, 2 documented, 1 dropped | M8 (memory bounds) and M9 (queued-backend gap) were documented. M10 (child sessions at replay start) was dropped with a note. | +| Scoped re-check | 0 | 0 | 4 open (R1–R4) | R2 is new, introduced by the I6 fix. | + +**The six Important findings, one sentence each:** +- **I1.** Re-attaching a session while a turn is running (`SessionReplayStarted`) wrote and released the half-streamed message. The rest of the answer was then dropped from the archive. This is archive data loss, reachable through external ACP clients such as Zed. +- **I2.** A stale write that failed, or was already claimed, retried every second without end, and each attempt bumped the write epoch. That made every read of the session do 4 full archive reads. +- **I3.** Gateway sessions (archiving off) lost their full history in the new read path, because the connector's own history was only asked when archive and live were both empty. +- **I4.** Opening a large session did two full merged reads, each with a paged drain that is roughly O(N²/200) record parses. That doubled the cost of opening a tab, or worse. +- **I5.** Stats recomputation (the startup backfill and the importer's recompute) reads raw logs, so it would count revision lines as extra messages and double-count their tokens. +- **I6.** Archiving-off sessions brought the H0 bug back in the live view: a late tool update after the stale sweep showed a partial message in place of the full one. + +**The athanor end review's zero findings were refuted.** Two of the six misses sat inside its own checklist: +- I5 falls under checklist item 5 (stats and count deltas). The reviewer checked the backend counters but not the other consumers of the raw read. +- I1 falls under item 3. The reviewer wrote that the replay-start release "collects all retained message ids". In fact the code collected *all* message ids, including unwritten streaming ones. Block 4's handoff note had flagged exactly this ("a broader sweep than the plan's wording. Flagged for the block 6 review"), and the review still passed it. + +The review read like a confirmation of the checklist, not a search for bugs: "No additional findings beyond the checklist items." Its model is unknown (§4.2). The independent review did not read the end review first, ran the gates itself, and traced concrete scenarios. It found all six in about 20 minutes. + +### 3.2 Where the bugs clustered + +- **The mechanical parts were clean.** No review found a bug in block 1's protocol changes, in the `MessageRecord` field sweep across 93 literals, or in the SSE `id:` plumbing (M1, about `lastEventId`, is a comment error and an H4 trap, not a bug today). The block 2 sweep script made one mistake (it inserted a field into a nested literal). The implementer caught it with the compiler in the same block. +- **All six Important findings sat in the complex parts:** retention and release semantics (I1, I2, I6, in blocks 3–4), the read core's precedence and cost (I3, I4, block 5), and stats consumers outside the plan's file list (I5, a ripple that block 2 did not cover). +- **Not all of them were Sonnet drafting errors.** My attribution, from the review text and the plan: + - **Implementation choices that the handoff notes flagged, and nobody adjudicated:** I1 (block 4 made the release broader than the plan) and I2 (block 4 chose its own failure semantics). + - **Plan-level gaps that the implementers carried out faithfully:** I3 (decision 7's "fallback only when empty"), I4 (the plan accepted "a full parse per count" without the page-drain multiplier), I5 (the plan did not list the raw-read stats consumers) and I6 (decision 8's "excluded → memory at the stale sweep"). + + So the user's conclusion that Sonnet is weak at complex work is supported by *where* the bugs were. But about four of the six would probably have survived an Opus implementer that followed the plan literally. Those four needed a stronger plan or a real end review. +- **The fix pass made the usual fix-induced mistake.** R2 is a narrow new bug from the I6 fix. The baseline had the same pattern, and worse: T9's first fix round produced a new **Important** finding (T9 R1). + +### 3.3 What the baseline caught per round + +| Round | Important | Minor | Outcome | +|---|---|---|---| +| T1+T2 review | 3 (I1 navigator flooded by archived children; I2 grandchildren never listed; I3 slow sequential snapshot reads that look like "no children") | 8 | One fix round, then a scoped re-review: approved, with 4 Minor (R1–R4) fixed in a last round. | +| T5+T6 review | 2 (I1 click on an `Available` subagent loads a synthetic id; I2 dozens of children expanded by default) | 10 | Fixes, then a scoped re-review: approved, with 3 Minor (N1–N3) plus M3 fixed in a last round. | +| T8+T9 review | 2 (I1 stale "running" status forever after a crash; I2 T8 could label a failed run "completed") | 7 | Fix, then scoped re-review 1: a **new Important** (R1, a stale "bg" chip after a manual Reconnect) and 4 Minor. Fix 2, then scoped re-review 2: approved, with 3 Minor (N1–N3) fixed in a last round. | +| **Total** | **8** (7 first-pass + 1 fix-induced) | **~42** | All fixed or dropped. Approved and fit for install at the end. | + +The baseline found more Important items per line of code than the lean end loop (8 vs 6). But its findings were mostly UI behaviour and degraded paths. None was archive data loss. The lean run's I1 was a data-loss bug in a hotspot (the archive write path) that a per-block review of block 4 would very likely have caught, because the handoff note named it. + +### 3.4 Residual open items (lean run) + +- **R1.** A `Load` re-attach still cuts a running turn's message if it was *already written* (for example, a tool pending for more than 300 s). This is a deliberate trade-off, but it is undocumented. +- **R2.** New, from the I6 fix: after archiving is turned back on, a `Load` replay can drop messages that are still held in `MemoryHistory`. They are then never written to the archive. Nothing is deleted, but content that should be archived is skipped, which touches the "archive keeps all data" rule. +- **R3.** A message abandoned after an hour of failed writes also disappears from the live view. The only trace is an `error!` log line. +- **R4.** A message parked while its session was excluded can move to memory without being written, after archiving is turned on. +- **Still open from the run log:** the `archived_messages` set grows without bound (pre-existing); `as_of_seq` is not used until H4. +- **Not yet measured:** the experiment's third criterion, bugs found in user testing. + +--- + +## 4. Confounders + +### 4.1 Sonnet vs Opus implementers (that experiment has now ended) + +- All six lean blocks were drafted by Sonnet. The fix pass was Opus 5.5. The baseline's first drafts and fix rounds were also Sonnet, with Opus reviews. +- The user ended the Sonnet-first-draft experiment after the independent review. The new rule: complex or design-heavy work goes to Opus 5.5, mechanical work to Sonnet. +- Because of this, the lean run cannot separate "lean process" from "Sonnet on hotspots". One Opus fix pass (33 min) cleared 6 Important items. Ten Sonnet fix commits were needed in the baseline. That points to the implementer model as a large part of the baseline's fix churn. + +### 4.2 The end reviewer's model cannot be verified + +- Athanor is pinned to Opus 4.6. The user ordered reviews on Opus 5.5, and Igor told athanor to pass `model: "opus"` explicitly. +- From inside the 4.6-pinned athanor, how the `opus` alias resolves cannot be verified. The review's header says only "Reviewer: Opus". +- So the zero-finding result is either a 4.6 review or a weak, checklist-bound 5.5 review. Either way, it does not count as a valid "one strong end review". The real datum is the independent review, which identified itself as `claude-opus-5-5`. + +### 4.3 Plan quality (4.6 vs 5.5) + +The blind comparison showed the plans were not of equal quality. +- **Plan A (4.6)** misidentified the H0 root cause. It folded revisions in the shared line reader, so the migrator and replace would have **collapsed lines on disk**. That is a silent break of the archive backward-compatibility rule. It also wrote archiving-off sessions, used a non-atomic watermark, never sent `seq` to the browser, and would have made new ACP sessions show errors and stall backfill for 30 s. +- **Plan B (5.5)** traced the cause in code and held up against the code. It still had 4 blockers, which were fixed before execution. +- The lean run executed an amended plan B, so its plan had effectively been reviewed once already. The baseline plan was written by Opus (version not recorded) after research, and was amended mid-run with user decisions and review scope additions. The lean run's plan advantage is real and helps its result. + +### 4.4 Different tasks + +- First-draft size was similar (about +3.5k lines each), but the work was different. +- The **linkage** work was mostly listing logic and web UI: navigator nesting, chips, refresh races. It needed user decisions in the middle of the run, and the user's wait time is part of its wall clock. +- **H0–H3** was archivist core: retention, concurrency, archive format and the read path. It is harder per line, and all its decisions were made before the run. +- The baseline also lost time to an OAuth expiry that killed the T9 implementer. + +### 4.5 Measurement quality + +- The journal clock drifted (see the warning at the top). The baseline figure that was first reported came from it. +- Tokens were recorded for the lean blocks, the end review and the fix pass only. The plans, the comparison, the independent review, the re-check and the whole baseline have no token figures. A token comparison is not possible. + +--- + +## 5. Lessons and recommendation + +### 5.1 Keep + +- **Blocks with fresh implementers and handoff notes.** No implementer ran out of context: the largest block used 344k tokens, against 500k–750k for baseline Sonnet tasks. The handoff notes were accurate and specific. They named the I1 deviation and the I4 cost before any reviewer did. +- **Compile-only gates between blocks, and one full test run at the end.** Block 6's single test run found both real fallout problems and took 36 min including docs. No per-task test churn. +- **A plan by Opus 5.5, checked by a short adversarial comparison before execution.** It took about 10 min and caught a would-be archive-compat break plus 4 blockers. This is the cheapest quality gate of the day. +- **One fix pass over all collected findings, then one fresh scoped re-check, then stop.** The 33-min Opus pass replaced what took the baseline 10 commits across 3 review cycles. + +### 5.2 Change + +1. **The end review must be a verified Opus 5.5 role, outside athanor's pin.** Igor dispatches it directly with `model: "opus"`, or uses a role agent pinned by full model id. The reviewer stamps the exact model id in the report header. A review without a stamped id does not count. +2. **The end review is adversarial, not checklist-only.** The risk checklist is the minimum, not the scope. The reviewer runs the gates and traces concrete scenarios. **It must answer every deviation and every "flagged for review" line in the handoff notes, one by one.** That rule alone would have caught I1. +3. **Implementer model by block nature.** Hotspot blocks (state, retention, concurrency, archive format, event handling, read-path precedence) go to Opus 5.5. Mechanical blocks (field sweeps, enum deletions, wiring, docs, test scaffolding) go to Sonnet. In this run, that means blocks 3, 4 and 5 on Opus, and blocks 1, 2 and 6 on Sonnet. +4. **Plans list every consumer of a changed semantic, not only the files that change.** I5 (stats consumers of the raw read) and I3 (who answers an excluded session's history) were ripple misses. The plan comparison should check this explicitly. +5. **For a hotspot plan, one mid-run review is allowed.** When a hotspot block on the archive write path finishes (block 4 here), a short scoped review of that block alone is worth it if the handoff note flags a deviation. This is the only exception to "no review between blocks". +6. **Measure with git and record tokens for every agent**, including plans and reviews. Report totals only after the last loop has closed. + +### 5.3 Proposed default process + +1. **Research** (Opus 5.5) when the root cause is unknown. Ask the user for decisions **before** the run, not during it. +2. **Plan** (Opus 5.5), cut into blocks of about 10–40 min of agent work. Each block has an owner model (Opus 5.5 for complex, Sonnet for mechanical), a compile gate and a list of expected-broken crates. +3. **Plan review** (Opus 5.5, about 5–10 min, adversarial against the code), then amend. *Conditional, see addendum A.1: needed when the plan was written by another model or method, or against older code. A plan written by Opus 5.5 against the current code skips it and gets a drift check instead.* +4. **Execution** (athanor may orchestrate): fresh implementer per block, compile gate only, handoff note, commit. Exception: an optional scoped review after a hotspot block whose handoff note flags a deviation. +5. **One full test run** in the last block, with the fallout fixed there. +6. **End review** (verified Opus 5.5, dispatched by Igor, adversarial, model id stamped). It answers every handoff flag and runs the gates. +7. **One fix pass** (Opus 5.5 for Important items; Minor items in the same pass). +8. **One fresh scoped re-check** (Opus 5.5). Remaining Minor items are logged as open follow-ups. No further loop unless the re-check finds a Critical or Important item. + +The memory note `feedback_review_by_risk` still marks the lean rules as an experiment. On today's evidence, the lean rules should become the default **with changes 1–3 above**. The final decision stays with the user, after the user-testing results for H0–H3 are in. + +### 5.4 Open remark owned by the user + +The user noted that spire needs **guard rails for pinned models**: +- pin role agents such as the reviewer and planner by full model id (for example `claude-opus-5-5`) instead of per-call aliases; +- no model aliases in athanor briefs; +- reviewers stamp the exact model id in report headers; +- update the model-tiers reference. + +This belongs to the user or a spire session (the reliquary repo), not to dirigent. Until it lands, change 1 above is the workaround: Igor dispatches the end review itself. + +--- + +## Addendum (2026-10-02): refinements from the stdio rework plan + +Author: Opus 5.5 (`claude-opus-5-5`). Source: the planning of `plans/2026-10-02-12-acp-stdio-transport-rework.md` (bugs_013), which was made lean in two steps: first from the user's direction ("avoid too many test runs, avoid too many review gates, write tests first"), before this report had been read; then aligned with this report after it was pulled. The points below are decisions from that plan that this report does not contain, or contains in a narrower form. None of them is measured yet; the stdio run will be the first data point. + +### A.1 The plan review is conditional + +Section 5.3 step 3 makes an adversarial plan review a default step. When the stdio plan was first aligned with this report, the step was copied in as is. The user removed it again, and the reasoning holds: the review earned its keep on 2026-10-01 because of how those plans were made, not because every plan needs one. + +A plan review is worth its ~10 minutes when **any** of these holds: +- **another model wrote the plan** (plan A by 4.6 misread the root cause, §4.3); +- **another method**: a blind plan, a plan from a template, or one written without tracing the code; +- **the plan is older than the code it targets**: commits landed in the touched area between planning and execution. + +It is redundant when the plan was written by Opus 5.5 in the same session, after research that traced the code paths the plan changes. Its two useful by-products move elsewhere: +- **Drift check instead of review.** The plan records its **plan-base commit**, and its line references are "as of" that commit. Before execution, and after every pull, the coordinator runs `git diff --stat HEAD -- `. Only touched paths get a closer look. On 2026-10-02, a pull of 38 commits left the stdio files untouched, but the check found that the linkage work had added subagent cleanup to every connection-loss path, which the plan's panic-supervision block must reuse. That took about 5 minutes and amended one block. +- **Consumer list without a reviewer.** Change 4 (list every consumer of a changed semantic) stays. The plan seeds the list, each block greps the consumers of its own change and notes any new ones in its handoff note, and the end review checks the list. + +### A.2 Tests first, and a repro block that must fail + +Section 5.3 moves all test suites to the end but says nothing about writing tests first. The stdio plan makes red-before-green binding wherever a block allows it: +- the block writes its tests, runs **only those**, and quotes the expected failure in its handoff note before implementing; +- for a bug fix, the first block is a **reproduction test that must fail on the current code** (T2). It proves the root-cause hypothesis before any fix is written, and it becomes the fix's acceptance test. + +Running a block's own new tests is cheap and targeted. It does not conflict with "one full test run at the end", which still covers everything else. + +### A.3 Gates between blocks: compile plus the block's own tests + +This sharpens "compile gate only": +- `just check` (or `cargo check -p` on owned crates); +- plus only the tests the block wrote or changed; +- no `just check-all` (the wasm build) unless the block touches the web; +- the web tests in both configurations run only in a web block. + +### A.4 Cut blocks by expensive verification, not only by crate + +Section 5.3 cuts blocks by crate or layer. A second criterion is **what a block costs to verify**. The stdio plan merged its two web-touching tasks (tool-name fallback and diagnostics display) into one block, so the slow two-configuration web tests run once instead of twice. + +### A.5 No baseline run up front + +A full test run before starting costs a whole gate. The stdio plan skips it: a test that is red at the final gate is re-run **alone** on `main`. Red there too means pre-existing (listed in the run report); green there means a regression. That costs a handful of single-test runs only when something is red. + +### A.6 The coordinator does trivial steps inline + +A dispatched agent costs startup, context loading and a handoff. Steps with no design content (copying evidence, creating the branch, a one-line config change) are done by the coordinator directly. Only real implementation work becomes a block. + +### A.7 A shippable hotfix block first, for incident work + +When a bug hurts users now, the first implementation block is the **smallest change that stops the damage**, committed on its own so it can ship ahead of the structural fix. In the stdio plan, T1 makes the log previews safe to cut, which removes the crash; the reader/writer rework follows. The rest of the run is not delayed by it. + +### A.8 Preserve evidence as step zero + +Incident logs rotate: the installed instance keeps 100 ACP protocol logs and was already deleting one per new connection. Copying the evidence read-only (with checksums) before any work is part of step 0, not an afterthought. + +### A.9 Estimate in measured block-minutes + +Section 2.1 notes that planner estimates in human-style hours are a poor yardstick. The stdio plan was first estimated at 11–15 h, then 8–11 h, both in planner hours. Recalibrated against this report's measured blocks (11–36 min each, 1h56m implementation for ~+3.5k lines), the estimate is about 4 h (3.5–5.5 h). Plans should estimate per block in minutes, calibrated on the last measured run, and state the main uncertainties per block. + +### A.10 Proposed amendment to 5.3 + +- Step 3 becomes: **plan review only under the conditions of A.1, otherwise a drift check** against the recorded plan base (and again after every pull during the run). +- Step 4 (blocks) gains: **tests first** where possible (A.2); gates as in A.3; block cutting by verification cost (A.4); trivial steps inline (A.6); for incident work, a hotfix block first (A.7) and evidence preserved at step 0 (A.8). +- Step 5 (one full test run) gains: **no baseline run**; a red test is re-run alone on `main` (A.5). +- Plans carry a plan-base commit and per-block minute estimates (A.1, A.9). + +--- + +## Addendum 2026-10-05: process lessons from project memory + +Source: the dirigent project memory directory (`~/.claude/projects/-home-g4b-Projects-dirigent/memory/`, 17 notes plus the `MEMORY.md` index), read 2026-10-05, and the Igor journal `docs/workpad/journals/2026-10-05-12-continue-implementations.md`. Author: Opus 5.5 (`claude-opus-5-5`). Read-only synthesis; the memory files were not changed. + +**Who this is for.** Authors of the spire/reliquary plugin, who will shape the next athanor and related agents. You cannot see the memory files, so each lesson below carries its rule, the evidence behind it, and what it means for athanor. Where a memory note has dated refinements, the latest one wins, and this addendum states the latest state. + +**Terms.** +- **Igor**: the session coordinator agent. It talks to the user, keeps a session journal, and dispatches subagents (spire skill `igor`). +- **Athanor**: the spire orchestration agent, pinned to Opus 4.6, that may spawn its own subagents. Igor hands it multi-part jobs. +- **Adept**: a spire domain agent that builds up knowledge about one subsystem and answers consultations. The dirigent memory has no lessons about adepts; they are mentioned only so the reader knows they were not overlooked. +- **Block**, **handoff note**, **compile gate**: see §1 of this report. In short: a block is one fresh implementer's share of a plan (about 10–40 min of agent work); the handoff note is that implementer's short entry in the run log (what it did, where it deviated, what it left for later); the compile gate is `cargo check` on the crates the block owns, the only check between blocks. +- **Hotspot**: code where a review is likely to find Important bugs: core state, concurrency, caches, invariants, archive formats and retention, event handling, id/routing rules, read-path precedence, cross-crate semantics. +- **Critical / Important / Minor**: the reviewers' severity levels. Important means "must fix before merge"; Minor means polish or small risk. +- **Settled** below means the user stated it as a rule. **Experiment** means the user is still measuring it. + +### A.1 Process cadence and review policy + +| Rule | Status | +|---|---| +| Lean process is the default: plan → plan review → blocks with no reviews between them → one test run in the last block → one end review → one fix pass → one scoped re-check → stop. This is §5.3 with changes 1–3 of §5.2. | Settled as default 2026-10-05; the experiment's third criterion (bugs found in user testing of H0–H3) is still not measured. | +| Review by risk, not by task. One review covers spec and quality together. Hotspots get their own Opus review; small tasks share one. | Settled 2026-09-29 (taken over from another project's measured post-mortem); now applied at plan level, see tensions below. | +| Re-review only Critical/Important findings, scoped to those findings, by a **fresh** reviewer. A resumed reviewer tends to confirm its own findings. | Settled. | +| Minor findings are fixed or dropped in the same round. No carried "minors ledger". | Settled. | +| Cheap verification first: compile across feature combinations before running tests. | Settled. | +| Briefs short: task, file pointers, acceptance commands. One journal (Igor's: decisions and dispatches only); one report per run. | Settled. | +| Change process rules only at a clean cut: checkpoint the running athanor and start a fresh one on the new rules. Never patch rules into a live run. | Settled. | +| Don't turn one user remark into many new rules. | Settled. | + +**Why.** +- 2026-09-29: the stacked gates (per-task review + batch review + slice review, minors ledger, long briefs) cost much more than they caught. Another project measured this; the user brought the post-mortem over. +- 2026-10-01: even the risk-sized per-task flow was too slow for the user. The measured baseline was 4h42m (git) for 7 tasks with 7 reviews and 10 fix commits; the lean H0–H3 run took 3h11m with far less fix churn (§2). +- 2026-10-05: the user made lean the default: "we have to write plans more lean now"; superpowers-style frequent reviews "dramatically increase development time". + +**Implications for athanor.** +- The default execution mode should be the lean block loop. Per-task review cycles should be opt-in, not the default. +- The skill should state the stop rule plainly: after the scoped re-check, remaining Minor items go to a follow-up list in the run report, and the loop ends unless the re-check finds a Critical or Important item. +- Athanor should refuse mid-run rule changes from its brief's sender, or at least log them as "apply from next run". A rule change means checkpoint and restart. +- Severity drives the next step, not the task count: a fresh reviewer for Critical/Important, no re-review for Minor. + +### A.2 Implementer model by task nature + +- **Rule (settled 2026-10-01):** complex or design-heavy implementation goes to **Opus 5.5**: core state, concurrency, archive format or retention, event handling, cross-crate semantics, anything a review is likely to find Important bugs in. Mechanical implementation goes to **Sonnet**: field sweeps, renames, literal updates, wiring along a clear pattern, docs, test scaffolding. Mixed blocks are split, or go to Opus if the complex part dominates. Haiku-tier work (running tests, compiles, commits, linear summaries) stays on Haiku and is never raised to Sonnet. Plans and reviews are Opus 5.5. +- **Why:** the Sonnet-first-draft experiment (2026-09-28 to 2026-10-01) gave Sonnet every first draft, with Opus reviews and fixes. In the lean run all 6 Important findings sat in the complex parts Sonnet drafted, while the mechanical parts were clean (§3.2). Sonnet implementers also ran out of context on complex tasks (500k–750k tokens). The user ended the experiment: "Sonnet is not good for complex work." +- **Caveat from this report (§3.2):** about four of the six findings were plan gaps, not drafting errors. A stronger implementer does not replace a strong plan and a real end review. +- **Implications for athanor:** + - Every block in a plan carries an **owner model**, and athanor dispatches with that model. Athanor should not pick or change the model itself. + - Dispatch by **full model id**, not alias, once spire supports it (§5.4). Until then, each implementer **stamps its exact model id in its handoff note** (added 2026-10-05), so the run log shows what actually ran. + - Keep housekeeping (test runs, commits, summaries) on the cheapest tier. + +### A.3 Planning and the planner agent + +- **Rule (settled):** plans are written by **Opus 5.5**, not by athanor's Opus 4.6. Use a general-purpose agent type that can write files, pass it the output path, and let it write the plan itself. Do not use a read-only "Plan" agent type. +- **Why:** + - 2026-09-21: plan agents without Write/Edit returned their plans as text, and Igor had to write them to disk. The user found this wasteful and it broke "agents write their own reports". + - 2026-10-01: blind comparison on the same scope. Opus 4.6 wrote a plan in about 3 min with no root cause and no repro gate; it would have silently broken archive compatibility (§4.3). Opus 5.5 took about 6.5 min, traced the root cause in code and deleted outdated paths. User: "plans should still be written by 5.5 — it simply finds more." Plans were never the slow part. +- **Also from the report:** plans must list every consumer of a changed semantic, not just the files that change (§5.2 change 4); user decisions are collected **before** the run (§5.3 step 1). +- **Implications for athanor:** + - Athanor should not write implementation plans for code work. It receives a finished, reviewed plan. If a brief asks athanor to plan, the planner it dispatches must be pinned to the planning model, and athanor's own model must not be the default. + - Any agent whose job is to produce a document must have write tools and an explicit output path in its brief. + +### A.4 Delegation boundaries: who dispatches what + +State as of 2026-10-05 (journal entries 12:36 and 12:40): + +| Step | Who dispatches | Model | +|---|---|---| +| Research (when the root cause is unknown) | Igor | Opus 5.5 | +| Plan | Igor | Opus 5.5 | +| Plan review (adversarial, against the code) | **Igor directly** | Opus 5.5, model id stamped | +| Blocks (implementation) | **Athanor**, from an explicit lean brief written by Igor | Owner model per block | +| End review (adversarial, answers every handoff flag) | **Igor directly** | Opus 5.5, model id stamped | +| Fix pass and scoped re-check | Igor (per §5.3; not yet exercised under the new split) | Opus 5.5 | + +- **Today's correction.** At 12:36 Igor read "run it manually" as "Igor dispatches the blocks itself, no athanor". At 12:40 the user corrected this: the agreed process is athanor running the blocks, guided by an explicit lean brief. "Manually" only means Igor writes the lean rules into the brief, because athanor's skill defaults have not been adjusted yet. Igor kept athanor for the blocks also because it is the same orchestrator as the measured H0–H3 run, which keeps the comparison clean, and it keeps Igor free for the user. +- **Why the reviews sit outside athanor:** athanor is pinned to Opus 4.6, and from inside it nobody can verify which model an `opus` alias resolves to. Its H0–H3 end review passed with zero findings; an independent Opus 5.5 review found 6 Important items in about 20 min, two of them inside the checklist athanor's reviewer had worked through (§3.1, §4.2). +- **The lean brief, as written today:** fresh implementer per block; owner model per block (Opus for hotspot, Sonnet for mechanical); compile gate only; handoff note including the stamped model id; no reviews between blocks; one test run in the last block. +- **Implications for athanor:** + - Build the lean brief's contents into athanor's skill as its default "implementation run" mode, so Igor no longer has to restate them. That is the stated reason the brief is explicit today. + - Athanor's job ends at "blocks done, tests run once, run log complete". It should not run its own end review unless the reviewer can be pinned by full model id and stamps it. A review without a stamped id does not count (§5.2 change 1). + - The run log should end with a list of every deviation and "flagged for review" line from the handoff notes, so the end reviewer can answer each one (§5.2 change 2). + - **Background grandchildren** (settled 2026-09-29): when athanor's subagents run in the background, their completion reports go to Igor, not to athanor, and athanor stalls waiting. Sequential steps must run in the foreground inside athanor. If an athanor stalls, Igor checks the agent list and feeds it the result. This is a harness behaviour athanor should be designed around. + - **Fix rounds:** the review-by-risk note says fix rounds resume the implementer who wrote the code, and an implementer is never carried across tasks. See the tensions section for how this conflicts with §5.3. + +### A.5 Implementer context and block size + +- **Rule (settled 2026-10-01):** "longer implementation before review" does not mean one long-running implementer. Use several implementers in sequence, a fresh one per block, handing off through commits and a short handoff note. +- **Why:** Sonnet implementers on long passes reached 500k–750k tokens of context. In the lean run, with blocks of 11–36 min, the largest block used 344k tokens and none ran out (§2.1, §5.1). The handoff notes were accurate and named two of the later Important findings before any reviewer did. +- **Sizing:** the memory note says blocks of "~2–3 h of work"; this report's §5.3 says 10–40 min of agent work. The measured blocks were 11–36 min. The 2–3 h figure is probably in human-style hours, which planners overestimate (§2.1, "Against the estimates"). Treat the measured range as the guide. +- **Implications for athanor:** + - Never carry an implementer from one block to the next. Fresh context per block is a design rule, not a tuning knob. + - Record tokens per block in the run log. If a block goes well past ~350k tokens, that is a signal to split it in the next plan. + - The handoff note format should be fixed by the skill: done / deviations from plan / flagged for review / left for later blocks / expected-broken crates / model id / start and end time from `date`. + +### A.6 Workspace and git + +- **Rule (settled 2026-09-29):** work in the single main checkout. For code runs, switch that checkout to the feature branch. Igor owns the branch state. No worktrees, even though the Igor skill suggests them for code runs; this project overrides that. +- **Why:** each worktree builds its own cargo `target/` (111 GB and 83 GB for two runs), on a `/home` already 88% full. The plan header even said "no worktrees", and Igor's brief overrode it. User: "this is why originally the idea was to work on one env, and no worktrees, and branch being your responsibility." +- **Consequences:** workpad commits made while a feature branch is checked out land on that branch. Agents stage only their own paths (`git add `, `git commit -- `), because other agents may be committing concurrently. +- **Implications for athanor:** + - Worktree isolation must be a per-project choice, with "off" as a valid and common setting. A brief that names a checkout and branch must win over any skill default. + - Athanor and its implementers never switch branches; they verify they are on the branch the brief names and stop if not. + - Every commit in a run stages explicit paths only. No `git add -A`. + +### A.7 Measurement + +- **Rule (settled 2026-10-01):** journal timestamps come from `date` at the time of writing, never estimated or incremented by feel. Every duration claim comes from git commit times or measured run logs. Record tokens for every agent, including plans and reviews. Report totals only after the last loop has closed (§5.2 change 6). +- **Why:** the 2026-10-01 journal's invented stamps drifted about 2.5× (last entry said 05:05, the real time was 22:20). A "~12 agent-h baseline" taken from them was repeated to the user; git showed about 4h42m. It inflated the lean speedup from about 35–40% to an apparent 5×. Implementers' self-written block times in the run log also contradicted git (§2.1). +- **Implications for athanor:** + - Athanor and its implementers read the clock with `date` for every timestamp they write, and athanor's run summary takes durations from git commit times. + - The run report has a fixed table: block, owner model (stamped id), start/end from `date` or git, tokens, commit hash. + - A run total is labelled "provisional" until the end review, fix pass and re-check are closed. + +### A.8 User interaction rules + +| Rule | Why (date) | Implication for athanor / Igor | +|---|---|---| +| **No midway gates for the user.** Don't block runs on smoke tests or item-by-item test results; assume untested parts work and collect them into a final test pass near feature completion. Don't re-ask about known bugs or present them as decisions. Plan reconciliations and between-task reviews are done by agents, not the user. Only stop where the user explicitly asked for a stop. (Settled.) | 2026-09-25 the user was annoyed by repeated gate questions after a smoke run. 2026-09-29, after Igor offered a manual plan check: "Why do I yet again need to check so much stuff manually?" | Athanor never pauses for user confirmation mid-run. Minor decisions get the recommended default, stated in the run log. Untested items go into a "final test pass" list in the report. | +| **Decisions before the run.** Open design decisions are put to the user before execution starts. (§5.3 step 1; consistent with the memory.) | The baseline lost wall-clock time waiting for mid-run user decisions (§4.4). | The brief lists decisions already made. A block that hits an undecided question picks the conservative default, flags it in the handoff note, and continues. | +| **Plain sentence per item.** Every ID or terse label in a user-facing report (roadmap IDs, finding codes like I1/R2, step names) gets a plain sentence saying what it is and why it matters. Explain jargon on first use. (Settled.) | 2026-09-26: "additional to cryptic summaries, also add a human readable sentence of what it is or does." | Put this in every report brief athanor writes or forwards, including reviewer briefs. Findings tables need a plain-language column. | +| **No external writes.** Agents never file issues, PRs or comments on foreign or upstream projects. Upstream requests become a drafted report in the workpad; the user files them. (Settled.) | 2026-09-23: the user wants every external interaction to be a deliberate user action. | State this in every brief that could touch upstream. A plan step "file upstream request" is rewritten as "draft report at path X". | +| **Start obvious research at once.** If an Igor session topic is itself a status question, start the read-only research with the greeting instead of offering it. Still ask before implementation or changes. (Settled.) | 2026-09-28: "i expected you to already have started that by now." The skill's "don't start work from topic alone" rule was read too literally. | Igor-skill change: read-only research that answers the topic's question is exempt from "don't start from topic alone". | +| **Sequential dispatch.** Implementers run one at a time, never in parallel batches, unless the user says to parallelize. (Settled 2026-09-19, but see tensions.) | The user wanted to review each result before the next started. | Blocks run strictly in sequence; this also fits shared-checkout builds (A.6, A.9). | + +### A.9 Environment hazards that affect orchestrated runs + +From the project memory: +- **Disk:** worktrees each build a ~80–110 GB cargo target on a nearly full `/home` (A.6). +- **Non-interactive PATH:** on the user's host, `node`/`npx` exist only in interactive zsh (managed by fnm). Agents' shells find no node. The fix is to put `~/.local/share/fnm/aliases/default/bin` on `PATH`; calling `npx` by full path is not enough because its shebang uses `/usr/bin/env node`. Lesson for athanor: briefs for tasks that start external tools should name the tool path or `PATH` addition; do not assume the user's interactive shell environment. +- **Auth expiry:** an OAuth expiry killed one baseline implementer mid-task (§2.2). Athanor should detect a dead implementer and re-dispatch a fresh one from the last commit and handoff note, not resume blindly. + +Not in the project memory, but recorded in the user's global instructions for this host (included because they directly affect orchestrated test runs): `/tmp` is a small RAM disk shared by all sessions, so test runs set `TMPDIR` to a disk path outside any git checkout; possibly non-terminating runs go under a memory cap, because an out-of-memory kill takes down the whole terminal pane including the coordinating session; and no background build or watch loops may be left running, because parallel builds added heavy write load. An orchestrator that runs test gates should take these as configurable per-host rules. + +### A.10 Conflicts and tensions + +These are left open on purpose. The user or the spire authors should resolve them. + +1. **"One at a time, review between each" vs lean.** The 2026-09-19 note (and its index line) still says: dispatch one implementer, review the diff, report to the user, then dispatch the next. Lean now has no reviews between blocks, and the 2026-09-29 refinement of the no-midway-gates note says between-task reviews are not the user's job. The sequential part still holds; the "review between each" part looks superseded but the note was never updated. +2. **Base review-by-risk rules vs lean default.** The note's base text (2026-09-29) gives every hotspot its own Opus review and runs mutation checks on risky seams. The 2026-10-01 refinement said those base rules stay the default outside the experiment; the 2026-10-05 refinement makes lean the default. Latest wins, so per-hotspot reviews are gone, but the note still carries both. Mutation checks have no place in §5.3 at all. +3. **Optional mid-run hotspot review.** §5.2 change 5 and §5.3 step 4 allow one scoped review after a hotspot block whose handoff note flags a deviation. Today's lean brief (memory, 2026-10-05) says "no reviews between blocks" and adopts changes 1–3 only. Whether change 5 is in or out is not stated. +4. **Who fixes.** Review-by-risk: fix rounds resume the implementer who wrote the code; the 2026-09-29 Sonnet note: minor fixes resume the Sonnet implementer. §5.3 step 7: one fresh Opus 5.5 fix pass over all findings, which is what H0–H3 did. With several block implementers, "resume the author" means several fixers; the report's data favours one fresh Opus fixer. +5. **Tests shown to fail first vs one test run.** Review-by-risk asks for tests shown to fail first. Lean runs the test suite once, in the last block. These fit only if "fail first" means a targeted single test (as block 1's repro test did), not a suite run. Not stated. +6. **Haiku for compiles vs block-owned compile gate.** The model note keeps compiles and test runs on Haiku. In lean, the block's own implementer runs its compile gate and fixes what breaks, so the gate effectively runs on the block's owner model. Probably fine, but the rules don't say. +7. **Athanor stays the block orchestrator although its pinned model is distrusted for plans and reviews.** Plans and reviews were moved off Opus 4.6 on evidence; block dispatch stays on athanor to keep the measured comparison clean. This is a deliberate experimental choice (2026-10-05), not a judgement that 4.6 is fine for orchestration. If 4.6 also mis-handles handoff flags or model choice, the guard rails in §5.4 become urgent. +8. **Block size.** Memory: "~2–3 h of work" per block. Report: 10–40 min of agent work, measured 11–36 min (A.5). +9. **Short briefs vs explicit lean brief.** Review-by-risk wants short briefs. Today's lean brief must spell out the process because athanor's defaults don't. This tension disappears once the lean defaults move into athanor's skill. +10. **Skill defaults the project overrides.** The Igor skill suggests worktrees (A.6) and "don't start work from topic alone" (A.8). The project overrides both. Skills should make these per-project settings rather than fixed rules. + +### A.11 Not process-relevant (excluded) + +These memory notes are dirigent product feedback or project tooling references, so they were left out above (except where noted): +- **Settings tab behaviour:** settings panels should reuse one settings tab instead of opening a new tab per panel; shift-click opens a new one. +- **Tab navigator tree:** the tab switcher should be a tree view in a right-side panel, not a flat list in a hamburger menu. +- **Split panel resizable:** the left/right split panels need a drag handle and a persisted ratio, like the old workbench. +- **Connector auto-detection:** the connector auto-detection wizard must come back as the first tab in connector settings. +- **Auth file store:** a reference for how dirigent stores users, API keys and tokens on disk, and how a script can provision an API key. +- **Archive backward compatibility:** archived session data must stay readable across format changes, because it is often the only copy; migrations take a backup first, and normal operation never silently deletes archive data. This is a product rule, but the note also says to put the constraint into every implementation brief that touches the archive. The general lesson for athanor is that projects need a place for **standing brief constraints**, injected into every brief whose scope touches a given area. +- **Node/npx via fnm:** where `node` lives on the user's host; its general lesson is kept in A.9. diff --git a/docs/workpad/reports/dirigent/2026-10-14-chatgpt-importer-retrospective.md b/docs/workpad/reports/dirigent/2026-10-14-chatgpt-importer-retrospective.md new file mode 100644 index 0000000..c3bb03c --- /dev/null +++ b/docs/workpad/reports/dirigent/2026-10-14-chatgpt-importer-retrospective.md @@ -0,0 +1,161 @@ +# Retrospective: why the ChatGPT importer took a day, not 1–2 hours + +**Date**: 2026-10-14 · **Author**: researcher agent, model `claude-opus-5-5` · **Scope**: research (2026-10-13 21:00) to Phase 7/8 running (2026-10-14 21:53) +**Sources**: git author times (`e6aa0532..HEAD`, branch `chatgpt-importer-phase8`), both journals, run log, handoff, design, plans, reviews, `spire` plugin skills (`~/.claude/plugins/cache/reliquary/spire/0.1.0/skills/igor/SKILL.md`), memory `feedback_lean_gates.md`. +**Clock caveat**: the second journal's times (23:00–00:35) do not match git (the same events are at 19:22–21:49) or the memory file's mtime (19:49Z = 21:49 local). All times below come from git. + +## Verdict + +The day went to three things, roughly equally. (1) **Scope**: a second-generation importer was built where a first one was needed. It has union merge with variants and revisions, six generic importer seams, a protocol part, hostile-input hardening, versioned side entries and approximate library matching. (2) **The verification loop**: every phase ran review, then a fix pass, then a re-check, then carry-over "Block 0" fixes. That took about 5 h, about as long as writing the features (about 6 h). (3) **Dead time**: about 9.6 h of the 24.9 h wall clock was waiting. That covers the night, waiting on the history-scrub answer, and about 3 h lost after the spend-limit kill. The heavy rules came from Igor and the plan/design agents, not from the user. Igor's own skill prescribes less than Igor ran. + +## 1. Timeline (git author times, local +0200) + +| Stage | Wall clock | Span | Notes | +|---|---|---|---| +| Research (format census, 2024 compare, desktop app, dedup, E2/E3) | ~1 h 25 m | 21:00–22:26 | 10-13. Desktop-app pipe / `read_thread` work is not importer scope | +| Design (independent Opus) | 23 m | 22:05–22:28 | 414 lines, 5 open questions | +| Plan (independent Opus) | ~17 m | 22:21–22:38 | 321 lines, 8 phases, 17 deviations | +| *Gap*: user Q&A, plan attack, decisions | 2 h 41 m | 22:38–01:19 | Attack 194 lines + reshaped build plan 637 lines; active share unknown (likely 30–45 m) | +| P1 fixtures: build / review / fix / re-check | 45 / 14 / 15 / 5 m | 01:19–02:40 | Generator 2,610 LOC; review C1 = leak in fixtures | +| *Idle*: night + scrub decision | 4 h 52 m | 02:40–07:32 | Scrub itself ~5 m | +| P2 v1 reader | 22 / 9 / 12 / 6 m | 07:32–08:21 | Includes Block 0 (P1 re-check R1–R3) | +| P3 mapping + citations + protocol | 63 / 13 / 23 / 6 m | 08:21–10:07 | Block 0 = P2 re-check N1–N5 | +| P4 seams, union, importer | 128 / 10 / 58 / 5 m | 10:07–13:28 | Block 0 = P3 re-check; fix pass incl. profiling + fsync batching | +| P5 v0 + union | 45 / 9 / 33 / 6 m | 13:28–15:01 | Union smoke 137–176 s per run | +| P6 assets | 60 / 7 / 18 m (part A) | 15:01–16:26 | Killed mid-fix by API spend limit (429) | +| *Dead*: spend-limit stop to handoff | 2 h 56 m | 16:26–19:22 | | +| P6 fix part B | 34 m | 19:22–19:56 | All suites + 4 mutations + 2 smoke runs (Igor's brief, later retracted) | +| P7 UI (main) ‖ P8 tests+audit (worktree) | ~1 h 55 m each, in parallel | 19:58–21:53 | P7: 6 commits + 1,021 uncommitted lines; P8: 16 commits, 3,970 lines | +| **Total** | **24 h 53 m wall** | | **~15.3 h active, ~9.6 h idle/dead** | + +## 2. Where the active time went (~15.3 h) + +| Category | Time | Share | Evidence | +|---|---|---|---| +| Pre-build docs (research, design, plan, attack, decisions) | ~2.9 h | 19 % | 6 docs; attack added 38 findings and 3 user decisions | +| Feature build blocks P1–P6 (incl. their gates and smoke) | ~6.0 h | 39 % | 363 m of block time | +| ↳ of which fixture generator + leak gate (P1) | ~0.75 h | | Exists only because fixtures were derived from private exports | +| Review → fix → re-check loop + carry-over Block 0s | ~5.2 h | 34 % | Reviews 62 m, fix passes 193 m, re-checks 28 m, Block 0s ~27 m | +| P7 + P8 so far (parallel, counted once) | ~1.9 h | 12 % | Partly more hardening (audit R1–R6, perf) | +| Incidents | ~0.1 h active, ~7.8 h waiting | | Scrub: ~5 m of work, but it held the build overnight. Spend limit: 2 h 56 m lost | + +The loop's fix passes alone (193 m) took more than half of the feature block time. The fix passes also fixed most **Minors** (for example P4 M1–M5 and M9–M12), although Igor's skill says "Lows stay in the report; never loop for lows" (`igor/SKILL.md` §Development Cycle). + +**Verification inside the blocks** is an estimate, because gate runs are not timed individually: +- full `dirigent_archivist --no-fail-fast` runs (857+ tests, 13 known failures) in almost every block and every fix pass; +- 37 mentions of mutation checks and 44 of smoke runs in the run log; +- release smoke runs: union test 137 s → 176 s → 192 s → 203 s, plus each release compile; +- two extra worktrees with their own fresh target dirs: a baseline at `e6aa0532` to prove failures were pre-existing, and a Phase-5 build to measure a converter bump. + +A conservative estimate is 25–35 % of block time. + +**Output.** 124 commits since `origin/main`, 71 of them docs-only. Code added: 17.1k lines of src, 8.8k lines of tests, 2.6k lines of generator and 29.4k lines of fixtures, with 340 new `#[test]` attributes on main. That excludes P8's 3,970 lines. Workpad docs for this importer come to about 7.2k lines: + +| Doc | Lines | +|---|---| +| Run log | 1,329 | +| Build plan | 637 | +| Design | 414 | +| Plan | 321 | +| Attack | 194 | +| Reviews and re-checks | 1,684 (11 docs) | +| Research | 1,027 | + +The archivist `CLAUDE.md` changed by 654 lines, and `dirigent_chatgpt/CLAUDE.md` grew into a 61-line spec. + +## 3. Scope: built vs. what a first importer needed + +**Needed for a first importer.** +- Read the user's own v1 export (folder or ZIP) and the v0 `conversations.json`. +- Turn each node into a record with `parent_id` and `active_leaf_id`, so branches survive. +- Map the basic kinds. +- Store images in the file store. +- Make imports idempotent by node id through the existing Incremental mode. +- Make the second export add the node ids that are missing. This satisfies the CLAUDE.md archive refinement: never silently lose archived data. +- Commit a small hand-written fixture. +- Run one smoke test on the real export. + +**Built beyond that need.** + +| Feature / hardening | Where | Why it was beyond need | +|---|---|---| +| Hostile-input hardening of a user's own OpenAI export: zip-bomb ratios, traversal, symlinks, nested-ZIP lazy spill with sub-range reader, manifest fast path for 3–20 GiB parts, `max_conversations` 250k, `max_nodes` 100k, output-amplification budget `REPEAT_SLACK`, cancellable aligner, P8 audit R1–R6 | `crates/dirigent_chatgpt/src/source.rs` (1,001), `tests/hostile_inputs.rs` (747), `src/citations.rs` (1,216), design §2.1 limits table | The input is trusted (the user downloads it). Real max is 210 nodes per conversation and 1,632 conversations. A `zip` size cap plus `enclosed_name()` would have covered the real risk. The P2–P3 re-checks became a "rolling audit" (journal 10-13, P3 re-check entry) | +| Union with variants, winner rule, metadata key union, parent rule, content hash vs raw hash, revisions, converter version in the digest, cross-order hash convergence asserts | `archivist/src/import/variants.rs` (493), `sources/chatgpt/convert.rs` (1,032), smoke `tests/import_chatgpt_real_export_smoke.rs` (1,573) | 303 shared conversations needed "add missing node ids". The full machinery produced 4,124 representational revision lines (+26.7 MB) on the real union | +| Six generic importer seams (opt-in prior, revisions, revision fold, digest, owned metadata, discovery context) | `archivist/src/import/mod.rs` (+519), `seam_tests.rs` (512) | Needed only for the union semantics above, and it put Claude and Codex paths at risk (a 4A gate and a review priority to prove them unchanged) | +| Fixture generator with an anonymiser and an independent leak gate, run on private exports | `scripts/ops/chatgpt_fixtures.py` (2,610), `tests/fixture_hygiene.rs` (393) | Caused the leak (P1 C1), the history scrub and the overnight block. A synthetic hand-written fixture had no leak surface | +| Versioned side entries (shares, feedback, model_comparisons, library records) and approximate library placement | `sources/chatgpt/library.rs` (689); P5/P6 fix passes | 10 shares, 0 unattached entries and 33 library files on real data. Plain storage would have done | +| Intra-build back-compat: converter bumps 2→3→4 measured from older builds; placeholder wording "fixed before more archives" | run log P6 6C, part A | No real archive holds ChatGPT data from this unpushed build (imports went only to temp archives). It protected nothing | +| `MessagePart::Sources` protocol part and a type-aware citation aligner (E2 rules) | `dirigent_protocol/src/conversation.rs` (+359), `citations.rs` | Nice to have. Text with inline links would have done for a first version | +| 8 phases, phase 4 split into 5 blocks | build plan | Each phase boundary triggered the full loop. 3 phases would have done | + +**Worth keeping from the "extra"**: the fsync batching (`49c733e3`, first import 137 s → 28.6 s; it also benefits live writes), branches as `parent_id`, raw `_source` retention (user decision 1), and the archived-asset fallback (attack BL1). + +## 4. Who drove the blow-up + +| Decision | Origin | Evidence | +|---|---|---| +| Design → plan before build; subagent-driven; "review between tasks" | **User** (brief + root `CLAUDE.md` §Superpowers) | journal 10-13 22:00 | +| Accept all recommendations (raw storage, full switcher, automatic revisions, agent runs generator on private exports) | **User**, on recommendations from the designer and attacker | journal "use recommendations" | +| Build on `main`, scrub history, approve limits 1–4, lean gates | **User** | journals | +| Union-of-everything, raw `_source`, safety-limits table, five seams, `MessagePart::Sources` | **Designer** (from the research's "Merge, not replace", overview §12) | design §1, §2.1, §6 | +| 8 phases; per-phase gates of full archivist + api + rest suites and `check-all`; `hostile_inputs.rs`; real-export smoke; field ledger | **Planner** | plan 10-13 l.14, l.83; build plan l.351–353, l.430–434 | +| Plan attack stage; extra blocks (4A1–4B2), converter version in digest, more leak-gate rules, decisions 6–8 | **Igor** dispatched it; the **attacker** added the content | Not in Igor's six-stage cycle (`igor/SKILL.md` l.95). No earlier attack doc exists in the repo | +| Fresh reviewer after **every** phase, plus a fix pass, plus a **re-check**; folding re-check findings into Block 0s; fixing Minors | **Igor** | journal 10-13: "Plan per phase: … reviewer → at most one fix pass", first re-check at P1. The skill says one review stage and "never loop for lows" | +| Mutation / fail-first checks of tests | **Builders**, via superpowers TDD habit, with reviewers grading "fails on mutation" | run log l.347, l.510 (`local/break_4a1.py`); in no plan or brief | +| Full suites + 4 mutations + repeated release smoke after the user approved cuts | **Igor** | journal 10-14 course-correction entry: "my rules, not theirs"; memory `feedback_lean_gates.md` | +| Baseline worktree to prove 13 + 9 failures were pre-existing; converter-bump worktree | **Igor**, **reviewer**, **builder** | journal P3 review and P4 entries; run log 6C | + +The user's claim holds. No user message sets per-phase reviews, re-checks, mutation runs, full-suite gates or hostile-input depth. The one user-sourced rule that pushes toward rigour is the archive-safety refinement. It justifies "add missing nodes, never drop". It does not justify revisions of representational differences or hostile-ZIP limits. + +## 5. Changes for builds of this size + +**Policy** + +| Area | Rule | +|---|---| +| Stages | Skip design + plan + attack when research already names the format and the seams. Write one combined design-plan of 100–150 lines instead. Run an attack only when a plan touches central storage formats *and* the user asks for one. | +| Phases | At most 3: reader, mapping + import, UI. No sub-block splits under about 300 LOC. | +| Review | One fresh review at the end, scoped to data loss and correctness. One fix pass for Critical/Important only. Minors are logged, never looped. No re-check unless a fix touches a Critical. | +| Gates | `cargo check -p` between blocks. Changed-crate tests once per phase. `check-all` once at the end. No mutation runs unless a Critical needs proof. Real-export smoke once, at the end. No baseline or measurement worktrees unless the user asks. | +| Hardening | A trusted local input gets the library's default safety (zip size cap, `enclosed_name`). It gets no adversarial audit unless the input crosses a trust boundary (upload, network). | +| Back-compat | Not before any real archive holds the data. Temp-archive data written by an unpushed build needs no migration story. | +| Fixtures | Hand-written synthetic fixtures. Never derive them from private data for a first version. | +| Docs | A run log of at most 1 line per block plus deviations (≤ 80 lines total). No per-phase trunk notes. A crate `CLAUDE.md` stays a nav map of 20–50 lines. | +| Spend | Check the API budget before a long serial run. A kill cost 3 h. | + +**Target budget for a comparable importer (≈ 2 h)** + +| Stage | Budget | +|---|---| +| Research (only if the format is unknown; here it already existed) | 0–15 m | +| Combined design-plan + user questions | 15 m | +| P1 reader + synthetic fixture | 25 m | +| P2 mapping, import, union-by-node-id, assets | 35 m | +| P3 UI (thread order, branch switcher) | 20 m | +| Final review + one fix pass | 20 m | +| Real-export smoke + docs | 10 m | +| **Total** | **~2 h** | + +**My view**: 1–2 h is realistic for the scope in §3 "Needed". The scope that was actually agreed (v0+v1 union with revisions, assets, library, Sources, full switcher) is closer to 3–4 h even with lean gates. Holding the 1–2 h line therefore needs the scope cut, not only the process cut. + +## 6. Phases 7 and 8: finish vs. drop + +| Item | Call | Reason | +|---|---|---| +| P7 7B thread view, branch switcher, Sources footer, missing-asset notes (committed 20:39–21:34) | **Keep** | Done; user-visible | +| P7 7A Import Hub (1,021 uncommitted lines across api/web/claude/codex importers) | **Finish, then stop** | Commit it after `just check-all`, and confirm the Claude and Codex edits are wiring only | +| P7 full phase review | **Merge into one final review** | Cover P6 part B + P7 + the P8 merge. Scope: data loss and display correctness. No hostile-input scope. No re-check | +| P8 e2e suite, per-node golden, last-session cancel fix (`763bbbd1`, `95817c6c`, `db4c8c37`) | **Keep, merge** | Already done; cheap regression value | +| P8 audit fixes R1–R6 and mapping-table perf (`8fe18a8f`) | **Keep (done), stop there** | Sunk cost. Add no further attack classes | +| Hostile-input audit report document | **Drop or ≤ 30 lines** | The fixes are the record | +| Remaining P8 perf/memory items (16k-session extrapolation, the 38.6 s vs 29.8 s re-time, asset-byte memory, shard cache) | **Drop to backlog** | Real account is 1.6k sessions; first import takes about 30 s | +| ZIP-form real export test | **Drop**; one manual import of a zipped copy if wanted | Synthetic ZIP tests already cover the code path | +| Further converter-bump measurements | **Drop** | No real archive to protect | +| Close: `dirigent_chatgpt/CLAUDE.md` back to a nav map; spec to `docs/architecture/chatgpt_importer.md` | **Keep, ≤ 20 m** | Already decided; keeps future agents from re-growing the spec | +| Pre-existing failures (13 archivist, 9 api, 8 web test-target errors) | **Separate ticket** | Not this build | + +## Gaps + +- The time from the plan commit to the attack commit (22:38–01:14) cannot be split into user time and agent time from the sources. +- Compile and test durations are not logged per run, so the verification share inside the blocks is an estimate. +- The research session's own brief is not in these journals, so the origin of the desktop-app/pipe research is not attributed. diff --git a/docs/workpad/reports/dirigent/2026-10-15-chatgpt-importer-handoff-lean-finish.md b/docs/workpad/reports/dirigent/2026-10-15-chatgpt-importer-handoff-lean-finish.md new file mode 100644 index 0000000..758f2eb --- /dev/null +++ b/docs/workpad/reports/dirigent/2026-10-15-chatgpt-importer-handoff-lean-finish.md @@ -0,0 +1,93 @@ +# ChatGPT importer: handoff for the lean finish + +**Date**: 2026-10-15 +**Written by**: Igor, from journal [2026-10-14-23-chatgpt-importer-continue.md](../journals/2026-10-14-23-chatgpt-importer-continue.md) +**Supersedes**: [2026-10-14-chatgpt-importer-handoff.md](2026-10-14-chatgpt-importer-handoff.md) for process and the remaining steps. Keep that file's **rules section** (private data, archive safety, git, worktrees, models); everything else here wins. +**Branch**: `main`, not pushed. Phase 8 sits unmerged on its own branch (below). + +## Why this file exists: the lean rules (binding) + +The importer took ~25 h wall clock for what the user expected to take 1–2 h ([retrospective](2026-10-14-chatgpt-importer-retrospective.md)). The user ordered testing and review time cut. The heavy gates were the coordinator's rules, never the user's. **Every brief to every agent from here on carries these rules verbatim:** + +1. **Between blocks:** `cargo check` on the changed crate only. No test suites. +2. **Once at the end of a step:** `cargo test` only for crates that step changed. `just check-all` only if UI/web/api changed. Never `dirigent_api` or `dirigent_rest` tests unless those crates changed. +3. **No mutation runs**, except for a Critical fix. One test per fix is enough. +4. **No real-export runs**, except one smoke at the very end if import/mapping behaviour changed after Phase 6. UI-only changes need none. +5. **Run gates once, in the foreground.** No queue of background gates watched one by one. +6. **One review total** (below), one fix pass for Critical and Important only, **no re-check**. Minors are logged, never fixed in a loop. +7. **No new scope.** No hostile-input audit, no perf/memory work, no extra compatibility checks. Anything the review suggests beyond Critical/Important goes into a list for the user. +8. **Docs:** crate `CLAUDE.md` files are 20–50 line navigation maps (`.claude/skills/documentation.md`). API detail goes to trunk notes or `docs/`, never into `CLAUDE.md`. +9. **Models:** builders and the reviewer are Opus 5.5 (`athanor` pinned, no `model` override); merge, compile and test runners may be Sonnet or Haiku. Stamp the model id. + +Known failures that don't count against a gate (verified at origin/main `e6aa0532`): `dirigent_archivist` has exactly 13 Windows path/lock failures and `dirigent_api --features server` exactly 9 (see the old handoff for the names). There are also 8 type errors in `dirigent_web` test targets, which `just check-all` doesn't build. + +## Timetable to beat + +From the pause: **1.5–2.5 h total**. Aim to come in under it. + +| Step | Budget | +|---|---| +| Merge Phase 8 + Phase 7 remainder (gates once, one smoke, UI check, close note) | ≤ 40 min | +| One final review | ≤ 25 min | +| One fix pass (C/I only) | ≤ 30 min, 0 if nothing C/I | +| CLAUDE.md shrink + close | ≤ 10 min | + +If a step runs past its budget, the coordinator stops and asks the user. It does not extend the step on its own. + +## Where things stand (at the pause) + +| Phase | Status | +|---|---| +| 1–5 | closed | +| 6 Assets | **closed**. Part A in the old handoff; part B `3ffa6ebb` (I2 abort), `b3820b3c`, `d560b087`, `fdcc9145`. User approved: no separate re-check; the final review covers it. | +| 7 UI | **soft-paused, all 5 blocks built and committed**, nothing uncommitted. `cargo check` is clean on archivist, api, web, protocol and chatgpt. Commits: `4818a7d3`, `74b199bc`, 7C `f5d1a969` `a38f69a1` `addb3f4d` `70e7c57c` (**converter version 4**), 7B1 `655acf10`, 7B2 `c0a10caf`, 7B3 `60ac0c02` `69d10447`, 7A `7279c781` `573922d2`, run log `aae6243e` ("Phase 7 — paused"). Block notes: [phase7-block-notes/](2026-10-15-chatgpt-importer-phase7-block-notes/). | + +**Phase 7 remainder (this is all of it):** +1. Phase-end tests, once each, for the crates Phase 7 changed: chatgpt, protocol, archivist (known 13), api `--features server` (known 9), web with and without `server`, rest. Then `just check-all`. **Run these once on `main` after the Phase 8 merge (resume step 3), not before**, so they aren't run twice. +2. One real-export smoke run, because 7C changed the mapping (converter 4): v1 alone and the union, with the digest counts. Into a temp archive, counts only. This is the single smoke run that lean rule 4 allows. Do it after the merge too. +3. A short manual UI check: `dx serve` on a temp `DIRIGENT_DATA_DIR`, using the click steps in the 7A, 7B2 and 7B3 notes. +4. Fold the block notes into the run log as a "Phase 7 close" section. Short. + +Final-reviewer flags from Phase 7: +- 7C edits `crates/dirigent_chatgpt/src/citations.rs`, which is in Phase 8's crate, so watch the merge there. +- The hub sorts warnings by matching the reader's warning *text*, which Phase 8 may have changed. Only the account hint is structured. +- Missing assets reach the web as a separate map. Audio placeholders match by prefix. Library files have no link, because no route serves stored files. +- The Dioxus 0.7 `key` remount works only inside an `if`/`for` block, and the archived transcript relies on that. +- Five crate `CLAUDE.md` files gained API detail before the stop order. All five get the close-step rewrite. +| 8 Integration tests | **built, not merged.** Worktree `.claude/worktrees/agent-a9adadbc70966bb15`. The branch was reported as `chatgpt-importer-phase8` and also as `worktree-agent-a9adadbc70966bb15`; run `git branch --contains 6efcc533` to find which. Logs in that worktree: `docs/workpad/reports/2026-10-14-chatgpt-importer-build-run-phase8.md` and `...-trunk-notes-phase8.md`. The user chose to **keep** its perf and reader-fix commits (`8fe18a8f`, `57728bbd`, `02cc5488`, `a4de6d0b`, `6cddcaef`, `fc0cf029`, `175f5ef6`, `5a14c616`). Tests: `95817c6c`, `763bbbd1`, `6efcc533`; cancel fix `db4c8c37`. Gates on the branch: chatgpt 153/0, archivist 975 plus the known 13. | + +Decisions since the old handoff (all from the user): +- Limits 1–4 approved, then amended: + - Phase 8 was cut to integration tests; the hostile-input audit and perf work were dropped (the commits that already existed are kept). + - The separate Phase 7 review was replaced by **one final review**. +- Phase 8 merges into `main` after Phase 7. + +## Resume steps, in order + +1. **Check state:** + - `git log --oneline fdcc9145..HEAD` on `main`; + - the run log's "Phase 7 — paused" section; + - `git status --short` for any uncommitted Phase 7 files. + + Re-read git; don't trust the state of agents that no longer exist. +2. **No more Phase 7 building.** Every block is committed. The remainder above is verification, and it runs after the merge. +3. **Merge Phase 8 into `main`, then do the Phase 7 remainder items 1–4 in a single pass.** Use a Sonnet agent and an ordinary merge commit (no rebase or history rewrite). + - Expected conflicts: `crates/dirigent_archivist/src/import/mod.rs` (the post-loop cancel block), `backends/jsonl/mapping.rs` and `backend.rs`, the `crates/dirigent_chatgpt/src/` reader files, and both crates' `CLAUDE.md`. + - New public items from Phase 8: `ReaderWarning::Omitted` and `Limits::max_read_cache`. Check for exhaustive matches or struct literals that Phase 7 added. + - Gates, once: chatgpt and archivist tests, plus `just check-all`. + - Then remove the Phase 8 worktree and its target dir. +4. **One final review.** A fresh Opus 5.5 reviewer covers the Phase 6 fix pass (I1, I2), all of Phase 7 and the Phase 8 merge. It answers the handoff flags in the run logs, reports Critical/Important/Minor and writes `docs/workpad/reviews/2026-10-15-chatgpt-importer-final-review.md`. It doesn't scope to hostile input. +5. **One fix pass**, for Critical and Important only, with lean gates. No re-check. +6. **Close:** + - Rewrite `crates/dirigent_chatgpt/CLAUDE.md` (currently a ~61-line API reference) into a 20–50 line navigation map, and move the API reference to `docs/architecture/chatgpt_importer.md`. Do the same for the other four crate `CLAUDE.md` files that Phase 7 extended: archivist, api, web and protocol (check `git log -p` from `e6aa0532`). + - Then the user reviews and pushes. Never push for them. + +## Carry-overs for later (not this run) + +- Phase 8 reviewer flags: + - the read cache now keeps all shards (~80 MB on the real export); + - the mapping-table cache misses a same-length rewrite within one mtime tick; + - a single-export re-import into a v0+v1 union re-converts shared conversations; + - an archived-tier digest mismatch is counted in no notice. +- Pre-existing failures (13 archivist, 9 api, 8 dirigent_web test type errors) are worth fixing separately. +- Skill-level lesson for spire: the full cycle (design → plan → attack → per-phase review/fix/re-check) is too heavy for a build of this size. See the retrospective's budget table. diff --git a/docs/workpad/reports/dirigent/README.md b/docs/workpad/reports/dirigent/README.md new file mode 100644 index 0000000..107a3fe --- /dev/null +++ b/docs/workpad/reports/dirigent/README.md @@ -0,0 +1,11 @@ +# Reports from Dirigent + +Process reports from the Dirigent project (`../dirigent`). They are copied here as input for replacing superpowers. They describe how superpowers-style orchestration (a subagent per task, a review between tasks, fix passes, re-checks, TDD/mutation habits) played out on real implementation work. + +The copies are snapshots from 2026-10-15. Relative links inside them point into Dirigent's own workpad (`../dirigent/docs/workpad/`) and do not resolve here. + +| Report | What it shows | +|---|---| +| [2026-10-14-chatgpt-importer-retrospective.md](2026-10-14-chatgpt-importer-retrospective.md) | Why the ChatGPT importer took ~25 h of wall clock instead of 1–2 h. Review → fix → re-check loops took about as long as writing the features (~5.2 h vs ~6 h). The table in §3 traces each heavy rule to its source: the user, the `CLAUDE.md` §Superpowers section, Igor, or builder habits. | +| [2026-10-01-lean-process-report.md](2026-10-01-lean-process-report.md) | A side-by-side comparison of the step-by-step baseline (an implementer per task, an Opus review every 1–2 tasks, scoped re-reviews) and the lean experiment, measured from git timestamps. It records the user's 2026-10-05 decision to make lean the default. | +| [2026-10-15-chatgpt-importer-handoff-lean-finish.md](2026-10-15-chatgpt-importer-handoff-lean-finish.md) | The lean rules that came out of the retrospective, written as binding brief rules: which checks run between blocks, tests once per step, no mutation runs. |