capability_ref and approval_mode?
Version. 0.1
Date. 2026-08-21
Status. Read-only findings. Answers §5.4 of loomworks-scoping-attribution-is-a-property-of-the-use-v0_1; nothing fixed, no CR drafted. Filed beside that note.
Engine. main at 70e5639.
Partial yes. Population is exactly where the inspection found it and nowhere else. Reuse-across-acts does not occur — that risk is structurally absent. But one real, currently-dormant path forwards a delegation-carrying actor into a naming field, by a different mechanism than the render_dispatch.py instance: a conditional fallback, not object reuse.
capability_ref and approval_mode populated?
Exactly two sites construct an ActorRef with either field set. Confirmed; no others.
delegation/action_dispatch.py:263-269, inside _execute_pre_authorized — capability_ref=delegation_ref, approval_mode="pre_authorized".notifications/service.py:713-720, inside the approval-processing path — capability_ref=auth.delegation_ref, approval_mode="explicit".
Everything else the grep for approval_mode= surfaces is a different field on a different class, and does not touch ActorRef:
delegation/authorization.py — AuthorizationResult.approval_mode (a check's outcome, not an actor's authorization story).delegation/schema.py, delegation/service.py — DelegationContent.approval_mode (the standing delegation's own configured mode, at grant time, not at any one act).
Both are named in ActorRef.approval_mode's own docstring as the thing it is not — the class docstring already draws this line, and the census confirms nothing crosses it.
Yes, one path — structurally live, exercised by tests, dormant in production today.
engagement/shaping.py::_job_attribution_ref:
def _job_attribution_ref(shaping: Shaping, triggered_by: ActorRef) -> ActorRef:
"""Return the ActorRef to attribute on the shaping_jobs row.
For an AgentExecutor this is the agent's ActorRef (so the job row
matches the producer). For a SkillExecutor no agent exists; the
triggering actor is used as a sensible stand-in..."""
if shaping.executor.kind == "agent":
return shaping.executor.agent_ref
return triggered_by
Its result is written to shaping_agent_ref — a naming field, the same field CR-2026-231 §2 ruled at the AgentExecutor branch. The SkillExecutor branch returns triggered_by unmodified.
The chain that makes this reachable from the delegation flow: companion_room_dispatchers.py::produce_specification_dispatch receives the delegation-authorized Companion actor (carrying capability_ref/approval_mode) and calls request_shape_production(triggered_by=actor, trigger="agent_request", ...), which calls _job_attribution_ref(current_shaping, triggered_by). If the Shaping in play is served by a SkillExecutor, the delegation actor's capability_ref and approval_mode land directly in shaping_agent_ref on the persisted shaping_jobs row.
Why this is dormant rather than live in production, checked rather than assumed. register_shaping_skill — the only way a Shaping acquires a SkillExecutor — has zero call sites outside tests. grep -rln "register_shaping_skill(" src/loomworks/ | grep -v test_ returns nothing but a docstring mention in shaping_bootstrap.py. No Shaping in any running deployment is ever bound to a SkillExecutor today, so the branch that forwards triggered_by is unreachable in practice — but it is real code, on the primary shape-production path, exercised by the test suite, and it activates with no code change the moment any skill is registered.
This is a different mechanism from the render_dispatch.py instance, worth being precise about: render_dispatch.py's leak is object reuse — one already-attributing object handed to a naming field in the same call. This one is conditional forwarding — a field that is naming in one branch (AgentExecutor) and receives an attribution-carrying object in the other (SkillExecutor), depending on data that is not visible at either call site. Two distinct root causes converging on the same failure shape.
No. Checked both construction sites and their full call trees; neither risk is present.
Both ActorRefs are function-local and single-use. action_dispatch.py:266's actor is built inside _execute_pre_authorized, which handles one pre-authorized dispatch and returns; notifications/service.py:719's actor is built inside the single-approval processing function. Neither is assigned to self., a module-level name, or any container that would outlive the call — grepped for exactly that and found nothing.
Where the object is used further, it is passed once, straight through, to a single dispatcher call (dispatch_action(actor=actor, ...) → the registered handler for that one action_type), and consumed there. Two of the delegation-reachable dispatchers (grant_decision_dispatcher.py:812, :1035) that need to build a further actor deliberately reconstruct a fresh, minimal one — ActorRef(kind="person", id=actor.id, display_name=actor.display_name) — explicitly dropping capability_ref/approval_mode rather than forwarding the object. That is the correct shape, and it is what every other dispatcher does implicitly by only ever reading actor.id.
Contrast with render_dispatch.py's agent_actor, which is exactly the opposite shape: constructed once at render_specialist_bootstrap.py, stored on the specialist instance, and reused for every job that specialist ever runs — which is why W1 needed a per-act model_copy derivation for session_id in the first place (CR-2026-231 §3.2). approval_mode's own docstring — "how this specific action was authorized at execution time" — is honoured here because there is no long-lived instance for it to be stored on. The sharpest version of the question does not apply to either delegation-flow site, because delegation objects are per-request, not per-process.
| Question | Answer |
|---|---|
| Where populated | Exactly action_dispatch.py:266 and notifications/service.py:719 — confirmed, no others |
| Reaches a naming field | Yes, via shaping.py::_job_attribution_ref's SkillExecutor fallback — structurally live, production-dormant (register_shaping_skill has no non-test callers) |
| Reused across acts | No — both construction sites are function-local and single-use; downstream dispatchers that need a derived actor rebuild fresh rather than forward |
Net: the object-lifetime risk (§5.4's sharpest form) does not occur — approval_mode never outlives the act it describes, because nothing holds the object past one dispatch. The field-shape risk does occur, by a mechanism the scoping note's four other forwarding sites don't cover: a naming field that is correctly naming on one branch and silently receives an attributing object on another, gated by data the two call sites never see together. It is dormant only because no code currently exercises the branch that would trigger it — a property of current configuration, not of the code's shape.