Rocko's packet agents/rocko/work/queue-73/ (candidate manifest bf4e5ed6, packet manifest 41ffcd5c, 53 files), their BUILD-LOG entry and SESSIONS line. Sage's SESSIONS line for the review request (comment 27467) and row 79 (#1573) for the stale text the packet names. Co-Authored-By: Claude Opus 5.5 <[email protected]>
8.6 KiB
Row 73 (#1567): drop the coder's task.reassign grant, candidate packet, round 1
Author: Rocko. Reviewer: Dewey. Brief:
docs/plans/2026-10-11_claude-pin-and-coder-grant.md, section "Coder role:
drop the task.reassign grant the broker always refuses". Base: 324c064b
(base.txt). At 23:16Z the checkout HEAD f6b9ea4e has no change since the
base to any candidate path or to packages/{bus,business,tasks}/src or
packages/harness/src/tools.mjs. build.patch applies to it cleanly. The
packet is uncommitted. I made no commits, pushes or Gitea calls and read no
token or private binding.
Files (files.txt, candidate-manifest.sha256)
| File | Change |
|---|---|
roles/coder.json |
crossRole: ["task.reassign", "task.scope.change"] → ["task.scope.change"]. Nothing else in the file changes. |
packages/business/tests/role.test.mjs |
"shipped authority follows the note's table": asserts that the coder's crossRole is exactly ["task.scope.change"] |
packages/business/tests/resolve.test.mjs |
"classify": the coder's task.reassign is now gated and its task.scope.change is cross. "limits.authority narrows cross-role actions too" moves from the coder to the pm (see below). |
packages/bus/tests/broker.test.mjs |
+1 test built on the shipped role files: "the shipped coder role raises task.reassign as gated to the human; task.scope.change stays cross-role" |
packages/harness/tests/tools.test.mjs |
+1 test: "a coder with a tracker gets its own task tools and no task_reassign" |
packages/tasks/tests/world.mjs |
the fixture's coder crossRole now matches the shipped role |
packages/tasks/tests/verbs.test.mjs |
in "assign and reassign …": a coder's task.reassign refuses field-writer and records no action.allowed |
agents/rocko/work/queue-73/mutants.sh |
the mutant rerun: mutants.sh <tree> |
No change to broker.mjs, PM_VERBS, the slice 1 field table or any other
role's grants.
Why the narrowing test moved to the pm
Before this change, the test limited the coder to task.scope.change and
watched task.reassign drop out of crossRole. With one cross-role action
left, that limit drops nothing from crossRole. I checked this: with the new
role file and the old test, the mutant resolve-cross-unnarrowed (crossRole
ignores limits.authority) passes the test (out/old-narrow-test-under-mutant.txt).
The pm still holds two cross-role actions. The test now limits the pm to
task.create, task.close and task.priority.change. It checks that
crossRole keeps task.priority.change and drops task.scope.change, and
that withinRole narrows too.
Every place that read the old grant, and what it says now
Probe (out/probe-base.txt, out/probe-candidate.txt): the shipped roles
through validateBusinessDocument, resolveInstance, busBusiness and a
real Broker, as bootConfig assembles them.
| Reader | Before (base) | After (candidate) |
|---|---|---|
business/src/resolve.mjs resolveInstance |
coder crossRole [task.reassign, task.scope.change] |
[task.scope.change]. The resolved digest of every coder instance changes too. Only the bundle manifest records it, and nothing compares it. |
business/src/resolve.mjs classify |
cross |
gated |
bus/src/broker.mjs #classification (via cli/src/config.mjs bootConfig → busBusiness) |
cross-role; decision.raise routes to the domain arbiter, pm by default (cto for technical) |
gated; routes to human |
harness/src/tools.mjs typedTools, with a tracker |
the coder gets a task_reassign tool |
no task_reassign tool; task_scope_change and task_update_assigned remain |
harness/src/tools.mjs untypedActions → bundle.mjs prompt, without a tracker |
the prompt lists task.reassign among "Actions you hold that have no bus tool yet" |
not listed |
tasks/src/verbs.mjs PM_VERBS |
field-writer before authority |
unchanged: field-writer before authority |
tasks/tests/world.mjs fixture |
copied the old grant | matches the shipped role |
| business, bus, harness and tasks tests | see Files | see Files |
Readers I did not change (outside the brief's files; Sage's call):
packages/business/README.md, lines 30-43: the version 2 example is the shipped coder file and still shows"crossRole": ["task.reassign", "task.scope.change"]. It goes stale with this change. Suggested fix: drop"task.reassign",from the example.packages/tasks/README.md, lines 193-196: "A coder role'scrossRolegrant oftask.reassigncan't be used. The writer check refuses it before authority is looked at. …" This will be stale too. Suggested text: "The coder role holds notask.reassigngrant (row 73). The writer check refuses a non-pmtask.reassignbefore authority is looked at anyway. If a coder should hand work on, that's a change to the field table, not to the role file."packages/tasks/live/run.mjs, line 32: the live run's own copy of the slice 1 authority still gives the codertask.reassign. Nothing runs it in the suites. It never has the coder calltask.reassign, so its result doesn't change. It should matchworld.mjs.- Unaffected:
scripts/test-task.shline 279 andbusiness/tests/role.test.mjsline 115 are role-validation fixtures, not the coder's grant. Historical notes are left as they are: the slice 1 plan, the Darkwing and Filbert work notes, and lead decision 90.
What a coder's task.reassign does end to end after the change
- A pi coder session has no
task_reassigntool, so it can't make the call through the harness. - It can still
raise_decisionwithaction: task.reassign, because the tool's action enum is every action. The broker classes itgatedand routes it to the human, where before it went to the pm as cross-role. The human is then asked a question that can only end infield-writer. - If the human approves and the coder calls the verb directly on the bus,
the broker's
authorizepasses asgated; the bus test shows that. The task verbs refuse first withfield-writer, beforeauthorize, so nothing is consumed and nothing is written (tasks test).
The brief names the follow-up but doesn't make it, and nor does this row. To
refuse a non-pm task.reassign (or any PM_VERBS action) at
decision.raise, before a decision opens, is a broker change and would be
its own row.
A bus that is already running keeps the authority it loaded at boot. The change reaches it on its next restart.
Mutants (out/mutants-candidate.txt, out/mutants-base.txt)
| Mutant | Edit | Base 324c064b |
Candidate |
|---|---|---|---|
role-keeps-reassign |
roles/coder.json puts task.reassign back |
n/a (the base is this mutant) | killed by role, classify, bus and harness tests |
broker-unlisted-cross |
#classification: an action in neither list → cross-role |
survived | killed by the new bus test |
resolve-cross-unnarrowed |
resolveInstance: crossRole ignores limits.authority |
killed | killed (by the narrowing test and the harness test "an action outside the instance's authority has no tool") |
classify-unlisted-cross |
classify: an unlisted action → cross |
killed | killed |
tools-all-task-verbs |
typedTools: a task tool for every verb, held or not |
killed | killed (now also by the new harness test) |
The script saves each file, applies the sed and checks it changed something.
It then runs the five test files and restores the file from the saved copy,
so it works on an uncommitted tree. out/mutants-*/ holds each diff and log.
I ran the candidate twice. The run recorded here uses the final script; the
first run used the same script before a comment-only reflow, with the same
results.
Gate (out/gate/, sequential, scratch worktree at 324c064b with the candidate, node_modules linked, 23:09:50Z-23:14:34Z)
| Suite | Result |
|---|---|
tasks node --test 'packages/tasks/tests/*.test.mjs' |
71 pass, 0 fail |
| bus | 81 pass, 0 fail |
| business | 60 pass, 0 fail |
| harness | 58 pass, 0 fail, 0 skipped |
| cli | 112 pass, 0 fail |
| webui | 50 pass, 0 fail |
| seat | 27 pass, 0 fail |
| test-auth | 15 passed, 0 failed |
| test-conductor | 17 passed, 0 failed |
| test-config | 24 passed, 0 failed |
| test-discord | 66 passed, 0 failed |
| test-extension-package | 18 passed, 0 failed |
| test-foundation | 44 passed, 0 failed |
| test-queue | 27 passed, 0 failed |
| test-release | 14 passed, 0 failed |
| test-task | 98 passed, 0 failed (Docker) |
cli, webui and seat go beyond the gate the brief names. I ran them because
they read the shipped roles. After the gate I removed the rocko-r73_default
network.