Skip to content

feat(turnover): skip registry-known-exhausted subs, and leave a durable handoff when a turn is cut - #813

Merged
Kyzcreig merged 6 commits into
mainfrom
feat/turnover-hardening
Sep 25, 2026
Merged

Kyzcreig merged 6 commits into
mainfrom
feat/turnover-hardening

Conversation

@Kyzcreig

Copy link
Copy Markdown
Collaborator

Why

The 2026-09-21 #apollo pattern, three times in one night: the primary sub hits its 5h/7d cap mid-turn, the gateway walks the fallback chain (claude-bpx-17 → apx-1 → … → apx-15, most also exhausted), spends ~60 s emitting "Rate limited — switching to fallback provider..." ×10, then dies. The next session reconstructs state from Discord scrollback — 15-25 min per turnover — and the work in flight at the cut is silently lost.

Two independent defects, one PR each half.

(A) The walker tries subs the usage registry already knows are dead

agent/quota_registry_gate.py reads the published usage snapshot (var/usage-portal/site/usage.json) and prunes, in one pass before any client is constructed, every chain entry whose 5h or 7d window is measurably rejected with a reset beyond a 5-minute horizon. The loop's quota-failover site emits one skipping N exhausted subs line instead of N. When the whole tail is pruned it fails fast naming the soonest reset.

Conservative by construction — missing file, corrupt JSON, unknown provider, stale observation (>6 h), a rejection with no reset time, and scoped per-model (Fable) allowances all fail OPEN to the historical walk. Only a quota reason (rate_limit / billing / upstream_rate_limit) triggers the gate; a transport timeout says nothing about quota and walks as before.

Measured against the live registry, 2026-09-21 ~02:10 PT

registry: 21 claude accounts published

BEFORE: 21 providers attempted, 21 "switching to fallback provider..." lines
AFTER:   4 providers attempted, 1 line
         ("⚠️ Rate limited — skipping 17 exhausted subs (quota registry) …")

requests avoided: 17
live config.yaml chain (5 entries): 2 pruned, 3 survive
  -> ['claude-apx-14', 'claude-apx-16', 'openai-codex']

Per-sub verdicts spot-checked against the raw usage.json windows (e.g. apx-10 five_hour 102.0 rejected 2.1h → SKIP; apx-14 five_hour 90.0 allowed_warning → ELIGIBLE).

That measurement found a real bug the unit tests could not see. _coerce_epoch parsed only numeric reset values; the registry publishes ISO-8601 Z strings, so against the live payload the first implementation pruned nothing — a vacuous pass, because the tests used epoch floats. Fixed, with ISO tests added.

(B) No durable handoff at the cut

agent/turn_handoff.py persists the in-flight turn state to $HERMES_HOME/state/turn-handoff/<session_key>.json: last user message id + text, the assistant's in-progress text, every tool call issued this turn with its result truncated to 500 chars and an explicit flag on the one that never completed (the most valuable single fact), and the open todo items.

  • Written from the conversation loop's terminal provider-failure return, which appends a 3-line notice.
  • Consumed by the turn prologue into the next turn, via the existing plugin/gateway user-context channel (so the ephemeral system prompt stays byte-stable).
  • Consume-once; expires after 24 h; corrupt and expired files are deleted rather than retried forever.
  • Session keys are sanitized + digest-disambiguated, so a key with separators or traversal cannot escape the handoff root.
  • Every entry point swallows its own failures — a dying turn must not die twice.

/resume-handoff is registered in the command registry (alias resume_handoff) and dispatched in gateway/run.py, so the notice names a command the dispatcher actually knows.

Notes for the reviewer

  • /resume-handoff is listed in _SLACK_VIA_HERMES_ONLY. Slack's 50-slash cap would otherwise have evicted /usage — caught by tests/hermes_cli/test_commands.py::TestSlackNativeSlashes::test_telegram_parity, and confirmed as mine by a clean-base control run (green on base, red with my registry entry).
  • No live tree was deployed or synced.

Verification

scripts/run_tests.sh, sandboxed HOME, 216 passed / 0 failed, rc=0:

=== Summary: 13 files, 216 tests passed, 0 failed (100% complete) in 12.3s ===

New: test_quota_registry_gate (27), test_quota_gate_fallback_wiring (9), test_turn_handoff (28), test_turn_handoff_wiring (9), test_resume_handoff_command (10). Neighbours re-run: test_commands, test_turn_context, test_turn_context_overflow_warning, test_conversation_loop_interpreter_shutdown, test_lazy_command_exports, test_fallback_announce, test_quota_window_cooldown, test_fallback_reason_threading.

Every new module was RED first: ModuleNotFoundError / ImportError before implementation, and the ISO-8601 pair failed for the right reason before the parser fix.

@Kyzcreig

Copy link
Copy Markdown
Collaborator Author

Review round 1 addressed in 430e7b0.

  1. Recovered subscriptions return on later turns
  • The configured _fallback_chain is no longer destructively pruned.
  • Registry-known exhausted providers are memoized in _quota_gate_skipped_providers and skipped locally before client construction.
  • build_turn_context() clears every snapshot-derived gate field before primary restoration on each turn.
  • Added a two-turn regression: apx-1 is exhausted on turn 1 (skipped for apx-2), healthy on turn 2, and is selected again. The source chain remains unchanged.
  • RED proof: restoring the destructive mutation makes the test fail because apx-1 disappears from the cached agent.
  1. Fail-fast message and one-line cascade are now live consumers
  • The terminal failure path calls append_quota_exhaustion_message(); an all-dead tail now surfaces the soonest resets in 6h in final_response.
  • rate_limited_status_line() emits at most once per turn. The new emitted-sequence regression drives a 21-entry chain (17 dead, 4 eligible) across all surviving failures and asserts the exact platform-status list contains one line total.
  • Removed the dead _quota_gate_summary_line / _quota_gate_skipped_count attributes.
  • RED proofs: removing the dedupe yields 5 emitted lines; removing the terminal consumer drops the reset text and fails the test.
  1. Windows footguns fixed
  • Added explicit UTF-8 to the one os.fdopen() and three Path.read_text() sites.
  • python3 scripts/check-windows-footguns.py --all -> No Windows footguns found (1214 files).

Verification:

  • 14 focused files: 246 passed, 0 failed via scripts/run_tests.sh with sandboxed HOME.
  • Ruff: all changed Python files clean.
  • git diff --check: clean.
  • Live registry re-measurement: 21 Claude accounts, 17 skipped locally, 4 eligible, 17 network attempts avoided, 1 emitted status line.

No live tree deployed or synced.

@Kyzcreig

Copy link
Copy Markdown
Collaborator Author

🔁 re-enqueue for FleetReview (Apollo): head's terminal record was stamped ERROR by a router restart (release cut 20260921T104203Z / sibling cuts 10:25-10:32Z), not by a review verdict; close/reopen re-submits the unchanged head. No code change.

@Kyzcreig Kyzcreig closed this Sep 21, 2026
@Kyzcreig Kyzcreig reopened this Sep 21, 2026
@Kyzcreig

Copy link
Copy Markdown
Collaborator Author

Review round 2 rework pushed at 4075faaaeb44bdc2eb14100e6c5e19bf14e5c2e9.

/resume-handoff now previews the saved payload without consuming it; the next real model-turn seam consumes and injects the original request, assistant progress, tool calls, and todos exactly once. The regression test drives the actual GatewaySlashCommandsMixin._handle_resume_handoff_command handler, then consume_handoff_context twice.

RED before implementation: next-turn context was empty after command dispatch. GREEN after implementation: focused feature test 10/10; broader turnover/turn-context/command suite 174/174. Ruff, Windows footgun scan, and git diff --check pass. No deploy performed.

@Kyzcreig

Copy link
Copy Markdown
Collaborator Author

Round-3 rework pushed at df71280579dde2839ce23550e4822b21e6c70407.

The handoff now reads the runtime-shaped _current_streamed_assistant_text, strips think blocks through the agent helper, merges it with already-materialized assistant rows without repeating overlapping text, and persists early provider cuts when only the original user request and/or open todos exist.

TDD evidence: the four new cases first failed at 4075faaaeb (no file/notice for user + partial stream; streamed suffix absent beside a materialized row; user-only early cut returned None). They now pass, including capture -> consume-on-next-turn -> consume-once round trip with original request, visible partial stream, and open todo.

Verification:

  • canonical focused suite: 8 files, 125 tests passed, 0 failed
  • Ruff: All checks passed!
  • Windows footguns: No Windows footguns found (1214 files)
  • git diff --check: clean

No live tree deployed or synced.

@Kyzcreig

Copy link
Copy Markdown
Collaborator Author

Round-4 rework @ addf4b6c0aeef6f6ecc57677dfb614332e670d9c.

Finding 4 (blocking) fixed — the gate was inert on 8 of 9 gateways. default_snapshot_path() now resolves through hermes_constants.get_default_hermes_root() instead of get_hermes_home(). Measured with the real resolver, one fresh interpreter per home:

BEFORE                                          AFTER
~/.hermes                    21 accounts        21 accounts
~/.hermes/profiles/aegis      0 accounts        21 accounts
~/.hermes/profiles/argus      0 accounts        21 accounts
~/.hermes/profiles/daedalus-opus  0 accounts    21 accounts
/opt/data/profiles/coder  -> /opt/data/profiles/coder/var/...  ->  /opt/data/var/...  (Docker rule)

Same chain pruned identically under both homes now: 21 entries -> 16 skipped / 5 eligible under the root home AND under profiles/aegis (was 0 skipped under the profile home).

Three regressions added, all RED first: profile-shaped home resolves to the root snapshot; the non-profile layout resolves byte-identically to today; one chain prunes identically under both homes. Fail-open on a genuinely missing file is pinned separately and unchanged.

Class-sweep honored: turn_handoff.py state/turn-handoff is per-profile state and was left alone, per the review.

Non-blocking item closed rather than deferred. prune_expired_handoffs() now has a production caller: the write path sweeps after a successful write, so an abandoned session_key no longer leaks its file past the 24h TTL. Guarded — a failing sweep can never cost a handoff that was already written (pinned by a test that makes the sweep raise).

Verification: scripts/run_tests.sh sandboxed HOME, 7 files / 177 passed, 0 failed; ruff All checks passed!; ✓ No Windows footguns found (1214 files); git diff --check clean. No live tree deployed or synced.

Kyzcreig and others added 6 commits September 25, 2026 04:55
…ing it

A mid-turn 5h/7d cap sent the walker through the whole fallback chain
(claude-apx-1..15), paying a request round-trip and one "Rate limited —
switching to fallback provider..." status line per entry — ~60s and ten
lines to discover what the usage registry already had on disk.

agent/quota_registry_gate.py reads the published usage snapshot
(var/usage-portal/site/usage.json) and prunes, in ONE pass before any
client is constructed, every entry whose 5h or 7d window is measurably
rejected with a reset beyond a 5-minute horizon. The loop's quota-failover
site emits one "skipping N exhausted subs" line instead of N.

Conservative by construction — missing file, corrupt JSON, unknown
provider, stale observation, a rejection with no reset time, and scoped
per-model (Fable) allowances all fail OPEN to the historical walk.

Verified: 34 tests in tests/agent/test_quota_registry_gate.py (25, truth
table + loader) and tests/agent/test_quota_gate_fallback_wiring.py (9,
live try_activate_fallback seam) pass under scripts/run_tests.sh.
…quota gate

(B) A turn cut by an unrecoverable provider failure now leaves a
machine-readable handoff instead of a bare "Operation interrupted".

agent/turn_handoff.py persists the in-flight state at the cut —
$HERMES_HOME/state/turn-handoff/<session_key>.json holding the last user
message id + text, the assistant's in-progress text, every tool call
issued this turn with its result truncated to 500 chars (and an explicit
flag on the call that never completed), and the open todo items. The
conversation loop's terminal provider-failure return writes it and
appends a 3-line notice; the turn prologue consumes it into the next
turn via the existing plugin/gateway user-context channel. Handoffs are
consume-once and expire after 24h; corrupt and expired files are deleted
rather than retried forever. Every entry point swallows its own failures
— a dying turn must not die twice.

/resume-handoff is registered in the command registry (alias
resume_handoff) and dispatched in gateway/run.py, so the notice names a
command the dispatcher actually knows. It is listed in
_SLACK_VIA_HERMES_ONLY: Slack's 50-slash cap would otherwise have
evicted /usage, which tests/hermes_cli/test_commands.py caught.

(A, follow-up) _coerce_epoch parsed only numeric reset values. The
published registry uses ISO-8601 Z strings, so against the LIVE payload
the gate pruned NOTHING — a vacuous pass that the unit tests (which used
epoch floats) could not see. Found by measuring, not by testing.

MEASURED against the live registry snapshot, 2026-09-21 ~02:10 PT:
  before: 21 providers attempted, 21 "switching to fallback provider..."
  after:   4 providers attempted, 1 line ("skipping 17 exhausted subs")
  live config.yaml chain (5 entries): 2 pruned, 3 survive
Per-sub verdicts spot-checked against the raw usage.json windows.

Verified: 151 tests green under scripts/run_tests.sh —
test_quota_registry_gate (27), test_quota_gate_fallback_wiring (9),
test_turn_handoff (28), test_turn_handoff_wiring (9),
test_resume_handoff_command (10), plus the neighbour suites
test_commands, test_turn_context, test_turn_context_overflow_warning,
test_conversation_loop_interpreter_shutdown, test_lazy_command_exports,
test_fallback_announce, test_quota_window_cooldown,
test_fallback_reason_threading.
Keep the configured fallback chain immutable, reset registry verdicts at each turn boundary, dedupe quota status messages across the full cascade, and append the soonest reset to terminal failures. Add explicit UTF-8 I/O for handoff state.

Verified: 246 tests across 14 focused files; Windows footgun scan and Ruff clean. Regression tests proved RED when each behavior fix was removed.
Verified command dispatch previews the saved handoff, then the next model-turn seam consumes it exactly once. Focused turnover suite: 88 passed.
Capture the current visible stream, deduplicate materialized overlap, and persist user-only early cuts. Verified 125 focused turnover tests via scripts/run_tests.sh; Ruff and Windows footgun checks pass.
…expired handoffs

The usage system publishes ONE snapshot, at the top-level Hermes root. The
quota gate resolved it off HERMES_HOME, which is <root>/profiles/<name> for
8 of the 9 live gateways, so the gate loaded 0 accounts and degraded to the
historical walk on every specialist. Measured before: root home 21 accounts,
every profile home 0. After: all homes resolve the same file, and the aegis
chain prunes identically (21 entries -> 16 skipped / 5 eligible) under both.

Resolution now goes through hermes_constants.get_default_hermes_root(), which
already implements the <root>/profiles/<p> -> <root> rule including the Docker
/opt/data layout. Fail-open on a genuinely missing file is unchanged. The
sibling join in turn_handoff.py (state/turn-handoff) is per-profile state and
is deliberately left alone.

Also closes the carried-over handoff leak: prune_expired_handoffs() had no
production caller, so the 24h TTL only ran for a session that came back. The
write path now sweeps, guarded so a failing sweep can never cost a handoff.

Verified: 7 files / 177 tests green under scripts/run_tests.sh with a
sandboxed HOME; ruff clean; windows-footgun scan clean.
@Kyzcreig
Kyzcreig force-pushed the feat/turnover-hardening branch from addf4b6 to bd89db0 Compare September 25, 2026 12:07
@Kyzcreig

Copy link
Copy Markdown
Collaborator Author

🤖 merged-by: apollo · lane: boil-ocean-aged · gate: BYPASS: FR PAUSED by Ace ruling 2026-09-22 (state/fleetreview-pause-20260922.md); Apollo-reviewed lands via bypass · why: 0/6 commits on main by patch-id; rebased clean onto 7ed45d9 (was 206 behind), diff limited to PR's own 14 files; 97 passed own tests; gateway/cli command-adjacent suites show the same 11 local-env failures on main and PR (no new)

@Kyzcreig
Kyzcreig enabled auto-merge September 25, 2026 12:07
@Kyzcreig
Kyzcreig added this pull request to the merge queue Sep 25, 2026
@Kyzcreig
Kyzcreig removed this pull request from the merge queue due to a manual request Sep 25, 2026
@Kyzcreig
Kyzcreig added this pull request to the merge queue Sep 25, 2026
@Kyzcreig
Kyzcreig removed this pull request from the merge queue due to a manual request Sep 25, 2026
@Kyzcreig
Kyzcreig added this pull request to the merge queue Sep 25, 2026
Merged via the queue into main with commit 49740cd Sep 25, 2026
60 checks passed
@Kyzcreig
Kyzcreig deleted the feat/turnover-hardening branch September 25, 2026 18:48
@Kyzcreig Kyzcreig added the fleetreview:post-merge Ask FleetReview to review this MERGED pull (merge commit vs first parent) label Sep 25, 2026
@ang-prism

ang-prism Bot commented Sep 26, 2026

Copy link
Copy Markdown

FleetReview

FleetReview's daily member-call budget is spent (600/600 for 2026-09-26 UTC); review skipped.


FleetReview · reviewKind: skipped-budget

ang-fleet-workers Bot added a commit that referenced this pull request Sep 27, 2026
…s (t_9c9e757c)

FleetReview retro-backfill 2026-09-27, class C4. Each finding re-verified at
5a9d284; one RED-on-base / GREEN test per confirmed instance.

- #813 agent/quota_registry_gate.py: missing/unparseable observed_at now fails
  open (docstring contract), no longer skips a working fallback.
- #1017 cron/lifecycle_guard.py: mask allowlist refuses module callables passed
  as values (json.dumps(p, default=subprocess.run), sorted(key=...)).
- #1019 agent/lsp/manager.py: slot-dir OSError in _has_capacity -> run without
  LSP instead of raising out of enabled_for()/write_file.
- #1026 cron/scheduler.py: owner-deadman exemption scoped to the host it owns;
  a note naming only another DOWN host is gated.
- #1229 scripts/ci/live_comment.py: comment lookup/update network errors no
  longer kill the poller; a failed post is retried next poll.
- #1230 plugins_cmd.py: pinned-plugin remedy shell-quotes the recorded source
  (CLI + dashboard).
- #1238 tools/mixture_of_agents_tool.py: reference responses move from the
  aggregator system message to a tagged data block in the user message.

Verified: test-gate narrow pytest; new tests 13 RED on base, all GREEN with fix;
neighbouring suites (lifecycle_guard x4, host_down_gate, quota wiring,
plugins_cmd, fallback_policy, fork toolsets) pass.
ang-fleet-workers Bot added a commit that referenced this pull request Sep 27, 2026
…fill

Class fix for backfill section C5 (race-atomicity), 20 confirmed instances:
- kanban_db: home-session ownership re-checked inside the mutator's first
  write txn (TOCTOU, #951); backfill_unhomed stamp+comment in one txn (#987)
- turn_handoff: consume claims via atomic rename; prune/expired drop only
  deletes unchanged content (#813 prune race, lost handoff)
- lcm lifecycle_state: prune DELETE conditioned on the judged session ids (#966)
- checkout_admission: reject negative per-entry work counts (#1035)
- provider_seam: materialize publish inputs before the retryable build;
  models: SeamCollision no longer latches discovery (#1072)
- gateway/session: turn-marker publish gated on revision (#1043 x2), clear
  override keeps a newer concurrent set + its pin, off-lock prune detects an
  in-place heal; run.py stuck-loop suspend under the store lock; Telegram HWM
  tracker serialized across worker threads (#1043)

Verified: 13 new tests red on base, green on head; neighbouring gateway and
kanban suites green (1 pre-existing env-dependent failure, same on base).

(cherry picked from commit 0ccb18e)
ang-fleet-workers Bot added a commit that referenced this pull request Sep 27, 2026
…s (t_9c9e757c)

FleetReview retro-backfill 2026-09-27, class C4. Each finding re-verified at
5a9d284; one RED-on-base / GREEN test per confirmed instance.

- #813 agent/quota_registry_gate.py: missing/unparseable observed_at now fails
  open (docstring contract), no longer skips a working fallback.
- #1017 cron/lifecycle_guard.py: superseded by #1348 (6662bbd) on main; this
  slice's 5 callback cases pass against it, so the edit was dropped on rebase.
- #1019 agent/lsp/manager.py: slot-dir OSError in _has_capacity -> run without
  LSP instead of raising out of enabled_for()/write_file.
- #1026 cron/scheduler.py: owner-deadman exemption scoped to the host it owns;
  a note naming only another DOWN host is gated.
- #1229 scripts/ci/live_comment.py: comment lookup/update network errors no
  longer kill the poller; a failed post is retried next poll.
- #1230 plugins_cmd.py: pinned-plugin remedy shell-quotes the recorded source
  (CLI + dashboard).
- #1238 tools/mixture_of_agents_tool.py: reference responses move from the
  aggregator system message to a tagged data block in the user message.

Verified: test-gate narrow pytest; new tests 13 RED on base, all GREEN with fix;
neighbouring suites (lifecycle_guard x4, host_down_gate, quota wiring,
plugins_cmd, fallback_policy, fork toolsets) pass.
ang-fleet-workers Bot added a commit that referenced this pull request Sep 27, 2026
…fill

Class fix for backfill section C5 (race-atomicity), 20 confirmed instances:
- kanban_db: home-session ownership re-checked inside the mutator's first
  write txn (TOCTOU, #951); backfill_unhomed stamp+comment in one txn (#987)
- turn_handoff: consume claims via atomic rename; prune/expired drop only
  deletes unchanged content (#813 prune race, lost handoff)
- lcm lifecycle_state: prune DELETE conditioned on the judged session ids (#966)
- checkout_admission: reject negative per-entry work counts (#1035)
- provider_seam: materialize publish inputs before the retryable build;
  models: SeamCollision no longer latches discovery (#1072)
- gateway/session: turn-marker publish gated on revision (#1043 x2), clear
  override keeps a newer concurrent set + its pin, off-lock prune detects an
  in-place heal; run.py stuck-loop suspend under the store lock; Telegram HWM
  tracker serialized across worker threads (#1043)

Verified: 13 new tests red on base, green on head; neighbouring gateway and
kanban suites green (1 pre-existing env-dependent failure, same on base).

(cherry picked from commit 0ccb18e)
Kyzcreig pushed a commit that referenced this pull request Sep 27, 2026
)

* fix(security): Backfill C3 secret/PII exposure class (t_36b0277a)

- tools/tool_wait_watchdog: redact tool args (force + URL creds) before the
  240-char cut; long-wait log lines carried raw commands/tokens (#1012).
- tools/openrouter_client: one client per OpenRouter credential, not per process;
  a multiplexed gateway sent later profiles' MoA prompts under the first profile's
  key (#1238). mixture_of_agents_tool uses the scope-aware key check.
- plugins/kanban-home-cards: redact URL credentials in card text and redact the
  board slug, both injected into model context (#968).
- agent/fallback_events: persisted err_head redacts URL credentials (#1211).
- gateway/run.py: STT INFO line logs size+latency, not the user's words (#1064).
- agent/turn_handoff: tool args/results redacted before /resume-handoff (#813).

Verified: each new test fails on base and passes on head; test_turn_handoff (34),
test_voice_inbound_accounting + test_gateway_foreground_deafness (39),
test_kanban_home_cards + test_fallback_events_ledger (101),
test_secret_scope_tier1_migration (23 passed, 2 skipped).

* test: build fake URL credentials by concatenation (gitleaks generic-api-key) (t_36b0277a)

---------

Co-authored-by: ang-fleet-workers[bot] <333956806+ang-fleet-workers[bot]@users.noreply.github.com>
Kyzcreig pushed a commit that referenced this pull request Sep 27, 2026
…s (t_9c9e757c) (#1353)

FleetReview retro-backfill 2026-09-27, class C4. Each finding re-verified at
5a9d284; one RED-on-base / GREEN test per confirmed instance.

- #813 agent/quota_registry_gate.py: missing/unparseable observed_at now fails
  open (docstring contract), no longer skips a working fallback.
- #1017 cron/lifecycle_guard.py: superseded by #1348 (6662bbd) on main; this
  slice's 5 callback cases pass against it, so the edit was dropped on rebase.
- #1019 agent/lsp/manager.py: slot-dir OSError in _has_capacity -> run without
  LSP instead of raising out of enabled_for()/write_file.
- #1026 cron/scheduler.py: owner-deadman exemption scoped to the host it owns;
  a note naming only another DOWN host is gated.
- #1229 scripts/ci/live_comment.py: comment lookup/update network errors no
  longer kill the poller; a failed post is retried next poll.
- #1230 plugins_cmd.py: pinned-plugin remedy shell-quotes the recorded source
  (CLI + dashboard).
- #1238 tools/mixture_of_agents_tool.py: reference responses move from the
  aggregator system message to a tagged data block in the user message.

Verified: test-gate narrow pytest; new tests 13 RED on base, all GREEN with fix;
neighbouring suites (lifecycle_guard x4, host_down_gate, quota wiring,
plugins_cmd, fallback_policy, fork toolsets) pass.

Co-authored-by: ang-fleet-workers[bot] <333956806+ang-fleet-workers[bot]@users.noreply.github.com>
ang-fleet-workers Bot added a commit that referenced this pull request Sep 27, 2026
…fill

Class fix for backfill section C5 (race-atomicity), 20 confirmed instances:
- kanban_db: home-session ownership re-checked inside the mutator's first
  write txn (TOCTOU, #951); backfill_unhomed stamp+comment in one txn (#987)
- turn_handoff: consume claims via atomic rename; prune/expired drop only
  deletes unchanged content (#813 prune race, lost handoff)
- lcm lifecycle_state: prune DELETE conditioned on the judged session ids (#966)
- checkout_admission: reject negative per-entry work counts (#1035)
- provider_seam: materialize publish inputs before the retryable build;
  models: SeamCollision no longer latches discovery (#1072)
- gateway/session: turn-marker publish gated on revision (#1043 x2), clear
  override keeps a newer concurrent set + its pin, off-lock prune detects an
  in-place heal; run.py stuck-loop suspend under the store lock; Telegram HWM
  tracker serialized across worker threads (#1043)

Verified: 13 new tests red on base, green on head; neighbouring gateway and
kanban suites green (1 pre-existing env-dependent failure, same on base).

(cherry picked from commit 0ccb18e)
ang-fleet-workers Bot added a commit that referenced this pull request Sep 27, 2026
…fill

Class fix for backfill section C5 (race-atomicity), 20 confirmed instances:
- kanban_db: home-session ownership re-checked inside the mutator's first
  write txn (TOCTOU, #951); backfill_unhomed stamp+comment in one txn (#987)
- turn_handoff: consume claims via atomic rename; prune/expired drop only
  deletes unchanged content (#813 prune race, lost handoff)
- lcm lifecycle_state: prune DELETE conditioned on the judged session ids (#966)
- checkout_admission: reject negative per-entry work counts (#1035)
- provider_seam: materialize publish inputs before the retryable build;
  models: SeamCollision no longer latches discovery (#1072)
- gateway/session: turn-marker publish gated on revision (#1043 x2), clear
  override keeps a newer concurrent set + its pin, off-lock prune detects an
  in-place heal; run.py stuck-loop suspend under the store lock; Telegram HWM
  tracker serialized across worker threads (#1043)

Verified: 13 new tests red on base, green on head; neighbouring gateway and
kanban suites green (1 pre-existing env-dependent failure, same on base).

(cherry picked from commit 0ccb18e)
ang-fleet-workers Bot added a commit that referenced this pull request Sep 28, 2026
…fill

Class fix for backfill section C5 (race-atomicity), 20 confirmed instances:
- kanban_db: home-session ownership re-checked inside the mutator's first
  write txn (TOCTOU, #951); backfill_unhomed stamp+comment in one txn (#987)
- turn_handoff: consume claims via atomic rename; prune/expired drop only
  deletes unchanged content (#813 prune race, lost handoff)
- lcm lifecycle_state: prune DELETE conditioned on the judged session ids (#966)
- checkout_admission: reject negative per-entry work counts (#1035)
- provider_seam: materialize publish inputs before the retryable build;
  models: SeamCollision no longer latches discovery (#1072)
- gateway/session: turn-marker publish gated on revision (#1043 x2), clear
  override keeps a newer concurrent set + its pin, off-lock prune detects an
  in-place heal; run.py stuck-loop suspend under the store lock; Telegram HWM
  tracker serialized across worker threads (#1043)

Verified: 13 new tests red on base, green on head; neighbouring gateway and
kanban suites green (1 pre-existing env-dependent failure, same on base).

(cherry picked from commit 0ccb18e)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fleetreview:post-merge Ask FleetReview to review this MERGED pull (merge commit vs first parent)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant