Skip to content

feat(t12): durable coding lanes with task-bound belts (off by default) - #1520

Merged
DealAppSeo merged 25 commits into
mainfrom
feat/cc-2026-11-07-t12-durable-lanes
Nov 8, 2026
Merged

DealAppSeo merged 25 commits into
mainfrom
feat/cc-2026-11-07-t12-durable-lanes

Conversation

@DealAppSeo

@DealAppSeo DealAppSeo commented Nov 8, 2026 •

Copy link
Copy Markdown
Owner

Durable coding lanes for T12: claim, make, independently check, integrate, refill. They run on trinity_tasks with no new table. Off by default and not scheduled. The most a lane can publish is a draft PR, and a human merges.

What this adds

  • Lanes (src/orchestration/t12-lane-*.ts, scripts/t12/lanes.ts): leases with a fencing token, exact-file path locks, hash-chained decision receipts, automatic refill, duplicate-wake refusal, and the emergency halt.
  • Independent check: a different lane re-runs the test in a fresh checkout. The test must also fail when the code change is reverted and when each break the task names is applied.
  • Free-only routing: per-provider cooldowns in the database, at most two hosts per claim, and WAITING_FOR_CAPACITY when every route is cooling. Together is removed. A 429 still stops that wave; the next claim routes elsewhere.
  • Restricted worker: the CLI refuses to start with privileged environment variables or a database role that can bypass row security.
  • Task-bound belts: a lane needs a live belt for this task and this claim before it can submit. Postgres enforces this through the worker role's row policy. The worker has no privilege on the grants or the denial log, and a denied belt never reaches a model.

Needs the owner before it can run against production

migrations/2026-11-08_t12_lane_worker_role_DRAFT.sql is a draft and has not been applied. Set the role's login password separately.

Review it as a change to more than the lanes. It closes PUBLIC EXECUTE on existing SECURITY DEFINER functions in public that are still open to PUBLIC, because PUBLIC cannot exclude one role. Every other existing role is granted EXECUTE by name first, so none of them gains or loses access. A role created later would not inherit access to those functions through PUBLIC.

Limits

  • A belt does not gate model calls. The worker holds its free provider keys. It refuses the OpenRouter key, whose account holds paid credit, so a restricted worker cannot use that route.
  • Maker and checker share one database role, so a compromised worker could forge a verdict on work already submitted. The human merge is the gate for that.
  • A denied direct write is refused, but only Postgres's own log records it. Checkout denials are recorded where the worker cannot edit them.
  • A belt is a server-issued grant. It is not a signature or a ZK proof.
  • The verdict is labelled same_controller_rerun. Controls are only as strong as the breaks a task names.

Evidence

  • Full suite at 1d952b86: 12,958 passed, 150 failed. By test name against main at 1869bd40, the only new failures are two 5-second timeouts in tests/hal-crag-corroboration. That suite already fails on main and varied between 1, 2 and 4 failures across runs today. This branch changes no HAL file.
  • Enforcement mutations: 27 of 27 belt rules caught by a named test, plus all 37 fixes made after Strix's review, each red without the fix. An earlier pass found a real defect, since fixed: a same-named role that already existed kept its privileges.
  • Lane, handoff and halt suites at 8855a180: 437 passed. The full-suite figure above predates the review fixes.
  • Real run: three OS processes under the restricted role took three different tasks at once on TrustShell with free models. Two commits were approved by a different lane than the maker, with negative controls red. A third was rejected on a real compiler error.
  • Crash recovery and duplicate-wake refusal use real processes and SIGKILL, with a loopback model.

The Postgres test blocks need a throwaway database and report as skipped without one. The variable is named at the top of each block.

🤖 Generated with Claude Code

DealAppSeo and others added 17 commits November 8, 2026 00:20
The orchestration pieces (leases, handoff gate, admission) had no caller that
composed them into claim, make, check, integrate, refill. This adds that, on
existing trinity_tasks columns, so it needs no DDL.

- Fenced transitions: each is one transaction that appends a hash-chained
  decision receipt. metadata.t12.epoch is the fencing token.
- Leases use expires_at and the existing trinity_reap_expired_claims cron.
- Exact-file path locks are decided under one advisory lock.
- A different lane re-runs the test in a fresh checkout, then removes the
  deliverable and requires the test to fail.
- Lane rows avoid every status the RepID bridge polls, so this path cannot
  move a score. Publishing stops at a draft PR.

Nothing arms it: T12_LANES_ENABLED, T12_LANES_ALLOW_EXEC and T12_LANES_PUBLISH
are each off unless exactly true, and nothing schedules it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The negative control deleted the test, so it proved only that a file went
  missing and approved an empty test. Controls now revert the code change and
  apply breaks the task names to the code under test.
- spec.context was unvalidated, so a task row could send any local file to a
  model. It now has the same fence as a write.
- A dead host looped on one row and exhausted it. Blameless releases refund the
  claim, infra pauses the run, and an exhausted task gets a terminal state.
- Checks no longer block the event loop and starve other lanes' heartbeats.
- One dropped connection no longer kills the sibling lanes.
- A commit this host cannot see is NOT_CHECKED, not a failed check.
- dependsOn is refused: a maker bases on main, which lacks an unmerged parent.
- Removed an epoch bump in recovery that mutation testing showed did nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A live run showed a free model overwrite two existing test files with its own
shorter versions. The new tests passed, so the check would have approved
deleting real coverage. The check now rejects any changed or deleted file
unless the spec lists it in `overwrites`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found when a free-tier rate limit stopped a live run: each attempt left an
empty t12/ branch on the clone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Groq 429 paused every lane for the whole run, and the wave's Cerebras step
used an archived model (404), so there was no real second host.

- T12_ROUTES is now the only set of cloud routes a lane can reach: nvidia,
  openrouter, cerebras, groq. A key being present never makes a host eligible.
  OpenRouter uses a free id and a zero price cap, so a paid model is refused.
- A failed host gets a durable cooldown in agent_resource_claims, no DDL. A 429
  still stops that wave; the task is released at no cost and its next claim
  routes to a host that is not cooling.
- Every route attempt is receipted with provider, model, reason, status,
  cooldown and task id.
- All routes cooling is a durable WAITING_FOR_CAPACITY state. It costs the task
  nothing and it is not offered again until a route returns. Checks continue.
- together is removed from FREE_PROVIDERS, which gates spend in dev-codegen.

Lane routing has its own order, so the default wave and B21 are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reasoning models spent their whole budget thinking and returned nothing, and
those tokens came out of a limit the whole Groq organization shares. Each route
now caps output, and the two gpt-oss routes use low reasoning effort. Measured
on real calls: valid file JSON in about a second, in 702 and 544 tokens.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mutation testing found this unpinned.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The registry invariant that every lane can reason rejected the HARNESS entry,
and it was right: a re-run does no reasoning and takes no assignments.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A filesystem-pinned test requires each tick loop to gate on the halt, and the
lane runner did not. Lanes now check it before every step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…igin

A lane worker runs model-written code, so it now refuses to start with any
signing, finance, trading or admin credential, or on a database role that can
bypass row security. A draft role confines it to the lane pool. Removing the
import chain to the engine config means it no longer needs a service key.

A second wake of a running lane leaves without doing anything, and a crashed
lane's slot lapses by timer. Each receipt now says whether a person, a
schedule, the system or recovery caused the decision.

Proved on the real path: the CLI as separate OS processes under the restricted
role, with real git and a real SIGKILL mid-task, recovering from durable state.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The migration only created the role IF NOT EXISTS, so a pre-existing
t12_lane_worker with BYPASSRLS kept it. Found by a mutation that survived.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…efused

All five maker failures in the three-lane run were raw newlines inside JSON
strings, and the parser discarded the reason. The lease check is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…path

A lane needs a live belt for this task and this claim before it can submit.
The grant lives in principal_grants, the worker role holds no privilege on it,
and a policy function decides. Denials are recorded where the worker cannot
edit them, and a denied belt never reaches a model. Draft; the owner applies it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… document belts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@DealAppSeo
DealAppSeo marked this pull request as ready for review November 8, 2026 17:03
@strix-security

strix-security Bot commented Nov 8, 2026 •

Copy link
Copy Markdown

Strix Security Review

✅ No open security findings. All previously reported findings have been resolved.

PR summary: Adds durable T12 coding lanes (claim, make, independently check, integrate, refill) on the existing `trinity_tasks` table, with leases and fencing tokens, exact-file path locks, hash-chained decision receipts, free-only model routing with per-provider cooldowns, and a draft migration that creates a restricted `t12_lane_worker` Postgres role whose row policy requires a task-bound belt before a submission can be written. Everything is off by default and unscheduled, and the most a lane can publish is a draft PR.

Review summary

I reviewed the full PR — the lane store, git adapters, runner, router, worker profile, the draft worker-role migration, and the free-provider change — and traced the worker-controlled values into every SQL, git and filesystem sink. The one prior finding, the migration failing open because its sanitising guard aborted only its own DO block, is fixed: the file is now a single BEGIN/COMMIT transaction, so a refusal stops the whole apply, and the new test runs it statement-by-statement as psql -f would. No new security issues were confirmed. The remaining observations are hardening gaps rather than vulnerabilities: check() trusts spec.verify.controls[].file without re-validating it, but the only actor who can author that spec is the lane worker role, which already has the same filesystem write on the same host and already executes arbitrary code there under T12_LANES_ALLOW_EXEC; and the free-only guarantee for the paid OpenRouter route is enforced by the CLI's credential refusal rather than by the routing table itself.

13 resolved findings
Ruled out (5)
  • Can the lane worker role read or write data outside the lane pool through the migration's grants, RLS policies or SECURITY DEFINER functions?
    The sanitising block revokes memberships, table/sequence/column ACLs, function grants, schema grants and default ACLs and aborts the whole transaction on ownership, the belt functions pin search_path and schema-qualify every reference, and the worker holds no grant at all on principal_grants or tri…
  • Can a worker-controlled value reach a git command or filesystem path outside the task's lease?
    submission branch, commit and base are constrained to this task's branch and full object ids by both the row policy and submissionRefProblem before git sees them, and spec.paths/context pass validateSpec plus an exact-match check before any write.
  • Can a lane reach the paid-credit OpenRouter route or start with a privileged credential or database role?
    The CLI refuses OPENROUTER_API_KEY and every credential-shaped name before any work begins, and with T12_FREE_WAVE unset the wave order is empty so no host is attempted regardless of the order override.
  • Can a planted spec.verify.controls[].file make the checker write outside the fresh checkout?
    The mechanism is real but the only actor who can author that spec is the t12_lane_worker role, which already has the same filesystem write on the same host and already executes arbitrary code there under T12_LANES_ALLOW_EXEC, so no privilege boundary is crossed.
  • Does the new T12 route table let an attacker-controlled URL reach the providerFetch passthrough?
    T12_ROUTES holds only hardcoded PROVIDER_URLS literals and the local base is validated to a loopback host, so no attacker-controlled destination reaches the passthrough from the changed code.
Review history (7)
  • Review 7 · 5f9f5b3 · Nov 8 18:59 UTC · Fixed 1
  • Review 6 · 79c61f9 · Nov 8 18:47 UTC · Found 1 new Medium Vulnerability · Fixed 2
  • Review 5 · 8855a18 · Nov 8 18:30 UTC · Found 1 new Medium Vulnerability and 1 new Low Vulnerability · Fixed 3
  • Review 4 · 5fb9ea8 · Nov 8 17:57 UTC · Found 1 new High Vulnerability and 2 new Low Vulnerabilities · Fixed 1
  • Review 3 · 3d8997d · Nov 8 17:46 UTC · Found 1 new Medium Vulnerability · Fixed 6
  • Review 2 · 4aed5c1 · Nov 8 17:23 UTC · Found 1 new High Vulnerability and 2 new Medium Vulnerabilities
  • Review 1 · 1d952b8 · Nov 8 17:13 UTC · Found 1 High Vulnerability and 2 Medium Vulnerabilities and 1 Low Vulnerability

Review 7 on this PR · 5f9f5b3 · requested Nov 8 18:50 UTC on a new commit


Reviewed by Strix
Re-run review · Configure security review settings

prod-fixture-guard refused it: a comment said its definitions were copied from
production, and a made-up row used a real agent's name. It holds table
definitions and invented rows only, and now says so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@strix-security strix-security Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strix flagged 4 new security findings below. See the pinned summary comment for the full PR status.

Comment thread tests/t12-lane-profile.test.ts Resolved
Comment thread scripts/t12/lanes.ts Resolved
Comment thread src/orchestration/t12-lane-profile.ts Resolved
Comment thread src/orchestration/t12-lane-profile.ts Resolved

@strix-security strix-security Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strix flagged 3 new security findings below. See the pinned summary comment for the full PR status.

DealAppSeo and others added 3 commits November 8, 2026 09:23
A compromised worker could set a lane row to a status the RepID bridge scores,
so the row policy now refuses those and the role can write only lane columns.
Re-applying the migration now strips memberships and object grants, not just
attributes. Publishing and running model-written code cannot share a process.
The boot refusal matches credential name families instead of fixed spellings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The worker could call SECURITY DEFINER functions open to PUBLIC, so the migration
closes PUBLIC on exactly those and re-names every other role, and the CLI refuses
to start if a worker can still reach one. Checkout no longer locks or logs tasks
outside the pool, repeated denials write one row, and a belt can only name a lane.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@strix-security strix-security Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strix flagged a new security finding below. See the pinned summary comment for the full PR status.

Comment thread src/orchestration/t12-lane-profile.ts Resolved
An owner skips row policies unless they are forced, so a non-superuser owner
passed the check and escaped every lane policy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@strix-security strix-security Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strix flagged 3 new security findings below. See the pinned summary comment for the full PR status.

Comment thread src/orchestration/t12-lane-store.ts Resolved
Comment thread src/orchestration/t12-lane-store.ts Resolved
Comment thread src/orchestration/t12-lane-profile.ts Resolved
Comment thread src/orchestration/t12-attempt.ts Resolved
Comment thread src/orchestration/t12-attempt.ts Resolved
Comment thread src/orchestration/t12-lane-git.ts Resolved
Comment thread src/orchestration/t12-lane-store.ts Resolved
…ified

Publish pushed a branch and commit read from a row the worker can write. Postgres
now accepts only this task's branch and full object ids, and the checker and
publisher check them again. A refused publish ends the task. The verdict column
no longer says verified_done for a same-controller re-run, and a restricted worker
may not hold a key whose account has paid credit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@strix-security strix-security Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strix flagged 2 new security findings below. See the pinned summary comment for the full PR status.

Comment thread src/orchestration/t12-lane-profile.ts Resolved
…g role

REPLICATION can decode the write-ahead log past row security, and a default
privilege would grant the role every object created later.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@strix-security strix-security Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strix flagged a new security finding below. See the pinned summary comment for the full PR status.

Run with psql -f, the ownership refusal stopped only its own block and the rest
of the file still applied.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@strix-security strix-security Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed the full PR — the lane store, git adapters, runner, router, worker profile, the draft worker-role migration, and the free-provider change — and traced the worker-controlled values into every SQL, git and filesystem sink. The one prior finding, the migration failing open because its sanitising guard aborted only its own DO block, is fixed: the file is now a single BEGIN/COMMIT transaction, so a refusal stops the whole apply, and the new test runs it statement-by-statement as psql -f would. No new security issues were confirmed. The remaining observations are hardening gaps rather than vulnerabilities: check() trusts spec.verify.controls[].file without re-validating it, but the only actor who can author that spec is the lane worker role, which already has the same filesystem write on the same host and already executes arbitrary code there under T12_LANES_ALLOW_EXEC; and the free-only guarantee for the paid OpenRouter route is enforced by the CLI's credential refusal rather than by the routing table itself.


Reviewed by Strix
Configure security review settings

@DealAppSeo
DealAppSeo merged commit 759c8f6 into main Nov 8, 2026
18 checks passed
@DealAppSeo
DealAppSeo deleted the feat/cc-2026-11-07-t12-durable-lanes branch November 8, 2026 21:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant