# ARC Delegate v4

ARC Pi keeps Analyze in the active parent session. Bounded Explore, Research,
Plan, Implement, Verify, and authorized Deploy work uses
`runner-routing-v4`. Automatic calls omit backend/model/route pins. Explicit
routes execute one pinned candidate and inherit no fallback.

Explore, Research, and Plan are operator-gated. Before ARC Pi creates a session
run or starts the runner, dialog-capable Pi UI (TUI or supported RPC) asks the
operator to approve automatic routing or select one of the valid `-explore`
aliases. Decline, cancel, and calls without such UI launch nothing. CI-only
tests may bypass the prompt only with both `CI=true` and
`ARC_PI_READ_ONLY_APPROVAL_BYPASS=1`; this environment gate is not a
model-callable authorization parameter.

## Automatic worker stacks

The stacks below are the human-readable view of the normative
`arc-model-policy` block in
[`docs/arc-model-update-08-30-26.md`](arc-model-update-08-30-26.md). That
block is parsed by `scripts/sync-model-policy.mjs` into
`extensions/arc-orchestrator/model-policy.generated.ts` (route consumer),
`defaults/model-policy.json` (launcher parent default), and the sibling
runner's `plugins/arc-orchestrator/lib/model-policy.generated.ts`.
`npm run policy:check` fails closed when any copy is stale.

Explore, Research, and Plan use the same primary rungs:

`fable-5.1@high → gpt-5.6-sol@high → gpt-5.6-luna@max → opencode-go-glm-5.3@none`

Verify uses:

`gpt-5.6-luna@max → gpt-5.5@low → opencode-go-deepseek-v4-pro@none → opus-4.8@low → cursor-grok-4.6-high@high`

Deploy is unchanged by the OpenCode Go expansion:

`gpt-5.5@low → opus-4.8@low → cursor-grok-4.6-high@high`

Implement uses the approved `workload_class`:

| Workload class  | Primary ordered rungs                                                                                                     |
| --------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `hard-heavy`    | `fable-5.1@high → gpt-5.6-sol@high → cursor-grok-4.6-high@high → opencode-go-glm-5.3@none`                                |
| `hard-medium`   | `gpt-5.6-sol@high → cursor-grok-4.6-high@high → opencode-go-glm-5.3@none`                                                 |
| `hard-light`    | `gpt-5.6-sol@high → cursor-grok-4.6-high@high → opencode-go-glm-5.3@none`                                                 |
| `medium-heavy`  | `gpt-5.6-sol@high → cursor-grok-4.6-high@high → opencode-go-glm-5.3@none`                                                 |
| `medium-medium` | `opus-5@high → cursor-grok-4.6-high@high → opencode-go-glm-5.3@none`                                                      |
| `medium-light`  | `opencode-go-glm-5.3-flash@none → cursor-grok-4.6-high@high → opus-4.8@low → gpt-5.5@high → opus-5@high`                  |
| `easy-heavy`    | `opencode-go-glm-5.3-flash@none → opus-5@high → gpt-5.6-luna@max → opus-4.8@low → opus-5@low → cursor-grok-4.6-high@high` |
| `easy-medium`   | `opencode-go-glm-5.3-flash@none → gpt-5.6-luna@max → opus-4.8@low → gpt-5.5@low → cursor-grok-4.6-high@high`              |
| `easy-light`    | `opencode-go-glm-5.3-flash@none → gpt-5.5@low → cursor-grok-4.6-high@high`                                                |

Every automatic worker stack then appends the same emergency tail:

`opencode-go-kimi-k3@none → minimax-m3@high → composer-2.5@none → cursor-auto@none`

Cursor Auto is terminal. MiniMax M3 uses high effort. Composer, OpenCode Go
(`opencode-go/*` identities on the `opencode` transport), and Cursor Auto
(`cursor-auto` on the `cursor` transport) have no effort value, and ARC does
not forward a generic effort argument to transports that do not expose one.
GLM 5.3 Flash, GLM 5.3, and DeepSeek V4 Pro are the only OpenCode Go models
with automatic rungs; the remaining OpenCode Go bases are explicit-only. The
2026-09-05 revision promotes OpenCode Go Kimi K3 to the head of the emergency
tail (replacing the removed `cursor-kimi-k3` rung) and adds the new Cursor
Auto terminal rung after Composer 2.5. Because fallback is availability-only,
a GLM 5.3 Flash task failure at the head of a chain is terminal rather than
an excuse to advance.

Fallback is availability-only. Provider unavailability, authentication/rate
limits, and response timeouts may advance the stack. Task failure, malformed
output, and verification failure are terminal and must not silently move to a
different model.

## Lifecycle and authorization

1. Explore only when context is missing, after the operator approves its route.
2. Analyze locally with the currently selected Pi parent. The launcher default
   is `openai-codex/gpt-5.6-sol` at high thinking.
3. Research and Plan only when needed, with a fresh operator route approval for
   each worker call.
4. Before Implement, present the exact bounded contract and proposed canonical
   `workload_class` to the operator. Call the tool only after approval, with
   `implement_authorized: true`.
5. Verify independently. Verification failure stops the lifecycle; any further
   implementation needs a revised contract and new Implement approval.
6. Optional Code Review remains separate from Verify and must skip the resolved
   implementation model.
7. Deploy remains human-in-the-loop and requires `deploy_authorized: true` for
   the exact approved deployment action.

### Default background jobs

`arc_delegate` runs every worker phase other than Deploy as a session-scoped
background job by default. Authorization, route selection, operator approval,
and Decision Ledger readiness checks still run before a job is created — an
unready call returns its readiness warning and starts no worker. A ready call
returns promptly with a stable `arc-bg-…` job ID. Passing `background: false`
is the explicit synchronous escape hatch and preserves the awaited result;
`background: true` remains accepted and unchanged. The default applies to the
registered ARC extension tool, which owns the session job manager.

Use `arc_delegate_status` to inspect one job by ID or list the current
session's in-memory jobs. Use `arc_delegate_cancel` with the job ID to request
cancellation. After a worker settles, ARC Pi queues exactly one bounded custom
follow-up containing completion evidence or a failure/cancellation result. The
footer shows the supported running-job count. Successful session shutdown and
extension reload cancel outstanding workers and wait only for the bounded
process termination window. A cancellable pre-switch event does not tear down
the active session. Once shutdown begins, the session accepts no new background
jobs and emits no further job follow-ups or footer updates, including for
workers that settle after that window. Background jobs are intentionally not
restored after reload. Background Deploy is always rejected; authorized Deploy
remains synchronous.

## Decision Ledger v1

ARC Pi exposes three model-callable, non-authorizing ledger tools:
`arc_ask_operator` asks one clarification question, `arc_decisions` reads the
current-effective records on the active session branch, and
`arc_record_assumption` records one explicit assumption. Questions support
single-select, multi-select, yes/no, and freeform responses. Each question has
optional structured context that defaults to `{}`, an optional recommendation and tradeoffs, and a
`blocking` flag that defaults to `false`. Select questions accept two through
five unique options and reserve all dialog control labels, including `Done`.
The rich TUI card and RPC dialog fallback always expose
`Undecided` and `Write my own`; an existing semantic key first offers
`Keep existing` or `Change`. `request_rationale` optionally asks the operator
why they chose an answer. Headless modes return structured `needs_operator`
without writing, while cancellation also writes nothing.
Normal yes/no answers persist as booleans. Choosing `Write my own` persists an
explicit `customAnswer` marker; custom yes/no answers are non-empty text, while
custom multi-select answers remain string arrays.

Records are append-only custom session entries with opaque IDs, optional
`semantic_key`, optional rationale, and an explicit `sensitive` flag. A newer
confirmed decision supersedes effective records with the same semantic key;
an assumption may supersede only an assumption or unresolved record. The
`arc_decisions` lookup returns effective decisions by default and accepts
opaque IDs or semantic keys plus `includeHistory` and `includeAssumptions` for
the other projections. `/arc-decisions [ref] [--history] [--assumptions]` is a
read-only human audit view; quote or backslash-escape refs containing whitespace
or beginning with `--` (for example, `/arc-decisions "--release target"`).
Sensitive values, including semantic keys, are
redacted in lookup, audit, and post-answer human rendering. The active TUI/RPC
prompt remains usable and the immediate clarification result remains available
to the active model/session. Assumptions must identify their affected ARC contract
fields and the risk if they are wrong.

Sensitivity is monotonic across every record kind for a semantic key: any
effective prior sensitive record makes a new decision or assumption sensitive
when the new call omits `sensitive` or sets it to `false`. Lookup, history,
audit, and post-answer projections redact every record sharing a key with any
sensitive record, including mixed decision/assumption records. Keep/Change
prompts and replacement records inherit that privacy.

All Decision Ledger call, TUI, audit, and readiness-warning displays remove C0
and OSC terminal controls. Stored branch records and immediate model-facing tool
results retain their original values. A ref that matches one effective record by
ID and a different effective record by semantic key remains unresolved; a dual
match resolves only when both forms identify the same effective record.

`arc_delegate` accepts opaque or semantic `decision_refs`, `assumption_refs`, and
`readiness_acknowledged` fields. Readiness runs after existing route and
authorization selection but before session-run creation or runner launch.
Unknown or unresolved refs, referenced assumptions without acknowledgment, and
explicit whole-field or embedded placeholders such as `TBD: ...`,
`[placeholder]`, `<placeholder>`, and `{{decision}}` in the five bounded contract
fields return a normal
`readiness_warning` with `launchStarted: false`. Acknowledgment applies only to
the explicitly referenced assumptions and cannot bypass unresolved decisions or
placeholder warnings. Decisions and assumptions are not injected into worker
contracts, and clarification answers never authorize Implement or Deploy.

## Task-scoped Markdown artifacts

Artifacts are disabled by default. When the operator supplies an explicit
`task_slug`, pass that lowercase letters/numbers/hyphens-only value on related
`arc_delegate` calls. Analyze-mode Explore, Research, and Plan add
`--task-slug <slug>` to runner argv, never to the bounded `--task` contract, so
a capable worker may author `docs/<task_slug>/<phase>.md`. Implement and Verify
retain harness-only evidence, while Deploy rejects a slug.

ARC Pi snapshots `docs/<task_slug>/` before launch. Exact `completed` evidence
triggers custody: regular top-level `explore.md`, `research.md`, and
`plan.md` files survive with a 32 KiB cap (checked before and after
sanitization), no-follow opens, line sanitization, and atomic rewrites.
Regular top-level `analyze.md`, `implement.md`, and `verify.md` pass through
untouched so parent-written sibling phase files survive. All other entries are
removed, and kept/deleted paths are surfaced as a warning. Harness evidence is
then appended as an audit footer. Blocked, failed, timed-out, cancelled, and
launch failure outcomes restore snapshot file contents (mode normalized to
`0o644`; mtime is not restored). An older runner that rejects `--task-slug` is
retried once without it after rollback, with a warning and the prior
harness-only behavior.

Use `arc_task_artifact` in the active parent to record Analyze or a manual
Explore, Research, Plan, Implement, or Verify summary. It always roots writes
at the current project cwd. Repeated calls append bounded entries. Unsafe,
absolute, traversal, nested, uppercase, underscore, and overlong slugs fail
without writing. Declines, cancellation (including after runner completion),
readiness warnings, launch failures, timeouts, and blocked, failed, unknown,
malformed, or non-JSON worker results do not create success artifacts.
Automatic writes require parsed worker evidence with status exactly
`completed`. Deploy is excluded from both automatic and manual artifact
creation. Post-worker cancellation checks added for artifact safety run only
when `task_slug` is supplied, so calls without a slug retain their existing
delegation result behavior.

After completed worker-authored custody, ARC Pi best-effort compares Git
porcelain status and warns about newly changed paths outside
`docs/<task_slug>/`. This is advisory: Git may be unavailable, ignored files
are invisible, and status cannot attribute a write to a process.

Only compact evidence fields are persisted: status, summary, changes,
verification, risks, and next actions. Raw contracts/prompts, provider output,
secrets, absolute paths, hidden reasoning, and chain-of-thought are excluded or
redacted. Secret assignments are redacted even when their value is short.
Quoted secret-like keys containing dots, spaces, underscores, or hyphens are
treated the same way. Evidence fields containing a local absolute, UNC, or
`file:` URL path are redacted in full.

Worker artifact sanitization uses the same per-line evidence sanitizer: each
line is whitespace-collapsed and truncated to 240 characters, which mangles
markdown indentation, tables, and code blocks. Secret and absolute-path
heuristics replace the whole line, including benign prose such as `monkey: yes`
or any ` /path` fragment. That fail-closed default is intentional; the
false-positive rate is not quantified.

Artifact writes inspect existing targets before opening them, reject non-regular
files, and use nonblocking, no-follow file opens. Symlinked or non-directory
`docs` and task-directory components are also rejected. This hardening is scoped
to a trusted local project filesystem; it does not defend against hostile
concurrent path replacement or adversarial network filesystem semantics.
Cancellation restores an existing artifact to its prior size; a cancelled first
write removes its new file and any directories that operation created and left
empty. Artifact operations are serialized at the shared `docs` root so cleanup
for one task slug cannot race creation or writing for another. A successfully
returned worker session is recorded as completed before
artifact persistence. Artifact I/O failures are still surfaced to the caller,
but do not rewrite that successful worker session as failed.

After automatic availability exhaustion, ask the operator to choose any
accepted explicit route and recommend the matching Composer route. The chosen
route is pinned without fallback. Obsolete workload names, legacy classes,
Terra, and Grok 4.5 aliases are rejected rather than remapped.

The explicit v4 allowlist has 30 bases, each with `-explore`, `-implement`, and
`-check`: `fable` / `fable-5.1`, `sol` / `gpt-5.6-sol`, `luna` /
`gpt-5.6-luna`, `gpt-5.5`, `opus` / `opus-5`, `opus-4.8`, `grok` /
`grok-4.6`, `kimi` / `kimi-k3`, `minimax` / `minimax-m3`, `composer` /
`composer-2.5`, `cursor-auto`, and the OpenCode Go bases `glm-5.3-flash`,
`glm-5.3`, `deepseek-v4-pro`, `deepseek-v4-flash`, `go-kimi-k3`,
`qwen-3.8-max`, `muse-spark-1.2`, `glm-5.2`, `kimi-k2.7-code`, `go-grok-4.6`,
and `go-luna`. These are exactly 90 executable aliases. Stable bases resolve
to the listed current versions. Kimi is Cursor Kimi K3 through Composer with
provider model `kimi-k3`, never OpenCode; `go-kimi-k3`, `go-grok-4.6`, and
`go-luna` are the provider-qualified OpenCode Go (`opencode-go/<model>`)
twins and never change the existing aliases' transports. `cursor-auto` is
the new last-resort terminal emergency-tail rung on the `cursor` transport;
it has no automatic phase/workload placement. `opus-review` remains a
separate taste-review surface, not an executable runner alias.

Eco remains an explicit opt-in runner mode. ARC Pi selects it only when the
operator asks for `orchestrator: "eco"`; normal worker calls always carry the
`runner-routing-v4` marker so incompatible runners fail closed with an upgrade
message.
