From 9101d4d6b4a2fba42f8c89a62148ec30c8af7737 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Oct 2026 17:00:48 +0700 Subject: [PATCH 1/2] route: a T27 OS pane on the free key tier is the base tier of every sub-task, Sonnet its first escalation and the orchestrator's tier, Opus after 4 failures or on the owner's word; skills model-routing and t27os-orchestra follow (Closes #11317) specs/claw/model_route.t27 gains TIER_PANE = 2 (TIER_OPUS = 0 and TIER_SONNET = 1 keep their numbers, so no caller changes; no spec imports the module). base_tier is Sonnet for orchestration roles and a pane for every sub-task role, known or not. route escalates one step per ESCALATE_AFTER failures on the same task (pane -> Sonnet at 2, Opus at 4; orchestration Sonnet -> Opus at 2), and the owner flag is Opus at any time. is_waste is now "a stronger tier than route names", so Sonnet on a fresh sub-task is waste like Opus is. 9 tests, 0 vacuous, 1 comptime invariant, t27b --check clean; the new pins cover route(R_IMPLEMENT, 0/2/4), route(R_ORCHESTRATE, 0), the owner flag and a negative control. .claude/skills/model-routing/SKILL.md follows the spec (pane first for sub-tasks, a short "how a sub-task runs as a pane"); .claude/skills/t27os-orchestra/SKILL.md is new: today's T27OS_CTL verbs, the pending ones (#11316) marked, the lane loop and its rules. The seal of the spec is stale until a master-built t27c reseals it. Co-Authored-By: Claude Sonnet 5.5 --- .claude/skills/model-routing/SKILL.md | 36 +++--- .claude/skills/t27os-orchestra/SKILL.md | 67 +++++++++++ specs/claw/model_route.t27 | 145 ++++++++++++++++-------- 3 files changed, 186 insertions(+), 62 deletions(-) create mode 100644 .claude/skills/t27os-orchestra/SKILL.md diff --git a/.claude/skills/model-routing/SKILL.md b/.claude/skills/model-routing/SKILL.md index ed082e760e..723609db01 100644 --- a/.claude/skills/model-routing/SKILL.md +++ b/.claude/skills/model-routing/SKILL.md @@ -1,11 +1,11 @@ --- id: model-routing name: model-routing -description: Which Claude model does which job -- every agent runs on Sonnet 5.5 by default, the orchestrator included, and any job escalates to Opus 5.5 only after two failed attempts or on the owner's word. Load before spawning any subagent, writing a workflow, or picking a model in TRI CLAW or the Queen. +description: Which model does which job -- a sub-task starts in a T27 OS pane on the free key tier, the orchestrator runs on Sonnet 5.5, Sonnet is the first escalation of a sub-task, and Opus 5.5 is reached only after failed attempts or on the owner's word. Load before spawning any subagent or pane, writing a workflow, or picking a model in TRI CLAW or the Queen. argument-hint: "[role: orchestrate|plan|review-final|implement|port|search|test|docs|fix]" --- -# /model-routing -- Sonnet by default for every agent, Opus only on evidence +# /model-routing -- a pane for sub-tasks, Sonnet to orchestrate, Opus only on evidence > **Only t27: everything is written in `.t27`.** (Owner hard rule 2026-10-05; budget #7371; restated in every skill per #7588.) @@ -16,40 +16,44 @@ argument-hint: "[role: orchestrate|plan|review-final|implement|port|search|test| > - What gen cannot express yet is a compiler defect. File it on #5980 with a minimal `.t27` repro instead of writing the code by hand. > - This rule overrides any step below that says to write a script or code in another language. The full text is in `AGENTS.md`, "Only t27". -Owner directive 2026-10-19 (translated): "set Sonnet as the default model for all agents -- it is cheaper with the same result" (#10921). It replaces the 2026-10-18 rule (orchestration on Opus 5.5, sub-tasks on Sonnet 5.5, #10493). The rule is part of TRI CLAW so development stays economical. +Owner directive 2026-10-20 (#11317, summarised): run lanes through T27 OS instead of paid subagents -- cheaper, and the owner watches every lane live in the window. It adds the pane tier below Sonnet for sub-tasks. It builds on the directive of 2026-10-19 (translated): "set Sonnet as the default model for all agents -- it is cheaper with the same result" (#10921), which keeps the orchestrator on Sonnet 5.5; that one replaced the 2026-10-18 rule (orchestration on Opus 5.5, #10493). The rule is part of TRI CLAW so development stays economical. **The law is `specs/claw/model_route.t27`.** This skill is how to follow it in a Claude Code session. If the two disagree, the spec wins; fix the skill. ## The rule -| Role | Kind | Model | -|---|---|---| -| orchestrate, plan, review-final | orchestration | **Sonnet 5.5** (`sonnet`, `claude-sonnet-5-5`) | -| implement, port, search, test, docs, fix | sub-task | **Sonnet 5.5** (`sonnet`, `claude-sonnet-5-5`) | +| Role | Kind | Starts at | Escalates to | +|---|---|---|---| +| implement, port, search, test, docs, fix | sub-task | **a T27 OS pane** on the free key tier (`TIER_PANE`, `pane`) | Sonnet 5.5 after 2 failures, Opus 5.5 after 4 | +| orchestrate, plan, review-final | orchestration | **Sonnet 5.5** (`TIER_SONNET`, `sonnet`, `claude-sonnet-5-5`) | Opus 5.5 after 2 failures | -- Any job goes to Opus 5.5 (`opus`, `claude-opus-5-5`) only on evidence: **2 failed Sonnet attempts on the same task** (`ESCALATE_AFTER`), or the owner says so. Nothing else raises a tier. -- Opus without that evidence is waste for every role (`is_waste`), the orchestrator included. -- Why: epic #10066 measured Sonnet 5.5 at least as good as Opus 5.5 on ten bounded spec-to-RTL tasks (9 vs 8 direct Verilog, 7 vs 7 in .t27) at about 40% of the cost. +- Escalation is one step per `ESCALATE_AFTER` (2) failed attempts on the same task: pane, then Sonnet, then Opus (`opus`, `claude-opus-5-5`). The owner's word is Opus at any time (`owner_flag`). Nothing else raises a tier. +- Any tier stronger than `route` names is waste (`is_waste`): Opus on a fresh job for every role, and Sonnet on a fresh sub-task that a pane could have run. +- Why: epic #10066 measured Sonnet 5.5 at least as good as Opus 5.5 on ten bounded spec-to-RTL tasks (9 vs 8 direct Verilog, 7 vs 7 in .t27) at about 40% of the cost; a pane costs no tokens, and the gate decides what lands, not the model that wrote the diff. ## How it is wired in Claude Code -- `.claude/settings.json` sets `CLAUDE_CODE_SUBAGENT_MODEL=claude-sonnet-5-5`, so any subagent with no model of its own runs on Sonnet. +- `.claude/settings.json` sets `CLAUDE_CODE_SUBAGENT_MODEL=claude-sonnet-5-5`, so a subagent spawned on escalation, with no model of its own, runs on Sonnet. - Every agent in `.claude/agents/` carries `model: sonnet`, the orchestrator `trinity.md` (Queen) included. - The main session is the orchestrator: pick **Sonnet 5.5** for it in the app's model menu; switch it to Opus only for a job that failed twice on Sonnet or on the owner's word. +## How a sub-task runs as a pane + +The pane tier is a place, not a Claude model: a Claude Code pane in the T27 OS window, started in the lane's worktree through `T27OS_CTL`, on the free key tier (glm-4.5-flash, then an OpenRouter `:free` model). The skill `t27os-orchestra` is the procedure: the brief as a file, spawn, wait, read the report, verify the diff, land with the gates, kill the pane. Which `T27OS_CTL` verbs exist today and which are pending (#11316) is stated there. + ## When you are the orchestrator 1. Plan (on Sonnet): split the task into sub-tasks with a clear input, output and done-check each. -2. Spawn each sub-task with the Agent tool. Leave `model` unset (the default is Sonnet) or pass `model: "sonnet"`. Give the subagent everything it needs in the prompt: file paths, the issue, the acceptance check. A sub-task prompt that needs Opus to understand is a planning failure, not a reason to escalate. +2. Start each sub-task as a pane (`t27os-orchestra`). Give it everything it needs in its brief file: paths, the issue, the boundary, the acceptance check. A brief that needs a stronger model to understand is a planning failure, not a reason to escalate. 3. Verify the result yourself (that is review-final): read the diff or the output, run the check. -4. If the same sub-task fails twice on Sonnet, re-spawn it once with `model: "opus"`, and say in the result why it escalated. -5. In a Workflow script, set `model: 'sonnet'` on sub-task `agent()` calls and keep the orchestration logic in the script itself. +4. If the same sub-task fails twice in a pane, re-run it once as a Sonnet subagent (the Agent tool, `model` unset or `"sonnet"`); if it fails twice there too, once more with `model: "opus"`. Say in the result why it escalated. +5. In a Workflow script, set `model: 'sonnet'` on `agent()` calls for escalated sub-tasks and keep the orchestration logic in the script itself. -Parallelism: at most 3 subagents at once on this 8 GB Mac (swap eats the disk); more on the Railway lab. +Parallelism: about 3 working lanes (panes or subagents together) at once on this 8 GB Mac (swap eats the disk); more on the Railway lab. ## Audit -`is_waste(role, tier, failed_attempts, owner_flag)` in the spec answers whether a run spent Opus on any role without evidence. Use it when TRI CLAW or the Queen records which model ran a job. +`is_waste(role, tier, failed_attempts, owner_flag)` in the spec answers whether a run spent a stronger tier than `route` names. Use it when TRI CLAW or the Queen records which model ran a job. ## Not covered yet diff --git a/.claude/skills/t27os-orchestra/SKILL.md b/.claude/skills/t27os-orchestra/SKILL.md new file mode 100644 index 0000000000..35571a28cc --- /dev/null +++ b/.claude/skills/t27os-orchestra/SKILL.md @@ -0,0 +1,67 @@ +--- +id: t27os-orchestra +name: t27os-orchestra +description: Run a lane as a T27 OS pane on the free key tier instead of a paid subagent -- spawn a Claude Code pane in the lane worktree through T27OS_CTL, give it the brief as a file, wait, read the report, verify the diff, land through the gates. Load before starting any sub-task lane (implement, port, search, test, docs, fix) and whenever model_route.t27 names TIER_PANE. +argument-hint: "[issue number | pane id | list|spawn|kill|read|write]" +--- + +# /t27os-orchestra -- lanes run as panes in the T27 OS window + + +> **Only t27: everything is written in `.t27`.** (Owner hard rule 2026-10-05; budget #7371; restated in every skill per #7588.) +> - New logic starts as a `.t27` spec with `test` / `invariant` blocks. It reaches Rust, C, Zig, JS or Python only through `t27c gen-*`, and generated files are never hand-edited (L2). +> - Hand-written code in any other language is denied by the hooks and by CI: `.rs .py .ts .js .sh .zig .c .go .v .yml .toml`, Dockerfile, Makefile; the full list is in `specs/policy/own_language.t27`. +> - Existing foreign code is debt that only shrinks. Delete it, or replace it with a spec and its generated output. +> - Thin hand-written glue is capped at 40 added lines per file and 80 per PR. No label lifts the cap. Never split a PR to slip under it. +> - What gen cannot express yet is a compiler defect. File it on #5980 with a minimal `.t27` repro instead of writing the code by hand. +> - This rule overrides any step below that says to write a script or code in another language. The full text is in `AGENTS.md`, "Only t27". + +Owner directive 2026-10-20 (#11317): run lanes through T27 OS instead of paid subagents. The law is `specs/claw/model_route.t27` (`TIER_PANE`, the base tier of every sub-task role); the `model-routing` skill says which tier a job gets, this skill says how a pane runs it. If they disagree with the spec, the spec wins. + +## Why + +- **Cheaper.** A pane runs Claude Code on a free key tier (glm-4.5-flash, then an OpenRouter `:free` model, then paid last); a subagent bills Sonnet tokens. +- **Visible.** Each lane is a pane in the T27 OS window; the owner watches it live and can type into it. +- **Same gates.** Nothing about a diff changes because a pane wrote it: the gate decides what lands. + +## Today's verbs (they exist now) + +The client is the `t27os-pty` binary of the running build, run with `T27OS_CTL=`; it makes one call to the running server's socket and exits. The Claude Code Bash sandbox cannot reach that socket (`no server`, exit 10), so run it in a **Terminal tab** (the `run_in_terminal` tool). Facts and traps: `docs/t27os/run-local.md`, section 5 and 6. + +| Verb | Arguments (environment) | Prints | +|---|---|---| +| `list` | none | `pane 0 agent 0 state 2 flags 3 key 2` per pane | +| `spawn` | `T27OS_AGENT` (0 = claude, 9 = shell cell), `T27OS_CWD` (absolute), `T27OS_MODEL` | `spawned pane N` | +| `write` | `T27OS_PANE`, `T27OS_KEYS` | `sent` (text plus one carriage return) | +| `read` | `T27OS_PANE` | the oldest 4088 bytes of the scrollback, never the tail | +| `kill` | `T27OS_PANE` | `killed` | + +Editor panes: `T27OS_AGENT=9` with `T27OS_MODEL=vim|nvim|hx|micro|nano`. State: 0 stopped, 1 working, 2 blocked, 3 idle, 4 done. `T27OS_KEYS` and `T27OS_CWD` are cut at 200 bytes, silently: type a short line, never the brief itself. + +## Pending verbs (gHashTag/t27#11316 -- NOT AVAILABLE YET) + +Do not call these; until they land, use the workarounds in the loop below. + +- `spawn` with `T27OS_TITLE` (the pane's name in the window), `T27OS_PROMPT_FILE` (the brief), `T27OS_PERM` (a permission mode, allow-listed by the owner's decision). +- `wait`: returns `idle`, `exited` or `timeout`, driven by the agent's Stop hook. +- `status`: title, key, model, busy or idle, and the traffic light of #11314. +- `read` with `T27OS_TAIL=`: the end of the scrollback. + +## The lane loop + +1. **One issue per lane**, in its own worktree and branch (`lane/-`), based on a fresh `origin/master`. +2. **The brief is a file** in the lane worktree outside the tracked tree (or in the scratchpad): what to do, the boundary (files it may touch), the gates it should run itself, the branch name, the commit trailer, and "push your branch, no PR, no `gh`". Cite issue numbers as `Closes #N` in the commit only. +3. **Spawn** the pane in the worktree: `T27OS_CTL=spawn T27OS_AGENT=0 T27OS_CWD=`. Today it has no title, prompt file or permission mode: `write` one short line telling it to read the brief file (`T27OS_KEYS='read BRIEF.md and do it'`), and have the brief say to write its final report to a file in the worktree. +4. **Wait.** Today: poll `list` until the pane's state is idle (3) or done (4), at a sensible interval; after #11316 use `wait`. A pane in state 2 (blocked) needs a person or a permission mode: look at it, do not guess. +5. **Read the report** from the file it wrote (today `read` returns only the oldest bytes of the scrollback). +6. **Verify the diff yourself** (that is review-final): read it in full, rerun the checks, never trust the pane's own claim that tests pass. +7. **Land with the gates**: `t27c test-report` FAIL 0 with vacuous passes 0; `t27b test --check --quiet` exit 0; seals regenerated by a `t27c` built from master, not by the pane; seals of the importers; the types ratchet; the dupe scan as a subset of master's; no absolute home-directory path in a committed file; ASCII only. Merge through the usual auto-merge path. +8. **Clean up**: `kill` the pane, remove the lane worktree and the lane's Zig caches (`self-cleanup`). + +## Rules + +- **The gate, not the pane's model, decides what lands.** A weak model that passes every gate is a good diff; a strong one that fails a gate is not. +- **Escalation is the spec's** (`route`): a pane that fails the same lane twice goes to a Sonnet subagent, a Sonnet subagent that fails it twice goes to Opus, and the owner's word is Opus at any time. Say why in the lane's result. +- **At most as many panes as the machine allows.** On the 8 GB bench Mac that is about 3 working lanes. Stop starting lanes when free disk is under 4 GB, swap is over 6 GB or the load is over 40. +- **Never read, print or store a key.** Panes get their keys from the KEYS tab; a lane that needs a key asks the owner, and no brief, report or log contains one. +- **Nothing runs on a partner's machine beyond what its owner agreed.** A lane runs on this Mac or the lab, never on a partner's computer by this skill. diff --git a/specs/claw/model_route.t27 b/specs/claw/model_route.t27 index 70148dfd96..0be0ab2833 100644 --- a/specs/claw/model_route.t27 +++ b/specs/claw/model_route.t27 @@ -1,45 +1,64 @@ // SPDX-License-Identifier: Apache-2.0 -; specs/claw/model_route.t27 -- which Claude model does which job in TRI CLAW and in every agent -; session of this project: every role starts on Sonnet 5.5, the orchestrator included; Opus 5.5 is -; reached only on evidence (failed attempts) or on the owner's word. +; specs/claw/model_route.t27 -- which model does which job in TRI CLAW and in every agent session of +; this project: a sub-task starts in a T27 OS pane on a free key tier, the orchestrator starts on +; Sonnet 5.5, Sonnet is the first escalation of a sub-task, and Opus 5.5 is reached only on evidence +; (failed attempts) or on the owner's word. +; Owner directive 2026-10-20 (#11317, summarised): run lanes through T27 OS, the Mac app built from +; specs/t27os, instead of paid subagents -- cheaper, and the owner watches every lane live in the +; window. It adds a tier below Sonnet for sub-tasks and leaves the orchestrator where 2026-10-19 +; put it. ; Owner directive 2026-10-19 (translated): "set Sonnet as the default model for all agents -- it is -; cheaper with the same result" (#10921). It replaces the directive of 2026-10-18 (#10493): +; cheaper with the same result" (#10921). It replaced the directive of 2026-10-18 (#10493): ; "orchestration through Opus 5.5, sub-tasks through Sonnet 5.5", which kept the orchestration roles ; on Opus as "not a false economy"; the owner has since judged the result the same on Sonnet. ; -- ; WHY. Epic #10066 measured one-shot spec-to-RTL work on the same ten tasks: Sonnet 5.5 passed 9 of ; 10 direct-Verilog tasks against Opus 5.5's 8, and 7 of 10 .t27 tasks against Opus's 7, at about 40% ; of Opus's cost (~$0.41 vs ~$0.99 and ~$0.77 vs ~$1.53 per task, list-price estimates). N = 10, one -; shot: the robust part is that Sonnet is not worse on bounded tasks and is much cheaper. What Opus -; was kept for until 2026-10-19 is the part no sub-task sees -- splitting the work, deciding what is -; true, saying "merge" or "stop" -- and that is now the owner's call per task, through owner_flag. +; shot: the robust part is that Sonnet is not worse on bounded tasks and is much cheaper. A pane on a +; free key tier costs nothing per token, and the gate (tests, seals, ratchets), not the model that +; wrote the diff, decides what lands -- so a bounded sub-task may start there and pay for a stronger +; model only when the pane fails it. What Opus was kept for until 2026-10-19 is the part no sub-task +; sees -- splitting the work, deciding what is true, saying "merge" or "stop" -- and that is now the +; owner's call per task, through owner_flag. ; -- ; THE RULE. ; - A role is either ORCHESTRATION (orchestrate, plan, final review) or a SUB-TASK (implement, -; port, search, test, docs, fix). The distinction stays for records and reviews, but base_tier() -; maps every role to Sonnet. -; - Any role escalates to Opus only on evidence: ESCALATE_AFTER failed Sonnet attempts on the same -; task, or the owner's explicit flag. route() is that rule; nothing else may raise a tier. -; - Opus without that evidence is waste, for an orchestration role as much as for a sub-task. +; port, search, test, docs, fix). base_tier() maps orchestration to Sonnet and a sub-task to PANE. +; - A job escalates ONE step per ESCALATE_AFTER failed attempts on the same task: pane -> Sonnet +; after 2 failures, Sonnet -> Opus after 2 more (4 in all); an orchestration job, already on +; Sonnet, goes to Opus after 2. The owner's flag goes straight to Opus at any time. route() is +; that rule; nothing else may raise a tier. +; - Spending a stronger tier than route() names is waste, for every role and every tier: Opus on a +; fresh job, and Sonnet on a fresh sub-task that a pane could have run (is_waste). ; - The rule names models by the aliases Claude Code's Agent tool and agent frontmatter accept ; ("opus", "sonnet") and by the full API ids, so a host that is not Claude Code (TRI CLAW's own -; chat agent, the Queen) reads the same table. +; chat agent, the Queen) reads the same table. The pane tier is not a Claude model but a place: a +; T27 OS agent pane running Claude Code on a free key tier (glm-4.5-flash, then an OpenRouter +; ":free" model), driven by T27OS_CTL; PANE_ALIAS names it. ; -- ; WHERE IT BINDS. Claude Code: `.claude/settings.json` sets CLAUDE_CODE_SUBAGENT_MODEL to the Sonnet -; id, every agent in `.claude/agents/` (the orchestrator `trinity.md` too) carries `model: sonnet`, -; the main session picks Sonnet 5.5 in the app's model menu, and the skill -; `.claude/skills/model-routing/SKILL.md` tells the orchestrator how to spawn and when to escalate. -; TRI CLAW's app and the Queen read this table when they pick a model (follow-up in their repos). +; id, so a subagent spawned on escalation runs on Sonnet, every agent in `.claude/agents/` (the +; orchestrator `trinity.md` too) carries `model: sonnet`, the main session picks Sonnet 5.5 in the +; app's model menu, and the skill `.claude/skills/model-routing/SKILL.md` tells the orchestrator how +; to spawn and when to escalate; `.claude/skills/t27os-orchestra/SKILL.md` is how a sub-task runs as +; a pane. TRI CLAW's app and the Queen read this table when they pick a model (follow-up in their +; repos). ; ASCII only (L3). phi^2 + 1/phi^2 = 3 | TRINITY module ClawModelRoute; ; --- tiers --------------------------------------------------------------------------------------- +; Ordered by strength, strongest first: a LOWER number is a stronger (dearer) tier, so escalating is +; subtracting one. TIER_OPUS and TIER_SONNET keep the numbers they had before the pane tier existed. pub const TIER_OPUS : u32 = 0; pub const TIER_SONNET : u32 = 1; +/// A T27 OS agent pane on a free key tier: the base tier of the sub-task roles (owner 2026-10-20). +pub const TIER_PANE : u32 = 2; pub const OPUS_ALIAS : str = "opus"; pub const SONNET_ALIAS : str = "sonnet"; +pub const PANE_ALIAS : str = "pane"; pub const OPUS_ID : str = "claude-opus-5-5"; pub const SONNET_ID : str = "claude-sonnet-5-5"; @@ -65,32 +84,34 @@ pub const R_FIX : u32 = 8; pub const ROLE_COUNT : u32 = 9; ; --- escalation ---------------------------------------------------------------------------------- -/// Failed Sonnet attempts on the same task before it may go to Opus. +/// Failed attempts on the same task per step up the tiers: pane -> Sonnet after one multiple of this, +/// Sonnet -> Opus after the next. pub const ESCALATE_AFTER : u32 = 2; pub fn is_orchestration(role : u32) -> bool { return role <= R_REVIEW_FINAL; } -/// The tier a role starts at: Sonnet for every role, known or not (owner 2026-10-19). +/// The tier a role starts at: Sonnet for orchestration, a pane for every sub-task, known or not. pub fn base_tier(role : u32) -> u32 { - _ = role; - return TIER_SONNET; + if (is_orchestration(role)) { return TIER_SONNET; } + return TIER_PANE; } -/// The tier a job runs at: the base tier, raised to Opus for any role only after ESCALATE_AFTER -/// failed attempts on the same task or on the owner's flag. +/// The tier a job runs at: the owner's flag is Opus at any time; otherwise the base tier, raised one +/// step per ESCALATE_AFTER failed attempts on the same task and capped at Opus. pub fn route(role : u32, failed_attempts : u32, owner_flag : bool) -> u32 { - if (base_tier(role) == TIER_OPUS) { return TIER_OPUS; } if (owner_flag) { return TIER_OPUS; } - if (failed_attempts >= ESCALATE_AFTER) { return TIER_OPUS; } - return TIER_SONNET; + const base : u32 = base_tier(role); + const steps : u32 = failed_attempts / ESCALATE_AFTER; + if (steps >= base) { return TIER_OPUS; } + return base - steps; } -/// Is a job running on Opus without the evidence route() asks for? The audit question for a session -/// log or a TRI CLAW run record, for every role. +/// Is a job running on a stronger tier than route() asks for? The audit question for a session log or +/// a TRI CLAW run record, for every role: Opus on a fresh job, Sonnet on a fresh sub-task. pub fn is_waste(role : u32, tier : u32, failed_attempts : u32, owner_flag : bool) -> bool { - return tier == TIER_OPUS and route(role, failed_attempts, owner_flag) == TIER_SONNET; + return tier < route(role, failed_attempts, owner_flag); } test orchestration_roles_start_on_sonnet { @@ -101,26 +122,41 @@ test orchestration_roles_start_on_sonnet { assert is_orchestration(R_IMPLEMENT) == false; } -test sub_tasks_run_on_sonnet { - assert base_tier(R_IMPLEMENT) == TIER_SONNET; - assert base_tier(R_PORT) == TIER_SONNET; - assert base_tier(R_SEARCH) == TIER_SONNET; - assert base_tier(R_TEST) == TIER_SONNET; - assert base_tier(R_DOCS) == TIER_SONNET; - assert base_tier(R_FIX) == TIER_SONNET; +test sub_tasks_start_in_a_pane { + assert base_tier(R_IMPLEMENT) == TIER_PANE; + assert base_tier(R_PORT) == TIER_PANE; + assert base_tier(R_SEARCH) == TIER_PANE; + assert base_tier(R_TEST) == TIER_PANE; + assert base_tier(R_DOCS) == TIER_PANE; + assert base_tier(R_FIX) == TIER_PANE; } test an_unknown_role_is_a_cheap_sub_task { - assert base_tier(ROLE_COUNT) == TIER_SONNET; - assert base_tier(99) == TIER_SONNET; + assert base_tier(ROLE_COUNT) == TIER_PANE; + assert base_tier(99) == TIER_PANE; } -test a_sub_task_escalates_only_on_evidence { - assert route(R_IMPLEMENT, 0, false) == TIER_SONNET; - assert route(R_IMPLEMENT, 1, false) == TIER_SONNET; - assert route(R_IMPLEMENT, 2, false) == TIER_OPUS; +test the_tiers_are_ordered_strongest_first { + assert base_tier(R_IMPLEMENT) > base_tier(R_ORCHESTRATE); + assert base_tier(R_ORCHESTRATE) > route(R_IMPLEMENT, 4, false); + assert route(R_IMPLEMENT, 0, false) - route(R_IMPLEMENT, 2, false) == 1; + assert route(R_IMPLEMENT, 2, false) - route(R_IMPLEMENT, 4, false) == 1; +} + +test a_sub_task_escalates_one_step_per_two_failures { + assert route(R_IMPLEMENT, 0, false) == TIER_PANE; + assert route(R_IMPLEMENT, 1, false) == TIER_PANE; + assert route(R_IMPLEMENT, 2, false) == TIER_SONNET; + assert route(R_IMPLEMENT, 3, false) == TIER_SONNET; + assert route(R_IMPLEMENT, 4, false) == TIER_OPUS; assert route(R_FIX, 5, false) == TIER_OPUS; + assert route(R_FIX, 9, false) == TIER_OPUS; +} + +test the_owner_flag_is_opus_at_any_time { assert route(R_SEARCH, 0, true) == TIER_OPUS; + assert route(R_IMPLEMENT, 0, true) == TIER_OPUS; + assert route(R_IMPLEMENT, 1, true) == TIER_OPUS; } test orchestration_escalates_only_on_evidence_too { @@ -130,12 +166,16 @@ test orchestration_escalates_only_on_evidence_too { assert route(R_ORCHESTRATE, 0, true) == TIER_OPUS; } -test negative_control_opus_on_a_fresh_sub_task_is_waste { +test negative_control_a_stronger_tier_than_route_names_is_waste { assert is_waste(R_PORT, TIER_OPUS, 0, false) == true; - assert is_waste(R_PORT, TIER_OPUS, 2, false) == false; + assert is_waste(R_PORT, TIER_OPUS, 2, false) == true; + assert is_waste(R_PORT, TIER_OPUS, 4, false) == false; assert is_waste(R_PORT, TIER_OPUS, 0, true) == false; - assert is_waste(R_PORT, TIER_SONNET, 0, false) == false; + assert is_waste(R_PORT, TIER_SONNET, 0, false) == true; + assert is_waste(R_PORT, TIER_SONNET, 2, false) == false; + assert is_waste(R_PORT, TIER_PANE, 0, false) == false; assert is_waste(R_PLAN, TIER_OPUS, 0, false) == true; + assert is_waste(R_PLAN, TIER_SONNET, 0, false) == false; assert is_waste(R_ORCHESTRATE, TIER_OPUS, 0, true) == false; assert is_waste(R_REVIEW_FINAL, TIER_OPUS, 2, false) == false; } @@ -144,7 +184,20 @@ invariant every_role_routes_to_a_known_tier { var r : u32 = 0; while (r < ROLE_COUNT) { const t : u32 = route(r, 0, false); - assert t == TIER_OPUS or t == TIER_SONNET; + assert t == TIER_OPUS or t == TIER_SONNET or t == TIER_PANE; + r += 1; + } +} + +test more_failures_never_lower_the_tier { + var r : u32 = 0; + while (r < ROLE_COUNT) { + var f : u32 = 0; + while (f < 12) { + assert route(r, f + 1, false) <= route(r, f, false); + assert route(r, f, true) == TIER_OPUS; + f += 1; + } r += 1; } } From 9419d29ac494970422596e9c29e30d19f83dbe93 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Oct 2026 17:01:54 +0700 Subject: [PATCH 2/2] model routing: a free T27 OS pane tier below Sonnet for sub-tasks, and the t27os-orchestra skill (lanes as panes) (Closes #11317) Merge of master plus sealing, gates run on the merged tree with t27c from master: tests clean with vacuous passes 0, seal --verify MATCH, tri types ratchet CLEAN, dupe_scan failure set a subset of master's. Co-Authored-By: Claude Sonnet 5.5 --- .trinity/seals/claw_ClawModelRoute.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.trinity/seals/claw_ClawModelRoute.json b/.trinity/seals/claw_ClawModelRoute.json index ce4c6a6ab4..a4a4115a1d 100644 --- a/.trinity/seals/claw_ClawModelRoute.json +++ b/.trinity/seals/claw_ClawModelRoute.json @@ -1,24 +1,24 @@ { - "built_by": "t27c-bootstrap@0.5.2+ea35d9b72", + "built_by": "t27c-bootstrap@0.5.2+2d3203e90", "closure": [], "config": "gen=c,rust,verilog,zig;tests=zig", - "gen_hash_c": "sha256:dd581b1b0902f88cc5985caf5b9a6fffcb96d5e5bb136d361c39d3c907d80f94", - "gen_hash_rust": "sha256:0c02f37c6a0859250c13dcfd61998c5929c1d71c72f8fd46a726a557f99b1e67", - "gen_hash_verilog": "sha256:76412baed107fc229715114f3be64f0a6e1d7496eb563d569b32ded5ab9bf57d", - "gen_hash_zig": "sha256:711d11929e6ad2ad59beab7785ba672f5c7812eff2cc1a0aaa1e7e5ddc133ac6", + "gen_hash_c": "sha256:f389334bf5c80b21b056a49fd3c2c95674cb9aa971e93da8bd9f8f5ea1b2bb9c", + "gen_hash_rust": "sha256:17489afe3e8120783e4e8b5ceeb4103151478bce88c8ed55e445ea6db44be9d5", + "gen_hash_verilog": "sha256:155505cf4fb7d816971e0466f6994daa6689436e5935faf51dc62cfa4bab7519", + "gen_hash_zig": "sha256:0a8486007f976ba056ca3e3076920441f771e06324d26629bff358cadd688190", "module": "ClawModelRoute", "ring": 12, "seal_schema": 2, - "sealed_at": "2026-10-19T07:01:31Z", + "sealed_at": "2026-10-20T10:01:38Z", "sealed_by": "t27c-bootstrap@0.5.2", - "spec_hash": "sha256:4dd19b984389e06576034616ba920eb25171abc0b31fc9bde8cf728d248bd915", + "spec_hash": "sha256:841c0295252ade0ee3fb30578dc1efb327082c8c14794fbd99a8f4cba76dfa7b", "spec_path": "specs/claw/model_route.t27", "tests": { "failed": 0, "failing": [], "forced": false, - "passed": 6, - "total": 6, + "passed": 9, + "total": 9, "vacuous": 0 }, "toolchain": {