Skip to content

Persist commander notices and optional-order head verdicts - #2469

Merged
trissim merged 32 commits into
mainfrom
fix/p433-durable-pings
Oct 23, 2026
Merged

trissim merged 32 commits into
mainfrom
fix/p433-durable-pings

Conversation

@trissim

@trissim trissim commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Commander heartbeat observations now survive connector replacement: committed Info attachments own the last handled observation, unchanged passes send nothing, and urgent packets lead with at most five new decisions and publish every other new current observation under ALSO CURRENT. ServicePassStore records each commander's completed pass, including quiet passes and the completed prefix before another recipient fails.

PR verdicts now persist by repository, PR number and resolved full head, independently of an order. HeadVerdictTool supplies the same implementation to native/CLI and connector callers. judge ok/back --pr N --head SHA handles orderless reviews; linked rejection records the strike and revised order together, revises the goal and notifies the holder. The existing GitHub reader also finds overdue orderless heads.

Installation carry

HeadReviews in tools/cutover/carry_head_reviews.py declares TodoStore as its only store input. The existing installer discovers it through CarryChain. PreparedMigration.carry (installer/upgrade.py:929-935) runs the carry under maintenance before reconcile-stores in both practice and the backed-up live migration. Apply refuses a caller without that root's maintenance hold.

The carry moves embedded reviewed-head verdicts into StoredHeadReview and removes their old Todo.verdicts entries in one SQLite transaction. A later pass sees no embedded records and changes nothing. It derives each PR from the recorded order history, requiring one unique link in the Todo's repository. It preserves actor, quote, previous assignment, exact head and EventTime; no missing time or order ID is invented.

Carry proof on the private copy at 9fa56f5 (carry code is unchanged by this send-back):

The 72-line copy-only scratch converter was deleted. The real one-shot carry remains outside src for the next installation and is retired after that live carry; production has no old-format reader, alias or fallback. The live store was not changed by this work.

Caller migration and deletions

Replaced declaration or path Current owner and callers
ConnectorHeadReviewTool and ConnectorVerdictTool; connector.HeadReviewed Old classes have zero references. ConnectorHeadVerdictTool (connector.py:118) and CommsHeadVerdictTool (order_tools.py:181) inherit HeadVerdictTool.apply (:175); HeadReviewed is now only order_tools.py:159. Connector.exposed (:520) discovers the actual connector member.
AcceptedHeadReview / SentBackHeadReview Zero references. ReviewedHeadVerdict / RejectedHeadVerdict inherit HeadVerdict; only HeadVerdict.reviewed posts their persisted verdict.
Order-only ReviewedHeadVerdict constructor and reviewed(goals, problem, reviewer) Replaced by stateless verdict + PullRequestHead + HeadReviewOrder. Production callers are commander/judge.py:240, commander/judge.py:308 and order_tools.py:177. HeadVerb is deleted; ok/back --pr is the sole PR-head route. Current test callers are tests/test_head_review.py:43, :50, :86, :120. The carry constructs the new stateless verdict at tools/cutover/carry_head_reviews.py:51. No old constructor remains.
InstallDue.why Deleted; tests/test_proof_build.py:389-390 reads due.main and due.oldest_minutes. No rendered-wording assertion.
Todo.unjudged_since / OrderVerdict.judged_through TodoStore.unjudged_since owns the indexed review lookup; turn_digests.py:212 calls it. No judged_through calls remain.
PullRequests.read The one metadata reader is PullRequests.query (:710), used through rows (:677), listed and open; no old reader remains.
QuotedVerdict.require_quote / SentBackOrderGoalAction.revised Inherited from OrderQuote.require_quote (todos.py:3022) and HeldOrderGoalAction.revised (goal_actions.py:404).
CommanderReview and wake Deleted. CommanderHeartbeat.pass_body reads CommanderUpdate.latest, derives a packet and sends it; committed attachments replace the process dictionary.
heartbeat_group / heartbeat_line / heartbeat_change / heartbeat_changes / _heartbeat_groups Zero remaining calls or declarations in src/tests. CommanderUpdate.changed_lines and the CommanderNotice/CommanderDecisions members own notification rendering.
HeartbeatSilent.beats and sibling violations implementations HeartbeatSilent.violations reads ServicePassStore.commander_completed; health no longer depends on message traffic.
UnownedWheelSpin._identity and CheckoutHeldWheelSpin._identity comparison_values owns the semantic comparison input; no _identity call remains in this family.
Competing ce22c97 UnitState, Idle, Moving, DeliveredUnclosed, StalledOnNothing, Spinning, Stuck, AwaitingCommander, Detached, Blocked, UnitObservation Only main's ui_model/unit_state.py family remains. Both that module and tests/test_unit_state.py have zero diff from main. The separate todos.Moving progress capability remains legitimate.
UnitBlock / UnresolvedUnitBlock / RetryableUnitBlock Zero declarations, imports or references.
Competing UnansweredUnitAsks Only commander/questions.py:54 remains; commander/standing.py:13 and tests/test_holder_standing_rules.py:22 import that owner.

Current unit-state import sites:

  • src/agent_comms/commander_heartbeat.py:16: from agent_comms.ui_model.unit_state import UnitState
  • src/agent_comms/storage_rules.py:51: from agent_comms.ui_model.unit_state import UnitState
  • src/agent_comms/order_tools.py:66: from .ui_model.unit_state import UnitState
  • src/agent_comms/commander_pings.py:23: from agent_comms.ui_model.unit_state import UnitState
  • src/agent_comms/standing_rules.py:41: from agent_comms.ui_model.unit_state import UnitObservation, UnitState
  • src/agent_comms/commander/vibe_check.py:47: from agent_comms.ui_model.unit_state import UnitState
  • src/agent_comms/commander/standing.py:43: from agent_comms.ui_model.unit_state import AwaitingCommander, UnitState
  • tests/test_storage_violations.py:32: from agent_comms.ui_model.unit_state import UnitState
  • tests/test_unit_state.py:21: from agent_comms.ui_model.unit_state import AwaitingCommander, Blocked, DeliveredUnclosed, Detached, Idle, Moving, Spinning, StalledOnNothing, Stuck, UnitState, Unreadable
  • tests/test_todos.py:27: from agent_comms.ui_model.unit_state import AwaitingCommander
  • tests/test_commander_notifications.py:17: from agent_comms.ui_model.unit_state import UnitState
  • tests/test_unowned_checkout_work.py:45: from agent_comms.ui_model.unit_state import UnitState, Unreadable
  • tests/test_holder_standing_rules.py:69: from agent_comms.ui_model.unit_state import AwaitingCommander, Blocked, Detached, UnitState

CommanderHeartbeat now inherits main's CommanderService; sender and commander selection remain declared once. CommanderUpdate's publication check and latest-packet read use that parent directly, with the two watch-class local imports deleted.

Phase 4

ReviewQueuePhase requires ClassDeclared("HeadReviewRecord", ("src/agent_comms/todos.py",)) plus RulesetGates. A ruleset alone cannot declare an unimplemented verdict store finished. This evidence is unchanged by the review repairs; the recorded main/branch comparison at 9fa56f5 was false/true.

Review repairs at 328a7ac

  • tests/test_proof_build.py:389-390 asserts the declared main and oldest_minutes fields instead of deleted InstallDue.why.
  • CommanderUpdate.derive retains every current urgent ping in handled while selecting only five leading decisions. CommanderDecisions.body publishes the other new current pings under ALSO CURRENT, and resolutions remain outside that heading. The notification test now requires all seven observations in the first packet and no duplicate on the next pass; it no longer requires delayed publication.
  • HeadVerb and its unused scope imports are deleted. UNJUDGED directs the commander to judge ok --pr N --head SHA. No alias remains.

The five edited files parse. Grep across src/tests/tools finds no due.why, HeadVerb, judge head, or the old deferred-packet test name. No suites run and no passing-test claim is made for this head.

Assumed: none.

@trissim trissim changed the title Commander decisions: derived unit states and durable heartbeat pings WIP: durable commander decisions and head verdicts Oct 23, 2026
@trissim trissim changed the title WIP: durable commander decisions and head verdicts WIP P433: durable commander notifications and head reviews Oct 23, 2026
@trissim trissim changed the title WIP P433: durable commander notifications and head reviews Persist commander notices and optional-order head verdicts Oct 23, 2026
@trissim
trissim marked this pull request as ready for review October 23, 2026 22:33
Copilot AI balanced review requested due to automatic review settings October 23, 2026 22:33

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

debt-tools at d5c7576, every finding:

grew FamilyFlattened:tools/cutover/carry_head_reviews.py +2
grew StringIdentity:src/agent_comms/plan_phases.py +1
grew StringIdentity:tools/cutover/carry_head_reviews.py +2
grew StringSubscript +2
grew Unformatted:tools/cutover/carry_head_reviews.py +1

@trissim
trissim merged commit 930c7ce into main Oct 23, 2026
4 of 8 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.

2 participants