Skip to content

Latest commit

 

History

History
271 lines (234 loc) · 15 KB

File metadata and controls

271 lines (234 loc) · 15 KB

Interaction — Retro Log

Friction or wins in how Sebastian and the interactive agent work together — not runner/code process, that's harvest-ideas.jsonl. Logged as it happens, same "don't wait to be asked" rule as harvest. Reviewed periodically (see CLAUDE.md) and validated, recurring lessons get folded into CLAUDE.md directly rather than left to accumulate here indefinitely.


2026-08-13 — Session ran long because resuming didn't feel trustworthy

This session covered VISION items 5/6 across many build-babysit cycles (stalls, retries, spec corrections) and got compacted at least once, but never handed off to a fresh session — not because the work required staying in one session, but because starting over felt risky: would a new session actually pick up cleanly from runner status + the task list + CLAUDE.md, or lose something only visible in the transcript?

Why it matters: CLAUDE.md is meant to be the thing that makes a new session as good as a resumed one. If that's not trusted in practice, the tool isn't doing its job, and sessions run needlessly long instead. Promoted: CLAUDE.md now states this explicitly as a standing rule.

2026-08-13 — Diagnose-before-retry held up under repeated real stalls

Two 429s and two NEEDS_CONTEXT stalls hit one slice in a row; each time the actual cause was traced (rate-limits.json, grepping tests, reading the session transcript) instead of blind-retried. Worth keeping as the default for any repeated failure, not just build stalls.

2026-08-13 — Background-tasking long operations kept the conversation open

Spec runs and builds (5–20+ min) were launched via nohup ... & and waited on in the background, so mid-turn questions got answered immediately instead of after a long blocked wait. Kept doing this.

2026-08-23 — Handoff: wire-block-gate-categories landed, next is a decision not a slice

Session ended at a clean boundary: main green, wire-block-gate-categories landed, a pre-existing CHECK_SPEC_DIFF_SCOPE env-leak bug (found only because it blocked that land) fixed and harvested separately. Nothing here depends on this transcript — VISION/gates-and-scheduling.md now indexes today's three new gate-classification findings, and runner status / harvest-ideas.jsonl carry the rest.

What the next session should raise with Sebastian before drafting anything: RISK_PATHS, BLOCK_GATE_CATEGORY_PATHS, and REVIEWER_SKIP_CATEGORIES are now three separately-maintained hardcoded dicts with the same flaw (Python-specific, silent zero coverage for a non-Python project 2) — the classification artifact's shape has always been undecided (VISION doc's own "left open" section), and drafting another one-off migration slice would just add a fourth ad-hoc shape. Decide the shape once, then implement.

2026-08-23 — Harvesting the fix doesn't reliably extend to the friction around it

Fixed and harvested check-spec-diff-scope-leaks-into-slice-marks-fixture-tests (the bug) unprompted, per the standing rule. But the recovery arc around it — runner land re-running QA against a worktree that had gone stale relative to main mid-session, and a .git/index.lock collision on the retry after that — sat unharvested until Sebastian asked "harvest logged already? this is not the first time." Both turned out genuinely harvest-worthy (land-qa-gate-runs-against-stale-worktree-base, land-git-retry-window-too-short-for-real-contention), and neither was a duplicate of the bug I'd already logged.

Why it matters: the standing rule ("every failure... gets logged immediately... don't wait to be asked") reads as one incident, one harvest call — but a multi-step recovery arc is several distinct findings, and I stopped at the first one until prompted. Not promoting to CLAUDE.md yet (one sighting) — logging so a second occurrence gets caught as a pattern instead of rediscovered.

2026-08-24 — Handoff: harvest closed, 3 of 5 promoted specs landed,

first real 4-way parallel build surfaced a new git-contention family

Session did the requested harvest run first (closed 2026-08-20→08-23, 3 promotions), then a friction sweep of the last 6 runner sessions (found nothing unlogged), then drafted and built the 3 promoted specs plus the 2-sub-slice state_paths.py generalization VISION already planned — 6 specs total once wire-skip-categories split off from project-owned-skip-categories to dodge a Surface-cap bust from sessions.py's own hub-file tax.

Landed on main: blast-radius-honors-tier, project-owned-skip- categories, state-paths-project-scoped (project_state_paths.py, a new module — deliberately NOT an edit to state_paths.py, see that spec's own Decisions for why). The third one's land hit a real squash- merge conflict (its worktree predated the other two lands, all three shared test_runner.py in Surface) — resolved by hand (both slices' test sections are non-overlapping, kept both, verified qa-green), landed via a manual commit + runner mark-direct, then remove_slice to clear the ledger (mark-direct only touches legacy-marks.tsv, never state.json — same gap HARVEST-LOG's 2026-07-18 entry already named for manual lands). Worktree removed, ledger now shows BUILT correctly.

Still open, next session's queue:

  • claim-check-dispatch — CRASHED, twice, same failure (git commit inside its own worktree hit index.lock, both times right after the IMPLEMENTER phase checkpoint). Root cause not confirmed but a strong lead (see harvest id concurrent-worktree-checkpoint-commit-index- lock) — likely the dispatched agent's own parallel Bash/git tool calls, not cross-slice interference (each worktree has its own index, verified). Nothing was contending when checked after the fact both times — safe to just runner run it again. Its worktree still exists at /Users/sebastian/ai/redlich/2026-08-23-claim-check-dispatch.
  • wire-skip-categories — spec draft is git stashed (git stash pop to get it back), not yet run through spec run/approve. Was blocked on project-owned-skip-categories landing (now landed) — safe to proceed.
  • state-paths-status-land — already approved and committed to main, never built. Was blocked on state-paths-project-scoped landing (now landed) — safe to runner run it.
  • This was the first time 4 runner run builds were launched truly in parallel — 3 of 4 crashed on the git-lock issue above, none of it data-loss, all recoverable, but worth reading if it recurs (harvest id above has a refined hypothesis but no transcript-confirmed root cause yet).

Also this session: fixed the running devcontainer's missing tmux by hand (sudo apt-get install tmux, matches the Dockerfile's own already-landed fix — the container itself was never rebuilt) — this unblocked unsnooze's auto-resume, confirmed working overnight for a genuine rate_limit-kind stop. A different stop kind (kind=overload, logged in /home/vscode/.unsnooze/unsnooze.log) was NOT auto-resumed — unsnooze's hook only logged detecting it, never tracked or resumed it; logged as harvest id unsnooze-overload-stop-not-auto-resumed, unsure if updating past the installed 1.16.1 (1.17.0 available) covers this.

Decided, not yet acted on: project 2 (the multi-project plan's next real step) should be a genuinely different, non-Python stack — Sebastian's call, nothing built toward it yet. VISION/multi-project-onboarding.md still has the concrete next-step plan; re-read it fresh rather than trusting this entry's specifics past its shelf life.

Uncommitted, expected: state/runner/{costs,harvest-ideas,rework}.jsonl — routine ledger churn, safe to leave dirty per land.py's own _EXPECTED_DIRTY convention; will get swept into the next harvest close.

2026-08-26 — Handoff: previous session's 3-item queue cleared, all

BUILT and landed

Resumed b3c5a20e's handoff directly (confirmed via git log it really was the last session — no commits after its own handoff commit) and worked its stated queue to completion:

  • state-paths-status-land — was already approved, never built; ran clean (1735 tests), landed as 5668607.
  • claim-check-dispatch — was CRASHED twice on the git-lock issue that session's entry flagged; re-runner run resumed from checkpoint and completed clean, no manual ledger/lock surgery needed. Landed as fcbe51b.
  • wire-skip-categories — popped the stashed draft and ran it through spec run. Hit a real structural wall along the way: sessions.py + phases.py must land together (the no-silent-default Decision on the new skip_categories parameter rules out a safe temporal split), and the mechanical Surface caller-scan genuinely required 9 files against check-spec's SURFACE_CAP=8 — not a false positive, verified each entry by caller-count before accepting it. Asked Sebastian how to proceed (widen the cap generally, split the slice further, or override for this one spec); he chose "land as one slice, override the cap." Bumped SURFACE_CAP to 9 for exactly the run → approve → build → land window, then reverted it to 8 immediately after landing (1a859aa) — safe to revert unconditionally because check-spec's shipped-spec exemption (a Slice: trailer in built-slices) is permanent and cap-independent once a spec has landed. check-spec confirmed green repo-wide afterward with the cap back at 8.

Git-lock contention, three more sightings: hit .git/index.lock races directly against the shared main/ worktree three separate times this session — twice during git stash push (stashing the spec draft, then the check-spec cap edit, to unblock the other two lands sitting behind them), once during wire-skip-categories's own runner land commit step. All three were transient (no process running, no lock file left, content verified identical before touching anything) and cleared with a plain retry — no data lost. The third one matches an already-logged, already-recurring harvest idea almost exactly (land-git-retry-window-too-short-for-real-contention: land.py's _run_git_retrying retry budget is ~0.75s over 5 attempts, too short for a real concurrent holder on shared main) — logged as a third sighting rather than a new idea. The two stash-time races are a variant not previously logged (contention on main/'s own .git during a plain git stash push, not inside a build worktree's commit) — worth a fresh harvest id if it recurs; didn't promote off one sighting.

Queue is empty: runner status shows every slice BUILT, no crashed or in-flight entries; every spec file on disk has a matching ledger record. Nothing carried forward from this session's original ask.

Uncommitted, expected: same state/runner/{costs,harvest-ideas, rework}.jsonl routine churn.

2026-08-30 — Harvest digest was too big to work; two fixes specced and

landed

Started from Sebastian asking for a sanity check on why a harvest run passed through 289-291 of ~305 open ideas untouched. Measured directly rather than guessing: build_harvest_prompt was dumping every still- open idea's full raw event history into a single one-shot dispatch, unbounded — 510,176 chars / ~127,544 tokens for 305 ideas / 1044 events. No model can meaningfully reason about that in one pass. Root cause: _prune_stale_ideas only drops an idea once it's fully closed; every open idea keeps its entire history forever.

Also found the pre-existing harvest idea that had already diagnosed this (harvest-digest-unbounded-and-unaggregated) was marked built 2026-08-20, but re-verifying against current code showed only the costs/rework aggregation half had actually landed — the ideas-history half was never fixed. Another instance of ledger status not matching code reality; see harvest-ledger-goes-stale memory, now generalized past just promoted-when-fixed to built-when-only-half-fixed too.

Specced and landed both fixes:

  • harvest-digest-compression (d839d0e): each open idea becomes a rollup (seen_count, first_seen, last_seen, latest_event, eligible) instead of full history; ranked by seen_count desc, ties by recency; top 50 get full rollup detail, everyone else drops to a remaining_ideas: {id: seen_count} tail. Verified live before/after: ~127,544 tokens -> ~9,899 tokens, ~13x reduction.
  • harvest-maybe-stale-verification (ee58b90): new MAYBE_STALE: <id> | <reason> wire format — when the model suspects but can't confirm from digest text alone that an idea is already fixed, it flags it instead of guessing. Each flagged id gets one small follow-up dispatch (same model, same Read/Grep/Bash access the harvest dispatch already had) that must answer CONFIRMED: <proof> or NOT_CONFIRMED: <why> before anything closes as a real OUTCOME. Motivated by two false OUTCOME claims caught and hand-corrected the same day this session started (uv-project-flag-wrong-venv-in-worktree, check-repo-hygiene-bsd-date-and-suffix-regex).

New harvest idea logged: harvest-clustering-groups-unverified-and- already-fixed-ideas — the model's clustering instruction groups *-friction/*-efficiency/*-refactor ideas by keyword/theme with no check that the grouped ids share a real root cause or that the underlying fix hasn't already shipped. The two false-OUTCOME catches above are both instances of this.

Tool-harness anomaly, one sighting: a runner run build was hard SIGTERM-killed by the Bash tool's own harness at exactly the 2:00 mark instead of auto-backgrounding like every other long invocation this session (exit 143) — left a stale lock + state.json entry (checkpoints: [], nothing lost). Recovered via the documented CRASHED procedure (edit state.json, remove the lock, remove the worktree/branch, retry). Logged as a fresh sighting of runner-auto-retry-on-stall-build-crashes-silently. Working around it going forward: for a long runner run, background it explicitly (& + poll the real PID from separate short Bash calls, or a plain until ! ps -p <pid>; do sleep 5; done loop) rather than trusting the tool's own auto-backgrounding.

Housekeeping at close: committed one batch of harvest-ideas.jsonl lines that belonged to a concurrent session's own 2026-08-30-codex- devcontainer-cli spec work (cold-read/draft findings, plus a new idea spec-run-draft-path-not-normalized-to-repo-root) — Sebastian asked for this explicitly (fb4edd0), since per CLAUDE.md I don't stage another session's uncommitted work on my own judgment.

Push left undone, on purpose: git push failed with "Host key verification failed" — ~/.ssh/known_hosts is empty in this devcontainer, so SSH won't verify GitHub's host key. Didn't work around it (no ssh-keyscan blind-trust, no StrictHostKeyChecking=no). Sebastian confirmed pushing is his to do, not something to hand back to Claude to fix. main is 44 commits ahead of origin/main, unpushed at session end.

Second worktree, not abandoned: 2026-08-30-codex-devcontainer-cli sits at the same commit as main with its spec approved but not yet built — a concurrent session's pending work, left alone.