Skip to content

feat(seamless-p2): concurrency guards + collaboration semantics (Phase 2)#41

Merged
miguelrisero merged 37 commits into
mainfrom
chief/bc-seamless-p2
Jul 22, 2026
Merged

feat(seamless-p2): concurrency guards + collaboration semantics (Phase 2)#41
miguelrisero merged 37 commits into
mainfrom
chief/bc-seamless-p2

Conversation

@miguelrisero

@miguelrisero miguelrisero commented Jul 21, 2026

Copy link
Copy Markdown
Owner

feat(seamless-p2): concurrency guards + collaboration semantics (Phase 2)

Contract

Implements Phase 2 ONLY of the owner-approved design (merged via #38, approved 2026-07-20 with all §9 recommendations): docs/superpowers/specs/2026-07-20-cli-ui-seamless-sync-design.md — §6 (Design C), §8 Phase 2 scope + verification, §9 decisions F1 (paste-into-TUI, auto-submit), F2 (fork "bring these back"), F3 (busy-notice), F6 (explicit replace + durable slot), F7 (auto-attribute), F11 (foreign-writer detect + banner). Phase 1 base: #39. Phase 3 items (F10/F12/F13 — nicknames, presence chips, idle-surface notifications, composing awareness) are explicitly NOT here.

What ships (backend — pushed; frontend — in progress)

  • Derived single-writer lease per claude sid: running executor → launch-time pane binding + synchronous probe (tmux + /proc --resume cmdline evidence) → free; per-session critical sections; the 2s poller cache is never authority. DB/probe errors fail CLOSED (flips the previous fail-open sid guard, unwrap_or(false) → withhold-on-error).
  • UI-send-while-CLI-holds-lease ⇒ paste into the live TUI through the existing paste plumbing, upgraded to a durable delivery state machine (queued→pasting→pasted→imported): imported is acknowledged in the same SQLite transaction that imports the matching native user record (prompt equality + sid + time-window matcher, executor-linked records excluded). Timeout/pane-death returns the message to the persisted slot + a visible notice — never dropped, and (post-review hardening) never blind re-pasted: requeue is evidence-conditioned (pane binding dead/replaced, or 15-min hard cap), auto-re-paste is suppressed while the original pane lives, and a late ack binds a requeued row straight to imported (blocking duplicate dispatch).
  • Durable DB-backed queue slot (session_queued_messages) replaces the in-memory DashMap (survives restarts; consumed via on_executor_finished + a lease-aware drain loop). Explicit replace contract: enqueue over an occupied slot without replace: true ⇒ 409 carrying the queued message's text/source; in-flight deliveries are never silently replaced.
  • CLI-attach-while-executor-runs (F3): sid withheld fail-closed; the pane bootstrap prints "agent busy in UI — this pane will resume the conversation when it finishes" and polls a server-owned resume-ready file (UUID-validated, TTL-guarded), then execs --resume <sid> — no more silent --continue || fresh fork.
  • Launch-time pane bindings (cli_pane_bindings, cli-resume/cli-fresh) + fenced per-workspace spawn reservations (workspace_spawn_reservations, TTL) close the spawn-visibility TOCTOU; §4 cli-fresh auto-bind (new sid file + only-live-pane evidence) with quarantine as the unchanged fallback.
  • Foreign-writer detection (F11): native user records with no app-known origin (no executor link, no turn binding, no delivery binding, no live app pane, executor re-checked in-tx) set foreign_writer_seen_at → surfaced in feed health for the banner. Detection only, fail-safe on probe failure.
  • Fork recovery (F2): POST /sessions/{id}/fork-recovery re-sends a dropped branch's user turns through the lease-aware dispatch gate.
  • Dispatch gate API: follow_up now returns DispatchOutcome (started | queued | routed_to_cli | conflict) so the composer can tell the truth about where a message went.
  • Kill-switch: DISABLE_CLI_COLLAB_ROUTING disables paste-routing/auto-dispatch; durable queue, replace contract, fail-closed guards, and detection stay unconditional.

Merge notes

  • Contains 1 DB migration (20260721090000_add_session_queued_messages.sql: session_queued_messages, cli_pane_bindings, workspace_spawn_reservations, + cli_native_records.bound_queued_message_id, claude_session_links.foreign_writer_seen_at) — never-auto-merge class. Head verified non-colliding against main at ce97ca6.
  • Touches dispatch paths (design's own risk rating for Phase 2: medium). DRAFT until the evidence bar below is fully met.

Evidence

Backend unit/integration (DONE) — 555 tests green across the workspace (verified by the lane driver, not just the executor), including: closed-DB-pool fail-closed lease test; scoped-reservation lifecycle observed via recording dispatcher (held during dispatch, released after, released+requeued on dispatcher failure); paste-ack atomicity proven with an injected mid-transaction ABORT trigger (ack rolls back with the failed import); matcher window/exclusion bounds; evidence-conditioned requeue suite (long live paste survives past the old timeout with zero re-pastes; dead-pane requeues with notice; late ack imports the requeued slot and blocks duplicate claim; 15-min hard cap); foreign-writer fail-safe matrix; cli-fresh auto-bind vs quarantine; busy-notice resume-ready file lifecycle; Phase 1 read-only fixture + T4 canary stayed green.
Frontend tests run locally via npx vitest run (tsconfig excludes *.test.ts from CI by repo convention).

Live e2e (DONE) — scratch instance (dev_assets/ inside this worktree, scratch tmux socket bc-seamp2-e2e), real backend, real installed claude CLI, real Anthropic API calls, two-browser + raw-terminal-writer methodology matching Phase 1's:

  • Row 1 (executor running ⇒ durable queue): genuine headless execution_process dispatched (status=running, real CodingAgentInitialRequest); a second send while it ran returned outcome=queued with a real DB-backed row; replace-without-flag correctly 409s showing the queued text+source; the row auto-drained and dispatched the instant the executor freed up.
  • Row 2 (CLI idle ⇒ paste + ack to imported): UI send while a real CLI pane sat idle produced the exact contract toast ("Sent to CLI — waiting for it to appear in the conversation"); the pane screenshot shows the text pasted AND auto-submitted with zero manual keystrokes; claude answered inline; the full pasting→pasted→imported cycle completed and the queue returned to empty.
  • Row 3 (CLI mid-turn ⇒ TUI-native queuing) — not isolated as its own test. The general paste mechanism is proven multiple times over (rows 2/5/crash-recovery); the specific "claude actively generating when the paste lands" sub-case was not separately captured. Deferred (owner-approved).
  • Row 4 (CLI attach during executor ⇒ busy-notice): attaching a CLI terminal while a genuine executor was running produced the exact contract text verbatim ("agent busy in UI — this pane will resume the conversation when it finishes"), and no silent --continue/fresh fork occurred. A real bug was found live: after the blocking executor genuinely finished, the pane never auto-resumed (polled 60+ seconds, no resume-ready signal). Root cause (confirmed, not guessed): a no-repository-change coding-agent completion took a "skip cleanup" branch in container.rs that bypassed the collaboration finish hook entirely (fixed in 96bee803). Fix hardened further with a periodic drain-loop reconciliation (reconcile_waiting_panes, cli_collab.rs) that self-heals any missed/late finish-hook call by scanning active pane bindings against completed-writer evidence (fixed in dc7917d4), plus error propagation on the resume-signal write path (previously silent-failure-prone) with retry. Verified two ways: (1) regression-test discipline — manually reverted just the reconcile_waiting_panes call, watched drain_recovers_busy_resume_pane_when_finish_hook_was_missed go genuinely red (left: [] vs the expected signal), restored it, watched it go green again; (2) live re-verification against the exact original stuck pane — rebuilt the binary, restarted the backend cleanly, found the SAME pane that had been frozen on the busy-notice text for 30+ minutes now showing a live, resumed claude conversation, and confirmed it was genuinely interactive (not just stale text) by sending it a fresh command and getting a real response.
  • Row 5 (simultaneous sends ⇒ one winner, visible loser path): two follow-ups fired at literally the same instant (parallel requests) against the same session both resolved against the exact same DB-backed queued-message id — the per-session critical section serialized them into one row, never a split/duplicate state. Winner got routed_to_cli (pasted); loser got conflict showing the winner's exact text and source.
  • Row 6 / F11 (raw-terminal writer ⇒ banner, detection only) — exercised, not isolated; no gap confirmed. Ran claude -p --resume <sid> from a plain terminal, completely outside the app, against a session whose app-attached CLI pane's claude process was still alive (never explicitly detached/killed). The write landed and imported correctly (content visible, correct attribution) — the ingester's read/import path is writer-agnostic as designed. claude_session_links.foreign_writer_seen_at stayed NULL and no banner appeared; the actual gating logic (app_pane_absent = !(probe_failed || (pane_session_exists && agent_running == true)), cli_native_record.rs:~574-600 / claude_transcript_ingest.rs:~761-762) means this is CORRECT behavior for this test: a write landing while the app's own pane has a live agent is definitionally ambiguous (could be that very pane), so the classifier rightly does not flag it. F11's actual target case — a raw write to a session with NO live app agent — was not isolated in this session, so no gap is confirmed either way. My first pass at this drew the wrong conclusion (guessed the gate checked binding-row existence rather than live-agent state) and was corrected before being written here. Follow-up: a dedicated live test with the app-side agent genuinely stopped before the raw write.
  • Replace contract (409 + confirm showing text/source): proven as part of row 1/row 5 above — error_data carries {outcome:"conflict", status:{...queued text, source...}} exactly per contract.
  • Kill server between paste and ack ⇒ recovered from the persisted queue: killed the backend the instant a paste API response landed (pasted_at set, acked_at null). Backend stayed completely down for 30 seconds while claude answered unsupervised in the live tmux pane. On restart, startup reconciliation correctly discovered and bound the native record (acked_at lands exactly at the restart moment) — full pasted→imported cycle survived a genuine mid-flight crash, message present in the transcript, zero duplicate dispatch.
  • T4-fork-unproducible through app surfaces (DAG stays single-leaf): built a DAG analyzer, validated it against the design doc's own known-forked evidence transcript (correctly finds the documented fork, exact matching parent uuid e647b0e3…). Ran it against a real session that went through three different writers (CLI-mode creation, a UI-send routed via paste while the CLI pane was genuinely alive — the precise T4 collision shape, and a raw external write): zero forks, one root, one leaf — the app-routed paths (paste, executor dispatch, racing sends) provably do not fork. Nuance recorded: a later fork DID appear once a raw-terminal write (row 6 above) was followed by continued app-routed use of the same pane — confirming, not contradicting, the design's explicit scope boundary that raw-terminal writers bypass the app-side lease entirely (§6) and are a detection-only case (F11).
  • Council round (systems-architect + data-integrity personas, cross-engine) + /simplify (4 angles) + deep code review (10 angles) + a full RE-gauntlet after the fix stack — done; findings and their fixes summarized above.
  • Full gates green on the final tree: cargo fmt, CI-exact clippy -D warnings, cargo test --workspace (583 passed / 0 failed), prepare-db, generate-types:check, and the full frontend mirror (local-web lint+format+build, remote-web, ui, web-core, i18n, unused-i18n, legacy-paths).
  • Busy-notice live proof re-verified after the container.rs restructuring: attached a CLI pane during a genuine 75s executor run (busy notice shown), executor completed, pane auto-resumed immediately into a live session showing the run's own result, and answered a fresh command sent to it.

Known limitations (deliberate, tracked for Phase 2.1)

  • Other coding-agent entry points bypass the CLI lease. start_review (crates/server/src/routes/sessions/review.rs) and the PR-description auto-follow-up (crates/server/src/routes/workspaces/pr.rs) start a coding agent — including resuming the latest Claude session id — without consulting the writer lease or spawn reservation. A live CLI owning sid X plus one of these starting --resume X can still fork the conversation. This is pre-existing, not a regression from this PR: git diff origin/main...HEAD touches neither file, and their last modifications predate this branch. Phase 2's scope (§8) was the lease on follow-up dispatch + terminal attach; retrofitting these surfaces is Phase 2.1.
  • Hardening deferred (Phase 2.1): the spawn reservation's fence is not re-validated at the point of use (an expired holder can still perform its side effect) and the reservation leaks for its 15s TTL if a terminal WebSocket upgrade aborts; the busy-wait "waiting for executor" intent is not durable, so an attach that races a completion can miss the resume signal and rely on the periodic reconciler. Neither strands data under normal operation.
  • Resume-handoff observability: whether a waiting pane has been signalled lives in memory plus a short-lived dotfile, so a wedged handoff is not queryable from the DB. A resume_signal_attempts/last_signaled_at column or a "panes awaiting resume" gauge would make it diagnosable.
  • Abandoned in-process claim (see the per-process design note above): if a dispatch task panics or is cancelled between claiming a row and reaching mark_consumed/requeue, the row keeps that still-alive process's claim owner and stays protected from reconcile until the process restarts (a new owner uuid on restart requeues it normally — no permanent wedge, no data loss, no duplicate). This is a deliberate risk trade, not an oversight: (1) it's a liveness issue, not a correctness one — the message is preserved and never duplicated, worst case is delayed-until-restart; (2) it requires a panic/cancellation specifically, since the normal failure path (dispatch_executor_locked's Err branch) already requeues explicitly; (3) the reconcile/claim-ownership clause has already been rewritten three times across this review, and that clause is precisely where the last two real defects were found — a fourth edit to close a liveness-only edge case was judged higher-risk than the edge case itself.

Post-review fix stack (rounds 2-3) — read this before reviewing the diff

A full review gauntlet (council + /simplify + a 10-angle deep review) after the initial implementation found a P0 and six data-loss/correctness bugs that the live e2e had NOT caught. All are fixed, each with a regression test that was individually verified to fail when its fix is reverted (see "Revert-check discipline" below). The two most severe, for reviewer attention:

  • FIX A — d7eceafb (+ real test fa1ecd77): the writer probe fabricated ConfirmedResume(expected) purely from DB agreement (expected_sid == binding.claude_session_id) without checking the live process's actual --resume arg. That inverts the design's own authority order (§6: live re-probe is authority, the poller cache is a hint) and could paste a UI message into the wrong live conversation when a pane was relaunched onto a different sid — the exact T4-class silent misroute this feature exists to prevent. Now sid_evidence trusts live cmdline evidence only; a DB/live disagreement resolves CliAmbiguous → the safe queue path.
  • FIX B — a145c4f3 (executor side) + 2267390e (paste side): the 1s reconcile loop requeued any pasting row older than a 5s grace while holding no session lock, but an executor spawn is allowed 30s and a paste issues ≥3 sequential tmux ops (each bounded 5s). A slow-but-healthy delivery was therefore requeued mid-flight, its mark_consumed/mark_pasted then matched 0 rows and was silently discarded, and the row was re-dispatched later — running the same user prompt twice. Now both delivery kinds take a process-scoped claim (executor_claim_owner / paste_claim_owner) that reconcile respects, a zero-row consume/paste-ack is a hard error instead of a silent no-op, and a legitimately-abandoned pasting row keeps pasted_at + the PASTED_REQUEUE marker so a late ack can still bind it.

Design note — why the claim owner is per-process, not per-dispatch (do not "simplify" this without reading this note): executor_claim_owner/paste_claim_owner are a single Uuid::new_v4() generated once at CliCollabService construction, not a fresh id per individual claim. This is deliberate. reconcile is a global bulk UPDATE across all sessions, but it takes only one active-owner value per call (cli_collab.rs:1182-1183). If the owner were minted per-dispatch instead, a single reconcile tick could only recognize one in-flight claim as "mine" and would requeue every other concurrent in-flight claim in the same process out from under it — reintroducing the exact duplicate-submit bug this column exists to close, just with a narrower blast radius. Per-process ownership means every claim this process is actively holding is protected by the same comparison simultaneously, no matter how many sessions are dispatching at once. The tradeoff this accepts (see "Known limitations" below) is that a claim abandoned by a panic/cancellation within a still-alive process stays protected — i.e. un-recoverable — until that process restarts, rather than being individually reclaimable.

Also fixed: destructive retry (a 409 conflict was swallowed after the git reset had already run, silently dropping the prompt while the UI reported success — 5dcb0a88; retry also lost its transcript truncation, restored + threaded through d83a5ea5); a killed/failed agent still auto-running its queued follow-up (5945c87a); queue lost-updates from deciding success by state re-read instead of rows_affected, plus routes that bypassed the per-session lock (6125487e); and the finish hook being scattered across multiple completion branches that each had to remember to call it — collapsed to one unconditional idempotent call with a shared writer predicate (bf6418bb, af398038).

Revert-check discipline (how these tests were validated)

Every fix's regression test was verified to actually bite: disable the fix mechanism, confirm the test goes red, restore, confirm green. This caught two tests that passed both ways (a correct fix with a hollow guard — one tested an extracted helper that bypassed the real call site, the other used a fake probe so the production type never ran); both were replaced with tests that exercise the real path.
Technique note for sqlx-cached queries: you cannot edit the SQL text of a sqlx::query! to disable a protective branch — the offline cache won't compile the modified query. Instead shadow the bound parameter (e.g. let active_executor_claim_owner: Option<&str> = None;), which makes that protective branch always-match and reproduces the pre-fix behavior exactly, without touching the cached query. This isolates precisely one mechanism per check.

What the gauntlet checked and found SOUND (not only what it found broken)

The paste-ack matcher is genuinely single-transaction (candidate select → native-record insert → imported transition → outbox → cursor advance all inside one caller-committed transaction), with ack-wins-before-age ordering; its bind order, 15-min/-5s window and recursive-CTE are correct. No std::sync::Mutex is held across an .await in production paths. The single-active-slot and single-ack invariants are enforced by real partial unique indexes, not app convention. Foreign keys are ON at runtime, so the migrations' CASCADE/SET NULL clauses are effective. Spawn reservations are race-safe via PK + fence + TTL. The DispatchOutcome/QueueStatus unions are exhaustively handled on both sides.

Review rounds (so far)

  • Lane-driver review of the executor's stack found one P1 — unconditional 30s 'pasted' requeue vs §6 row 3's mid-turn native queuing (duplicate-injection risk) — fixed in 5899881/86402187/6cf5c4c0 (evidence-conditioned requeue, no-auto-re-paste-while-pane-alive, late-ack binding) with the timeout tests transformed to the new contract.
  • Busy-wait bootstrap shell audit: clean (no workspace-path interpolation; quoted asset-dir path; sid UUID-validated at write; $bc_sid double-quoted; numerics sanitized; guarded rm; TTL + future-timestamp checks).
  • Live e2e found one real, confirmed gap beyond the unit-test surface (row 4 auto-resume hang — see checklist for status). A second suspected gap (row 6/F11) was investigated and the initial root-cause guess was WRONG on inspection of the actual gating code — corrected before being written here; no F11 gap is actually confirmed, see checklist for what was and wasn't isolated.
  • Full council/simplify/deep-review/sweep gauntlet: pending.

Translation provenance (read before merging)

This PR adds 28 new i18n keys (queue/delivery states, replace-confirm dialog, foreign-writer banner, fork-recovery toasts) and needed them in all 6 non-English locales (es/fr/ja/ko/zh-Hans/zh-Hant) to pass check-i18n.sh. Those ~168 non-English strings are machine-generated (Codex) and have NOT been reviewed by a native speaker of any of the 6 languages. Verification performed so far is mechanical only: check-i18n.sh/check-unused-i18n-keys.mjs pass (key parity, no dupes, no unused keys), and a programmatic diff confirmed zero strings are byte-identical to their English source (no lazy English-as-placeholder leakage) in any locale. That is necessary but not sufficient — it proves the strings are translations, not that they are correct or natural ones.

  • Highest-risk for a native-speaker pass: conversation.queue.replaceTitle / replaceUiMessage / replaceRecoveryMessage (the replace-confirmation dialog) — this is the one safety-relevant string set; a confusing translation here could lead someone to overwrite the wrong queued message.
  • Also worth a look: conversation.queue.queued/pasting/pasted (novel state-machine concept with no prior art elsewhere in the app) and conversation.foreignWriter.message (an unusual English idiom — "being edited outside the app" — worth checking it reads naturally rather than just literally in each language).
  • Not a risk: "lease" (the Design C term for the writer-ownership concept) is never surfaced in user-facing copy — it only appears in code/docs — so there is nothing to mistranslate there.
  • English (en/*.json) is authoritative and unaffected; config.ts defines fallbackLng, so any future correction to a non-English string is a pure content fix with no code risk.

Deviations (recorded)

  1. Commit 9b2ea03 is deliberately cross-cutting: the edit set was authored as one interlocked change (the ClaudeTranscriptIngest::spawn signature ripples db→services→local-deployment→server); it was salvaged intact from an executor run killed by a harness restart after it had fully compiled. A granular split would have produced non-compiling intermediate commits.
  2. The §6 "pasted → submitted → imported" states collapse to pasted → imported in the schema — the ingester ack IS the import commit; UI copy keeps the doc's "not yet submitted" wording.
  3. The spec's initial unconditional 30s ack-timeout requeue was superseded during lane review by the evidence-conditioned contract above (doc language "returns to a persisted queue slot + a notice" is preserved; what changed is that retries require delivery-evidence loss).
  4. CodeRabbit CLI unusable non-interactively on this fork → one lane-owned read-only Codex sweep substitutes (same as Phase 1), pending in the checklist.

…h bindings, gated dispatch

Cross-cutting completion of the Phase 2 backend: same-transaction paste-ack
matcher (NativeImportContext + bound_queued_message_id), foreign-writer
detection, cli-fresh auto-bind with quarantine fallback, writer-probe and
paste-transport impls, busy-wait bootstrap (resume-ready file + TTL),
fail-closed sid guard, launch-time pane bindings + spawn reservations, and
follow_up routed through the dispatch gate (DispatchOutcome API).

Known gaps closed in follow-up commits: ingest-ack test suite (helpers staged),
cli_collab unit tests, clippy strictness, shared/types.ts regeneration.
@miguelrisero
miguelrisero marked this pull request as ready for review July 22, 2026 02:42
@miguelrisero

Copy link
Copy Markdown
Owner Author

Reviewer handoff (chief run bc-lanes-2026-07-19) — READY, NOT AUTO-MERGED

What it does: Phase 2 of the owner-approved CLI↔UI design (#38) — the collaboration write-side. A UI message sent while someone is on the CLI is pasted into their live pane and auto-submitted (one writer, both people see the same turn); messages sent during a run queue durably and auto-drain; sending over an occupied slot returns an explicit conflict showing whose message and what text; attaching the CLI mid-run shows a busy notice and auto-resumes when the run finishes.

Why this is ready-for-review rather than merged

The boss (orchestrator) holds the merge deliberately, despite standing merge authorization, because: it carries 3 DB migrations, it modifies dispatch paths that touch real work, and it is by a wide margin the highest-risk change of this run. One word from the owner merges it.

Live-proven (real backend, real Claude API, real tmux)

  • Paste-into-live-pane with auto-submit; full pasting→pasted→imported cycle
  • Durable queue + auto-drain after the blocking run finishes; explicit 409 replace-contract
  • Crash recovery: server killed the instant a paste landed, down 30s while Claude answered unsupervised — on restart, reconciliation bound the record correctly, no duplicate dispatch
  • T4 fork provably not producible through app surfaces (three writers, 20 minutes, one root, one leaf — verified with a DAG analyzer that was itself validated against the design doc's known-fork evidence)
  • Simultaneous senders serialize into one queue row — winner routes, loser gets the conflict
  • Busy-notice auto-resume — re-verified live four consecutive times across four restructurings of the same code

Four rounds of review found and fixed 8 real defects, including two severe

  1. P0 — wrong-conversation paste. The lease upgraded to "confirmed" from DB agreement alone, without checking the live process actually carried that session. A relaunched pane with a stale binding would route a UI message into the wrong live conversation. Fixed (d7eceafb + real probe-level test fa1ecd77); live cmdline is now sole authority.
  2. P1 — two agents, one worktree. Orphan cleanup marks stale runs failed without any liveness check (pre-existing), and this PR newly wired that to release the lease → auto-redispatch. If the original process was still alive, two coding agents would mutate the same git worktree. Root cause was narrower than it looked: the abnormal-completion hold was being laundered away by the requeue. Fixed (c088154f) by stamping the hold marker in the same UPDATE, biased toward over-holding — "a false hold costs an explicit resend, while a missed hold can run two coding agents against one worktree."
    Plus: duplicate executor dispatch (5s-vs-30s race), destructive retry that git-reset and silently dropped the prompt, killed agents still running queued follow-ups, queue lost-updates, a hang-forever busy notice, and a false-delivery timing bug.

Verification discipline

Every fix was verified by disabling it and confirming its test goes red — 11 revert-checks total. This caught two hollow guards (correct fixes whose tests bypassed the real call site) that would otherwise have passed forever. Two revert-check techniques for sqlx-cached queries are documented in the PR body for future use.

Known limitations (documented, tracked as Phase 2.1)

Gate-bypass on start_review/PR-auto-follow-up (verified pre-existing — empty diff on those files); reservation TTL and busy-wait hardening; abandoned in-process claim (liveness only, self-clears on restart — deliberate risk trade against a 5th edit to the most-churned clause); two collaboration matrix rows exercised but not isolated.

CI green on 3864881b. Boss verification passed: all checks green, no junk files, 37 commits under the correct identity with zero AI trailers, and personal re-reads of both severe fixes.

@miguelrisero
miguelrisero merged commit 0fbc096 into main Jul 22, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant