fix(hooks): decouple secretary-spawn carve-out to a members-only join witness (#1023)#1025
Merged
michael-wojcik merged 5 commits intoJun 24, 2026
Conversation
… witness (Synaptic-Labs-AI#1023) Synaptic-Labs-AI#1021's inbox-witness fallback in _team_has_secretary was also consumed by the bootstrap_gate carve-out (binding 5). The inbox is created by TaskUpdate(owner=secretary) before the Agent spawn, so the witness read True prematurely and the carve-out DENIED the canonical secretary spawn — re-deadlocking bootstrap on every fresh CLI session. Add a members[]-only JOIN witness _secretary_in_members() in bootstrap_gate (broad except for the get_claude_config_dir/Path.home RuntimeError seam); binding 5 calls it and the reciprocal-cycle local import is removed. _team_has_secretary keeps its inbox DISPATCH witness for the marker writer. A witness-read error now fires the carve-out (allow) instead of deny — the safe direction, since it only ever permits the canonical secretary spawn (bindings 1-3 gate all else). Migrate the obsolete-design tests that encoded the old error->deny direction, strengthen the import-discipline test to any-scope, and shrink the bootstrap_gate SEAM-closure literal to match the live import graph.
…tic-Labs-AI#1023) Additive regression + unit coverage for the members-only join witness, on top of the obsolete-design migrations in the fix commit. TestPrematureInboxCarveOutRegression: a premature task-assignment inbox (members[] still lacking the secretary) no longer defeats the carve-out — the canonical secretary spawn is allowed (R1), in both in-process and tmux topologies (R2/R3); the carve-out fires under config-less Desktop (C2); empty-SSOT still fails closed even with a premature inbox (E1); and a non-canonical input stays blocked even with a pending witness error (containment). TestSecretaryInMembersUnit: the helper is members-only and broad-except total (False on a raising read). Non-vacuity measured by single-file source revert of bootstrap_gate.py: RED set {7 failed, 2 passed} (R1/R2/R3/C2 behavioral; U1 trio import-absent; E1 + containment correctly fix-independent), restored byte-identical.
PATCH — the Synaptic-Labs-AI#1023 bootstrap-gate carve-out regression fix (restores the pre-Synaptic-Labs-AI#1019 CLI secretary spawn; no visible behavioral change beyond that).
…t line number (Synaptic-Labs-AI#1023) Re-cite the D3 one-shot-migration docstring anchors (and two sibling drift-prone self-references) by symbol name instead of bare line numbers, which had drifted when the _secretary_in_members helper was inserted (the cited mechanism was always correct; only the numbers were stale). Docstring/comment-only, AST-proven behavior-neutral. The 16 cross-subsystem line pins found in the audit are left for a separate cleanup (some are load-bearing, e.g. the session_init.py docstring-parity byte-equality ranges).
…/ intentional_wait / session_state Convert 7 purely-navigational `<file>.py:NNN` self-references to durable symbol / pattern / test-name anchors across 4 hook files (merge_guard_post, merge_guard_pre, shared/intentional_wait, shared/session_state). Docstring and comment only, AST-proven behavior-neutral. Each converted citation was verified to have no test coupling on its line number. The pin_caps cluster (its citations ARE test-coupled — hook+test pairs that must convert together) and the session_init.py docstring-parity byte-equality ranges (deliberately line-based for the parity gate) are left for a dedicated follow-up.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the #1023 bootstrap-gate deadlock regression introduced by PR #1021 (the #1019 fix, v4.4.39). The first fresh CLI session under 4.4.39 had its canonical secretary spawn DENIED by
bootstrap_gate, re-deadlocking bootstrap.Root cause
#1021 widened
bootstrap_marker_writer._team_has_secretarywith a config-less inbox-witness fallback for the marker writer. Butbootstrap_gate._is_canonical_secretary_spawnbinding 5 also consumes that predicate.TaskUpdate(owner="secretary")(bootstrap Step 2) createsinboxes/secretary.jsonBEFORE theAgent(secretary)spawn (Step 3), so the inbox arm returnedTrueprematurely → binding 5 (not True) → carve-out declined → DENY of the very spawn it exists to permit.What landed (3 commits)
5463821a— fix: members[]-only JOIN witness_secretary_in_members()inbootstrap_gate.pyfor binding 5; the localmarker_writerimport is removed;_team_has_secretarykeeps its inbox DISPATCH witness for the marker writer. Broadexcept Exception: return False(load-bearing — catches theget_claude_config_dir()/Path.home()RuntimeError seam that would otherwise re-deadlock). Migrates the obsolete-design tests that encoded the old error→DENY direction, strengthens the import-discipline test to any-scope, and shrinks thebootstrap_gateSEAM-closure literal.a56d5134— test: non-vacuous regression (R1 premature-inbox repro + in-process/tmux legs + config-less always-fire + empty-SSOT-preserved + containment + helper unit tests).4e3370a3— chore: version bump to 4.4.40 (PATCH).Key decisions
TestInboxWitnessGate2); a revert would re-break Bootstrap deadlock under Claude Desktop / Agent-SDK harness: no native team scaffold → config-less UUID team defeats name resolution, #989 self-heal, and marker #1019's Desktop fix.deny-on-errorwas the re-deadlock the fix removes.is_marker_setfast-path (which runs before the carve-out) is the durable one-shot.if not expected_team: return Falseguard stays ahead of the witness; empty/None team → DENY, unchanged.Testing
marker_writer's existingTestInboxWitnessGate2/TestWritabilityInvariant— not duplicated.Scope
bootstrap_gate.pyonly (source);bootstrap_marker_writer.pyunchanged.session_init.pydocstring-parity orpact-protocols.mdSSOT extracts.Closes #1023. Deferred follow-up tracked as #1024 (marker writer's inbox witness optionally excluding task-assignment-only inboxes — availability/liveness, not priv-esc).