CR identifier. CR-2026-059
Version. 0.1
Date. 2026-05-06
Status. Approved for execution.
Author. Claude.ai (CR drafting layer). Operator: Marvin Percival.
Executing agent. Claude Code (CC) on DUNIN7-M4.
Depends on. Phase 44 complete (tag phase-44-sse-and-proactive-behavior, substrate b474d26, frontend 0f1edee). Phase 43 complete (personal memory contribution, remember_about_me / forget_about_me flows). Phase 42 complete (classify → route → respond pipeline, stub intents, conversation turns). Phase 41 complete (personal engagement, ActorRef(kind="companion")). Phase 40 complete (vocabulary wall, orchestration API).
Informed by. Phase 45 scoping note v0.1 (eight decisions settled). Companion as agent investigation v0.1 (§§3–7, 10 — capability tiers, delegation contract, approval card pattern, trust escalation, OVA credential seam, implementation sequence). Personal memory investigation v0.1 (§§3, 7 — personal engagement as storage surface). Phase 44 CR (SSE channel, notification surface, trigger evaluator, event bus). Phase 43 CR (personal memory contribution, remember_about_me flow, cross-promotion instruction). Phase 42 CR (intent taxonomy, stub intents, classifier prompt, router architecture). Product identity standing note v0.1. Current status manifest v0.29.
Phase 45 closes Arc 2 by giving the Companion the ability to act — not just inform. Phases 41–44 built a Companion that converses, classifies intent, routes to engine operations, reads and writes personal memory, pushes notifications through SSE, evaluates triggers, and observes patterns. What it cannot yet do is propose an engine operation and execute it with the Operator's approval.
Three capabilities ship:
per_action or pre_authorized). The contract is managed through conversation — the Operator grants, queries, and revokes delegations by talking to the Companion.request_draft (Companion identifies shape type, checks delegation, creates approval card or executes directly), approve_draft (Companion processes conversational approval of a pending action), and request_revision (Companion proposes re-production through the same delegation check and approval flow). request_redirect remains a stub.One thing is seam-only: the OVA credential interface. Phase 45 implements authorization as a delegation assertion lookup. The function's contract is designed so that OVA can replace the implementation later without changing call sites.
Full-stack phase. One migration (extend companion_notifications). Two checkpoints (substrate then frontend). Arc 2 complete after this phase.
All eight decisions from the scoping note v0.1 are adopted without modification.
| Decision | Summary |
|----------|---------|
| S1 | Capability scope: Tier 1 engine-internal only. The Companion can propose and execute operations the Operator could do through the existing UI (trigger shaping, initiate render, commit assertion). Tiers 2–5 (external) are post-Arc 2. |
| S2 | Delegation contract as structured personal memory assertions. Each delegation is a committed assertion with structured JSON content: capability identifier, scope, constraints, approval mode. Delegation assertions are distinguished from regular personal memory by a delegation category or prefix convention. |
| S3 | Approval card pattern: notifications with action controls. The companion_notifications table gains columns for approval metadata. Approval cards are delivered through SSE using the existing notification_created event type. The frontend distinguishes them by approval_status. |
| S4 | Three stub intents activated (request_draft, approve_draft, request_revision). Router handlers change from returning stub markers to performing real operations with delegation check and approval flow. request_redirect remains a stub. |
| S5 | Approval through conversation and notification surface. Two paths, same outcome. Notification surface: [Approve] / [Decline] buttons call REST endpoints. Conversation: "yes, go ahead" classified as approve_draft. Both converge on the same approval-processing function. |
| S6 | OVA credential seam: verify_companion_authorization function. Currently implemented as delegation assertion lookup. Interface designed for OVA replacement. ActorRef extended with capability_ref and approval_mode. |
| S7 | Trust escalation: substrate support, no proactive suggestion. Pre-authorized delegation is available but Operator-initiated only. The Companion does not suggest "would you like me to just do this?" |
| S8 | Migration: extend companion_notifications, no new table. Six new nullable columns for approval card metadata. Informational notifications unaffected. |
phase-44-sse-and-proactive-behavior (substrate b474d26, frontend 0f1edee).Step 0 confirms:
companion_notifications table exists with columns from Phase 44 (person_id, trigger_type, trigger_ref, title, body, engagement_id, status, snoozed_until, timestamps). [CC verifies: model file, column names and types, existing status enum values (pending, delivered, seen, dismissed).][CC verifies: bus module file, publish function signature, that notification_created and notification_updated event types are in use.]GET /operator/notifications, PATCH .../seen, PATCH .../dismiss). [CC verifies: router file, function names, response schemas.]GET /operator/notifications/stream. [CC verifies: streaming response, heartbeat, auth dependency.][CC verifies: service module file, create/list/mark-seen/dismiss functions.][CC verifies: personal_engagement_id FK on person table.]load_personal_memory). [CC verifies: function file and signature — this is the function that loads committed assertions from the personal engagement.]remember_about_me intent and router handler exist (Phase 43). [CC verifies: router dispatches remember_about_me, creates held assertion in personal engagement with conversational commit.]forget_about_me intent and router handler exist (Phase 43). [CC verifies: router dispatches forget_about_me, keyword-matches and retracts personal assertions.]request_draft, approve_draft, request_revision, request_redirect. [CC verifies: classifier prompt text asset lists all four, router returns stub markers for them.]ActorRef(kind="companion") exists (Phase 41). [CC verifies: model, kind enum includes companion, fields used for Companion-created events.][CC verifies: how new schemas are registered, that approval-related schemas must pass the wall.]ClassifiedIntent model exists with intent, confidence, extracted_parameters. [CC verifies: model file, that extracted_parameters is a dict suitable for carrying action-specific data from the classifier.]assemble_prompt). [CC verifies: component structure and assembly order (persona → engagement context → personal memory → cross-promotion → observation → intent instruction → conversation history).][CC verifies: template files for request_draft, approve_draft, request_revision — these are the stub templates that will be replaced with live templates.][CC verifies: component file, that it renders notification cards from the notification list. Identify where conditional rendering for approval cards inserts.][CC verifies: badge component, that it reads unseen count from notification state.][CC verifies: API module, function signatures.][CC verifies: hook file, that incoming events update notification state.]Pre-flight divergence stops execution at Step 0 and drives a CR amendment.
Archive this CR to docs/phase-crs/phase-45-cr-delegation-contract-and-approval-cards-v0_1.md at Step 0 before Step 1 begins.
Delegation assertions live in the personal engagement as committed assertions with structured JSON content. The assertion's content is structured (not natural language) so the router can query delegation state programmatically.
Content schema:
{
"type": "delegation",
"capability": "produce_specification",
"scope": "all",
"constraints": {},
"approval_mode": "per_action"
}
Fields:
type — always "delegation". Distinguishes delegation assertions from regular personal memory assertions. The delegation query function filters on this field.capability — string identifier for the authorized action. Initial capability identifiers: produce_specification, produce_artifact, commit_notes, initiate_render. [CC determines: the definitive set of Tier 1 capability identifiers by inspecting available engine operations that can be triggered through the orchestration API.]scope — "all" or a list of engagement IDs. "all" means the delegation covers every engagement the person operates. A list restricts the delegation to specific engagements.constraints — nullable object. Optional bounds (e.g., {"shape_type": "specification"} to restrict produce_artifact to specifications only). Empty object or null means no constraints.approval_mode — "per_action" (default) or "pre_authorized". per_action means every proposed action creates an approval card. pre_authorized means the Companion acts within bounds and reports after completion.Delegation CRUD through conversation:
remember_about_me handler recognizes this as a delegation intent (the content matches a delegation pattern). Instead of storing raw text, it creates a delegation assertion with structured content. [CC determines: the recognition mechanism — whether the remember_about_me router handler inspects the content for delegation keywords ("you can," "I authorize," "without asking," "go ahead and") and constructs the structured JSON, or whether a sub-classifier separates delegation instructions from regular personal memory. The requirement is that the Operator speaks in natural language and the system stores structured JSON.]forget_about_me handler matches against delegation assertions and retracts the matching delegation. [CC determines: whether delegation revocation uses the existing forget_about_me keyword-match logic or needs delegation-specific matching (since the stored content is JSON, not natural language). The stored content's capability field may need to be matched against the Operator's natural language description.]ask_about_past_input handler (or a delegation-specific sub-handler) queries delegation assertions and returns a natural-language summary. [CC determines: whether this reuses the ask_about_past_input handler with delegation-specific filtering or warrants its own routing. The requirement is that the Companion can answer "what can you do?" with a list of active delegations in Operator vocabulary.]verify_companion_authorizationA function that answers: "is the Companion authorized to perform this action for this person on this engagement?"
Signature:
async def verify_companion_authorization(
person_id: UUID,
capability: str,
engagement_id: UUID,
db: AsyncSession
) -> AuthorizationResult
AuthorizationResult model:
class AuthorizationResult(BaseModel):
authorized: bool
delegation_ref: UUID | None # assertion ID of the matching delegation
approval_mode: str # "per_action" | "pre_authorized" | "denied"
reason: str # human-readable explanation
Current implementation: query the personal engagement for committed assertions with type: "delegation" matching the requested capability. Check scope (does the delegation cover this engagement?). Check constraints (does the proposed action satisfy constraints?). Return the result.
OVA seam contract: the function name, signature, and return type are the stable interface. When OVA hardens, the internals change from "query personal memory" to "verify OVA credential against capability claim." Callers (router handlers, approval processor) are not modified.
[CC determines: the module location for this function — alongside the notification service, in the orchestration module, or in a new delegation module. The requirement is that the function is importable from router handlers and the approval endpoint.]
ActorRef extension
ActorRef(kind="companion") gains two optional fields:
capability_ref — nullable UUID. The assertion ID of the delegation that authorized this action. Present when the Companion creates events through the delegation flow.approval_mode — nullable string ("explicit" or "pre_authorized"). Indicates how the action was authorized.
These fields appear on every event the Companion creates through the delegation flow. Events created through the existing reactive flow (Phase 42 add_knowledge, Phase 43 remember_about_me) do not carry these fields.
[CC determines: whether capability_ref and approval_mode are added to the ActorRef model directly or carried in a separate authorization_context field on ActorRef. Direct fields are simpler; a nested object is cleaner for OVA replacement. The requirement is that the fields are present on Companion-created events and accessible for audit.]
companion_notifications
Six new nullable columns on the companion_notifications table:
action_type — nullable string. The engine operation type (e.g., produce_specification, produce_artifact, initiate_render). Null for informational notifications.action_params — nullable JSONB. The engine operation parameters the Companion would invoke on approval. Null for informational notifications.approval_status — nullable string: pending_approval, approved, declined. Null for informational notifications. [CC determines: whether this is an enum, a check-constrained string, or a plain string — consistent with the approach taken for status in Phase 44.]approved_at — nullable timestamp.declined_at — nullable timestamp.execution_result — nullable JSONB. Outcome of the engine operation after approval (success/failure, reference to created object).All columns nullable. Existing informational notifications are unaffected — rows without approval metadata continue to render as informational cards.
No new indexes. The existing (person_id, status, created_at DESC) index serves approval card queries.
Creation flow:
When the router determines an action requires approval (delegation check returns per_action), it creates a companion_notifications row with:
status = the existing status value appropriate for a newly created notification. [CC determines: whether to use pending (existing value) or add a new approval_required value to the status enum. The scoping note says approval_required — CC confirms whether the existing enum supports addition or whether pending is sufficient, with approval_status = "pending_approval" distinguishing approval cards from informational notifications.]trigger_type = a value that identifies this as a Companion-proposed action. [CC determines: whether to add a new trigger_type value (e.g., companion_action) or reuse event_based. A new value is cleaner.]action_type, action_params, approval_status = populated from the proposed action.title and body in Operator vocabulary, describing the proposed action.
The notification is pushed through SSE using the existing event bus (notification_created event type).
Approval endpoint:
POST /operator/notifications/{id}/approve
approval_status is pending_approval.approval_status = "approved", approved_at = now().action_type and action_params. The operation is executed with ActorRef(kind="companion") carrying capability_ref and approval_mode = "explicit".execution_result with the outcome (success + created object reference, or failure + error).notification_updated SSE event so the frontend can update the card state.Decline endpoint:
POST /operator/notifications/{id}/decline
approval_status is pending_approval.approval_status = "declined", declined_at = now().notification_updated SSE event.Both endpoints use the vocabulary wall.
[CC determines: the exact endpoint path prefix — whether these are under /operator/notifications/ alongside the Phase 44 endpoints or under a new prefix. The requirement is that approve/decline are person-scoped and authenticated.]
When the delegation check returns pre_authorized, the Companion skips the approval card and executes the engine operation directly.
Flow:
verify_companion_authorization. Result: authorized=True, approval_mode="pre_authorized".ActorRef(kind="companion") carrying capability_ref and approval_mode = "pre_authorized".No approval card, no [Approve] button, no REST call. The Operator has already granted standing authority.
request_draft
Classifier update: the request_draft description in the classifier prompt changes from a stub description to an action description. Parameter extraction guidance added:
shape_type — what kind of shape to produce (specification, storybook, report, etc.).engagement_name or engagement_ref — which engagement.grammar — which grammar to use (e.g., Loompa), if specified.
[CC determines: the parameter extraction field names and the exact classifier prompt wording, consistent with existing parameter extraction patterns (e.g., add_knowledge extracts knowledge_text).]
Intent instruction template: replaces the stub template. The new template guides the responder through the delegation flow outcome:
per_action and approval card created: "You proposed [action]. An approval card was sent. Ask the Operator to approve when ready."pre_authorized and executed directly: "You executed [action] under your standing delegation. Report the outcome."Router handler:
shape_type, engagement_ref, grammar from extracted_parameters.produce_specification).verify_companion_authorization(person_id, capability, engagement_id).pre_authorized: dispatch engine operation (D6 flow). Return route result with operation data.per_action: create approval card (D5 flow). Return route result with pending approval data.
[CC determines: how to map the classifier's shape_type to an engine capability and to the actual engine function call (e.g., triggering shaping, calling the produce function). The requirement is that the router can dispatch the engine operation — identify the function to call and the parameters to pass.]
approve_draft
Classifier update: the approve_draft description changes from stub to live. This intent fires when the Operator says "yes, go ahead" or "approved" in conversation, after the Companion has proposed an action.
Router handler:
pending_approval notification for this person. [CC determines: the lookup strategy — most recent by created_at, or matched by conversation context (the Companion's last response proposed a specific action). Most recent is simpler; context-matched is more accurate if multiple approval cards are pending.]POST .../approve endpoint — update status, dispatch engine operation, record result, push SSE update).Intent instruction template: replaces the stub template. Guides the responder:
request_revision
Classifier update: the request_revision description changes from stub to live. Parameter extraction:
target_description — what the Operator wants revised (a shape, a render, a specific artifact).revision_guidance — any specific revision instructions.Router handler:
extracted_parameters and engagement context.verify_companion_authorization with the appropriate capability.request_draft (D7 steps 5–7).
Intent instruction template: replaces the stub template. Same outcome guidance as request_draft.
[CC determines: how to identify the target — whether the classifier extracts enough information to pinpoint the shape/render, or whether the router queries available shapes/renders and matches by description (similar to request_download in Phase 42).]
The classifier prompt text asset is updated:
request_draft moves from the stub section to the live section with full action description and parameter extraction guidance.approve_draft moves from the stub section to the live section.request_revision moves from the stub section to the live section with parameter extraction guidance.request_redirect remains in the stub section.The stub section shrinks from four intents to one. The live section grows from nine intents (Phase 43) to twelve.
[CC determines: the exact prompt wording for each activated intent, consistent with the existing classifier prompt structure and Operator vocabulary.]
One migration: Alembic 0061.
Adds six nullable columns to the companion_notifications table per D4: action_type, action_params, approval_status, approved_at, declined_at, execution_result.
May also add a new value to the trigger_type enum if CC determines a new trigger type value is needed (D5). [CC determines: whether enum alteration is needed or whether an existing value suffices.]
No data backfill. Existing rows have null values for all new columns.
Phase 45 modifies existing files and creates new files.
| File | Change |
|------|--------|
| New: src/loomworks/delegation/ module | Delegation assertion schema, query functions, verify_companion_authorization. [CC determines: whether this is a new top-level module or nested under orchestration/.] |
| New: delegation assertion schema | Pydantic model for delegation content per D1. |
| New: verify_companion_authorization function | OVA seam per D2. |
| New: AuthorizationResult model | Per D2. |
| ActorRef model | Add capability_ref and approval_mode fields per D3. |
| companion_notifications model | Add six new columns per D4. |
| Notification schemas | Add approval-specific fields to NotificationResponse (action_type, approval_status, action_params, execution_result). New schemas for approve/decline request and response. |
| Notification service | Add approval card creation, approval processing, decline processing functions per D5. |
| New: approval endpoints | POST /operator/notifications/{id}/approve and POST /operator/notifications/{id}/decline per D5. In the notifications router. |
| Router (src/loomworks/orchestration/router.py) | Replace stub handlers for request_draft, approve_draft, request_revision with live handlers per D7–D9. |
| Classifier prompt text asset | Update intent taxonomy: three intents from stub to live, parameter extraction guidance per D10. |
| Intent instruction templates | Replace stub templates for request_draft, approve_draft, request_revision with live templates per D7–D9. |
| remember_about_me router handler | Extend to recognize delegation instructions and create structured delegation assertions per D1. |
| forget_about_me router handler | Extend to match and revoke delegation assertions per D1. |
| ask_about_past_input router handler (or new sub-handler) | Extend to query and summarize active delegations per D1. |
| Alembic | Migration 0061 per D4. |
Frontend changes:
| File | Change |
|------|--------|
| Notification card component | Add approval card variant with [Approve] and [Decline] buttons per scoping note §4. Conditional rendering based on approval_status. |
| API client | Add approve and decline endpoint calls. |
| Notification drawer | Handle approval card state transitions (pending → executing → complete, pending → declined). |
| Notification badge | Include pending approval cards in badge count. |
[CC determines: exact file paths and component names following existing frontend conventions.]
Delegation assertions (D1):
"all" matches any engagement.
OVA seam — verify_companion_authorization (D2):
authorized=True, approval_mode="per_action" when per-action delegation exists.authorized=True, approval_mode="pre_authorized" when pre-authorized delegation exists.authorized=False when no delegation exists for the requested capability.authorized=False when delegation exists but scope does not cover the requested engagement.authorized=False when delegation exists but constraints do not match the proposed action.delegation_ref when authorized.ActorRef extension (D3):
ActorRef(kind="companion") accepts capability_ref and approval_mode.ActorRef persist capability_ref and approval_mode.Approval card creation and processing (D4, D5):
action_type, action_params, approval_status on notification row.approval_status = "pending_approval".POST /operator/notifications/{id}/approve sets approval_status = "approved", approved_at.POST /operator/notifications/{id}/approve triggers the engine operation specified in action_params.POST /operator/notifications/{id}/approve records execution_result with operation outcome.POST /operator/notifications/{id}/approve pushes notification_updated SSE event.POST /operator/notifications/{id}/decline sets approval_status = "declined", declined_at.POST /operator/notifications/{id}/decline does not trigger any engine operation.POST /operator/notifications/{id}/decline pushes notification_updated SSE event.pending_approval.Pre-authorization bypass (D6):
request_draft routing (D7):
request_draft classified correctly (no regression from Phase 42 classification tests).request_draft with per-action delegation creates approval card.request_draft with pre-authorized delegation executes directly.request_draft with no delegation returns denial (responder explains Companion needs authorization).request_draft extracts shape type and engagement from classifier parameters.
approve_draft routing (D8):
approve_draft processes conversational approval of pending approval card.approve_draft with no pending card returns "nothing to approve."approve_draft triggers engine operation (same result as REST approval endpoint).
request_revision routing (D9):
request_revision with per-action delegation creates approval card.request_revision with pre-authorized delegation executes directly.request_revision identifies target shape or render from classifier parameters.Backward compatibility:
Expected substrate test count: ~30–40 new tests.
Approval card rendering:
approval_status is present.POST /operator/notifications/{id}/approve.POST /operator/notifications/{id}/decline.Badge and drawer integration:
Expected frontend test count: ~8–12 new vitest tests.
| Step | What | Auto/checkpoint |
|------|------|-----------------|
| 0 | Pre-flight: verify baseline (substrate 1,701 + 26 skipped, frontend 270 vitest, Alembic 0060). Verify all 19 pre-flight items. Archive this CR to docs/phase-crs/. | Auto |
| 1 | Migration 0061: extend companion_notifications with six nullable columns (D4). Verify migration runs, columns exist, existing rows unaffected. | Auto |
| 2 | Delegation assertion schema and query functions (D1). Delegation content model, create/query/revoke functions. Tests §7 items 1–7. | Auto |
| 3 | OVA seam: verify_companion_authorization function and AuthorizationResult model (D2). Tests §7 items 8–13. | Auto |
| 4 | ActorRef extension (D3). Add capability_ref and approval_mode. Tests §7 items 14–15. | Auto |
| 5 | Approval card creation and processing (D5). Notification service additions, approve/decline endpoints, SSE integration. Tests §7 items 16–27. | Auto |
| 6 | Pre-authorization bypass (D6). Direct execution flow for pre-authorized delegations. Tests §7 items 28–30. | Auto |
| 7 | Intent activation: request_draft handler, classifier prompt update, intent instruction template (D7, D10). Tests §7 items 31–35. | Auto |
| 8 | Intent activation: approve_draft handler, intent instruction template (D8, D10). Tests §7 items 36–38. | Auto |
| 9 | Intent activation: request_revision handler, intent instruction template (D9, D10). Tests §7 items 39–41. | Auto |
| 10 | Delegation CRUD through conversation: extend remember_about_me, forget_about_me, delegation query response (D1 CRUD). | Auto |
| 11 | Backward compatibility and vocabulary wall. Tests §7 items 42–46. Full substrate test sweep. | Auto |
| A | Checkpoint A — Operator confirms substrate work. All substrate tests pass. | Checkpoint |
| 12 | Frontend: approval card component with Approve/Decline buttons. API client additions for approve/decline endpoints. Tests §7 items 47–52. | Auto |
| 13 | Frontend: notification drawer and badge updates for approval cards. Tests §7 items 53–54. | Auto |
| 14 | Frontend verification: npm run lint && npx tsc --noEmit && npm run build && npm run test clean. | Auto |
| B | Checkpoint B — Operator confirms. Tag both repos phase-45-delegation-contract-and-approval-cards. Implementation notes. Arc 2 complete. | Checkpoint |
verify_companion_authorization correctly resolves delegation state (authorized/denied, per-action/pre-authorized, scope check, constraint check).request_draft intent is live (no longer stub). Produces approval card or direct execution.approve_draft intent is live. Processes conversational approval.request_revision intent is live. Proposes re-production through approval flow.ActorRef on Companion-created events carries capability_ref and approval_mode.request_redirect activation. Cross-engagement knowledge transfer remains a stub.request_redirect).phase-45-delegation-contract-and-approval-cards on both repos.
Read the Change Request document at the path I supply below. This is
CR-2026-059 v0.1, the Phase 45 Change Request. You are the executing
agent named in the CR.
CR path: ~/Downloads/phase-45-cr-delegation-contract-and-approval-cards-v0_1.md
Phase 45 adds delegation contract, approval cards, and OVA seam.
The Companion becomes an agent with bounded autonomy: it proposes
engine operations, the Operator approves or declines, and a
delegation contract governs what the Companion can do. Three stub
intents activate (request_draft, approve_draft, request_revision).
Full-stack phase. One migration (extend companion_notifications).
Two checkpoints: A after substrate, B after frontend. Arc 2 final
phase.
Code baseline: tag phase-44-sse-and-proactive-behavior (substrate
at b474d26, frontend at 0f1edee). Substrate: 1,701 tests, 26
skipped, Alembic 0060. Frontend: 270 vitest (27 files).
eslint/tsc/build clean.
Run pre-flight (Step 0) per Section 3.2. Nineteen pre-flight items
covering substrate (items 1–15) and frontend (items 16–19).
Per Section 3.3: archive this CR to
docs/phase-crs/phase-45-cr-delegation-contract-and-approval-cards-v0_1.md
in the substrate repo at Step 0.
Per Section 8, fourteen steps with two checkpoints. Steps 1–11
(substrate) then Checkpoint A. Steps 12–14 (frontend) then
Checkpoint B (final, tag both repos, Arc 2 complete).
Pre-flight surprises stop at Step 0 and drive a CR amendment.
Implementation notes at Checkpoint B:
docs/phase-impl-notes/phase-45-implementation-notes-v0_1.md
DUNIN7 — Done In Seven LLC — Miami, Florida Phase 45 CR — v0.1 — 2026-05-06