Skip to content

P440: keep the assigner typed so reissues and fork verdicts act under their commander (supersedes #2540) - #2555

Merged
trissim merged 21 commits into
mainfrom
commander/p440-fork-identity
Oct 21, 2026
Merged

trissim merged 21 commits into
mainfrom
commander/p440-fork-identity

Conversation

@trissim

@trissim trissim commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

Supersedes #2540 (P440, keep commander reads separate from fork actors). It carries every #2540 commit, through #2540's head c73e229, merged with main, and fixes the four defects head-review found on that head. unit-forks has two strikes on P440, so a commander fork took the task over.

The defects and their fixes

  1. Blocked units never got their orders back (todos.py, require_unit_in). AssignTodo rebuilt its actor from the Assignment's wire fields, which lost a fork's authority, and Core's watcher reissued as itself, so it competed with the fork that first assigned the unit. AssignTodo now carries the typed actor; AssignTodo.by is the one place both the actor and the recorded assigner are made. A reissue acts as Todo.acting_assigner, the stored assigner under its order's commander (RecordedThreadIncarnation.acting_for builds the CommanderForkIdentity; the watcher keeps its own authority). Competition is still keyed on the acting fork, so a sibling fork's competing order on one unit is still refused (the fork-two refusal in test_registered_fork_sends_parent_problem_with_fork_actor). The five test_holder_standing_rules reissue tests pass.
  2. Authorization ignored the actor (IDEN-1). GoalRef.authorize_order let the goal reference stand in for the actor. It is deleted, along with the base method it overrode; AssignTodo.apply calls the actor's own require_may_change, as main did. test_clean_transfers_keep_history_and_third_owner_requires_a_trace passes.
  3. Every fork's judge superseded was refused. SupersededVerdict.prepare now reads the commander's orders (actor.commanding_identity). New test: test_fork_superseded_verdict_reads_its_commanders_orders.
  4. Wrong refusal. resolve_order refuses an unknown or foreign problem as "UNIT holds no order on P", never "Unknown todo". test_a_problem_not_held_by_the_unit_is_refused passes.

Also: UnownedWheelSpin.order_for and paired no longer take an assigner, and CommanderForkIdentity moves from tool_caller.py into thread_identity.py beside the class it extends. One integration fix: the blocked-goal test #2539 added on main now passes its assigner.

Proof

All 14 test files #2540 touches, run serially at this head and at main d555338 (pytest -n 0; under xdist these files collected nothing locally, so those runs were not used):

Assumed

  • An order's authority is always its Todo's creator, so acting_assigner derives the fork's commander from Todo.creator instead of storing it again on the Assignment.
  • Rows whose recorded assigner is Core's watcher (reissued before this change) reissue as the watcher, which keeps its own unconditional authority.
  • The comms_todo tool's AssignTodo wire form gains actor, like StrikeTodo's; authored_by always overwrites it with the calling identity.

🤖 Generated with Claude Code

trissim and others added 10 commits October 21, 2026 16:02
… their commander

AssignTodo rebuilt its actor from the Assignment's wire fields, so a fork's
authority was lost before apply and Core's watcher, reissuing as itself,
competed with the fork that first assigned the unit. AssignTodo now carries
the typed actor (AssignTodo.by is the one place it and the recorded assigner
are made), and a reissue acts as Todo.acting_assigner: the stored assigner
under its order's commander. A sibling fork's competing order is still
refused.

- GoalRef.authorize_order is deleted: the goal reference no longer stands in
  for the actor (IDEN-1); the actor's own require_may_change decides.
- CommanderForkIdentity moves beside RecordedThreadIncarnation, whose
  acting_for builds it; the watcher keeps its own authority.
- SupersededVerdict reads the commander's orders, not the fork's own.
- resolve_order refuses an unknown or foreign problem as "holds no order".
- UnownedWheelSpin.order_for and paired no longer take an assigner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… its assigner

The registered-fork test now checks that Todo.acting_assigner is the fork
that assigned the unit, acting under its commander, and that it passes the
unit competition check. The blocked-goal reactivation test that main added
in 2539 builds CreateProblemGoalAction, which now requires its assigner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 21, 2026 21:17

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 reached their quota limit.

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.

debt-tools grew Unformatted:tools/carry_rts_orders.py +1. Black only; no behaviour change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@trissim

trissim commented Oct 21, 2026

Copy link
Copy Markdown
Contributor Author

review-batch verdict on a67f49b: pass on semantics. Two hosted reds remain, and a unit carries the fix.

Checked against the ruling: the competition key stays the acting assigner (require_unit_in keys on Assignment.parent). The watcher reissues as Todo.acting_assigner, the stored assigner acting under the order's commander through CommanderForkIdentity, so a sibling fork is still refused. AssignTodo.by is the one place the typed actor and the recorded assigner are made, which removes the rebuild from wire fields. GoalRef.authorize_order is deleted. SupersededVerdict.prepare reads commanding_identity. The private commanding()/_caller rebinding on CommanderContext is replaced by a typed actor.

Tests: test_order_claims, test_commander_forks, test_holder_standing_rules and test_todos give 60 passed and 6 failed at this head. The same 6 fail on main 09d45c6 (five test_order_claims tests with CandidateMaintenanceFailed, plus test_watcher_git_and_github_reads_leave_wire_free), so this PR adds no failures.

Remaining red, exact edits for the holder:

  1. GodClassExcess, Commander (commander/order.py): move board_text (18 lines, now inside class Commander) onto CommanderContext, after last_activity. It only reads todos(), progress(), last_activity(), comms and incarnation, all owned by CommanderContext ("canonical reads, shared by command families"), so the render belongs with them. That is a real move, not a counter dodge. Both callers (ctx.board_text() at :1244, and tests/test_order_claims.py:69 and tests/test_todos.py:541) call it on a Commander, so nothing else changes. Verified locally: ruff findings on order.py are unchanged at 48, and the same 60/6 test result holds with the move.
  2. StringIdentity on tools/cutover/carry_problem_numbers.py:33 clears when StringIdentity: a module name counts only where a string selects a module; FrozenFieldWrite skips own __post_init__ #2553 lands; merge main after that.

Not blocking, noted: RecordedThreadIncarnation.__eq__ now compares wire_birth across every ThreadIncarnation subclass, so a fork identity equals its recorded incarnation by design. Two threads created at the same float timestamp would compare equal; that was already true within one class before.

# Conflicts:
#	src/agent_comms/goal_actions.py
trissim and others added 8 commits October 21, 2026 17:47
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AeUaZjvChAcb6qAd6zPYmw
…r through P448's owner

P448 moved the blocked holder's reissue onto BlockedExecution and
ReissuedOrderGoalAction.for_todo; P440's typed assigner now lives there
(todo.acting_assigner), and UnownedWheelSpin.order_for is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AeUaZjvChAcb6qAd6zPYmw
# Conflicts:
#	src/agent_comms/goal_presentation.py
#	tests/test_holder_standing_rules.py
@trissim

trissim commented Oct 21, 2026

Copy link
Copy Markdown
Contributor Author

P440 reviewed carry result

PR #2555; head 1c8d374c23ccc4df3eec3bdb9183f2aadefa69db; git ls-remote origin refs/heads/commander/p440-fork-identity equals HEAD. Auto-merge remains enabled. #2559 is closed with a pointer to #2555; its experimental allocator/strike changes were not ported.

Preserved reviewed AssignTodo.by, Todo.acting_assigner, the deletion of GoalRef.authorize_order, original fork competition and superseded-verdict authority. Moved board_text unchanged to CommanderContext immediately after last_activity; AST equality of the moved function passed. Added an actual shared-context board comparison to the existing registered-fork test.

Merged current main through 0cb1356f51f9c149469b5b6a0ed93f23583883f1. P448 moved reissue into ReissuedOrderGoalAction.for_todo: preserved that owner and derived its assigner from Todo.acting_assigner. Deleted the old local helper, migrated both production consumers and obsolete test calls. Merged the commander's concurrent fbfb5fc integration, keeping its doc/layout. The only storage change is sorting the new import; re remains required and retained.

Executed comparison (aggregate counts over the same 14 files)

  • Head 1c8d374: 120 passed, 3 failed, 1 xdist assert-rewrite warning, zero setup errors, 121.37s; exit 1.
  • Main 0cb1356: 113 passed, 5 failed, the same warning, zero setup errors, 130.72s; exit 1.
  • All four copied-bus cases and the fork superseded-verdict case passed at head. Output: Core send actor: fork-one; problem commander: lead; judge show: 1 unjudged; judge show --fork review-fork: 1 unjudged. Sibling competition refusal remains exercised.
  • Shared failures: test_todos::test_watcher_git_and_github_reads_leave_wire_free (fixture config has no repository holding agent_comms.plan_phases); test_unowned_checkout_work::{test_dirty_then_unpushed_then_pushed_linked_checkout,test_unreadable_checkout_is_its_units_state_and_the_pass_carries_on} (stale fixture config/path expectations). They are not hidden or marked passed; commander triage is still needed for these baseline fixture failures.
  • Main's additional failures: test_holder_standing_rules::test_an_order_to_a_blocked_goal_activates_it_and_keeps_other_orders and test_todos::test_blocked_enforcement_preserves_reassigned_orders call the removed UnownedWheelSpin.order_for. Head migrated them to the new owning factory.

Files: test_bus_files.py, test_commander_forks.py, test_commander_run_rules.py, test_declared_schema_carry.py, test_held_problem_orders.py, test_holder_standing_rules.py, test_order_progress.py, test_order_scopes.py, test_order_story.py, test_owned_turn_goal_replacement.py, test_proof_build.py, test_storage_violations.py, test_todos.py, test_unowned_checkout_work.py (all under tests/).

Used shared installed dependencies, unchanged pinned SDK af3cb0e12a5fb250, PYTHONPATH=src:tests, timeout 300, pytest -q -s -n 0 -o faulthandler_timeout=60 --noconftest --basetemp= plus those files. A real-file Python entrypoint selected all existing FixtureFunctionDefinition objects from tests/conftest.py as a plugin, cleared its canonical managed-environment set and selected LaunchRoot.unstarted. This retains the existing root lifetime fixture without the eager session-start rebuild hook. The stdin prototype caused a multiprocessing re-import failure; a missing SDK caused a setup error. Both were harness defects corrected before these final results. Final runs have no bus maintenance teardown warning. All original/failed stages remain preserved; no uncertain inputs were replayed.

Source evidence

Existing refactor-audit Package parser: 440 production modules + 471 test modules, zero parse omissions. One board_text declaration, on CommanderContext; one reissue factory deriving todo.acting_assigner; all consumers enumerated; no old order_for calls and no authorize_order declaration. Mandatory whole-src commander-rebinding search: 0. git diff --check passed. Targeted F401/F821 lint on the integrated production files passed. No local ratchets or full suite were run. NRA tree_sitter remains unavailable; dynamic SQL/MRO resolution is outside the syntactic proof.

Exact-head hosted checks (run 39682968305)

SUCCESS: smoke, native-scripts, install-rehearsal, review-verdict.
FAILURE: debt-src, debt-tools. Both logs report only grew StringIdentity:tools/cutover/carry_problem_numbers.py +1; storage import lint and Commander class excess are gone.
#2553 is still OPEN at 9d508a2, with all six reported checks successful. It must land, then main must be merged again into #2555; no false-positive workaround was added here.

Remaining acceptance

Not merged or installed. Copied-bus/source acceptance is demonstrated, not installed acceptance. Merger still owes the retained-bus practice installation and installed fork order-check/superseded-verdict/sibling-refusal journey. The unrelated #2549 and installation channel updates do not qualify P440.

Assumed: #2553 removes the observed detector false positive; this has not yet been demonstrated on a post-#2553 #2555 head. Installed acceptance is not assumed.

Evidence owner: unit-mi-1b. Logs: p440-2555-final-head-tests.log, p440-final-main-tests.log, p440-final-compare-driver.log, p440-converged-ast.txt, p440-1c8-debt-logs.txt, p440-delivery-github-state.log under /home/ts/.cache/agent-scratch/unit-mi-1b/. Owned disposable SDK copy: /home/ts/wt/unit-mi-1b--P440/stack/.pi-native-af3cb0e12a5fb250; retained failed/final test stages remain in that scratch directory until acceptance/diagnosis is complete.

@trissim
trissim merged commit 4e6038d into main Oct 21, 2026
6 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.

3 participants