Merge row 333: proxy usage and human model-key quotas, R4 (Gitea #1831)

This commit is contained in:
jason.woltje committed 2026-11-02 19:40:46 -06:00
commit 1ff45c4ad6
122 files changed
+20116 -66

No files matched your search

+27
View File
@@ -5934,3 +5934,30 @@ the reviewer's control shape; .git keeps its raw lstat, the mapper stays ENOENT
.git/objects directory, inside its listed lstat after the real stat, for a symlink to a fixture-only outside directory
or a file; both refuse "expected local .git directory", and were red on 9944100ad (symlink resolved, raw ENOTDIR).
Mutant walk(path, entry) using the passed stat: killed by both. project 44/0/0; read.test.mjs alone 11/0/0 5 of 5.
## 2026-10-26 — row333/P5 Mos1961 implementation begins (Codex)
Base 09a847eda on isolated t3/model-proxy-p5-quota-usage includes landed 362893d04. Accepted scope: human-only per-key quotas and optional value-free usage queue polling; no 657/658/662 work, live proxy/accounts/credentials, broad gates, queue mutation or push. Parent owns independent review and landing. Runtime overlap coordinated with Sage: collector wiring/tick/close at createUsage; Fethry owns launcher/proxy context. Evidence: agents/codex/work/queue-333/BUILD.md.
## 2026-10-26 — row333/P5 Mos1961 scoped candidate verified (Codex)
Implemented human-only model-key quota settings and human-only optional usage plugin/poll changes, native per-key accounting with trusted current/retiring run attribution, bounded management queue reads with immediate client/upstream value hashing, append-only telemetry isolated from quota decisions, and proxy-labelled Console numbers. No schema/deadline/role/launcher/harness/session/business-route changes. Parent-authorized additive usage registry inventories retain every old entry/assertion. Original limit-stop exact subject assertion caught an extra-run regression; retained RED18, reported before retry, corrected production through separate internal context without changing that assertion. Further missing-context and supplied-ID bypass tests fail closed.
Final scoped current whole-file proof: 174/174 PASS across 24 files, serial nice19/private config and tmp roots, unchanged budgets. Upstream-value mutant killed (4 failures), restored byte-identically, positive restoration plus final GREEN. Evidence and 202-input source freeze: agents/codex/work/queue-333/BUILD.md, source-inputs.sha256 and receipts/24-final-current-wholefiles-green.txt. Own scratch cleaned; worktree retained. Parent owns fresh review and admitted combined/full/browser gates under1014.Q264. No queue mutation, remote post, push, merge or landing.
## 2026-10-26 — row333/P5 independent R1 CHANGES repair begins (Codex)
Same isolated branch at503b91e; original history preserved. Verified complete real review SHA2567c95672a30c0d5c39189c7c7d610ada89cd539dcb9413617071fbb81200fd008; findings: P1 foreign-listener queue drain after identity refusal; P2 plain twelve-hex legacy account reinterpretation and empty-check metadata lookup; P2 startup blocked on optional first poll. All source-confirmed. Sequential RED→GREEN repairs in P5 ownership only; receipts/review/response at agents/codex/work/queue-333/r1-repair. Parent retains new independentR2 and heavy/full/browser/combined gates. No queue mutation/push/landing.
## 2026-10-26 — row333/P5 R1 local test priority STOP (Codex)
Mos1971 priority correction applied: earlier R1 nice-only behavior receipts01–06 are priority-unverified. First own-native setPriority/readback attempt07 observed real drift: testPID2643590 entered19, finished16; wrapper2643577 entered19, finished16. Exit78 UNVERIFIED/STOP; six behavior assertions do not establish GREEN. Node test-runner root did not run the forwarded preload, so direct-child handshake capture was incomplete too. All local test execution stopped; no scheduler change/retry. Continue only authorized source/regression preparation for admitted runner, preserving503 and everyrawreceipt. Detailed evidence agents/codex/work/queue-333/r1-repair/RESPONSE.md.
## 2026-10-26 — row333/P5 R1 source packet preparation (Codex)
All3 R1 fixes authored without subsequent local execution: serialized fresh/sticky instance identity fence before queue drain; shared validated daily-model leaf classification restoring plain12hex account semantics and no-check bypass; initial optional poll moved to the same supervised background singleflight path as interval polling. Current controls cover matching/foreign/no-issued-key identity, native current/retiring attribution, legacy matching/report/chief reset and old/new daily fences, held-response native readiness/work/release/failure and unchanged5000ms close deadline. Existing503 cumulative-model fixtures retargeted to accepted daily leaves or plain legacy-account semantics; pre-P5/base assertions/deadlines remain.
Owner directed static-only fallback after actual nativepriority drift: no new product commit, original503 HEAD retained, R1/rawhistory preserved. Full source/test diff, original503+controls baseline and fixed overlays, exact bytes/SHA256/size/Gitblob pins, static dependencies and24+4 whole-file list are prepared under agents/codex/work/queue-333/r1-repair/packet. Static pins are not consumed-source/runtime provenance; all current controls need admittedrunner native root+actualtestchild strict19 evidence and realRED/GREEN before any productcommit. Parent owns pending1014 gate entry/profile, independentR2 and later integration/full/browser/landing; no source freeze will be silently changed.
2026-11-03T00:12:08Z | Claude Opus 5.5 implementation sub-agent (lead T3 c5c1e8ba) | row 333 (#1831) R3 rotation fix on t3/row333-r3-fix, product commit 3692fca52 on b37cc5087 | Ruling 1: a daily key quota follows the agent's key lineage (current, retiring, then up to 64 earlier ids kept in a new optional `previous` field on the model record), so rotation and re-issue keep the quota and its count; an id in two lineages refuses proxy-key-refused; a fired agent's leaf is orphaned, limits nothing, logs limit-key-orphaned once and is listed in the Console usage view. Ruling 2: key-quota-no-model-key for an agent with no model key under a key quota, passed through by name. Ruling 3: covered by the lineage, no mayLaunch change. Ruling 4: the usage module gets one frozen object holding readUsageQueue only. Ruling 5: every telemetry fixture wait rejects by name at a real-timer deadline. Runs: bus 1393/1393, plugins 132/132, business 293/293, webui 499/499, cli stack-release 225/225, stack-release-external 25/25, stack-upgrade 25/25 and launch-limit-checks 5/5; no skips, the model-final-completion flake did not appear; mutants M1 to M4 and M4b each killed. Departure: the human settings writer still stamps a new since on a renamed leaf, so a moved leaf restarts its count; follow-up recommended, not built. No migration, push, queue or PR action.
2026-11-03T01:27:26Z | Claude Opus 5.5 implementation sub-agent (lead T3 c5c1e8ba) | row 333 (#1831) R4 since carry fix on t3/row333-r4-fix, product commit f65faf9df on fe3ef5128, BUILD.md R4 section a13050012 | Ruling 1: the bus runtime passes launchSettings a key lineage lookup read from its own credential records (ids only); a new daily key quota takes the earliest stored since among the old document's daily key quotas in its key's lineage, now only when there is none, so a quota moved from a rotated or re-issued key keeps its count; a reset still sets now, a caller since still refuses, a quota removed and added back later is new, and a failed or malformed lookup refuses proxy-key-refused. Ruling 2: every limits refresh updates the remembered orphan set, empty when no daily key quota is left, so remove then re-add logs again; in memory only, a restart observes afresh. Ruling 3: the poll barrier's last yield is on the captured real setImmediate inside the deadline. Ruling 4: BUILD.md records the 64-id bound as a limit and corrects R3 departure 4 (a late queued event loses telemetry attribution to the reconcile log; not a quota bypass). Runs: bus 1397/1397, plugins 132/132, business 295/295, webui 499/499 (run 1 498/499 with editor-browser.test.mjs:93 timed out under load, the file 16/16 alone, then 499/499 twice), cli stack-release 225/225, stack-release-external 25/25, stack-upgrade 25/25, launch-limit-checks 5/5, harness tools 23/23; no skips, the model-final-completion flake did not appear; mutants M1 to M4, M4b and M5 each killed. Not run: 19 cli files that import bus runtime.mjs without pinning it. No migration, push, queue or PR action.
+295
View File
@@ -0,0 +1,295 @@
# row333 P5 implementation — Mos1961
Base: 09a847eda. Branch: t3/model-proxy-p5-quota-usage. Actor: Codex.
Accepted brief: docs/plans/2026-10-24_model-proxy-rows.md P5; associated design D18–D20 with mos-1600 correction.
Queue next codex refused a linked worktree; no canonical mutation. Parent supplied accepted assignment/authority and coordinated runtime collector ownership. No remote issue posting or live configuration/credential reads.
Ruling: preserve existing schema by carrying safe modelKeyId in usage cursor metadata; proxy telemetry uses a separate source excluded from turnRecords and every quota check. Existing account limits stay compatible. A model key daily quota is keys.<12-hex-id> with reset/timeZone; unset remains no quota. Human-only protection applies to model-key limit changes and resets. No launcher/session/harness/business route edits.
Verification uses serial nice19 node tests with private HOME/XDG_CONFIG_HOME/TMPDIR/MOSAIC_CONFIG and unchanged test budgets. Broad/full gates reserved to parent after row334 target returns. Receipts below are actual command outputs; failures retained.
Parent steering receipts: runtime ownership confirmed createUsage/createLimits collector wiring/tick/close exclusively P5; Fethry avoids this area. Broker changes only usage option accepted by human plugins.set and mustStop run identity. No launch/harness/session/business-route bytes changed.
Exact additive old expectation update authorized by parent: kinds.test.mjs old five-entry Object.keys(KINDS) expected array retains all five in their original order and adds usage. loader.test.mjs complete loaded() expected objects retain all original members and add usage:[]. No old assertion was removed, guard relaxed, timeout increased or sleep added.
First RED receipts: 01-token-red (native key limit incorrectly allows); 02-contract-red (daily key quota, key schema and HTTP method absent); 04-integration-red (new collector absent; native attribution and plugins.set config missing); 08-edges-red (lookup fails open, nonhuman usage writer allowed, Console labels absent); 10-lookup-behavior-red (existing runtime lookup extracted unchanged: missing exception for missing/foreign/ambiguous ownership). 09 captured the preceding missing export, not behavior proof. 05 captured duplicate local variable syntax error, fixed before 06. Runtime fixture failures 12/13 were missing required process identity then incorrect cap extraction; corrected fixture follows actual runtime contract. 14 proves actual model-key issue/preflight, native accounting at key quota, stopping, later launch denial and broker human plugin setting path.
Unexpected existing named failure (reported to parent before any rerun): receipt18 was 169/170, failing `REQ-LIMIT-4 a role run at its limit stops at the end of its turn: RESULT and read land first, the claim is revoked by limit-check` at limit-stop.test.mjs:61. Cause: additional run in the broker's second mustStop argument violated its existing exact subject contract. Fix keeps that argument unchanged; run moves to a separate internal third context and is consumed by host lookup only. The old assertion remains byte-for-byte unchanged. Correction to initial parent message: the quoted name here is the exact failing test name (the first report paraphrased it).
Scoped receipt19: original contract corrected, 170/170 current whole-file tests GREEN. Parent then required direct native-context/no-bypass regression: receipt20 genuinely RED (`stop:false` on a supplied safe-looking modelKeyId when lookup returned null). Removed that fallback entirely and stripped caller modelKeyId/run from the public check subject. Only trusted host resolver can provide the ID; only the separate third internal context provides run. Receipt21: direct context tests, original unmodified limit-stop file and proxy telemetry whole files 15/15 GREEN. Retiring/current mapping rejects wrong business/instance/run and unknown or ambiguous retained IDs.
Final implementation decisions and evidence:
- Native source records carry only the immutable run modelKeyId. New and retained generations resolve from safe Credentials.status metadata; missing, duplicate, foreign or no-longer-retained mappings fail `proxy-key-refused`. Third mustStop context is internal and associated by the broker from its authenticated session, never an agent argument. Missing context is fail-closed (receipt23 genuine RED `stop:false`, fixed in receipt24).
- `tokens.keys.<12hex>` accepts the daily quota shape, uses daily-quota when reset/timeZone are present, and remains unset by default. Existing named account keys and account daily quotas retain their plugins and contracts. All model-key quota/reset changes and usage module/poll changes are fenced at both organization validation points for every writer, tester included.
- Management queue HTTP GET is fixed to loopback with count=100, original 5-second default and 8 MiB response cap, no retries/redirects. Client api_key and upstream source hash immediately to the first 12 SHA-256 hex characters. Fields are whitelisted; malformed batches are atomic. No raw values, upstream body or arbitrary error text reaches product store/log/view/audit.
- Exactly one bus writer owns the collector, shares one management client, drains once and assigns metadata owners, including retained keys. Unknown msk IDs get reconcile receipts; disabled businesses and foreign unmanaged keys get no telemetry. Polling defaults 15 seconds, accepts integer 1..59 and serializes concurrent ticks. `@proxy/cliproxy-queue` records are append-only but excluded before every native turn record/total/limit decision. Availability and account counts are explicitly proxy-reported in the Console.
- Named upstream-value mutant changed `accountId: sha256(event.source).slice(0,12)` to the raw `event.source`: receipt16 exit1, four tests failed. Restoration matched original client SHA256 f5f86cad661034f223a76352d877fa8d7883bfa921a7a01282347a9a03272441, receipt17 positive 15/15. Final receipt24 also runs after restoration and is GREEN.
- Final current whole-file verification: `bash agents/codex/work/queue-333/verify-scoped.sh` → 174/174 PASS, 24 explicitly listed whole files, serial nice19, private HOME/XDG_CONFIG_HOME/TMPDIR/MOSAIC_CONFIG, original test budgets. Raw output: receipts/24-final-current-wholefiles-green.txt SHA256 3358af061c35d42b00d5ee1e001939534c5e7563d4f5418ea85431605d0b9f6d. Runner SHA256 c8a2bf4539bffe38f3198308fd60e9c1ad338841b406af160ab0739c15394290.
- Source freeze: source-inputs.sha256 enumerates all 202 consumed repository inputs (182 modules/scripts plus 20 schema/PIN/other files), traced on final execution and rehashed unchanged after it. Manifest SHA256 b4662dcafb2aeb27a06e5dbd3b9d0b6d184e8624e344fed351ff20e3b255951b. Raw per-process trace is receipts/source-inputs.raw.jsonl. candidate-sourcepaths.txt and candidate-sourcehashes.sha256 list every changed package file for parent combination; receipts.sha256 covers every raw run and source trace. Runner/trace use no content logging.
- Cleanup: original private mktemp root removed and absence verified; scoped runner EXIT trap removes its separate private root. All fixture servers/stores close through test cleanup. Mutant backup and temporary root marker removed. Isolated worktree retained for parent review; no production process, real proxy, account, config, credential path or provider was contacted.
Limits and handoff: scoped GREEN is not the full landing gate. No package/full gates, Chromium/browser gates, acceptance binary, canonical queue mutation, remote issue post, push, merge or landing was run. Full/browser/combined gates remain with the parent under 1014.Q264 after admission; fresh independent Codex review is the parent's next task. No self-approval is claimed. Base remains 09a847eda and no unlanded662/657/658 feature bytes were imported.
## R2 fixtures
Base 09a847eda, row 333 tip ddb3e961f, R2 fixture commit 12eba4b59. Author: Claude (sub-agent of the Mosaic Stack lead, T3 c5c1e8ba). Issue #1831. No product code, business document schema or test assertion changed.
Cause. Row 333 added packages/plugins/src/model-quota.mjs and imports it from packages/business/src/launch.mjs:3 and packages/business/src/organization.mjs:11. The cli release fixtures build smaller copies than a real stack copy: they copy packages/business/src and add only packages/plugins/src/kinds.mjs. Their business loader therefore failed with "Cannot find module .../packages/plugins/src/model-quota.mjs". Real copies are unaffected, because scripts/stack-copy.sh ships all of packages/plugins (COPY_PATHS, line 41). R1's evidence ran the 24 touched test files only (verify-scoped.sh, 174/174) and no package or cli gate, so it never built a release fixture copy and could not see this.
Fixture changes (tests only):
- packages/cli/tests/business-imports.mjs (new, 26 lines): businessImportedFiles(repo) reads the relative imports of every .mjs under packages/business/src and returns, sorted and repo-relative, the files outside that directory they reach, following those files' own imports. An import of a missing file throws. At this tip it returns packages/library/src/limits.mjs, mapping.mjs, problems.mjs, packages/plugins/src/kinds.mjs and packages/plugins/src/model-quota.mjs.
- packages/cli/tests/stack-release-fixture.mjs:314 (copies for stack-release.test.mjs, stack-release-external.test.mjs and stack-upgrade.test.mjs): after the business, library and roles copy, copy each returned file that is not already in the copy. kinds.mjs is skipped on purpose, because the fixture has already written its KINDS_OLD or KINDS_NEW form there.
- packages/cli/tests/stack-release.test.mjs:1994 (the RCOPIES copies): same loop.
Searched for other fixtures that copy packages/business/src without the whole plugins directory: the grep over packages/*/tests, scripts and scripts/testing finds only those two. packages/cli/tests/case2-install.test.mjs:74 copies packages/business/src/vocabulary.mjs alone, which has no imports. stack-copy.test.mjs and stack-release-external.test.mjs:450 copy tracked files or the whole repository, so they carry model-quota.mjs already.
Production check (every place that copies, mounts or packages business code or plugins/src/kinds.mjs without the whole plugins directory):
- scripts/stack-copy.sh:32 copies packages/business/src and :41 copies the whole packages/plugins, so model-quota.mjs reaches every real copy. scripts/case2-install.sh:185 calls it.
- scripts/stack-release.sh:371 and :378 import the copy's own packages/business/src/business.mjs, which reaches launch.mjs and so model-quota.mjs. That copy comes from stack-copy.sh, which takes both directories from the same commit.
- packages/seat/src/sandbox.mjs RUNNER_FILES (:50-:72) mounts packages/business/src/vocabulary.mjs (:67) and packages/plugins/src/kinds.mjs (:68) only. A transitive import walk from all 19 listed files reaches no file of packages/business or packages/plugins outside that list; launch.mjs, organization.mjs, business.mjs, loader.mjs and model-quota.mjs are not reached. vocabulary.mjs and kinds.mjs import nothing. packages/seat/src imports only vocabulary.mjs from business (compactions.mjs:46, sandbox.mjs:40, session.mjs:42). model-quota.mjs is therefore not needed in the sandbox.
- scripts/test-darkwing-launch.mjs:34 and scripts/test-rocko-launch.mjs:25 copy packages/seat/src alone, which needs only vocabulary.mjs.
- Containerfile:23-26 copies contracts, src, two processing-control files and adapters; src imports nothing from packages. compose.yaml mounts the data root and the auth file only.
- scripts/mosaic:35 and scripts/case2-precheck.sh:85,171 import business code from the repository or copy they sit in, which holds all of packages/plugins.
Result: no production path misses model-quota.mjs. No product change was needed or made.
RED, on ddb3e961f before the change (whole files, from packages/cli, one at a time, TMPDIR /mnt/storage/scratch/tmp/QYOMZY):
- stack-release.test.mjs: 224 tests, 56 pass, 168 fail, 0 skip, 186 s. 127 log lines carry the missing-module message.
- stack-release-external.test.mjs: 25 tests, 4 pass, 21 fail, 0 skip, 32 s.
- stack-upgrade.test.mjs: 21 tests, 7 pass, 14 fail, 0 skip, 25 s.
These match the counts the join child recorded (56/168, 4/21, 7/14).
GREEN, on 12eba4b59:
- stack-release.test.mjs: 224/224 pass, 0 fail, 0 skip, 694 s. stack-release-external.test.mjs: 25/25, 88 s. stack-upgrade.test.mjs: 21/21, 66 s.
- cli whole (node --test tests/*.test.mjs): 1045 tests, 1044 pass, 0 fail, 1 skip, 656 s. The skip is "FED R7 scratch two-instance acceptance", which names scripts/test-federation-acceptance.sh as the way to run it.
- business 286/286, 3 s. bus 1380/1380, 49 s. plugins 123/123, 1 s. model-proxy 108/108, 1.4 s. webui 492/492, 63 s. No skips in these. The model-final-completion.test.mjs:69 host flake (16 !== 19) did not appear, so no rerun was needed.
- The counts for business (286) and plugins (123) are lower than the join's (292, 128) because the join included row 332's tests; this branch stays on base 09a847eda.
Mutant. With the helper changed to drop model-quota.mjs from its result (a one-line filter in business-imports.mjs), stack-release.test.mjs gave 224 tests, 56 pass, 168 fail in 183 s, with 127 "Cannot find module .../packages/plugins/src/model-quota.mjs" lines. The helper then printed four files, without model-quota.mjs. git checkout restored the file; git status --short printed nothing afterwards.
## Join onto landed 332
Written 2026-11-02T22:49Z by Claude (sub-agent of the Mosaic Stack lead, T3 c5c1e8ba), author of this join. Issue #1831. Checkout branch t3/row-333-join-replay.
Base and heads. Row 333 R2 head 0ef269da9 on base 09a847eda (R1 503b91e56, overlay 2627321f6, docs c012b2e0a and ddb3e961f, R2 fixtures 12eba4b59 and 0ef269da9). Row 332 landed on refactor at 5df0e9d6f (R2 and the lead correction). The branch started at 5df0e9d6f with no commits of its own and a clean tree. Command: git -c core.attributesFile=/mnt/storage/scratch/q284gate/union.attributes merge --no-ff --no-commit 0ef269da9. Merge commit c0c291cda, parents 5df0e9d6f and 0ef269da9, made at 22:33:47Z.
Why a replay. The earlier join (eabeb1aa8) was made on 332 R1. Row 332 then changed (R2 and a lead fix) and row 333 gained two fixture commits. Both rows change packages/business/src/launch.mjs and packages/plugins/README.md.
Conflicts. Exactly two paths, the two named in the brief. No other path conflicted.
- packages/business/src/launch.mjs, import block (lines 3 to 8 before resolution). 332 changed the errors import to `{ BusinessError, refuse }` for the proxy route refusals in checkModels. 333 added `import { isDailyModelQuota } from "../../plugins/src/model-quota.mjs"` for the daily model leaves in checkTokenLimits. They do not contradict. Resolution: both imports, the model-quota line first, then `{ BusinessError, refuse }`. The rest of launch.mjs merged without conflict: 332's checkModels route handling and the checkAccount `proxy` credential, and 333's checkTokenLimits keys block.
- packages/plugins/README.md, end of file (lines 331 to 378 before resolution). 332 appended "Per-session proxy context (P3)" and 333 appended "Proxy usage telemetry (row333 / P5)" after the same last paragraph. Resolution: keep both, P3 section first, one blank line between, P5 section last.
Other paths touched by both sides, merged without a conflict and not edited by hand: BUILD-LOG.md and docs/SESSIONS.md (union attribute, both sides' lines kept), and packages/cli/tests/stack-release.test.mjs (333's 3 lines for the business-imports helper, 332's R2 hermetic-launch edits). No product or test file was edited by hand.
Comparison with the reference resolution (/mnt/storage/scratch/tmp/iLeQSZ/join-resolution.patch). I took git diff 5df0e9d6f for the two files and compared it with the reference patch after removing the index lines. The result is identical, and the hunk headers (-1,5 +1,6; -76,8 +77,16; -365,3 +365,12) are equal too, so there is no difference to explain. The reference was a diff against the 332 R1 blobs. launch.mjs is d9ef01b40 and README.md is d4625c9f6 on both 332 R1 and landed 332, so R2 and the lead fix did not change these two files, which is why the earlier resolution carries over unchanged. A correction to the merge commit message: it says the files match the reference "apart from hunk offsets", but the hunk offsets match as well. The commit stays as made.
Tests, on c0c291cda. node_modules linked from /mnt/storage/src/mosaic-stack (a link at the root and a real directory of links under packages/webui), TMPDIR /mnt/storage/scratch/tmp/Z280Ko (31 bytes), each suite whole, one at a time, from its package directory with node --test tests/*.test.mjs, 30-minute limit, started 22:34:09Z. Nothing was skipped, failed or rerun except as noted.
| Suite | Tests | Pass | Fail | Skip | Time |
| --- | --- | --- | --- | --- | --- |
| business | 293 | 293 | 0 | 0 | 2 s |
| plugins | 129 | 129 | 0 | 0 | 1 s |
| bus | 1382 | 1382 | 0 | 0 | 48 s |
| model-proxy | 108 | 108 | 0 | 0 | 1 s |
| harness | 205 | 205 | 0 | 0 | 13 s |
| seat | 223 | 223 | 0 | 0 | 6 s |
| webui | 498 | 498 | 0 | 0 | 132 s |
| cli | 1102 | 1101 | 0 | 1 | 669 s |
| bash scripts/test-federation-acceptance.sh | 1 | 1 | 0 | 0 | 5 s |
The one cli skip is "FED R7 scratch two-instance acceptance", which names scripts/test-federation-acceptance.sh as the way to run it. That script passed 1/1 in the last row, with "R7 cleanup: no child groups, ports or sockets remain". The model-final-completion.test.mjs:69 host flake (16 !== 19) did not appear, so no rerun was needed. Business and plugins are one test higher than the earlier join's 292 and 128, and bus 1382 is two above R2's 1380 on the 09a847eda base; this record does not attribute those differences to a cause.
Cleanup. No test process of mine remained after the runs. The node_modules links and the TMPDIR were removed; git ls-files -co --exclude-standard | grep node_modules printed nothing, and git status --short showed only this file and docs/SESSIONS.md before this commit.
## R3 rotation fix
Written 2026-11-03 by Claude Opus 5.5, implementation sub-agent of the Mosaic Stack lead (T3 c5c1e8ba). Issue #1831. Brief: /mnt/storage/scratch/mosaic-lead/briefs/row333-r3-fix.md. Review: /mnt/storage/scratch/mosaic-lead/reviews/row333-opus.md, findings 1 to 5. Branch t3/row333-r3-fix on base b37cc5087. Product, tests and docs are commit 3692fca52.
### Ruling 1: the quota follows the agent's key lineage
- Model record. `Credentials.#format` accepts an optional `previous`: a non-empty array of at most 64 entries, each exactly `{ keyId, retiredAt }` with a 12-hex id and a canonical ISO time. Anything else refuses `credential-format`, on write and when the file is opened. A record without the field loads unchanged. Safe status shows `previous` (ids and times) next to `retiring`, and an empty array for a record without it. No key value is in it.
- When an id is added. `ModelKeys` adds an id when the key leaves the record. On a rotation the old key first becomes retiring, as before, and its id moves to `previous` when the sweep removes it, at grace expiry or at once when no run is bound to it. On a re-issue (the `#issue` path where the proxy no longer lists the old key) the old id goes straight to `previous`. The field stays absent until the first id leaves. Past 64 the writer drops the oldest, so a record never carries 65; the format refuses 65 as well. A fire removes the record, as before, so a re-hired agent starts a new lineage. The revocation proofs still compare whole records with `isDeepStrictEqual`; a test fires an agent whose record carries `previous` and the proof holds.
- Lineage. An agent's lineage is its current id, its retiring ids, then its earlier ids. `modelUsageKey` checks uniqueness over every lineage on the host: an id in two agents' lineages, or twice in one, refuses `proxy-key-refused`. The new `modelKeyLineages` lists the business's lineages and applies the same host-wide check. `createLimits` takes a `keyLineages` hook, which refuses by default, and passes `lineages` to the checks only when a daily key leaf exists. The subject's key must be in exactly one lineage read in the same call, or the launch refuses and the turn stops. `report` shows every limit `check failed: proxy-key-refused` when the lineages can't be read.
- daily-quota. A key leaf applies to a subject whose key is in the lineage holding the leaf's id, and its tally sums the day's records for every id in that lineage. Usage records and the Console per-key counts stay per key id. Missing or malformed `lineages` throws `bad-lineages`; account quotas never need them.
- mustStop resolves the run's bound key, and that key's lineage decides the leaf. A run may be bound only to the current or a retiring key. A run whose bound id has moved to `previous` refuses `proxy-key-refused`, which stops it.
- Orphaned leaves. A leaf whose id is in no hired agent's lineage counts its own id only and matches no subject, so it refuses no launch. The limits code logs `{event: 'limit-key-orphaned', business, path}` once when a leaf becomes orphaned, not per launch, and again only if it stops being orphaned and becomes orphaned later. `orphanedKeys` feeds `orphanedKeyQuotas` in the usage view, and the Console usage view lists each one: "Key quota <id> matches no agent, so it limits nothing. A fire and re-hire gives the agent a new key; set the quota on the new key id." A fire and re-hire therefore leaves the old leaf orphaned, and the human sees it in that view. The Token limits panel can only reset leaves, not rename them, so the text points at the new key id rather than at that panel.
- Docs. packages/plugins/usage/cliproxy-queue/README.md (where row 333 documents `tokens.keys` leaves), packages/plugins/README.md (the limit-check interface gains `lineages` and `subject.modelKeyId`, plus the daily-quota section) and packages/plugins/limit-check/daily-quota/README.md each gain the rotation and orphan sentences. The business package documents no model-key leaf, so it has no doc change.
- Rollback. A release from before this round refuses a record that carries `previous` with `credential-format`, which fails closed. No live stack holds proxy model records yet (no proxy cutover until Vikunja #774), so no migration was built.
Departures from the expected shape, and why:
- 65 entries: both refuse and trim. The format refuses 65 (a hand-edited or foreign record), and the writer trims to the newest 64 so the bus never writes one. Both are pinned.
- A keyless agent under a key quota refuses even when every key leaf is orphaned. An orphaned leaf matches no subject, so the refusal is not needed to enforce it, but resolving the subject's key comes first and I kept that fail-closed order rather than add a second path that skips it.
- Moving a leaf through the human writer. The brief says moving a leaf from A to B on rotation day must not reset the count. The tally does sum A and B: a leaf named B whose `since` is the day's start counts 160 (90 on A, 70 on B) and refuses. But the human settings writer treats a rename as a new leaf and stamps `since` with the move time, so a leaf moved through the writer counts only the usage after the move (100 in the test, not 160). I did not change the writer: the `since` stamping is the row 125/126 human-writer contract, in the business package, and changing it widens this round. With the lineage, the move is not needed, since the leaf on A keeps applying after rotation. Both cases are pinned in p5-key-lineage.test.mjs. Recommended follow-up if the lead wants a moved leaf to keep its count: let the writer carry `since` over when the old and new ids are in one lineage.
- The proxy-usage owner map stays current plus retiring. It attributes proxy queue events, which can only name keys the proxy still accepts, so earlier ids would never match. That is telemetry, not the quota, and I left it.
### Ruling 2: key-quota-no-model-key
`modelUsageKey` throws `key-quota-no-model-key` when the agent has no model record, or one with no key issued. `createLimits` passes that code and `proxy-key-refused` through by name; any other lookup failure is still `proxy-key-refused`. Pass-through, after grepping `proxy-key-refused` across packages/*/src: the broker's organization-error pass-through list gains the code (bus/src/broker.mjs; no organization writer raises it today, but it now passes through the same way as the other proxy key codes). The launcher maps every bus refusal to `limit-check-failed` with message `bus: <code>`, and the turn-end stop reason is `limit: bus failed <code>`; neither needed a change, and both are pinned for the new code (cli launch-limit-checks.test.mjs, bus limit-stop.test.mjs). With no key quota there is no lookup and no refusal.
### Ruling 3: rotation between preflight and mayLaunch
The lineage covers it. Finding 3's case is preflight admitting A, the sweep rotating A to B, and `mayLaunch` checking B. B and A are now one lineage, so a leaf named A matches the subject B and counts A and B: the launch refuses. The rotation test asserts exactly this state (A retiring, B current, `mayLaunch` refuses under the A leaf). After a re-issue, A is not current or retiring, so binding a run to A refuses. I found no gap, so `mayLaunch` does not take the admitted key id.
### Ruling 4: the usage module gets readUsageQueue only
`createProxyUsage` hands the module `Object.freeze({ readUsageQueue: () => management.readUsageQueue() })`. cliproxy-queue reads `read({ readUsageQueue })`. The test wraps the real loader to capture the argument. It has exactly one own key, `readUsageQueue`, a function, is frozen with `Object.prototype` as its prototype, and a walk over every own property, accessor and prototype reachable from it finds neither the client, its prototype, its class nor any of its other methods by name or by reference. Spies on every client method show only `readUsageQueue` was called, and the event was still recorded.
### Ruling 5: fixture deadlines
Each wait in p5-telemetry-fixture.mjs (`waitLog`, `waitQueue`, `settleInitial`, `pollSettledAfterTick`) races a deadline on the real `setTimeout`, captured when the module loads, before any test mocks timers. The default is `WAIT_MS` = 5000 ms; the fixture takes `waitMs`. The rejection names what it waited for, for example `p5 fixture: no usage queue read number 1 within 50 ms`. The new test mocks every timer API, never advances it, and asserts all four rejections by exact message with `waitMs: 50`. The p5-background.test.mjs header is updated.
### Tests
Added: packages/bus/tests/p5-key-lineage.test.mjs (9 tests). It uses the real `Credentials`, `ManagementClient`, `ModelKeys` and its sweep, `createLimits`, `modelUsageKey`, `modelKeyLineages` and the daily-quota module, with a fake loopback management server, a made-up management key and a fresh temp root. Only `Date` is mocked.
- Rotation mid-day under a hit leaf named A: refuses before, right after (A retiring, B current), inside the grace, after the grace (A in `previous`) and after a restart that reloads the record. The run bound to A stops at its turn end after the rotation. Another agent stays allowed.
- Re-issue: the proxy no longer lists A at preflight, B is issued, A is in `previous`, and the leaf still refuses, including after a restart. A limit of 101 allows.
- The leaf moved from A to B on rotation day still refuses with count 160, and the run bound to A stops.
- The settings-writer move: `since` is the move time and the count is 100.
- Lineage uniqueness: an id in two agents' lineages refuses both, and the report shows check failed. An id twice in one lineage refuses too.
- Format: a record without `previous` loads; thirteen malformed values refuse `credential-format` on write and on open, including 65 entries, a key value in place of an id and an empty array; 64 earlier plus 64 retiring load within the 16384-byte cap.
- A re-issue on a record holding 64 drops the oldest.
- Fire and re-hire: the revocation proof holds with `previous` present, the old leaf is orphaned, three launches go ahead, one log line, the view lists it, and no key value is in the logs, view, receipts, status or store files.
- Ruling 2 on `modelUsageKey`, `mayLaunch` and `mustStop`, and no lookup without a key quota.
Also added: three daily-quota tests (lineage match and count, orphan, `bad-lineages`), one usage-render test (the orphan list, escaped), the ruling 4 test in proxy-usage.test.mjs, the ruling 5 test in p5-background.test.mjs, and the new code in limit-stop.test.mjs and cli launch-limit-checks.test.mjs. Changed for the new rules: limit-checks.test.mjs (a leaf on a retiring key now applies to the agent's current key too, so the launch refuses; an unrelated lineage still allows), p5-key-context.test.mjs (the two no-owner cases now expect `key-quota-no-model-key`; a wrong run stays `proxy-key-refused`), p5-key-compatibility.test.mjs (passes `lineages` to the module) and the p5-telemetry-fixture.mjs waits.
### Runs
All on 3692fca52, one at a time, each under a 30-minute limit, with TMPDIR under /mnt/storage/scratch/tmp and output to files there. Each whole run is `node --test` over the package's tests directory.
| Run | Tests | Pass | Fail | Skip | Time |
|---|---|---|---|---|---|
| bus whole | 1393 | 1393 | 0 | 0 | 49 s, 23:55:28Z to 23:56:17Z on 2026-11-02 |
| plugins whole | 132 | 132 | 0 | 0 | 0.3 s, 23:56Z |
| business whole | 293 | 293 | 0 | 0 | 2.6 s, 23:56Z |
| webui whole | 499 | 499 | 0 | 0 | 66 s, 23:56:50Z to 23:57:56Z |
| cli stack-release.test.mjs | 225 | 225 | 0 | 0 | 664 s, 23:58:03Z on 2026-11-02 to 00:09:07Z on 2026-11-03 |
| cli stack-release-external.test.mjs | 25 | 25 | 0 | 0 | 88 s, 00:09:07Z to 00:10:35Z |
| cli stack-upgrade.test.mjs | 25 | 25 | 0 | 0 | 69 s, 00:10:35Z to 00:11:44Z |
| cli launch-limit-checks.test.mjs | 5 | 5 | 0 | 0 | 0.2 s, 00:11:44Z |
The model-final-completion.test.mjs:69 host flake (16 !== 19) did not appear, so no rerun was needed. Against the join record above, bus is up 11 (the 9 lineage tests, the ruling 4 test and the ruling 5 test), plugins up 3 (the daily-quota tests) and webui up 1 (the usage-render test); business is unchanged. The other changed tests changed existing cases or added table rows, not tests.
### Mutants
Each was applied to the committed tree, run against the named file, and restored with `git checkout -- <file>`; `git status --short` was clean after each.
| Mutant | Change | Killed by | Result |
|---|---|---|---|
| M1 | daily-quota matches a key leaf to the subject by the leaf's own id only | p5-key-lineage.test.mjs:101, the rotation test: right after the rotation the launch was allowed where a refusal with count 100 was expected. Also :138 (re-issue), :156 (moved leaf, run not stopped), :252 (fire and re-hire) and daily-quota.test.mjs:197 | lineage 4 of 9 fail, daily-quota 1 of 17 fail |
| M2 | the tally counts only the leaf's own id | p5-key-lineage.test.mjs:155, the moved-leaf test: allowed where limit 160 and count 160 were expected. Also :179 (writer move), :252 (count 100, expected 105) and daily-quota.test.mjs:197 | lineage 3 of 9 fail, daily-quota 1 of 17 fail |
| M3 | `#issue` records no old id on a re-issue | p5-key-lineage.test.mjs:137, the re-issue test: `previous` was undefined where `[{ keyId: 'f6548f12575e', retiredAt: '2026-10-24T12:01:00.000Z' }]` was expected. Also :241 (trim at 64) | lineage 2 of 9 fail |
| M4 | the usage module gets `{ client: management, readUsageQueue }` | proxy-usage.test.mjs:89: own keys were `['client', 'readUsageQueue']` | 1 of 8 fail |
| M4b | the client hidden as a non-enumerable property on the `readUsageQueue` function | proxy-usage.test.mjs:98: the walk reached the client | 1 of 8 fail |
M4b is extra; it shows the ruling 4 test finds a hidden path and not only an extra own key.
### Not done
- The settings writer still stamps a new `since` on a renamed leaf (Departures above). Recommended follow-up, not built.
- No migration, per the brief: no live stack holds proxy model records yet.
- No push, queue, Vikunja, Gitea or PR action, per the brief.
## R4 since carry
Written 2026-11-03 by Claude Opus 5.5, implementation sub-agent of the Mosaic Stack lead (T3 c5c1e8ba). Issue #1831. Brief: /mnt/storage/scratch/mosaic-lead/briefs/row333-r4-fix.md. Branch t3/row333-r4-fix on the R3 tip fe3ef5128 (base b37cc5087, no rebase). Product, tests and docs are commit f65faf9df. The R3 section above is unchanged; where R4 changes something it says, this section says so.
### Ruling 1: a moved key quota keeps its count
- The lookup. runtime.mjs builds `keyLineage(business, keyId)` as `modelKeyLineage(credentials.status(), business, keyId)` and passes it to `launchSettings`. `modelKeyLineage` (limits.mjs) returns the lineage in that business holding the id, or `[]` when none does. It is built on `modelKeyLineages`, so the same host-wide uniqueness check runs and a duplicate id throws. It reads the bus's own credential records through their safe status: ids, never a key value. The writer hands it only a business id and a key id, so no caller-supplied lineage reaches it, and the runtime spreads `organization` before `keyLineage`, so an organization option can't replace it.
- The writer. `stamp` keeps its rules: a leaf with a stored `since` at the same path keeps it, and a caller-supplied `since` that differs refuses `invalid-request` (on a new leaf any caller `since` differs, so it always refuses). New: a `tokens.keys` leaf with no stored `since` that is a daily key quota asks the lookup for its key's lineage and takes the earliest stored `since` among the old document's `tokens.keys` daily key quotas whose ids are in it. Whether the same write removes the old leaf doesn't matter. With none it takes now. `reset` runs after `stamp` in the same write, so a reset sets now, in the move write or a later one.
- Lookup failure. `launchSettings`'s default `keyLineage` throws, so a writer built without one refuses. A throw, an answer that isn't an array, an id that isn't twelve lowercase hex, or a non-empty answer without the asked id refuses `OrganizationError('proxy-key-refused')` and writes nothing. The broker already passes that code through by name. A write that adds no new daily key quota never calls the lookup: account limits, legacy leaves, a changed or unchanged quota, a reset.
- Remove then re-add. A quota removed in one write and added back in a later one finds no old leaf, so it is a new quota and gets now. Documented in the `carried` comment and the READMEs.
- Docs. packages/plugins/usage/cliproxy-queue/README.md: the last paragraph's "stamps a new `since` on a renamed leaf ... restarts its count" is replaced by the carry rule, the remove-then-re-add rule and the lookup refusal. packages/plugins/README.md (daily-quota section) and packages/plugins/limit-check/daily-quota/README.md (model-key section) gain the carry sentence. packages/business/README.md had no `since` rule and, as the R3 review said, no model-key leaf; it now has a paragraph after `launch.limits.tokens.daily` on the leaf, the writer's `since` rules with the carry, and `keyLineage`.
Choices and departures, and why:
- Which leaves ask. Only a new leaf that is a daily key quota once stamped (`isDailyModelQuota` with `since` set to now). A twelve-hex-named plain `{limit}` leaf is a legacy account limit under row 333's rule, so it keeps the plain new-leaf rule and the lookup is not called. Source leaves must be daily key quotas too, so a legacy leaf's `since` never carries into a daily quota.
- A leaf that changes shape at the same path, a legacy `{limit, since}` becoming a daily quota, keeps its stored `since` under the existing same-path rule. Unchanged; found while writing the default-lookup case, which now adds a fresh id.
- Earliest against latest. The business test separates them: A from T0, B added from A (T0) and then reset to T1, both moved to C, and C takes T0 where the latest would give T1. Mutant M3 shows the test tells them apart.
- The real-runtime test uses a re-issue, not a rotation. The runtime keeps its `ModelKeys` inside and exposes no rotate, and its sweep rotates only at `rotateBy`, 30 days after issue, which no daily window spans without mocking the runtime's clock. The re-issue gives the same shape of lineage (B current, A among the earlier ids) and goes through the real `startBroker` wiring, the broker's `limits.set` and the runtime's own lookup. The rotation path through the writer is p5-key-lineage's R4 writer test, with the real `Credentials`, `ModelKeys`, `createLimits` and daily-quota module.
- The R3 "settings-writer move" test, which pinned a count of 100, now requires 160 and is renamed for R4. The R3 departure 3 and its "Not done" item are superseded by this ruling.
### Ruling 2: the orphan set on every refresh
`observeOrphans` (limits.mjs) runs in `refresh`, which the runtime calls after each committed verb and at boot, and in `orphanedKeys`. With no daily key quota left it stores an empty set for the business; otherwise it reads the lineages and calls `noteOrphans`, which logs each id not in the stored set and stores the current set. When the lineages can't be read it leaves the stored set as it was and logs nothing. So a quota removed and added back logs again, and an unchanged orphan logs once however many refreshes see it. The set is in memory: a restart is a fresh observation, and a quota still orphaned after it logs once more. No marker is persisted. This is in the `orphansLogged` comment and the cliproxy-queue README.
Consequence: the orphan line now comes at the first refresh that sees the orphan, which can be boot or the refresh at the start of a launch decision, before that decision's own refusal line. Two R3 tests asserted the old order and now expect the orphan line first: the fire and re-hire test (the line comes at the keyless launch before the re-hire, not at the first launch after it) and the ruling 2 test. The number of orphan lines is unchanged in both.
### Ruling 3: the barrier's last yield
p5-telemetry-fixture.mjs captures `realSetImmediate` at module load with the other real timers, and `pollSettledAfterTick` yields on it inside the deadline, so a mocked `setImmediate` can't hold the barrier and the deadline covers the whole wait. Both options in the ruling, since together they cost nothing. The new p5-background test mocks `Date`, `setInterval`, `setTimeout` and `setImmediate`, advances one poll tick through the barrier, never ticks again, and requires the barrier to settle within a real bound of twice `WAIT_MS`, with the second queue read seen and the proxy state `available`. Against the R3 fixture it fails "pollSettledAfterTick did not settle" (about 10 s, the outer bound); I checked that before keeping the test.
### Ruling 4: records
- The 64-id bound is a limit. A lineage holds the current id, the retiring ids and the newest 64 earlier ids. Once an id falls out of the newest 64, a quota named by it is in no lineage, so it is orphaned while the agent stays hired: it limits nothing and the usage view lists it. Moving the quota to a current id fixes it, and since the old id is no longer in the lineage the writer can't carry its `since`, so the moved quota starts at now. Recorded here and in the cliproxy-queue README.
- R3 departure 4, corrected. Its reason, that proxy queue events "can only name keys the proxy still accepts, so earlier ids would never match", is wrong. A queued event the proxy accepted before the key left the record and that the bus drains after it names an id that is no longer current or retiring. proxy-usage.mjs:42-67 builds its owner map from current and retiring ids only, so that event goes to the reconcile log as `proxy-usage-unknown-key` and is not recorded. That loses telemetry attribution for the event. It is not a quota bypass: quotas count the native transcript records, which carry the run's bound key id. The owner map is unchanged in R4.
### Tests
Added:
- packages/bus/tests/p5-key-lineage.test.mjs. The R3 writer test becomes the R4 writer test: A's quota is set at the start, the agent uses 60 on A, rotates, the human moves the unchanged quota to B, B's `since` equals A's, and after 30 more on A and 70 on B the launch refuses with count 160 and the report shows 160; a reset after the move sets now, the count is 0 and the launch goes ahead. New: a lineage that can't be read (an id in two agents' lineages) refuses a write adding a key quota with `proxy-key-refused`, the file unchanged, and a write adding none (a changed limit and a legacy hex leaf) saves without asking. New: an orphaned quota removed and added back logs twice, three more refreshes, a launch and `orphanedKeys` add nothing, and after a restart three refreshes add exactly one.
- packages/bus/tests/p5-runtime.test.mjs. Real `startBroker`, fake loopback proxy: a 2-token quota on A, a turn spends 2 on A, the launch refuses, the proxy stops listing A, `modelPreflight` issues B, `limits.set` moves the unchanged quota to B with no reset, the stored leaf is B with A's `since`, no key value is in the limits view, and the next `mayLaunch` refuses.
- packages/bus/tests/p5-background.test.mjs. The ruling 3 barrier test.
- packages/business/tests/token-limit-settings.test.mjs, with a stub lookup. One test: B added beside A carries A's time; earliest over latest; an id in no lineage gets now; a caller-supplied `since` refuses on a new leaf, a moved leaf and with the carried time itself; a reset in the move write sets now; removed and added back gets now. The other: no lookup for account limits, legacy hex leaves, a changed quota or a reset; a lookup that throws (with and without a code) or answers a string, a list holding a number, a list holding an uppercase id, a list without the asked id or an object refuses `proxy-key-refused` with the file unchanged; the default writer refuses a new daily key quota and saves account and legacy limits.
Changed: the existing P5 business test passes a lookup answering `[]`, since a writer without one now refuses that leaf. In p5-key-lineage, the R3 fire and re-hire test and the ruling 2 test expect the orphan line first (Ruling 2 above).
### Runs
One at a time, each under a 30-minute limit (`timeout -k 10 1800 node --test`), Node v26.8.1, with TMPDIR under /mnt/storage/scratch/tmp and output to files there. Each whole run is `node --test` over the package's tests directory. All times are 2026-11-03 UTC. The first runs were on the working tree that became f65faf9df, committed with no edit between; the cli stack runs and the closing whole-package runs were on f65faf9df itself, the latter after the mutants were restored.
| Run | Tree | Tests | Pass | Fail | Skip | Time |
|---|---|---|---|---|---|---|
| bus whole | before commit | 1397 | 1397 | 0 | 0 | 50 s, 00:55:51Z to 00:56:41Z |
| plugins whole | before commit | 132 | 132 | 0 | 0 | under 1 s, 00:56:53Z |
| business whole | before commit | 295 | 295 | 0 | 0 | 4 s, 00:56:53Z to 00:56:57Z |
| webui whole, run 1 | before commit | 499 | 498 | 1 | 0 | 88 s, 00:57:00Z to 00:58:28Z |
| webui editor-browser.test.mjs alone | before commit | 16 | 16 | 0 | 0 | 15 s, 00:58:47Z to 00:59:02Z |
| webui whole, run 2 | before commit | 499 | 499 | 0 | 0 | 119 s, 00:59:06Z to 01:01:05Z |
| cli launch-limit-checks.test.mjs | before commit | 5 | 5 | 0 | 0 | under 1 s, 01:01:23Z |
| cli stack-release.test.mjs | f65faf9df | 225 | 225 | 0 | 0 | 741 s, 01:02:50Z to 01:15:11Z |
| cli stack-release-external.test.mjs | f65faf9df | 25 | 25 | 0 | 0 | 98 s, 01:15:25Z to 01:17:03Z |
| cli stack-upgrade.test.mjs | f65faf9df | 25 | 25 | 0 | 0 | 148 s, 01:17:07Z to 01:19:35Z |
| harness tools.test.mjs | f65faf9df | 23 | 23 | 0 | 0 | under 1 s, 01:20:41Z |
| bus whole | f65faf9df | 1397 | 1397 | 0 | 0 | 54 s, 01:22:35Z to 01:23:29Z |
| plugins whole | f65faf9df | 132 | 132 | 0 | 0 | 1 s, 01:23:29Z to 01:23:30Z |
| business whole | f65faf9df | 295 | 295 | 0 | 0 | 4 s, 01:23:30Z to 01:23:34Z |
| webui whole | f65faf9df | 499 | 499 | 0 | 0 | 131 s, 01:23:38Z to 01:25:49Z |
The webui run 1 failure was editor-browser.test.mjs:93, the CSP editor test: `Condition timed out: !document.querySelector("#doc-save").disabled` at :122, with the host's load average between 45 and 60. R4 changes nothing webui loads. The file passed alone and the whole package passed twice after, so I read it as load, not R4; both runs are listed. The model-final-completion.test.mjs:69 flake (16 !== 19) did not appear in either bus run. Against R3, bus is up 4 (p5-key-lineage's lookup-failure and orphan re-add tests, the p5-runtime move test, the p5-background barrier test; the writer test is renamed, not added) and business up 2. Plugins and webui are unchanged.
Pins. No test pins any changed path with a hash: the grep of every test, script and fixture naming a changed file's basename for a 64-hex string found only packages/queue/tests/fixtures/queue-marked.md, which names none of the four READMEs. The tests that read a changed file by path (limit-checks.test.mjs:319 and :323, host-run.test.mjs:429) are in packages/bus, run whole. Outside the four packages, harness tools.test.mjs imports `SETTINGS_KEYS` from launch-settings.mjs and ran whole (above). Nineteen packages/cli test files import `startBroker` from bus runtime.mjs; they import, they don't pin, and beyond the four cli files the brief names they were not run (Not done).
### Mutants
Each was applied to f65faf9df, run against the named files, and restored with `git checkout -- <file>`; `git status --short` was empty after each.
| Mutant | Change | Killed by | Result |
|---|---|---|---|
| M1 | launch-settings.mjs:73 `entry.since = kept ?? now;`, so stamp ignores the lineage | p5-key-lineage.test.mjs:173, the writer test, at :185: B's `since` was the move time `2026-10-24T12:01:00.000Z` where A's `2026-10-24T12:00:00.000Z` was expected. p5-runtime.test.mjs:62 at :106: the stored B leaf had the move time, not A's. token-limit-settings.test.mjs:178 at :184: B took the write time 08:00 where A's 07:00 was expected. Also p5-key-lineage :198 at :206 and token-limit-settings :204 at :212, both because the lookup is never called (`asked` was 0 where 1 was expected, and `[]` where `[A]` was) | p5-key-lineage 2 of 11 fail, p5-runtime 1 of 2, token-limit-settings 2 of 9 |
| M2 | runtime.mjs:346 passes `launchSettings` no `keyLineage` | p5-runtime.test.mjs:62 at :88: `proxy-key-refused` from the broker at the first `limits.set` that adds a key quota, since the writer's default lookup refuses. The R3 P5 runtime test at :39 fails the same way | p5-runtime 2 of 2 fail |
| M3 | launch-settings.mjs:96 sorts descending, so the latest `since` wins | token-limit-settings.test.mjs:178 at :189: C had `since` 08:00 (T1, B's reset time) where 07:00 (T0, A's) was expected | token-limit-settings 1 of 9 fail. p5-key-lineage and p5-runtime pass (13 of 13): each of their moves has one source leaf, so earliest and latest are the same there |
| M4 | limits.mjs:130, `refresh` no longer calls `observeOrphans` | p5-key-lineage.test.mjs:348, the orphan re-add test, at :358: one `limit-key-orphaned` line where two were expected; the set was never cleared, so the re-added leaf was still remembered. Also the R3 fire and re-hire test at :299 and the R3 ruling 2 test at :341, each missing the orphan line the refresh now logs first | p5-key-lineage 3 of 11 fail |
| M4b | limits.mjs:90 returns `[]` with no daily key quota but leaves the remembered set alone | p5-key-lineage.test.mjs:348 at :358, the same one-line-for-two failure | p5-key-lineage 1 of 11 fail |
| M5 | p5-telemetry-fixture.mjs restored to its R3 content | p5-background.test.mjs:71, the barrier test: `pollSettledAfterTick did not settle` after 10 s | p5-background 1 of 5 fail |
M4b and M5 are extra. M4b shows the empty set itself is needed, not only the refresh call. M5 shows the ruling 3 test fails on the R3 barrier, whose last yield used the mocked `setImmediate` outside the deadline.
### Not done
- No push, queue, Vikunja, Gitea or PR action, per the brief.
- No migration or persisted orphan marker, per the rulings.
- The proxy-usage owner map still holds only current and retiring ids (Ruling 4 above).
- The nineteen packages/cli test files that import bus runtime.mjs were not run beyond the four the brief names: they import it and pin nothing, and the runtime change adds only the lookup, used when a write adds a daily key quota.
@@ -0,0 +1,31 @@
packages/bus/src/broker.mjs: OK
packages/bus/src/limits.mjs: OK
packages/bus/src/proxy-usage.mjs: OK
packages/bus/src/runtime.mjs: OK
packages/bus/src/usage.mjs: OK
packages/bus/tests/limit-checks.test.mjs: OK
packages/bus/tests/p5-key-context.test.mjs: OK
packages/bus/tests/p5-runtime.test.mjs: OK
packages/bus/tests/proxy-usage.test.mjs: OK
packages/bus/tests/usage.test.mjs: OK
packages/business/src/business.mjs: OK
packages/business/src/launch.mjs: OK
packages/business/src/organization.mjs: OK
packages/business/src/plugin-settings.mjs: OK
packages/business/tests/plugin-settings.test.mjs: OK
packages/business/tests/token-limit-settings.test.mjs: OK
packages/model-proxy/README.md: OK
packages/model-proxy/src/client.mjs: OK
packages/model-proxy/tests/usage-client.test.mjs: OK
packages/plugins/README.md: OK
packages/plugins/limit-check/daily-quota/index.mjs: OK
packages/plugins/limit-check/token-limit/index.mjs: OK
packages/plugins/src/kinds.mjs: OK
packages/plugins/tests/daily-quota.test.mjs: OK
packages/plugins/tests/kinds.test.mjs: OK
packages/plugins/tests/loader.test.mjs: OK
packages/plugins/tests/token-limit.test.mjs: OK
packages/plugins/usage/cliproxy-queue/README.md: OK
packages/plugins/usage/cliproxy-queue/index.mjs: OK
packages/webui/src/public/bus.js: OK
packages/webui/tests/usage-render.test.mjs: OK
@@ -0,0 +1,31 @@
c0144adade79c2cfc6b8247721393f0250b1d64f6c6c04d85738cb80939c42e5 packages/bus/src/broker.mjs
18c1aacd280ebf0f200d5e6fc1dd1a7e098a3046c1cb8427140bb2198ac81cd3 packages/bus/src/limits.mjs
5a6c3707e6a64304cfd37f1875eb378c6eb58bf438cc40365fe913eaec7cee59 packages/bus/src/proxy-usage.mjs
969d04eb06b97093c7f9f0dfa6b51084c781e967e2668814083bbba84a2af7b6 packages/bus/src/runtime.mjs
4ae57d053c4b217e1c1a22ada3ed1c5d4a3f0e61b8d2798e9db37997cd071a29 packages/bus/src/usage.mjs
45870a4903d1996915c0086a6beb4d0a4c75b38386b7c5e6d98b5bc811c3b541 packages/bus/tests/limit-checks.test.mjs
e37114eab9c5f21015ea8e429f0574d3ea34b06263f1e42b83b31b8d2df222a7 packages/bus/tests/p5-key-context.test.mjs
241e779016ffd0b54c5646cb4fac7e21ea1167e77afbd652ff4e01f8d238f99c packages/bus/tests/p5-runtime.test.mjs
84c8351029272b6ee05e7fd81b4cc4453553ceeb7a5127a1333dae63d1336ad5 packages/bus/tests/proxy-usage.test.mjs
2613ba0561572a7d4f753066922fddc90cca812cb0ce2b3e0a9a4d249a15e340 packages/bus/tests/usage.test.mjs
aaa4578fd4133f64119de6c8786a14759240a8910677529fdeae57173058b7d9 packages/business/src/business.mjs
0aa94dbd14acd379a4837cc3e70b9618b3fa797d74124314e7245a8a3070e98c packages/business/src/launch.mjs
fa4ba1ae878cd27287865fa12115f8a6c1175a2dfd1011d5f8aca11e46e669c7 packages/business/src/organization.mjs
9d2c68dd21c6c9553af75f4b137c4f169e95761f32528767e0518d0313311f50 packages/business/src/plugin-settings.mjs
f0dfe004905dce31317d85d89a05802db878c3472e765e85dc9f1e04166e1df6 packages/business/tests/plugin-settings.test.mjs
bc6b3a31e8918d70aced7151b91ac4b39afec4081054024b162acb0e8f8fae07 packages/business/tests/token-limit-settings.test.mjs
2e97ddcf7deac43002f60c44571056273ddffd4aa0ed0d86f15f550d958a106e packages/model-proxy/README.md
f5f86cad661034f223a76352d877fa8d7883bfa921a7a01282347a9a03272441 packages/model-proxy/src/client.mjs
1ad66d56800a31cfbd387939e640653bc72150f4e73822d9e3c777b3bffbf1e1 packages/model-proxy/tests/usage-client.test.mjs
d54d94604d2f8944292fd5a11be8378afc84c06fb6a04137221bfe1a89c5389c packages/plugins/README.md
3749b9f6dd681ef424ee7d7e4d80ccee87b3655df8cd8fe9ccd0d505dcaaee9b packages/plugins/limit-check/daily-quota/index.mjs
4d0c6f5f87101f94608c02001a49d62cef113da48c539b2d2488dfbed1a4c524 packages/plugins/limit-check/token-limit/index.mjs
eaa258a1aadadb5a75450fa73fdbcea0b53636adb50ed9a508193d29d564ca78 packages/plugins/src/kinds.mjs
3d4fab56fea4c45c6a317ef41121aa5b6da0502a6ef614b7931f91cafdfc1f71 packages/plugins/tests/daily-quota.test.mjs
f3081e1dbdac20ade2246c743bcbb3934be686f79f378af21c365cd1451893ba packages/plugins/tests/kinds.test.mjs
8588ad7eee0c9ce5de3b53e3b88562812a155a3d791a2bd3413bb1754655d78b packages/plugins/tests/loader.test.mjs
6e96bb96278ec754ca1816a24f49ef677771615ab5cf186ae41969fc2f93d8cc packages/plugins/tests/token-limit.test.mjs
e9deb2504741f45645cd52ea6a1daee031cd2d3d44775a1221e76cec73c6b480 packages/plugins/usage/cliproxy-queue/README.md
6096a577cd5d7e8bf84fd6b98ab284e2f47d5facebd027548e07e6aeec442f96 packages/plugins/usage/cliproxy-queue/index.mjs
3c7a35e25b4c1cfda19ac9466d4b2fbc86c880761a1d04ad3ece8bc485f60f93 packages/webui/src/public/bus.js
39f50991578b98594183390a00efbca84fda90ef61617eea4215e2c75f90b82c packages/webui/tests/usage-render.test.mjs
@@ -0,0 +1,31 @@
packages/bus/src/broker.mjs
packages/bus/src/limits.mjs
packages/bus/src/proxy-usage.mjs
packages/bus/src/runtime.mjs
packages/bus/src/usage.mjs
packages/bus/tests/limit-checks.test.mjs
packages/bus/tests/p5-key-context.test.mjs
packages/bus/tests/p5-runtime.test.mjs
packages/bus/tests/proxy-usage.test.mjs
packages/bus/tests/usage.test.mjs
packages/business/src/business.mjs
packages/business/src/launch.mjs
packages/business/src/organization.mjs
packages/business/src/plugin-settings.mjs
packages/business/tests/plugin-settings.test.mjs
packages/business/tests/token-limit-settings.test.mjs
packages/model-proxy/README.md
packages/model-proxy/src/client.mjs
packages/model-proxy/tests/usage-client.test.mjs
packages/plugins/README.md
packages/plugins/limit-check/daily-quota/index.mjs
packages/plugins/limit-check/token-limit/index.mjs
packages/plugins/src/kinds.mjs
packages/plugins/tests/daily-quota.test.mjs
packages/plugins/tests/kinds.test.mjs
packages/plugins/tests/loader.test.mjs
packages/plugins/tests/token-limit.test.mjs
packages/plugins/usage/cliproxy-queue/README.md
packages/plugins/usage/cliproxy-queue/index.mjs
packages/webui/src/public/bus.js
packages/webui/tests/usage-render.test.mjs
@@ -0,0 +1,20 @@
# Intended admitted-runner controls — execution pending
These are first guards to establish on the admitted runner. Current controls have NOT run after the priority STOP; no source guard is described as observed RED/GREEN.
| R1 finding | Whole-file control | Baseline first guard / RED cause | Fixed positive and boundary controls |
|---|---|---|---|
|1 P1 identity|packages/bus/tests/p5-identity.test.mjs|Boot foreign sentinel still leaves queueCalls=1 where0 required; later foreign/refused listener increments calls; all are behavior assertions, not fixture errors.|Matching sentinel drains without any issued agent key; boot/later refusal zero queue consumption; human plugins/usage reads stay available; fresh sentinel check precedes each drain; sticky refusal never retries the management list.|
|2 P2 namespace/checks|packages/bus/tests/p5-key-compatibility.test.mjs|Plain abcdefabcdef account native count at10 is ignored; no-model lookup returns proxy-key-refused below limit; empty checks wrongly perform metadata lookup; chief reset of plain account leaf refuses.|Below/at legacy quota, original account count/report with no proxy and unrelated proxy metadata; zero lookups for plain leaves or empty checks (legacy and daily); shared validated daily shape; daily model matching/report positive; old/new daily/plain/removal/reset human fence; malformed partial daily schema refuses.|
|3 P2 nonblocking|packages/bus/tests/p5-background.test.mjs|The queue response is causally held; queue arrival plus one event-loop barrier leaves f.bus=null because503 startBroker awaits the poll. Startup assertion must fail before releasing the held response.|Ready/control/native key preflight/native usage/limit work completes while held; interval shares singleflight; explicit success/failure release updates availability; close of a held poll remains pending at4999ms and completes at the original5000ms virtual client deadline. No sleeps/deadline increase.|
The preserved24 whole files remain explicitly listed in whole-files.txt, plus the three new controls and the affected existing ModelKeys whole file (28 total). Current503-added cumulative-model fixture tests in token-limit/limit-checks/p5-key-context are corrected to legacy plain-account or accepted DAILY model semantics; their count/refusal/ownership assertions remain. All original09a847 base assertions/deadlines are retained; authorized usage inventory additions are unchanged.
Overlay sequence (isolated private copies only):
1. Materialize Git503b91e56137482abef475bc3b1b72a64b0a329c in a private admitted runner root. Do not run product from this author worktree.
2. Apply packet/baseline-controls.patch, which adds exactly the current three control files and fake fixture; it changes no production byte. This is the original503 baseline for all three first guards.
3. Execute each control whole file under the admitted private gate-tool/native priority contract. Retain every genuine behavior RED.
4. Apply packet/baseline-to-fixed.patch. It is the complete fixed source/test delta with the four already-installed controls removed from the patch to avoid reapplication. This must yield packet/source-tests.patch's exact fixed overlay on503.
5. Rehash every fixed input, run the three controls then all28 current whole files with original budgets, collect native priority root/actual-child evidence, raw receipts/exit codes, actual consumed-source map and cleanup. Priority/setup failure stops, not retries.
Additional forensic snapshot: baselines/runtime-before-background-fix.mjs captures finding1+2-prepared runtime immediately before the finding3 source edit. It is evidence only; canonical baseline for replay is Git503 plus controls. No snapshot substitutes unobserved source controls for runtime evidence.
@@ -0,0 +1,34 @@
# Admitted-runner entry and native priority contract — NOT RUN / NOT ADMITTED
Worktree/source root (unchanged binding):
`/home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f`
HEAD must remain `503b91e56137482abef475bc3b1b72a64b0a329c` until applicable runner GREEN. This packet is an UNCOMMITTED source/test overlay, not a new accepted product commit. Parent owns the dedicated1014 admission/profile and runtime execution. No full/browser/provider/namespace or scheduler change is part of this packet.
## Entry ownership and limitation
The actual diagnostic entry used in receipt07 was
`agents/codex/work/queue-333/r1-repair/run-strict19.sh`, calling the private
`run-priority.mjs` and `priority-guard.mjs` in that directory. Those exact source
bytes are preserved as evidence. It is **NOT an admitted gate entry and must not
be retried**: native drift was observed and Node --test's root did not execute
its forwarded preload, so the direct-child handshake capture was incomplete.
`run-light.sh` is likewise an old nice-only behavior runner, not a strict19 gate.
No new execution entry/profile on1014 has been admitted. The parent must name
and pin its private gate-tool entry and the actual selected root before running.
Do not substitute either old runner or the original503 scoped runner. Read-only
R2 may examine this packet before runtime acceptance; it cannot admit a gate.
## Requirements for the parent's private gate-tool entry
1. Invoke only the exact whole-file list in the frozen packet, serial concurrency1. Preserve all existing test timeouts and budgets. Use a fresh mktemp private HOME/XDG_CONFIG_HOME/TMPDIR/MOSAIC_CONFIG for each baseline/fixed pass; no real instance/auth/env/credential paths, provider traffic or host proxy.
2. Establish native own-process priority19 in the actual gate-tool root before module execution: setPriority(0,19) and native readback. A shell's relative nice or inherited priority is not evidence. The observer/root must itself retain the required priority for the run; any setup refusal or observed drift is STOP/UNVERIFIED, never behavior RED.
3. Establish the same own-process native preexec/set/readback in **every actual test child**, not only a preload forwarded to a Node test runner or an inert wrapper. The gate root must execute its own prelude, and each test child must execute its prelude before importing the tested modules. Do not add a no-op prelude that misses Node's --test parent. No retry/repeated renice or host-daemon modification around drift is permitted.
4. Capture native getPriority(child.pid) from the direct parent before tested module execution and after tested module work while that child still exists; use a causal acknowledgement barrier rather than a timed race. Capture child self-readbacks before/after and on exit as well. Record pid/ppid, phase, actual priority, exit/signal and the source pin of every private helper. Both root and actual testchild evidence are required. A missing/ESRCH sample, missing handshake, setup failure or drift makes the pass unverified, independent of test assertion counts.
5. Pin the gate helper path/hash/Gitblob, selected test root and applied overlay hash in each raw receipt. Resolve the baseline/fixed source manifests before execution. Record exact Node version and all consumed module/data inputs from the real admitted pass; the static map here is not execution provenance.
6. Run the per-control baseline first guards against the preserved503 baseline plus the current controls-only overlay. Only the named behavior assertion failure with complete strict19 capture is intended RED. Missing imports, fixture/setup errors, timeout/priority failures are not RED. Then apply the complete fixed overlay and run each control and all28 listed whole files. Preserve output/exit statuses without normalizing raw whitespace. Recheck hashes after execution and collect cleanup proof.
Programmatic Node test-runner entry or a native preexec wrapper may implement
these requirements, but the implementation and target profile remain the
parent's admission decision. This document authorizes no workstation retry.
@@ -0,0 +1,43 @@
# P5 independent R1 response
Starting candidate: 503b91e56137482abef475bc3b1b72a64b0a329c.
Original base:09a847edaa25b609bac7728ff83f224708a29399.
Review: REVIEW-R1.md, copied without edits; SHA2567c95672a30c0d5c39189c7c7d610ada89cd539dcb9413617071fbb81200fd008.
All findings preserved as CHANGES until fixes have actual RED/GREEN evidence.
Source verification:
1. Confirmed unconditional client callback permits queue reads after ModelKeys sentinel refusal.
2. Confirmed regex-only key classification changes valid legacy account limits and chief resets; host lookup also runs for zero checks. Accepted scope requires daily model quotas, not cumulative model namespace takeover. Repair will use the validated daily shape consistently and drop the invented cumulative model interpretation.
3. Confirmed startup awaits proxyUsage.tick and may wait the existing management-client timeout for optional telemetry. Repair will supervise first poll in background with unchanged deadlines/singleflight/close.
Original candidate, runner, raw receipts and source pins remain unchanged. R1 repair evidence is separate in this directory. No independent approval/self-review, heavy/full/browser gate or deployment authority claimed.
Priority evidence correction (Mos1971): command text `nice -n19` is insufficient on this workstation (ananicy node16/bash-4). Earlier R1 receipts01–06 are behavior observations with priority unverified; no strict19 acceptance claim attaches to them. New bounded checks use OWN-process native setPriority(0,19) plus readback before modules and at beforeExit/exit, and wrapper native getPriority(child.pid) before/after the direct child. A setup failure, any observed drift or incomplete capture returns78 UNVERIFIED/STOP; it is never treated as intended RED or GREEN. No scheduler/daemon mutation, repeated renice, deadline change or retry around a priority refusal is authorized.
## Native priority STOP (receipt07)
Actual trace07-priority-native.jsonl: wrapper PID2643577 before=19, after=16; test PID2643590 before-modules=19, after-modules=16, exit=16. Six behavior assertions completed, but the test runner reports a file failure because priority guard changed exit status. This is **UNVERIFIED/STOP exit78**, not intended RED and not GREEN. Node --test forwarded --import to its test subprocess, so the direct test-runner parent did not execute that preload: the requested direct-child handshake/capture is also incomplete. No priority or provenance proof is inferred from command text or the six assertions. No further local test runs are authorized after this observed drift; no scheduler mutation or retry was attempted. Admitted runner verification is required. Source/regression preparation continues under the user's explicit fallback mandate.
## Finding 1 source response / priority-unverified behavior observations
Added ModelKeys.verifyIdentity(), serialized by the existing controller. It requires the existing ready state, performs a fresh sentinel-only management-list check, never issues an agent credential, never reconciles, and honors sticky proxy-open refusal. Collector now awaits client acquisition; the P5 runtime usage callback verifies that identity before returning its management client. Boot refusal and later failure retain the human surface, unavailable telemetry and value-free receipt, with zero queue drain. Matching sentinel requires no issued agent key.
Receipts01/02: actual behavior REDs under nice-relative priority, later reclassified priority-UNVERIFIED. Boot observed queue1 vs expected0; later refusal queue2 vs expected1; changed-listener predrain control likewise failed. Receipt03 recorded12/12 behavior passes after the fix (identity, proxy collector, native quota runtime files), also priority-UNVERIFIED. These are observations only, not strict19 acceptance. Current identity controls now await the initial poll's actual receipt to preserve the same assertions after the nonblocking startup change; current bytes have not run.
## Finding 2 source response / priority-unverified behavior observations
A shared pure isDailyModelQuota() validates key ID and the full daily {limit,since,reset,timeZone} leaf. Business schema, daily and cumulative checks, host metadata lookup and both old/new organization fences use it. Plain {limit,since} keys stay legacy account leaves regardless of twelve-hex spelling; token-limit matches/reports account only. Zero loaded checks returns before any model metadata lookup. Daily model changes, plain→daily, daily→plain/removal and reset remain human-only; plain legacy chief resets remain permitted. The invented cumulative model-key interpretation is removed, not moved into a new namespace.
Receipts04/05 captured actual legacy failures (lookup refusals, wrong account matching, empty checks, chief reset) under nice-relative priority. Receipt04 also contained a new fixture missing-system error; receipt05 corrects the fixture and demonstrates the actual chief-reset refusal. Receipt06 recorded6/6 behavior passes after source repair, priority-UNVERIFIED. Receipt07 later observed strict-priority drift and STOP. Candidate503-specific cumulative-model test fixtures are retargeted to accepted daily leaves with every enforcement assertion retained; the appended token-limit test now asserts legacy account semantics. Pre-P5/base assertions and deadlines remain unchanged. No post-STOP execution is claimed.
## Finding 3 source response / execution pending
Prepared p5-background.test.mjs with a queue response held open, explicit queue-arrival/event-loop barriers (no sleeps or racing deadlines), native readiness/control/key-preflight/usage/limit work while held, scheduled singleflight, success/failure release, and cleanup at the original5000ms management deadline using virtual timers. First guard is that f.bus is nonnull while the queue is still held; original503 awaits that held response and should fail this behavior assertion. These controls have NOT RUN locally, not RED/GREEN evidence.
Saved exact immediately-pre-fix runtime bytes in baselines/runtime-before-background-fix.mjs. Fixed runtime uses one supervised usageTick function for the initial call and later interval. The first call is background; the same collector singleflight and original close/pending/client deadline apply. Only P5 usage wiring/tick hunks changed; no launcher/session/harness/business route edits. Admitted runner must establish genuine priority-verified RED then GREEN on the pinned baseline/fixed overlays before any new product commit.
## Static packet handoff — no product commit
Per latest owner direction, HEAD remains original503 and all repairs stay UNCOMMITTED. No local tests or Node product execution followed receipt07 STOP, including no syntax-check substitute. New background controls and final current source bytes are pending execution. The packet contains the complete source/test diff from503 (including untracked controls/helper), controls-only baseline overlay, baseline→fixed remainder, exact baseline/fixed bytes with SHA256/size/Gitblob IDs, static module/dependency edges and full28-file list. Its input map is explicitly STATIC, not a fresh consumed-source observation. Genuine strict19 baseline RED/fixed GREEN and actual consumed-source capture must come from the admitted runner before any product commit. The parent may request new read-onlyR2 on these exact bytes before execution; this author issues no independent/self-review verdict.
Gate entry/root and root+actual-testchild native preexec/readback requirements are in GATE-ENTRY.md. Existing diagnostic drivers are preserved only as failed/incomplete priority evidence and are not authorized for retry. Dedicated1014 admission/profile and private gate-tool entry remain pending with the parent. Cleanup from every actual test run used private mktemp EXIT/test fixture cleanup. No scheduler, live proxy/account/credential/provider, P3 launcher/session/harness/business-route, queue, remote or landing state was changed.
@@ -0,0 +1,82 @@
# P5 row333 independent implementation review — Mos1966 / Mos1961
Verdict: **CHANGES**
Reviewer: independent Codex review sub-agent; not the implementation author.
Implementation author: Codex builder, isolated worktree `/home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f`.
Git-recorded author/committer: Jason Woltje; commit subject `feat: add optional proxy usage and human model-key quotas (row333)`.
Candidate: `503b91e56137482abef475bc3b1b72a64b0a329c`.
Base: `09a847edaa25b609bac7728ff83f224708a29399`.
Review time: 2026-10-26 23:03 UTC (2026-10-26 18:03 CDT).
Reviewed the exact candidate/base Git objects, all 31 changed package files, and supporting callers/contracts. The isolated worktree HEAD equals the full candidate and its status was clean. The parent's integrated row334 product was not substituted for this candidate. Requirements are accepted P5 in `docs/plans/2026-10-24_model-proxy-rows.md`, design D18–D20 with the mos-1600 per-key/no-raw-upstream correction, and the review assignment's compatibility and nonblocking constraints.
## Findings
### 1. P1 — Do not drain a listener after its instance identity was refused
Primary location: candidate `packages/bus/src/runtime.mjs:387–389`; destructive read at `packages/bus/src/proxy-usage.mjs:31–33`.
Source trigger: enable `plugins.usage: "cliproxy-queue"`, point the instance at a loopback management listener that accepts its management authentication but lacks this config directory's sentinel (for example a different instance with a reused management key). `ModelKeys.reconcile()` checks the sentinel before modifying the list (`model-keys.mjs:80–84`) and throws `proxy-open`; runtime intentionally catches that refusal to retain the control surface (`runtime.mjs:326–327`). Nevertheless the new collector receives `client: () => modelProxyClient` unconditionally and performs the queue GET at startup and on later ticks. It never consults the controller's identity/readiness refusal.
The GET consumes the other listener's queue. Resolving local owners *after* `module.read()` and dropping/logging unknown IDs cannot undo that consumption. The local Store writer lock prevents two local writers, but does not establish ownership of a remote loopback listener. This is a new P5 side effect after a fail-closed refusal; it is not a request to change P2's existing decision to keep human controls available.
Smallest remedy: fence the collector's management-client access behind verified identity for this instance, honoring boot and subsequent sentinel refusals before any queue GET. Keep an unavailable telemetry state and value-free receipt when verification is absent; do not retry around `proxy-open`. This must not require a particular agent to have an issued key merely to establish instance identity.
Required regression evidence: a fake listener accepts management auth and returns a valid foreign sentinel/list, while its queue records/drains calls. With telemetry enabled, assert `proxy-open`, zero queue requests/consumption across startup and scheduled ticks, and an available human/control surface. Add the matching-instance positive case and a refusal after a previously successful identity check. Current `p5-runtime.test.mjs` uses the correct sentinel and enables telemetry only after startup; `proxy-usage.test.mjs` bypasses this host identity boundary entirely.
### 2. P2 — Twelve-hex legacy account names lose their quota, reset, and no-check behavior
Primary location: candidate `packages/plugins/limit-check/token-limit/index.mjs:33–35`; related new gates at `packages/bus/src/limits.mjs:126–136` and `packages/business/src/organization.mjs:85–91`.
Concrete legacy input: `launch.account.name = "abcdefabcdef"`, an ordinary existing `tokens.keys.abcdefabcdef = { limit: 10, since: <canonical timestamp> }`, and native records/subject whose `account` is `abcdefabcdef`. No proxy or model record is needed by this previously valid configuration. `ID_PATTERN` accepts this account name (`business/src/vocabulary.mjs:206`; `launch.mjs:85–92`), and the base token-limit matched every keys leaf against `account` (`base token-limit/index.mjs:31–34`). Nothing in the accepted P5 brief reserves existing twelve-hex account names.
The candidate changes this plain leaf to match `modelKeyId` solely because its name matches a regex. Consequently:
- With `token-limit` enabled and no proxy/model record, `createLimits` returns `proxy-key-refused` even below the account limit, before asking the check. At the plug-in level, known account records at the limit are instead ignored and its count becomes zero.
- With no limit checks configured, `state().checks` is `[]`, so it passes the `!st.checks` guard. The same lookup still runs before the empty loop and returns `proxy-key-refused`. The base returned `allow:true` / `stop:false` here. Thus an unused legacy limit now blocks launches/stops turns even though enforcement is switched off.
- With proxy metadata present, the resolved model ID generally differs from the account name; the account quota silently stops matching its original records. The new organization fence also prevents the chief's previously permitted reset of this plain account leaf.
These outcomes follow directly from the branches above, independently of the builder's test counts. They are introduced regressions, not Mos1864 baseline defects. The same reasoning applies to the previously examined valid name `abcdef012345`; the parent's additional `abcdefabcdef` example confirms the ambiguity without relying on a digit-leading name.
Smallest contract-preserving remedy within accepted P5: distinguish the genuinely new daily model-key leaf by its validated `reset`/`timeZone` shape, retain ordinary `{limit,since}` keys leaves as legacy account limits, and use that same classification consistently in the host lookup, matching, reports and both organization fences (including old-to-new/removal transitions). Preserve the empty-check path before performing metadata lookup. P5 requires daily model-key quotas; newly added cumulative model-key support must not silently take over the existing account namespace. If cumulative model-key quotas are retained, they need an unambiguous separately authorized representation.
Required regression evidence: cover `abcdefabcdef` with plain account limits, no proxy/model record, below/at limit, original account report count and chief reset; repeat with proxy metadata whose ID differs. Cover no configured checks with that legacy leaf and with a new daily model-key leaf: preserve the established no-check result without resolving model metadata. Retain positive daily per-key enforcement, current/retiring native lookup, and human-only changes/removals/resets for actual model-key daily quotas. Existing P5 tests cover an invented cumulative model-key interpretation and a daily key, but not this legacy collision or the empty-check branch.
### 3. P2 — Optional telemetry adds a blocking startup dependency
Primary location: candidate `packages/bus/src/runtime.mjs:865–867`.
Source trigger: correct sentinel/reconciliation, telemetry enabled at boot, and a queue endpoint that stalls while other management operations work. The initial `await proxyUsage.tick()` waits for that queue read, up to the existing five-second client deadline (`model-proxy/src/client.mjs:10,45`). The process waits for `startBroker()` before sending its ready answer and launch capabilities (`bus/src/process.mjs:147–152`). Thus optional telemetry delays native readiness/launch admission even though it has no quota authority. Later timer ticks are independent of native requests; the startup await is the exception.
Smallest remedy: start the first poll in the same supervised background path as subsequent ticks, preserving single-flight handling, value-free errors and close cleanup. Do not increase any existing deadline.
Required regression evidence: hold a fake queue response open while allowing required reconcile requests, prove startup/native readiness completes before releasing the queue, and exercise native usage/limit work while a poll is outstanding. Then release/fail the response and verify availability, no duplicate drain and bounded cleanup. Current whole-file receipts contain no such slow-queue readiness test.
## Independent evidence checks
Performed read-only Git/filesystem/hash analysis, not product execution:
- `source-inputs.sha256` SHA-256 is exactly `b4662dcafb2aeb27a06e5dbd3b9d0b6d184e8624e344fed351ff20e3b255951b`. All **202** listed file hashes match candidate Git blobs and the pinned isolated tree, with zero mismatches. The 944 raw JSONL entries contain exactly 202 distinct path/hash pairs, exactly equal to the manifest; no path has multiple traced hashes.
- All **31** changed package paths exactly equal `candidate-sourcepaths.txt`; every entry in `candidate-sourcehashes.sha256` matches both sources. That manifest's SHA-256 is `b1457ec57c0fb695f05a08ba20b420820be5f32cac2b77ac5ea20b02115153e2`.
- All **25** entries in `receipts.sha256` match candidate blobs and isolated-tree bytes. Receipt-manifest SHA-256: `a8b91660ada571eab9c0328b74407517ec63e1ff56172302acec1d347253a810`. Raw source-trace SHA-256: `9c16aa4b8e6d81aa5b9867fec5e0890b22e90db5c307da55badfcfa9f240aef1`.
- The scoped runner explicitly names **24 whole test files**, uses `nice -n 19`, `--test-concurrency=1`, and private HOME/XDG_CONFIG_HOME/TMPDIR/MOSAIC_CONFIG with cleanup. Its SHA-256 is `c8a2bf4539bffe38f3198308fd60e9c1ad338841b406af160ab0739c15394290`. These are verified runner bytes and recorded output, not independent observation of the original processes' environment.
- Receipt24 records **174 tests, 174 pass, 0 fail/cancelled/skipped/todo**, SHA-256 `3358af061c35d42b00d5ee1e001939534c5e7563d4f5418ea85431605d0b9f6d`. This remains builder scoped evidence, not an independent test run, full gate or browser gate.
RED history is retained as RED. Receipt16 records the upstream-value mutant with **11/15 passing and four failing tests**: the client exposes the raw account value, while collector validation refuses it and downstream expectations fail. Receipt17 records restored **15/15**. Final client bytes hash to `f5f86cad661034f223a76352d877fa8d7883bfa921a7a01282347a9a03272441`, matching the documented restoration hash and final source pins. The receipts do not contain a separately captured pre/post backup or mutant patch hash, so byte-identical restoration at that historical instant is documented by the builder rather than independently replayed here.
Receipt18 is **169/170**, with the exact existing `REQ-LIMIT-4 a role run at its limit stops at the end of its turn: RESULT and read land first, the claim is revoked by limit-check` assertion failing at `limit-stop.test.mjs:61` because `run` was added to the original second subject argument. The candidate keeps that argument's shape and puts `{run}` in the private third context. The entire original limit-stop file is byte-identical to base. Receipt19 records **170/170** after that correction. Receipt20 is a genuine **2/3** RED for the supplied modelKeyId fallback; receipt21 is **15/15** after its removal. Receipt22 records **173/173**. Receipt23 is a genuine **3/4** RED for missing native context; receipt24 records **174/174** after the explicit context refusal. These were builder development REDs, not prior independent review findings, and are not relabelled GREEN. Receipt05 also remains a syntax-error RED despite its filename; receipts12/13 remain failed runtime-fixture runs.
All modified pre-existing test files other than the two authorized inventory updates retain their entire base bytes as an unchanged prefix. The kinds/loader edits are the strictly additive `usage`/`usage:[]` expected inventories; no old assertion or deadline was removed or weakened.
## Other source conclusions and limits
Telemetry source rows are excluded at the start of `turnRecords`, before native totals and quota input. The collector validates and whitelists persisted fields, uses hashed client/upstream identities, retains only safe failure metadata, serializes concurrent ticks, and routes current/retiring ownership from credential status. Malformed/unknown/oversize/non-finite/unsafe counts cannot flow through the new queue client as raw values into store, error, audit or Console fields: the queue operation reuses fixed loopback GET, count=100, original response cap/deadline and value-free errors/receipts. No second queue consumer was found in the product sources; finding 1 concerns foreign-listener identity rather than local double counting.
Native model-key authority comes from the host's run map and credential metadata, not a JSON-supplied key ID. Lookup rejects missing/duplicate owners, foreign business/instance/run, missing retained generations and ambiguous IDs. The broker's private context is derived from its authenticated session; the public subject drops supplied run/modelKeyId fields. The new usage and model-quota fences run before validation and again against serialized bytes, compare against the old human, and reject tester/agent identities even when names collide. Finding 2 concerns which leaves those otherwise fail-closed fences classify.
Polling is absent by default, defaults to 15 seconds when enabled, validates integer 1..59, and is exposed through the exact human `plugins.set` argument contract. Console native key rows and optional proxy-reported account counts are separated and labelled; telemetry is explicitly described as incomplete and non-enforcing. Broker imports are unchanged, kinds remains import-free, and no host management implementation was added to the pure Broker/sandbox import closure. No P3 launcher/session/harness/business-routing files changed.
No tests, Node/product runtime, HTTP, browser, provider, real instance config, credential files or live proxy paths were run/read. Hash checking used repository files only. No code, tests, helpers, queue, session/build logs, issues, posts, pushes, commits, merges or live state were changed; this report is the only authorized write. Static analysis establishes the reported branch behavior; the suggested regression cases remain to be executed by the authorized builder/gate owner. Hash equality verifies the captured inputs/receipts, not completeness of uninstrumented reads or independent execution provenance.
These three findings are in the candidate delta. No pre-existing issue is being promoted to a new landing blocker; any separately identified baseline defect belongs under Mos1864 unless a required gate is RED. #662 / 72f77815 and #657/#658 remain excluded/backlog; #267/#289 are outside the 10-27 slice but remain in full scope. The #660 full-gate target is not admitted by this review. No landing authority or full/browser/combined-gate approval is implied.
@@ -0,0 +1,960 @@
import { lstatSync, readdirSync, readFileSync } from 'node:fs';
import { join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { Store } from './store.mjs';
import * as projectModule from '../../project/src/index.mjs';
import * as libraryModule from '../../library/src/index.mjs';
import { Broker, BusError, LIBRARY_FETCH_FIX } from './broker.mjs';
import { Credentials } from './credentials.mjs';
import { serve } from './server.mjs';
import { launchSettings } from '../../business/src/launch-settings.mjs';
import { readSessions, sessionsFile, stopSession } from '../../seat/src/session.mjs';
import { compactionCount, storeDir } from '../../seat/src/compactions.mjs';
import { publishRemote, workingRepo, WorkingError } from '../../seat/src/working.mjs';
import { createLoader, hasModule } from '../../plugins/src/loader.mjs';
import { pluginSettings } from '../../business/src/plugin-settings.mjs';
import { loadManagementClient } from '../../model-proxy/src/client.mjs';
import { ProxyPage } from './proxy-page.mjs';
import { sha256 } from '../../model-proxy/src/common.mjs';
import { initializeProxy } from '../../model-proxy/src/settings.mjs';
import { ModelKeys, modelOrganization, stopModelRuns, MODEL_STOP_TIMEOUT_MS } from './model-keys.mjs';
import { instanceSettings } from '../../business/src/instance-settings.mjs';
import { organizationWriter, OrganizationError, setReplyLimits } from '../../business/src/organization.mjs';
import { credentialVerbs } from './credential-verbs.mjs';
import { loadBusiness } from '../../business/src/business.mjs';
import { loadRole } from '../../business/src/role.mjs';
import { resolveInstance } from '../../business/src/resolve.mjs';
import { canonicalJson } from '../../business/src/util.mjs';
import { busBusiness } from './business.mjs';
import { webService } from './web.mjs';
import { hostExecutor, sweepRunDir } from './host-run.mjs';
import { grantKeys, hostGrant, hostReference, sweepHostKeys } from './host-grant.mjs';
import { giteaGrant, giteaKeys, giteaStart, giteaReference } from './gitea-grant.mjs';
import { verifyPrincipal } from './principal.mjs';
import { loadAccess } from '../../business/src/access.mjs';
import { inspectInterpreter, recordInterpreterStart } from './interpreter.mjs';
import { createPeerReader } from './peercred.mjs';
import { createUsage } from './usage.mjs';
import { createProxyUsage } from './proxy-usage.mjs';
import { createLimits, modelUsageKey } from './limits.mjs';
import { createProcessing } from '../../processing-control/src/coordinator.mjs';
import { discordProcessingHooks } from '../../discord/src/processing.mjs';
import { createContainerStopper } from '../../processing-control/src/containers.mjs';
// Row 194 (D3): the verbs the instance writer commits, whose answers carry restart.
const INSTANCE_VERBS = new Set(['instances.set', 'veto.set', 'instance.hire', 'instance.fire']);
// FED R4 (#1801, design 3.7): the revocation timer's period.
export const ACCESS_SWEEP_MS = 30_000;
// Trusted host API. S1 supplies resolved definitions, S6 supplies launch records and ends them.
// Human limits writes use the shared organization writer behind the verified transport.
// `tasks` is S3's adapter factory: ({broker, credentials, businesses}) => {handle, timeout, close}.
// REQ-HARN-2, REQ-PLUG-2 (decision 0b81b0c5): one web service per business. Its search source is
// the "search-source" plug-in the business's organization file switches on: searxng-url (the
// business var web.searxng) or searxng-bundled. With none, web.search refuses "not configured" and
// web.fetch still works. A plug-in that refuses to load is logged and leaves search off; it never
// stops the broker. Under harness-builtin the harness serves web itself, so the broker gets no
// service and refuses the web verbs.
export async function webServices(businesses, { log = (e) => process.stderr.write(`plugins: ${JSON.stringify(e)}\n`), deps } = {}) {
const services = new Map();
for (const [name, b] of Object.entries(businesses)) {
const loader = createLoader({ log });
await loader.load(b.plugins ?? {});
const [source] = loader.modules('search-source');
// "harness-builtin" is served by the harness itself, not the broker: no broker web verbs.
if (loader.loaded()['search-source'][0] === 'harness-builtin') continue;
// The module takes the business var web.searxng; "searxng-bundled" ignores it.
const settings = { searxng: b.vars?.['web.searxng'] };
const search = source ? { search: async (query, opts) => source.search(settings, query, deps, opts) } : null;
services.set(name, webService({ search, deps }));
}
return services;
}
// Row 65 (REQ-PLUG-2): the thinking levels each harness module in this tree applies, for the route
// checks a write runs, which are synchronous. A module that doesn't load, or answers anything but a
// list of names, answers null, which refuses the write. The tree is pinned, so a module changes only
// with a re-pin, and a re-pin restarts the bus.
export async function harnessLevels({ log = (e) => process.stderr.write(`plugins: ${JSON.stringify(e)}\n`) } = {}) {
const levels = new Map();
let names = [];
try {
names = readdirSync(fileURLToPath(new URL('../../plugins/harness/', import.meta.url))).filter((name) => hasModule('harness', name));
} catch (e) {
log({ event: 'harness-levels-unread', message: e.message });
}
for (const name of names) {
const loader = createLoader({ log });
if ((await loader.load({ harness: [name] })).refused.length) continue;
try {
const list = loader.modules('harness')[0].levels();
if (Array.isArray(list) && list.every((level) => typeof level === 'string')) levels.set(name, Object.freeze([...list]));
} catch (e) {
log({ event: 'harness-levels-failed', name, message: e.message });
}
}
return (name) => levels.get(name) ?? null;
}
// Row 224 C2-05b: a host-only adapter. A failed fetch keeps serving immutable old
// objects, as C2-03a requires; no caller may select a repo, commit or sync --accept.
export function createLibraryLookup({ dataRoot, sync, now = () => Date.now() }) {
const methods = { find: libraryModule.find, get: libraryModule.get, search: libraryModule.search,
manuscript: libraryModule.manuscript, universeInfo: libraryModule.universeInfo };
return async (context, { method, args, authorize }) => {
if (!Object.hasOwn(methods, method)) throw new libraryModule.LibraryError('query-argument-invalid', 'unknown lookup');
authorize();
const source = { ...context, dataRoot };
let state = await libraryModule.libraryStatus(source);
authorize();
// sage-2819 / dewey-0852: failed attempts also pace inline retries. Otherwise an
// outage makes every lookup refetch while lastFetch remains old or null.
const recentAttempt = Math.max(state.lastFetch === null ? -Infinity : Date.parse(state.lastFetch),
state.lastError === null ? -Infinity : Date.parse(state.lastError.at));
const age = now() - recentAttempt;
if (age > libraryModule.SYNC_INTERVAL_MS || age < 0) {
try { await sync(source); }
catch (error) {
// A timer may already be fetching this mirror. Its current served state is still safe.
if (!(error instanceof libraryModule.LibraryError) || error.code !== 'library-sync-busy') throw error;
}
authorize();
state = await libraryModule.libraryStatus(source);
}
if (!state.served) throw new libraryModule.LibraryError('library-commit', 'library has never been synced');
authorize();
return methods[method]({ repo: libraryModule.mirrorPath(source), commit: state.served,
mapping: libraryModule.checkMapping(context.business.projects[context.project]) }, args);
};
}
// B1: discovery is evidence of a process, never authority to stop it. Keep this
// host-only inventory across the launcher's Registry[] recovery gap and endLaunch.
// A failed boot read cannot be repaired by a later empty registry: that would lose
// the very prior runs whose existence this inventory must establish.
function modelRunInventory(dataRoot, bound, credentials) {
const known = new Map(), terminal = new Map(), validated = new Map();
const refuse = () => { throw new BusError('proxy-stop-failed'); };
const same = (a, b) => ['business', 'role', 'run', 'pid', 'startTime', 'runnerPid', 'runnerStartTime', 'keyId'].every(k => a[k] === b[k]);
const shape = s => {
if (!s || ['business', 'instance', 'run'].some(k => typeof s[k] !== 'string' || !s[k])
|| ['pid', 'runnerPid'].some(k => !Number.isSafeInteger(s[k]) || s[k] < 2)
|| ['startTime', 'runnerStartTime'].some(k => typeof s[k] !== 'string' || !/^\d+$/.test(s[k]))
|| (s.modelKeyId !== undefined && (typeof s.modelKeyId !== 'string' || !/^[a-f0-9]{12}$/.test(s.modelKeyId)))) refuse();
return { business: s.business, role: s.instance, instance: s.business + '/' + s.instance,
run: s.run, pid: s.pid, startTime: s.startTime, runnerPid: s.runnerPid,
runnerStartTime: s.runnerStartTime, keyId: s.modelKeyId };
};
const refresh = () => {
const file = sessionsFile(dataRoot), stat = lstatSync(file);
if (!stat.isFile() || stat.isSymbolicLink()) refuse();
const entries = readSessions(dataRoot).map(shape), seen = new Set();
const after = lstatSync(file);
if (!['dev', 'ino', 'size', 'mtimeMs', 'ctimeMs'].every(k => stat[k] === after[k])) refuse();
// Validate the whole snapshot before merging any of it. Missing entries do
// not erase known identities; the host may have just rewritten Registry[].
for (const r of entries) {
const key = r.business + ':' + r.run;
if (seen.has(key) || (known.has(key) && !same(known.get(key), r))) refuse();
seen.add(key);
}
for (const r of entries) known.set(r.business + ':' + r.run, r);
};
let bootChecked = false;
try { refresh(); bootChecked = true; } catch { /* hold retirement, not the human/control surface */ }
// startTimeOf/live alone conflate absence and read errors. Only a missing proc
// directory, or a zombie with the SAME recorded start ticks, confirms an exit.
const liveIdentity = (pid, ticks, proof, part) => {
if (proof[part]) return false;
let raw;
try { raw = readFileSync(`/proc/${pid}/stat`, 'utf8'); }
catch (error) {
if (error.code !== 'ENOENT') refuse();
try { lstatSync(`/proc/${pid}`); } catch (missing) { if (missing.code === 'ENOENT') { proof[part] = true; return false; } }
refuse();
}
const fields = raw.slice(raw.lastIndexOf(')') + 2).trim().split(/\s+/);
if (!/^[A-Z]$/.test(fields[0]) || !/^\d+$/.test(fields[19]) || fields[19] !== ticks) refuse();
if (fields[0] === 'Z') { proof[part] = true; return false; }
return true;
};
const runs = instance => {
try {
if (!bootChecked) refuse();
refresh();
const live = [], checked = [];
for (const r of known.values()) {
if (r.instance !== instance) continue;
const key = r.business + ':' + r.run;
const proof = terminal.get(key) ?? { outer: false, runner: false };
terminal.set(key, proof);
let associated = false;
if (!proof.outer || !proof.runner) {
const record = credentials.modelRecord(instance);
associated = !!record && [record.keyId, ...record.retiring.map(k => k.keyId)].includes(r.keyId);
const prior = validated.get(key);
if (!associated && (!prior || !same(prior, r))) refuse();
}
const outerLive = liveIdentity(r.pid, r.startTime, proof, 'outer'), runnerLive = liveIdentity(r.runnerPid, r.runnerStartTime, proof, 'runner');
// Never interpret an unknown/wrong key on a surviving prior run as no
// old-key users. A confirmed exit may be retired without key guessing.
if (outerLive || runnerLive) {
// Provenance permits strict exit confirmation, NEVER filtering away a
// surviving run whose model-key association has disappeared.
if (!associated) refuse();
const current = bound.get(r.business + ':' + r.run);
if (current && (current.instance !== r.instance || current.keyId !== r.keyId
|| current.pid !== r.pid || current.startTime !== r.startTime)) refuse();
live.push(r);
}
if (associated && (outerLive || runnerLive)) checked.push(r);
}
// A newly bound launch whose registry publication has not happened is
// uncertain, not absent. Do not grant retirement through that startup gap.
for (const r of bound.values()) if (r.instance === instance && !known.has(r.business + ':' + r.run)) refuse();
// Commit ONLY after the entire same-instance view passed both identities,
// live binding consistency, later known entries and unpublished bindings.
// Existing M1 terminal bits remain independently monotonic and unchanged.
for (const r of checked) validated.set(r.business + ':' + r.run, { ...r });
return live;
} catch { refuse(); }
};
return {
runs,
authorizeStop(requests) {
for (const r of requests) {
const current = bound.get(r.business + ':' + r.run);
if (!current || current.instance !== r.instance || current.keyId !== r.keyId
|| current.pid !== r.pid || current.startTime !== r.startTime) refuse();
if (!runs(r.instance).some(found => same(found, r))) refuse();
}
},
};
}
export async function startBroker({
dataRoot,
businesses,
launches = [],
readers = [],
repoRoots = [],
tasks = null,
organization = null,
// Row 199: the tests' scratch CA for publish's git (`-c http.sslCAInfo=...`). process.mjs drops
// it from the boot config, so only an in-process caller sets it.
publishTls = [],
// C2-03a: the tests' stand-in for syncCommand, a shorter timer and a scratch config dir for the
// slot, { command, intervalMs, configDir }. A boot config is JSON and can't carry a function, so
// a librarySync without one is refused.
librarySync = null,
// FED R3 (#414): the access file and its loader context, { file, context } (R1's loadAccess).
// Without it no user binds. R6 and R8 pass it; the live boot config doesn't yet. FED R4 (#1801):
// intervalMs, the revocation timer's period (design 3.7, 30 s), in-process only like librarySync's.
access = null,
// Row 252 (#1753, design section 2): the checked console.sso subjects, [{provider, iss, sub}], each an
// owner of the business (Webby N1). The boot config carries them; no socket verb sets them. Empty, no
// Console owner binds and the terminal owner is unchanged.
consoleOwners = [],
// P1 validated sidecar from the trusted host; never a socket request setting.
proxy = null,
}) {
if (!Array.isArray(consoleOwners) || consoleOwners.length > 512 || consoleOwners.some((o) => o === null || typeof o !== 'object' || Array.isArray(o) ||
Object.keys(o).length !== 3 || ['provider', 'iss', 'sub'].some((k) => typeof o[k] !== 'string' || !o[k] || o[k].length > 512)))
throw new BusError('invalid-host-request');
const owners = Object.freeze(consoleOwners.map((o) => Object.freeze({ provider: o.provider, iss: o.iss, sub: o.sub })));
if (access !== null && (typeof access?.file !== 'string' || access.context === null || typeof access.context !== 'object'
|| (Object.hasOwn(access, 'intervalMs') && !(Number.isSafeInteger(access.intervalMs) && access.intervalMs > 0))))
throw new BusError('invalid-host-request');
if (librarySync !== null && (typeof librarySync?.command !== 'function'
|| (Object.hasOwn(librarySync, 'intervalMs') && !(Number.isSafeInteger(librarySync.intervalMs) && librarySync.intervalMs > 0))
|| (Object.hasOwn(librarySync, 'configDir') && typeof librarySync.configDir !== 'string')))
throw new BusError('invalid-host-request');
let modelProxyClient = null, proxyPage = null, proxyUsage = null, usageTimer = null;
let modelKeys = null, modelTimer = null, modelSweep = null;
const modelRuns = new Map();
let store, credentials, server, adapter, processing, syncTimer = null, syncPass = null, accessTimer = null;
try {
const proxyReceipt = entry => process.stderr.write(`model-proxy: ${JSON.stringify(entry)}\n`);
const references = {};
for (const [business, b] of Object.entries(businesses)) {
for (const [role, r] of Object.entries(b.roles))
if (r.credentials) references[business + '/' + role] = r.credentials;
if (b.tracker?.sync?.credentials) references[business + '/@sync'] = b.tracker.sync.credentials;
}
const protectedRoots = [
fileURLToPath(new URL('../../../', import.meta.url)),
...repoRoots,
...Object.values(businesses).flatMap((b) => Object.values(b.projects ?? {}).filter(p => p.kind !== 'library').map((p) => p.root)),
];
// Row 199 (#1697, design D1): the per-agent store is <configDir>/secrets/agents.
const storeRoot = organization ? join(organization.dir, 'secrets', 'agents') : null;
store = new Store(dataRoot);
// Store's writer lock admits one bus per data root before it holds the management client.
if (proxy) {
if (!organization) throw new BusError('not-configured');
modelProxyClient = await loadManagementClient({ configDir: organization.dir, proxy, receipt: proxyReceipt });
}
// Row 234 (#1740, r6 X4 third bullet): each host grant record gives its agent a store reference to
// host.<id>, so a restart finds the keys the grant executor wrote. The loader refuses host.<id> in a
// role's credentials, so these never meet a business-file reference.
const granted = new Set();
for (const g of store.all('SELECT business, agent, host, rotate_by FROM host_grants ORDER BY business, agent, host')) {
granted.add(g.business + '/' + g.agent + '/' + g.host);
if (!Object.hasOwn(businesses, g.business)) continue;
const refs = (references[g.business + '/' + g.agent] = { ...(references[g.business + '/' + g.agent] ?? {}) });
refs['host.' + g.host] = hostReference(storeRoot, g.business, g.agent, g.host, g.rotate_by);
}
// Row 235 (r6 section 6, N1): a host.<id> key file with no record goes before Credentials loads.
for (const entry of sweepHostKeys(storeRoot, Object.keys(businesses), granted))
process.stderr.write(`hosts: ${JSON.stringify({ event: 'host-key-swept', ...entry })}\n`);
// Row 236 (#1742, #436b r5 section 5): each gitea grant record gives its agent a store reference to
// gitea, and `held` names the files memory must not load until reconcile or a revoke.
const { held } = storeRoot ? giteaStart(store, storeRoot, businesses, references) : { held: [] };
credentials = new Credentials({ references, repoRoots: protectedRoots, dataRoot, storeRoot, held,
modelAgents: proxy ? Object.entries(businesses).flatMap(([id, b]) => Object.keys(b.roles).map(role => id + '/' + role)) : [] });
if (proxy) {
const inventory = modelRunInventory(dataRoot, modelRuns, credentials);
modelKeys = new ModelKeys({ credentials, client: modelProxyClient, configDir: organization.dir,
baseUrl: `http://127.0.0.1:${proxy.port}`, receipt: proxyReceipt, rotateGraceMinutes: proxy.rotateGraceMinutes ?? 120,
runs: inventory.runs,
stopRuns: async runs => {
inventory.authorizeStop(runs);
await stopModelRuns({ runs, sessions: () => readSessions(dataRoot), stop: run => stopSession(dataRoot, run, { timeoutMs: MODEL_STOP_TIMEOUT_MS }), receipt: proxyReceipt });
for (const r of runs) {
if (inventory.runs(r.instance).some(found => found.run === r.run)) throw new BusError('proxy-stop-failed');
}
for (const r of runs) modelRuns.delete(r.business + ':' + r.run);
} });
// Keep the control/human surface available, but refuse every launch on failed reconcile.
try { await modelKeys.reconcile(); } catch (error) { proxyReceipt({ action: 'proxy.boot-refused', code: error.code }); }
}
const configureProxyPage = () => {
proxyPage = new ProxyPage({ client: modelProxyClient, instanceTag: sha256(organization.dir).slice(0, 12),
// P2 supplies the model metadata; only the matching business's record
// participates in this owner view. No credential value is read here.
keyRecords: business => credentials.status().filter(r => r.service === 'model' && r.instance?.startsWith(business + '/'))
.map(r => ({ keyId: r.keyId, agent: r.instance.slice(business.length + 1), issuedAt: r.issuedAt, state: r.state })),
});
};
if (modelProxyClient) configureProxyPage();
// vikunja:19/305: the plug-in switch through the same human-only path as the limits: the verbs
// plugins and plugins.set, logged in changes.jsonl with the actor, a missing module refused.
const plugins=organization?pluginSettings({dir:organization.dir,rolesDir:organization.rolesDir,exists:hasModule}):null;
const levels=organization?await harnessLevels():()=>null;
const settings=organization?launchSettings({...organization,sessions:()=>readSessions(dataRoot),levels}):null;
// Row 194 (#1692, brief item 8, row 199 D13): a fire or a delete revokes the agent's credentials
// after the writer's checks and before its write, under the writer's lock (row 239). Fire revokes
// each service of the entry and keeps the store directory, delete calls remove (sage-1593). A
// service the running bus doesn't know (an agent created since the start) has nothing in memory,
// so it goes on, and then no token or tmp file may remain in the agent's store directory
// (sage-1592). Any failure stops the verb with the file unchanged.
const revokeFailed = (message) => new OrganizationError('credential-revoke-failed', message);
function revoke(business, agent, how, services) {
const instance = business + '/' + agent;
const outside = [];
try {
if (how === 'delete' && storeRoot) credentials.remove(instance);
else
for (const service of services) {
try {
if (!credentials.revoke(instance, service).file) outside.push(service);
} catch (e) {
if (e.code !== 'credential-unknown') throw e;
}
}
} catch (e) {
throw revokeFailed(`${agent}: ${e.code ?? 'credential-file'}`);
}
if (storeRoot) {
let left = [];
try {
left = readdirSync(join(storeRoot, business, agent));
} catch (e) {
if (e.code !== 'ENOENT') throw revokeFailed(`${agent}: store directory can't be read`);
}
if (left.length > 0) throw revokeFailed(`${agent}: ${left.sort().join(' and ')} still in the store`);
}
// A file or env reference outside the store keeps its token for a restart (row 199 section 6).
return { revoked: services, outsideStore: how === 'fire' ? outside : [] };
}
// Row 165 (#1662): the human adds and changes role instances through instances and instances.set.
const proxyOrganization = modelKeys ? modelOrganization({ modelKeys, writer: organizationWriter({ dir: organization.dir, rolesDir: organization.rolesDir }) }) : null;
const instances=organization?instanceSettings({dir:organization.dir,rolesDir:organization.rolesDir,system:organization.system,levels,revoke,
...(proxyOrganization ? { writer: proxyOrganization.writer, revoke: proxyOrganization.revoke(revoke) } : {})}):null;
const usageLog = entry => process.stderr.write(`usage: ${JSON.stringify(entry)}\n`);
const keyForRun = (business, run) => modelRuns.get(business + ':' + run)?.keyId ?? null;
const usage = await createUsage({ store, dataRoot, businesses, log: usageLog, keyForRun,
proxyView: business => proxyUsage?.view(business) ?? null });
proxyUsage = createProxyUsage({ store, log: usageLog, client: async () => {
if (!modelKeys) return null;
await modelKeys.verifyIdentity();
return modelProxyClient;
},
records: () => credentials.status(),
read: () => Object.fromEntries(Object.keys(businesses).map(id => [id, settings ? settings.current(id) : businesses[id]])) });
// Row 125 (#1619, REQ-LIMIT-3, REQ-LIMIT-4): the limit checks read the organization file at
// each ask, so a limit, a reset or a switched-on check takes effect without a restart.
const limitLog = entry => process.stderr.write(`limits: ${JSON.stringify(entry)}\n`);
const limits = createLimits({ store, read: id => settings ? settings.current(id) : businesses[id], log: limitLog,
keyForSubject: (business, subject) => modelUsageKey(credentials.status(), modelRuns, business, subject) });
for (const id of Object.keys(businesses)) await limits.refresh(id);
const withTokens = (id, result) => ({ ...result, tokens: limits.report(id) });
// Row 210 (#1707, design D7 step 6) and row 234 (#1740, r6 E2): the run dir and the host enrollment half.
const runRoot = organization ? join(organization.dir, 'secrets', 'run') : null;
let broker;
processing = createProcessing({ dataRoot, ...discordProcessingHooks(dataRoot), containerStop: createContainerStopper({ dataRoot }),
onTransition: () => broker.reconcileProcessing(),
onStop: stop => broker.recordProcessingStop(stop),
log: line => process.stderr.write(`${line}\n`),
});
// C2-04: mirrors are host state, never session checkouts. An unsafe
// existing mirror refuses startup before a socket can become ready.
for (const business of Object.values(businesses))
for (const [project, entry] of Object.entries(business.projects ?? {}))
if (entry.kind === 'library') {
try { await processing.work(() => libraryModule.ensureMirror({ business, project, dataRoot })); }
catch (e) { if (!e.code?.startsWith('processing-')) throw e; }
}
// C2-03a: the slot is <configDir>/secrets/<business>/library-gitea (design 10 step 4). Sync only
// checks that it is there; the askpass helper reads it.
// C2-03b: the broker chooses. The chief's grant store file once a chief has Gitea grant evidence,
// the slot before that, or a refusal sync records. The answer carries no file to sync but this one.
const slotDir = librarySync?.configDir ?? organization?.dir ?? null;
const fetchCredential = business => {
const choice = broker.libraryFetchCredential(business.id);
if (choice.kind === 'chief')
return { kind: 'chief', user: choice.user, file: storeRoot ? giteaReference(storeRoot, business.id, choice.agent).file : null };
if (choice.kind === 'slot') return { kind: 'slot', file: slotDir ? join(slotDir, 'secrets', business.id, libraryModule.SLOT) : null };
return { refused: choice.refused };
};
const syncOptions = business => ({
credential: fetchCredential(business),
...(librarySync ? { command: librarySync.command } : {}),
});
const humanWriteOptions = context => {
const mapping = libraryModule.checkMapping(context.business.projects[context.project]);
if (!mapping.editor) throw new libraryModule.LibraryError('library-mapping-invalid', 'editor is required');
return { credential: libraryModule.humanCredential(context, { user: mapping.editor.user, configDir: slotDir }),
...(librarySync ? { command: librarySync.command } : {}) };
};
// Row 194 (#1692, D3): after every write that commits, the broker takes the business as a restart
// would load it. The credential references, the project roots the Credentials store protects
// and the tracker bots are fixed at start (the Credentials store, the tasks adapter), so a file
// whose references, roots or bots differ from the boot copy isn't reloaded, and the write
// answers restart: true. Hire adds neither. A human create of a credentialed definition adds
// references, so it answers restart: true, and issue works after the restart (brief item 7).
// A role not in the boot copy matches only with no references and no bot. A reference compares
// by its kind and path only: row 199's issue rewrites the date in the file outside this reload,
// Credentials keeps its own copy of the date, and the broker never reads it.
const fixedRef = ({ file, env, store }) => ({ file, env, store });
const fixedRole = r => canonicalJson({
credentials: Object.fromEntries(Object.entries(r?.credentials ?? {}).map(([service, ref]) => [service, fixedRef(ref)])),
tracker: r?.tracker ?? null,
});
const fixedAtStart = b => ({
roles: Object.fromEntries(Object.entries(b.roles).map(([role, r]) => [role, fixedRole(r)])),
sync: canonicalJson(b.tracker?.sync ?? null),
roots: canonicalJson(Object.values(b.projects ?? {}).filter(p => p.kind !== 'library').map(p => p.root).sort()),
// A library entry has no root, and its mirror is ensured at start (C2-04), so each one is fixed whole.
libraries: canonicalJson(Object.fromEntries(Object.entries(b.projects ?? {}).filter(([, p]) => p.kind === 'library'))),
});
const sameFixed = (boot, b) => fixedAtStart(b).sync === boot.sync && fixedAtStart(b).roots === boot.roots
&& fixedAtStart(b).libraries === boot.libraries
&& Object.entries(fixedAtStart(b).roles).every(([role, f]) => f === (boot.roles[role] ?? fixedRole(null)));
const booted = new Map(Object.entries(businesses).map(([id, b]) => [id, fixedAtStart(b)]));
const reloadLog = entry => process.stderr.write(`organization: ${JSON.stringify(entry)}\n`);
function reload(id) {
try {
const b = loadBusiness(id, { dir: organization.dir, rolesDir: organization.rolesDir });
const resolved = {};
for (const instance of Object.keys(b.roles)) resolved[instance] = resolveInstance({ system: organization.system, business: b, instance });
const next = busBusiness(b, resolved);
if (!sameFixed(booted.get(id), next)) {
reloadLog({ event: 'reload-needs-restart', business: id });
return false;
}
broker.reloadBusiness(id, next);
return true;
} catch (e) {
reloadLog({ event: 'reload-failed', business: id, message: e.message });
return false;
}
}
broker = new Broker({
// FED R3: the access file is read per user request; a refusal leaves the user no grant.
access: access ? () => loadAccess(access.file, access.context) : null,
// FED R4 (#1801, design 3.7 trigger 1): a request stats the file and reads it only when this
// changes. A failed stat is a stamp of its own, so a removed file reads (and refuses) once.
accessStamp: access ? () => {
try {
const st = lstatSync(access.file, { bigint: true });
return `${st.dev}:${st.ino}:${st.size}:${st.mtimeNs}:${st.ctimeNs}:${st.mode}:${st.uid}`;
} catch (e) {
return `unreadable:${e.code ?? 'error'}`;
}
} : null,
// Row 270 (264c): session.list's compaction count, read from the session store's ledger.
compactions: ({ business, thread, session, legacy }) => {
const dir = storeDir(dataRoot, business, thread, session, { legacy });
return dir ? compactionCount(dir) : { count: null, known: false, reason: 'store-unreadable', at: null };
},
hostGrant: runRoot ? hostGrant({ configDir: organization.dir, runRoot }) : null,
// Row 235 (#1741, r6 X4, X5): the grant executor's claim, register and issue, never use().
hostKeys: storeRoot ? grantKeys({ credentials, storeRoot }) : null,
processing,
// Row 236 (#1742): the Gitea grant path. The admin slot is <configDir>/secrets/grants/<business>/gitea.
giteaGrant: organization ? giteaGrant({ configDir: organization.dir }) : null,
giteaKeys: storeRoot ? giteaKeys({ credentials, storeRoot }) : null,
usage,
limits,
store,
businesses,
library: {
lookup: createLibraryLookup({ dataRoot, sync: context =>
processing.work(() => libraryModule.sync(context, syncOptions(context.business))) }),
log: entry => process.stderr.write(`library: ${JSON.stringify(entry)}\n`),
readFile: context => libraryModule.readLibraryFile({ ...context, dataRoot }),
status: context => libraryModule.libraryStatus({ ...context, dataRoot }),
sync: (context, { accept }) => processing.work(() => libraryModule.sync({ ...context, dataRoot }, { ...syncOptions(context.business), accept })),
// C2-02: trusted references only. The askpass helper alone opens a credential file.
writeDoc: (context, options) => processing.work(() => libraryModule.writeLibraryDoc({ ...context, dataRoot }, {
...options, credential: { ...options.credential,
file: storeRoot ? giteaReference(storeRoot, context.business.id, options.credential.agent).file : null },
...(librarySync ? { command: librarySync.command } : {}),
})),
saveFile: context => processing.work(() => libraryModule.saveLibraryFile({ ...context, dataRoot }, humanWriteOptions(context))),
revert: context => processing.work(() => libraryModule.revertLibraryCommit({ ...context, dataRoot }, humanWriteOptions(context))),
LibraryError: libraryModule.LibraryError,
// C2-06: the citation guard, the reply limits read from the business file at each check (none
// configured reads as unreadable, so requireCitation is true), and thread.messages' `last`.
guard: (context, body, options) => libraryModule.guardReply({ ...context, dataRoot }, body, options),
replyLimits: id => libraryModule.resolveReplyLimits(organization
? organizationWriter({ dir: organization.dir, rolesDir: organization.rolesDir }).readRaw(id) : { readable: false }),
last: (context, paths) => libraryModule.lastCommits({ ...context, dataRoot }, paths),
GuardError: libraryModule.GuardError,
},
project: {
readSpec: context => projectModule.readSpec({ ...context, dataRoot }),
writeRecord: context => processing.work(() => projectModule.writeRecord({ ...context, dataRoot })),
listFiles: context => projectModule.listProjectFiles({ ...context, dataRoot }),
readFile: context => projectModule.readProjectFile({ ...context, dataRoot }),
writeFile: context => projectModule.writeHumanFile({ ...context, dataRoot }),
ProjectError: projectModule.ProjectError,
},
// limits and limits.set (organization.set is limits.set) carry each token limit's count; a
// plugins.set reloads the business's limit checks in the background.
organization:settings?(proxyOrganization?.wrap ?? (operation => operation))((id,verb,args,actor,context)=>{
if(verb==='limits')return withTokens(id,settings.read(id));
if(verb==='plugins')return plugins.read(id);
// Row 256 (#1761): the actor is the reader, so endProtected is the delete check for that reader.
if(verb==='instances')return instances.read(id,actor);
// Row 65 (mos-0840): the Console's routing table.
if(verb==='routes')return settings.routes(id);
// Row 298 (#1804, Q228): the chief's grant scope as the file stands, the fallback shown.
if(verb==='grants.scope')return instances.grantScopeRead(id);
// Row 194 (#1692, V5): a delete's checks at the verb, with no write and no reload.
if(verb==='instances.check')return instances.checkDelete(id,args.instance,actor);
// Row 194 b6 (webby-0094 B1): a fire's checks against the file, before step A.
if(verb==='instance.fireCheck')return instances.checkFire(id,args.name);
// Internal read-only path: no reload, journal, credential or publication.
if(verb==='instance.hireCheck')return instances.checkHire(id,args);
let result;
if(verb==='limits.set')result=withTokens(id,settings.set(id,args,actor));
else if(verb==='instances.set')result=instances.set(id,args,actor);
else if(verb==='routes.set')result=settings.setRoutes(id,args,actor);
else if(verb==='plugins.set')result=plugins.set(id,args,actor);
// Row 194 (#1692, V6): the human's keep and noHire lists, through the instance writer.
else if(verb==='veto.set')result=instances.veto(id,args,actor);
// Row 298: the human's grant scope, through the instance writer.
else if(verb==='grants.scope.set')result=instances.grantScope(id,args,actor);
// C2-06 M11: the human's replyLimits, through the organization writer's fence.
else if(verb==='library.limits.set')result=setReplyLimits(organizationWriter({dir:organization.dir,rolesDir:organization.rolesDir}),id,args,actor);
// Row 194 (D2.1, D2.2): the chief's hire and fire, with the reason in the change context.
else if(verb==='instance.hire')result=instances.hire(id,args,{actor,context});
else if(verb==='instance.fire')result=instances.fire(id,{name:args.name},{actor,context});
else throw new BusError('invalid-request');
// Row 194 (D3 item 2): one reload, after every verb that committed, then the limit checks.
const live=reload(id);
limits.refresh(id).catch(e=>limitLog({event:'limit-refresh-failed',business:id,message:e.message}));
// Row 194 b6 (webby-0094 B1, sage-2241): every instance-writer verb says whether the reload
// took, so a refused one (credentials, roots, ...) shows the restart line for a keep or a
// hire too. The other writers' answers carry no restart field.
return INSTANCE_VERBS.has(verb)?{...result,restart:!live}:result;
}):null,
// Row 194 (D2.3): the role files as they stand, for the hire checks.
roleFile: organization ? (name) => loadRole(organization.rolesDir, name) : null,
secretCheck: (value) => credentials.assertClean(value),
credentialStatus: () => credentials.status(),
// Row 199 (#1697, design section 6): issue, rotate, revoke and delete, live with no restart; each
// rewrites or records through the organization writer, so changes.jsonl holds the receipt.
proxyPage: async (verb, args, scope) => {
if (!proxyPage) throw new BusError('not-configured');
return proxyPage.request(verb, args, scope);
},
proxyInit: organization ? async args => {
const settings = await initializeProxy({ configDir: organization.dir, dataRoot, ...args });
modelProxyClient = await loadManagementClient({ configDir: organization.dir, proxy: settings, receipt: proxyReceipt });
configureProxyPage();
return settings;
} : null,
credentialVerbs: organization
? credentialVerbs({ credentials, writer: organizationWriter({ dir: organization.dir, rolesDir: organization.rolesDir }) })
: null,
// Row 65: a new launch binds only on a harness its business switches on, read from the file
// as it stands now; an unreadable file switches none on.
harnessOn: (id, name) => {
try {
const b = settings ? settings.current(id) : businesses[id];
return Array.isArray(b?.plugins?.harness) && b.plugins.harness.includes(name);
} catch {
return false;
}
},
// Row 298 (#1804, Q228): one read binds launch.grantScope to the organization revision.
// A missing organization reader or unreadable file cannot authorize an automatic grant.
grantScope: (id) => {
if (!settings) return { value: undefined, revision: null };
const { document, revision } = instances.writer.read(id);
return { value: document.launch?.grantScope, revision };
},
// Row 194 (#1692, D4.1, B8): bus.tester as the file sets it now; an unreadable file is off.
testerOn: (id) => {
try {
const b = settings ? settings.current(id) : businesses[id];
return b?.vars?.['bus.tester'] === true;
} catch {
return false;
}
},
});
broker.reconcileProcessing();
processing.start();
const processingWork = () => {
const state = processing.read();
if (state.invalid) throw new BusError(state.code);
if (state.halted) throw new BusError('processing-halted');
};
// Process identities must be supplied for every managed run when using the human transport.
const launchRecords = [];
function bindLaunch(r) {
if (
!Number.isSafeInteger(r.pid) ||
r.pid < 2 ||
typeof r.startTime !== 'string' ||
!/^\d+$/.test(r.startTime)
)
throw new BusError('invalid-launch-process');
const { modelKeyId, ...record } = r;
if (modelKeys) {
modelKeys.assertLaunchable(r.business + '/' + r.role);
const m = credentials.modelRecord(r.business + '/' + r.role);
if (!m || ![m.keyId, ...m.retiring.map(k => k.keyId)].includes(modelKeyId)) throw new BusError('proxy-key-refused');
}
const cap = broker.bindLaunch(record);
launchRecords.push({ ...r });
if (modelKeys) modelRuns.set(r.business + ':' + r.run, { ...r, instance: r.business + '/' + r.role, keyId: modelKeyId });
return { business: r.business, run: r.run, cap };
}
const bound = launches.map(bindLaunch);
const readCaps = readers.map((business) => ({ business, cap: broker.bindReader({ business }) }));
if (tasks) {
adapter = await tasks({ broker, credentials, businesses, processing });
if (typeof adapter?.handle !== 'function' || !Number.isSafeInteger(adapter.timeout) || adapter.timeout < 1)
throw new BusError('invalid-adapter');
}
const web = await webServices(businesses);
// Row 210 (#1707, design D7 step 6): clear what a killed bus child left, before anyone can call.
if (runRoot) sweepRunDir(runRoot);
// Row 234 (r6 X3): end the enrollments a killed bus child left, before anyone can call.
broker.reconcileGrants();
const interpreter = inspectInterpreter();
recordInterpreterStart(store.directory, interpreter);
const peerReader = createPeerReader({ interpreter });
const principalPaths = {
human: fileURLToPath(new URL('./human-cli.mjs', import.meta.url)),
tester: fileURLToPath(new URL('./tester-cli.mjs', import.meta.url)),
user: fileURLToPath(new URL('./user-cli.mjs', import.meta.url)),
console: fileURLToPath(new URL('../../webui/src/cli.mjs', import.meta.url)),
consoleCli: fileURLToPath(new URL('./console-cli.mjs', import.meta.url)),
};
const path = join(store.directory, 'broker.sock');
// The existing host executor owns SSH and its key lifecycle. Combine its revocation
// signal with processing cancellation without changing its proof or credential entry points.
const host = runRoot ? hostExecutor({ root: runRoot, credentials: {
busy: (...args) => credentials.busy(...args),
useFor: (session, name, fn, options) => credentials.useFor(session, name, (token, meta) =>
fn(token, { ...meta, signal: meta.signal
? AbortSignal.any([meta.signal, processing.signal()]) : processing.signal() }), options),
} }) : null;
server = await serve({
web: (business) => web.get(business) ?? null,
host: host ? { busy: (...args) => host.busy(...args),
run: (...args) => processing.work(() => host.run(...args)) } : null,
tasks: adapter ? { handle: adapter.handle, timeout: adapter.timeout } : null,
broker,
path,
peerReader,
authenticateHuman: (proof, peer) => {
const p = verifyPrincipal({ human: proof }, { peer, paths: principalPaths, businesses, launches: launchRecords });
return broker.bindHuman({ business: p.business, human: p.id, via: 'cli', outsideAgent: true });
},
authenticateTester: (proof, peer) => {
const p = verifyPrincipal({ tester: proof }, { peer, paths: principalPaths, businesses, launches: launchRecords });
return broker.bindTester({ business: p.business });
},
// FED R3 (design 3.6): checks 1 and 2 are row 196's user kind; check 3, the live grant, is bindUser's.
authenticateUser: (proof, peer) => {
const p = verifyPrincipal({ user: proof }, { peer, paths: principalPaths, businesses, launches: launchRecords });
return broker.bindUser({ business: p.business, user: p.id });
},
// Row 252 (#1753): a fresh proof per connection, a cap for the Console verbs only.
authenticateConsole: (proof, peer) => {
const p = verifyPrincipal({ console: proof }, { peer, paths: principalPaths, businesses, launches: launchRecords, consoleOwners: owners });
return broker.bindConsole({ business: p.business, human: p.id, subject: p.subject });
},
});
// Row 235 (r6 X3): the remote undo of interrupted host grants, once the bus is up, so a start doesn't
// wait on the network.
broker.reconcileHosts();
// Row 236 (#436b r5 section 5): the Gitea grants' remote undo, settle and open revokes, likewise.
broker.reconcileGitea();
// S6 launcher operations. The host decides capacity and the instance list; the broker
// authorizes role.launch and keeps the evidence, refusals included.
// A refusal is recorded against the caller, as request() records one.
function refusing(cap, fn, subject = null) {
try {
return fn();
} catch (e) {
if (!(e instanceof BusError)) throw e;
broker.refuse(cap, e.code, subject);
throw e;
}
}
const authorizeLaunch = (cap, instance) =>
refusing(cap, () => broker.authorize(cap, 'role.launch', { target: instance }));
// Row 93 (#1587): the host's git socket. A push is checked before the host takes the bundle
// and recorded once the ref moved; a reviewer's fetch is checked against its review.requested.
const checkPush = (cap, task_ref) => refusing(cap, () => broker.checkPush(cap, task_ref), task_ref);
const reviewFetch = (cap, args) => refusing(cap, () => broker.reviewFetch(cap, args), args?.task_ref);
// Row 137 (#1631): the git socket's land op. checkLand's refusal is the run's, like checkPush's.
// A landing then ends in recordLand or landRefused under its ticket, which outlive the run's cap.
const checkLand = (cap, args) => refusing(cap, () => broker.checkLand(cap, args), args?.task_ref);
// Row 199 (#1697, design D9b): the git socket's publish op. checkPublish's refusal is the run's.
// The gitea token is used only under the open ticket, keyed from the agent checkPublish checked,
// and the op table returns no token. A publish then ends in recordPublish or publishRefused,
// which files any refusal once, withGitea's included.
const checkPublish = (cap, args) => refusing(cap, () => broker.checkPublish(cap, args), args?.task_ref);
const withGitea = async (ticket, fn) => credentials.useFor(broker.publishSession(ticket), 'gitea', fn);
// The push itself runs here, where the token is (D9 step 5), and the git socket's host polls
// for its end: the host's op channel answers one op at a time within 10 s, and ls-remote and
// push can take longer. Fork, user, source and dst all come from the ticket. A WorkingError's
// code is the refusal; git's stderr stays here.
const remotes = new Map();
function publishPush(ticket) {
if (remotes.has(ticket)) throw new BusError('publish-busy');
const { business, project, fork, user, source, dst } = broker.publishTarget(ticket);
const entry = { state: 'running' };
remotes.set(ticket, entry);
processing.work(() => withGitea(ticket, (token) =>
publishRemote({ repo: workingRepo(dataRoot, business, project), fork, user, source, dst, token, tls: publishTls }).catch((e) => {
throw e instanceof WorkingError ? new BusError(e.code) : e;
}),
)).then(
(r) => Object.assign(entry, { state: 'pushed', ...r }),
(e) => {
// Not a refusal: the error's name and code only, never a message that could carry git's output.
if (!(e instanceof BusError)) process.stderr.write(`bus: publish git-failed: ${JSON.stringify({ name: e?.name, code: e?.code })}\n`);
Object.assign(entry, { state: 'refused', code: e instanceof BusError ? e.code : 'git-failed' });
},
).then(() => {
if (entry.held) settle(ticket, entry, entry.held);
});
return { state: 'running' };
}
// Row 242 (#1748): the git socket gave up on a publish (publish-timeout) whose push it never
// collected. Its publishRefused waits for the push: until that ends the ticket stays open, so
// checkPublish refuses another publish on the decision with publish-busy (row 237). A push that
// reached the fork is then recorded, which spends the decision; one that didn't is filed with
// the socket's code. Either way the decision can't push a second ref.
function settle(ticket, entry, code) {
remotes.delete(ticket);
try {
if (entry.state === 'pushed') {
try {
broker.recordPublish(ticket, { ref: entry.ref, commit: entry.commit, previous: entry.previous });
process.stderr.write(`bus: publish ${ticket}: pushed after the git socket refused ${code}; recorded\n`);
return;
} catch (e) {
if (!(e instanceof BusError)) throw e;
code = e.code;
}
}
broker.publishRefused(ticket, { code });
} catch (e) {
process.stderr.write(`bus: publish ${ticket}: not settled: ${JSON.stringify({ name: e?.name, code: e?.code })}\n`);
}
}
function publishRefused(ticket, args) {
const entry = remotes.get(ticket);
if (!entry) return broker.publishRefused(ticket, args);
if (!/^[a-z-]{1,64}$/.test(args?.code ?? '')) throw new BusError('invalid-request');
if (entry.state === 'running') entry.held = args.code;
else settle(ticket, entry, args.code);
return args.code;
}
function publishResult(ticket) {
const entry = remotes.get(ticket);
if (!entry) throw new BusError('publish-unknown');
if (entry.state !== 'running') remotes.delete(ticket);
return { ...entry };
}
// Metadata only (service, date, state); the token stays in Credentials.
function credentialStatus(business, role) {
return credentials
.status()
.filter((c) => c.instance === business + '/' + role)
.map(({ service, date, state, keyId, issuedAt }) => ({ service, date, state, ...(service === 'model' ? { keyId, issuedAt } : {}) }));
}
// C2-03a: each library entry with a sync user fetches once at start, then every 60 s. A pass
// still running skips the tick. Only codes are logged, never git's output.
const timed = Object.values(businesses).flatMap(business => Object.entries(business.projects ?? {})
.filter(([, entry]) => entry.kind === 'library' && Object.hasOwn(entry, 'user')).map(([project]) => ({ business, project })));
const syncLog = entry => process.stderr.write(`library: ${JSON.stringify(entry)}\n`);
const syncAll = async () => {
for (const { business, project } of timed) {
try {
const { code } = await libraryModule.sync({ business, project, dataRoot }, syncOptions(business));
if (code !== null) syncLog({ event: 'library-sync-held', business: business.id, project, code,
...(code === 'library-fetch-no-grant' ? { fix: LIBRARY_FETCH_FIX } : {}) });
} catch (e) {
if (e?.code === 'library-sync-busy') continue;
syncLog({ event: 'library-sync-refused', business: business.id, project,
code: e instanceof libraryModule.LibraryError ? e.code : 'library-sync-failed' });
}
}
};
const tick = () => {
const state = processing.read();
if (!syncPass && !state.halted && !state.invalid)
syncPass = processing.work(syncAll).catch(e => {
if (!e.code?.startsWith('processing-')) syncLog({ event: 'library-sync-refused', code: 'library-sync-failed' });
}).finally(() => { syncPass = null; });
};
if (timed.length) {
tick();
syncTimer = setInterval(tick, librarySync?.intervalMs ?? libraryModule.SYNC_INTERVAL_MS);
syncTimer.unref();
}
const stopSync = async () => { clearInterval(syncTimer); syncTimer = null; await syncPass; };
// FED R4 (#1801, design 3.7 trigger 2): every 30 s the broker re-reads the access file, so a hand
// edit or an expiry with no request ends the lost runs within one period.
if (access) {
accessTimer = setInterval(() => {
try {
broker.accessSweep();
} catch (e) {
process.stderr.write(`access: ${JSON.stringify({ event: 'access-sweep-failed', code: e.code ?? 'error' })}\n`);
}
}, access.intervalMs ?? ACCESS_SWEEP_MS);
accessTimer.unref();
}
if (modelKeys) {
modelTimer = setInterval(() => {
if (modelSweep) return;
modelSweep = modelKeys.sweep().catch(error => proxyReceipt({ action: 'proxy.sweep-refused', code: error.code ?? 'proxy-key-issue-failed' })).finally(() => { modelSweep = null; });
}, 1000);
modelTimer.unref();
}
// One bounded queue read at a time. The service applies the configured
// 1..59 second poll deadline; this tick only checks whether a read is due.
usageTimer = setInterval(() => { proxyUsage.tick().catch(() => usageLog({ action: 'proxy.usage', code: 'proxy-usage-read-failed' })); }, 1000);
usageTimer.unref();
await proxyUsage.tick();
return {
broker,
credentials,
// P2 consumes this inside the bus only. No process IPC/verb returns it.
get modelProxy() { return modelProxyClient; },
path,
bindLaunch,
recoverLaunch: ({ modelKeyId, ...record }) => broker.recoverLaunch(record),
endLaunch: (r) => { const out = broker.endLaunch(r); modelRuns.delete(r.business + ':' + r.run); return out; },
modelPreflight: async ({ business, role }) => {
const current = settings ? settings.current(business) : businesses[business];
if (!Object.hasOwn(current?.roles ?? {}, role)) throw new BusError('unknown-role');
return modelKeys ? modelKeys.preflight(business + '/' + role) : null;
},
modelStall: async ({ business, role, run, keyId }) => {
const record = modelRuns.get(business + ':' + run);
if (!record || record.role !== role || record.keyId !== keyId) throw new BusError('proxy-stop-failed');
await stopModelRuns({ runs: [record], reason: 'proxy-stall', sessions: () => readSessions(dataRoot),
stop: id => stopSession(dataRoot, id, { timeoutMs: MODEL_STOP_TIMEOUT_MS }), receipt: proxyReceipt });
modelRuns.delete(business + ':' + run);
return { stopped: true };
},
threadsState: (business) => broker.threadsState(business),
threadIdle: (r) => broker.threadIdle(r),
// Row 125 (#1619, REQ-LIMIT-4): the launcher asks the limit checks before every launch.
mayLaunch: async ({ business, instance, provider, model, account = null }) => {
processingWork();
return limits.mayLaunch(business, { instance, provider, model, account });
},
identity: (cap) => broker.identity(cap),
authorizeLaunch,
checkPush,
recordPush: (cap, push) => refusing(cap, () => broker.recordPush(cap, push), push?.task_ref),
reviewFetch,
checkLand,
recordLand: (ticket, land) => broker.recordLand(ticket, land),
landRefused: (ticket, args) => broker.landRefused(ticket, args),
checkPublish,
withGitea,
publishPush,
publishResult,
recordPublish: (ticket, pushed) => broker.recordPublish(ticket, pushed),
publishRefused,
landHeld: (record) => broker.landHeld(record),
// Row 156 (#1651): the launcher's landing pass.
landHolders: (business) => broker.landHolders(business),
landRelease: (r) => broker.landRelease(r),
// Row 194 (#1692, D1.1): the launcher's lifecycle pass.
lifecycleRequests: (business) => broker.lifecycleRequests(business),
lifecycleTake: (r) => broker.lifecycleTake(r),
lifecycleDelete: (r) => broker.lifecycleDelete(r),
lifecycleDone: (r) => broker.lifecycleDone(r),
// Row 271 (264d, #1776): the launcher's clear pass.
sessionClears: (business) => broker.sessionClears(business),
sessionClearExited: (r) => broker.sessionClearExited(r),
sessionClearUncertain: (r) => broker.sessionClearUncertain(r),
sessionClearRetire: (r) => broker.sessionClearRetire(r),
sessionClearStart: (r) => broker.sessionClearStart(r),
refuse: (cap, code, subject) => broker.refuse(cap, code, subject),
credentialStatus,
launches: bound,
readers: readCaps,
async close() {
clearInterval(usageTimer);
await proxyUsage.close();
clearInterval(modelTimer);
await modelSweep;
clearInterval(accessTimer);
await stopSync();
await server.close();
await adapter?.close?.();
await processing?.close();
store.close();
credentials.close();
},
};
} catch (e) {
clearInterval(usageTimer);
await proxyUsage?.close();
clearInterval(modelTimer);
clearInterval(accessTimer);
await server?.close();
await adapter?.close?.();
await processing?.close();
store?.close();
credentials?.close();
throw e;
}
}
@@ -0,0 +1,157 @@
#!/usr/bin/env python3
"""Static bytes/Git/diff only. Never imports product modules or runs tests."""
from pathlib import Path
import hashlib, json, subprocess, re, io, tarfile, gzip, tempfile, shutil
ROOT=Path.cwd()
OUT=ROOT/'agents/codex/work/queue-333/r1-repair/packet'
OUT.mkdir(exist_ok=True)
HEAD='503b91e56137482abef475bc3b1b72a64b0a329c'
assert subprocess.check_output(['git','rev-parse','HEAD'],text=True).strip()==HEAD
assert subprocess.check_output(['git','diff','--cached','--name-only'],text=True).strip()==''
OBJECT_FORMAT=subprocess.check_output(['git','rev-parse','--show-object-format'],text=True).strip()
assert OBJECT_FORMAT=='sha1'
def digest(data): return hashlib.sha256(data).hexdigest()
def blob(data): return hashlib.sha1(b'blob '+str(len(data)).encode()+b'\0'+data).hexdigest()
def head_bytes(p):
result=subprocess.run(['git','show',f'{HEAD}:{p}'],capture_output=True)
return result.stdout if result.returncode==0 else None
def jsonfile(name,value): (OUT/name).write_text(json.dumps(value,indent=2,sort_keys=True)+'\n')
tracked=set(subprocess.check_output(['git','diff','--name-only',HEAD,'--','packages'],text=True).splitlines())
untracked=set(subprocess.check_output(['git','ls-files','--others','--exclude-standard','--','packages'],text=True).splitlines())
changed=sorted(tracked|untracked)
CONTROLS=['packages/bus/tests/p5-identity.test.mjs','packages/bus/tests/p5-key-compatibility.test.mjs','packages/bus/tests/p5-background.test.mjs','packages/bus/tests/p5-telemetry-fixture.mjs']
assert set(CONTROLS)<=untracked
parts={}
for p in changed:
if p in tracked:
part=subprocess.check_output(['git','diff','--binary','--full-index',HEAD,'--',p])
else:
result=subprocess.run(['git','diff','--no-index','--binary','--full-index','--','/dev/null',p],capture_output=True)
assert result.returncode==1,(p,result.stderr)
part=result.stdout
assert part
parts[p]=part
(OUT/'source-tests.patch').write_bytes(b''.join(parts[p] for p in changed))
(OUT/'baseline-controls.patch').write_bytes(b''.join(parts[p] for p in sorted(CONTROLS)))
(OUT/'baseline-to-fixed.patch').write_bytes(b''.join(parts[p] for p in changed if p not in CONTROLS))
jsonfile('changed-source-tests.json',[{'path':p,'bytes':(ROOT/p).stat().st_size,'sha256':digest((ROOT/p).read_bytes()),'git_blob':blob((ROOT/p).read_bytes()),'head_git_blob':blob(head_bytes(p)) if head_bytes(p) is not None else None} for p in changed])
whole=(ROOT/'agents/codex/work/queue-333/r1-repair/whole-files.txt').read_text().splitlines()
assert len(whole)==28 and len(set(whole))==28
(OUT/'whole-files.txt').write_text('\n'.join(whole)+'\n')
# Conservative static closure: old captured inputs + current controls/changed
# files + all shipped selectable plug-ins/role data, literal module and URL edges.
seed={line.split(' ',1)[1] for line in (ROOT/'agents/codex/work/queue-333/source-inputs.sha256').read_text().splitlines()}
seed.update(whole);seed.update(changed)
seed.update(str(p.relative_to(ROOT)) for p in (ROOT/'agents/codex/work/queue-333/r1-repair').glob('*') if p.is_file())
seed.update(str(p.relative_to(ROOT)) for p in (ROOT/'packages/plugins').glob('*/*/index.mjs'))
seed.update(str(p.relative_to(ROOT)) for p in (ROOT/'packages/plugins/src').glob('*.mjs'))
seed.update(str(p.relative_to(ROOT)) for p in (ROOT/'roles').rglob('*') if p.is_file())
for p in ['AGENTS.md','package.json','package-lock.json','RELEASE','docs/plans/2026-10-24_model-proxy-rows.md','docs/plans/2026-10-24_stack-model-proxy.md']:
if (ROOT/p).is_file(): seed.add(p)
patterns=[('module',re.compile(r'''\b(?:import|export)\s+(?:[^;'\"]*?\s+from\s*)?['\"]([^'\"]+)['\"]''')),
('dynamic-literal',re.compile(r'''\bimport\s*\(\s*['\"]([^'\"]+)['\"]''')),
('url-data',re.compile(r'''new\s+URL\s*\(\s*['\"]([^'\"]+)['\"]'''))]
inputs=set();pending=list(seed);edges=[];external=[];selectors=[]
while pending:
p=pending.pop()
if p in inputs: continue
file=ROOT/p
if not file.is_file(): continue
inputs.add(p)
if file.suffix not in {'.mjs','.js','.cjs'}:continue
src=file.read_text()
if re.search(r'\bimport\s*\(\s*(?![\'\"\s])',src) or 'pathToFileURL(' in src:
selectors.append(p)
for kind,pattern in patterns:
for spec in pattern.findall(src):
if not spec.startswith('.'):
if kind!='url-data': external.append({'from':p,'specifier':spec,'kind':kind})
continue
resolved=(file.parent/spec).resolve()
try: rel=str(resolved.relative_to(ROOT))
except ValueError: continue
if resolved.is_file():
edges.append({'from':p,'to':rel,'specifier':spec,'kind':kind});pending.append(rel)
parent=file.parent
while parent==ROOT or ROOT in parent.parents:
package=parent/'package.json'
if package.is_file(): pending.append(str(package.relative_to(ROOT)));break
parent=parent.parent
fixed={p:(ROOT/p).read_bytes() for p in sorted(inputs)}
baseline={}
for p in sorted(inputs):
before=fixed[p] if p in CONTROLS else head_bytes(p)
if before is not None:baseline[p]=before
def manifest(values):
return [{'path':p,'bytes':len(data),'sha256':digest(data),'git_blob':blob(data),'head_git_blob':blob(head_bytes(p)) if head_bytes(p) is not None else None} for p,data in values.items()]
jsonfile('fixed-inputs.json',manifest(fixed));jsonfile('baseline-inputs.json',manifest(baseline))
(OUT/'fixed-inputs.sha256').write_text(''.join(f'{digest(data)} {p}\n' for p,data in fixed.items()))
(OUT/'baseline-inputs.sha256').write_text(''.join(f'{digest(data)} {p}\n' for p,data in baseline.items()))
jsonfile('static-dependencies.json',{'provenance':'STATIC conservative input closure, NOT execution/consumed-source evidence','roots':whole,'literal_edges':sorted(edges,key=lambda e:(e['from'],e['to'],e['kind'])),'external_or_builtin_specifiers':sorted(external,key=lambda e:(e['from'],e['specifier'])),'nonliteral_selectors_require_actual_runner_capture':sorted(set(selectors)),'included_shipped_plugins_and_roles':True})
def archive(name,values):
with open(OUT/name,'wb') as raw:
with gzip.GzipFile(filename='',mode='wb',fileobj=raw,mtime=0) as zipped:
with tarfile.open(fileobj=zipped,mode='w') as tar:
for p,data in values.items():
info=tarfile.TarInfo(p);info.size=len(data);info.mode=0o644;info.mtime=0;info.uid=info.gid=0
tar.addfile(info,io.BytesIO(data))
archive('fixed-input-bytes.tar.gz',fixed);archive('baseline-input-bytes.tar.gz',baseline)
# Verify archived bytes match both manifests; hashes/Git blob IDs are byte pins,
# never claims that unexecuted modules or tests passed.
for name,values in [('fixed-input-bytes.tar.gz',fixed),('baseline-input-bytes.tar.gz',baseline)]:
with tarfile.open(OUT/name,'r:gz') as tar:
assert set(tar.getnames())==set(values)
for p,data in values.items(): assert tar.extractfile(p).read()==data
# Original evidence must remain identical to the original Git candidate.
original=ROOT/'agents/codex/work/queue-333'
old_files=subprocess.check_output(['git','ls-tree','-r','--name-only',HEAD,'--',str(original.relative_to(ROOT))],text=True).splitlines()
for p in old_files:
assert (ROOT/p).read_bytes()==head_bytes(p),f'original evidence changed: {p}'
# Base test prefixes are retained except the two explicitly authorized additive
# registry inventory changes which already existed at503 and remain unchanged.
base='09a847edaa25b609bac7728ff83f224708a29399'
prefixes=[]
for p in changed:
if '/tests/' not in p:continue
before=subprocess.run(['git','show',f'{base}:{p}'],capture_output=True)
if before.returncode==0:
retained=(ROOT/p).read_bytes().startswith(before.stdout)
assert retained,p
prefixes.append(p)
jsonfile('preserved-base-test-prefixes.json',prefixes)
# Static application check in disposable byte trees, never a product run or a
# second Git worktree/branch. Verify both overlay routes reproduce exact bytes.
tmp=Path(tempfile.mkdtemp(prefix='p5-static-overlay-'))
try:
archive_bytes=subprocess.check_output(['git','archive','--format=tar',HEAD,'--',*sorted(tracked)])
direct=tmp/'direct';staged=tmp/'staged';direct.mkdir();staged.mkdir()
for target in [direct,staged]:
with tarfile.open(fileobj=io.BytesIO(archive_bytes),mode='r:') as tar:tar.extractall(target,filter='data')
def apply(target,name):
subprocess.run(['git','apply','--check',str(OUT/name)],cwd=target,check=True,capture_output=True)
subprocess.run(['git','apply',str(OUT/name)],cwd=target,check=True,capture_output=True)
apply(direct,'source-tests.patch')
apply(staged,'baseline-controls.patch')
for path in tracked:assert (staged/path).read_bytes()==head_bytes(path)
apply(staged,'baseline-to-fixed.patch')
for path in changed:
assert (direct/path).read_bytes()==(ROOT/path).read_bytes()
assert (staged/path).read_bytes()==(ROOT/path).read_bytes()
jsonfile('static-overlay-check.json',{'status':'byte-application-verified-no-product-execution','source_patch_equals_controls_then_remainder':True,'changed_package_files':len(changed),'temporary_trees_removed':True})
finally:shutil.rmtree(tmp)
assert not tmp.exists()
review=ROOT/'agents/codex/work/queue-333/r1-repair/REVIEW-R1.md'
assert digest(review.read_bytes())=='7c95672a30c0d5c39189c7c7d610ada89cd539dcb9413617071fbb81200fd008'
evidence={str(p.relative_to(ROOT)):p.read_bytes() for p in sorted((ROOT/'agents/codex/work/queue-333/r1-repair/receipts').iterdir()) if p.is_file()}
evidence.update({str(review.relative_to(ROOT)):review.read_bytes()})
for p in sorted((ROOT/'agents/codex/work/queue-333/r1-repair/baselines').iterdir()):
if p.is_file():evidence[str(p.relative_to(ROOT))]=p.read_bytes()
jsonfile('r1-raw-evidence.json',manifest(evidence))
archive('r1-raw-evidence-bytes.tar.gz',evidence)
index={'status':'UNCOMMITTED_STATIC_PACKET_EXECUTION_PENDING','head':HEAD,'original_base':base,'review_sha256':'7c95672a30c0d5c39189c7c7d610ada89cd539dcb9413617071fbb81200fd008','changed_package_files':len(changed),'whole_test_files':len(whole),'fixed_static_input_files':len(fixed),'baseline_static_input_files':len(baseline),'git_object_format':OBJECT_FORMAT,'files':{p.name:{'bytes':p.stat().st_size,'sha256':digest(p.read_bytes())} for p in sorted(OUT.iterdir()) if p.is_file() and p.name not in {'INDEX.json','packet.sha256'}}}
jsonfile('INDEX.json',index)
(OUT/'packet.sha256').write_text(''.join(f'{digest(p.read_bytes())} {p.name}\n' for p in sorted(OUT.iterdir()) if p.is_file() and p.name!='packet.sha256'))
print(json.dumps({k:index[k] for k in ['status','head','changed_package_files','whole_test_files','fixed_static_input_files','baseline_static_input_files']},sort_keys=True))
print('source-tests.patch SHA256 '+digest((OUT/'source-tests.patch').read_bytes()))
print('INDEX.json SHA256 '+digest((OUT/'INDEX.json').read_bytes()))
@@ -0,0 +1,77 @@
{
"baseline_static_input_files": 301,
"changed_package_files": 18,
"files": {
"baseline-controls.patch": {
"bytes": 19496,
"sha256": "9b64bfe45f20f59ae62812529c5f4ef4a41f29ea9124cf42dd6e9c32f5089711"
},
"baseline-input-bytes.tar.gz": {
"bytes": 793317,
"sha256": "add6f177692f774a0a4370c95d28d3e72a3aa4e76adab886ed6bdcc01a965e2b"
},
"baseline-inputs.json": {
"bytes": 84849,
"sha256": "9f18698d9b327c8664461decf939e7fcbb6a756e81f93e88dc1d2d51511a7ea8"
},
"baseline-inputs.sha256": {
"bytes": 29893,
"sha256": "a287f6218039b825bb84c5902d68f0659cbedc9c89d5c2cff6e63fd0a64dfeed"
},
"baseline-to-fixed.patch": {
"bytes": 21127,
"sha256": "f3808e3a13fc9244f2301a8f6237fd07d5ed62f496765ef6c281f245713b7e68"
},
"changed-source-tests.json": {
"bytes": 5017,
"sha256": "42f770fc3e2384362efd1e416091355c064b6cca22dd40f3b5ef8f7b67e43a52"
},
"fixed-input-bytes.tar.gz": {
"bytes": 811710,
"sha256": "ce03510187334794f10c57b3ce022cbb31fb0324a50e9a225a1c8bb9a06540c4"
},
"fixed-inputs.json": {
"bytes": 87745,
"sha256": "505c022b46d0871d979c1dc9455a5d0a34ba5442fdeb5bc6195509e56a06b3b2"
},
"fixed-inputs.sha256": {
"bytes": 31194,
"sha256": "8f47fbe78ca155f2bc45f5c76e0cc2204af655b5485fc4bb55db5b21f2f7095f"
},
"preserved-base-test-prefixes.json": {
"bytes": 98,
"sha256": "fcbb8633c9cf0bdee9aeb1bfa8026c868c880cdbeea5369fa35928a9e87daacb"
},
"r1-raw-evidence-bytes.tar.gz": {
"bytes": 27138,
"sha256": "e7edd87316c9617caf2d30f7f8fc2ef38a6e918a781173bd40b251a81f878f6d"
},
"r1-raw-evidence.json": {
"bytes": 2825,
"sha256": "e2d81fd97a93d13805fe009428dcab77cafd2e99f6f9330b8ae08bc56af06306"
},
"source-tests.patch": {
"bytes": 40623,
"sha256": "a78bc385801b64be270fb9d6e84672c443738a5fce8eb68f7d2a01359a57a770"
},
"static-dependencies.json": {
"bytes": 168863,
"sha256": "3a1878a64719ad3c733c4e6a7b3fee091fb97be5591e126a6d2cb971262fc8b1"
},
"static-overlay-check.json": {
"bytes": 186,
"sha256": "521a779bb862349c137bd3cce0e319e7565c80657c437cc794bf3f9848689319"
},
"whole-files.txt": {
"bytes": 1217,
"sha256": "c32f33ebc78f09a0549b0b0ba185771bf1cdb3149e9579204147f4b827a66a56"
}
},
"fixed_static_input_files": 312,
"git_object_format": "sha1",
"head": "503b91e56137482abef475bc3b1b72a64b0a329c",
"original_base": "09a847edaa25b609bac7728ff83f224708a29399",
"review_sha256": "7c95672a30c0d5c39189c7c7d610ada89cd539dcb9413617071fbb81200fd008",
"status": "UNCOMMITTED_STATIC_PACKET_EXECUTION_PENDING",
"whole_test_files": 28
}
@@ -0,0 +1,247 @@
diff --git a/packages/bus/tests/p5-background.test.mjs b/packages/bus/tests/p5-background.test.mjs
new file mode 100644
index 0000000000000000000000000000000000000000..bb51ad3527280f0db0449c27eb42474dd8b9e894
--- /dev/null
+++ b/packages/bus/tests/p5-background.test.mjs
@@ -0,0 +1,51 @@
+// Prepared after Mos1971 STOP. These controls have NOT been executed locally.
+// Only fake loopback HTTP, explicit event barriers and virtual existing timers.
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import { mkdirSync, writeFileSync } from 'node:fs';
+import { join } from 'node:path';
+import { startTimeOf } from '../../seat/src/proc.mjs';
+import { telemetryFixture } from './p5-telemetry-fixture.mjs';
+async function nativeTurn(f) {
+ const model=await f.bus.modelPreflight({business:'demo',role:'coder'});
+ const keyId=createHash('sha256').update(model.key).digest('hex').slice(0,12),dir=join(f.root,'native-transcript');mkdirSync(dir);
+ const {cap}=f.bus.bindLaunch({business:'demo',role:'coder',run:'held-poll-native',harness:'pi',modelKeyId:keyId,transcript:dir,
+ pid:process.pid,startTime:startTimeOf(process.pid)});
+ f.bus.broker.request(cap,{verb:'role.claim'});
+ assert.deepEqual(await f.bus.mayLaunch({business:'demo',instance:'coder',provider:'fixture',model:'fake'}),{allow:true});
+ const human=f.human(),{id}=f.bus.broker.request(human,{verb:'message.send',args:{to:'coder',body:'native work while optional queue is held'}});
+ f.bus.broker.request(cap,{verb:'message.receive'});
+ await f.bus.broker.request(cap,{verb:'usage.begin',args:{turn:id}});
+ writeFileSync(join(dir,'native.jsonl'),JSON.stringify({type:'message',id:'native',message:{role:'assistant',usage:{input:2,output:1,cacheRead:0,cacheWrite:0}}})+'\n');
+ await f.bus.broker.request(cap,{verb:'usage.end',args:{turn:id}});
+ const view=f.bus.broker.request(human,{verb:'usage'});
+ assert.equal(view.total.input,2);assert.equal(view.byKey[0].modelKeyId,keyId);
+ assert.deepEqual(f.bus.broker.request(cap,{verb:'message.receive'}),[]);
+}
+for(const fail of [false,true])test(`P5 R1 held first optional poll does not delay native startup or work; ${fail?'failure':'release'} settles safely`,async t=>{
+ t.mock.timers.enable({apis:['Date','setInterval'],now:Date.now()});
+ const f=await telemetryFixture(t,{hold:true});const started=f.start();
+ await f.waitQueue(1);await new Promise(setImmediate);
+ // Causal first guard: the queue is still held, so a ready runtime cannot
+ // have depended on its response. No racing timeout or longer budget.
+ assert.notEqual(f.bus,null,'startBroker must resolve while the first queue response is held');
+ await started;assert.equal(f.state.held.length,1);
+ assert.equal(f.bus.broker.request(f.human(),{verb:'plugins'}).plugins.usage,'cliproxy-queue');
+ await nativeTurn(f);assert.equal(f.queueCalls(),1);
+ t.mock.timers.tick(1000);await new Promise(setImmediate);assert.equal(f.queueCalls(),1,'scheduled ticks share the held first read');
+ const from=f.logs.length;f.release(fail);
+ await f.waitLog(fail?'proxy-usage-read-failed':'proxy.usage.reconcile',from);
+ assert.equal(f.bus.broker.request(f.human(),{verb:'usage'}).proxy.state,fail?'unavailable':'available');
+ await f.close();assert.equal(f.queueCalls(),1);
+});
+test('P5 R1 close bounds an outstanding first poll by the unchanged five-second client deadline',async t=>{
+ t.mock.timers.enable({apis:['Date','setInterval','setTimeout'],now:Date.now()});
+ const f=await telemetryFixture(t,{hold:true});const started=f.start();await f.waitQueue(1);await new Promise(setImmediate);
+ assert.notEqual(f.bus,null,'native readiness precedes the held optional poll');await started;
+ let closed=false;const closing=f.close().then(()=>{closed=true;});
+ t.mock.timers.tick(4999);await new Promise(setImmediate);assert.equal(closed,false);
+ t.mock.timers.tick(1);await closing;
+ assert.equal(closed,true);assert.equal(f.queueCalls(),1);
+ assert.ok(f.logs.some(line=>line.includes('proxy-usage-read-failed')));
+});
diff --git a/packages/bus/tests/p5-identity.test.mjs b/packages/bus/tests/p5-identity.test.mjs
new file mode 100644
index 0000000000000000000000000000000000000000..4ee111f7c9ec75dbae24c184c3310b71973fc7c2
--- /dev/null
+++ b/packages/bus/tests/p5-identity.test.mjs
@@ -0,0 +1,38 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import { telemetryFixture } from './p5-telemetry-fixture.mjs';
+for(const foreign of [true,false])test(`P5 R1 boot identity ${foreign?'refusal prevents queue consumption':'matching sentinel permits telemetry without an agent key'}`,async t=>{
+ t.mock.timers.enable({apis:['Date','setInterval'],now:Date.now()});
+ const f=await telemetryFixture(t,{foreign});await f.start();await f.settleInitial();
+ const human=f.human();assert.equal(f.bus.broker.request(human,{verb:'plugins'}).plugins.usage,'cliproxy-queue');
+ if(foreign){
+ await assert.rejects(f.bus.modelPreflight({business:'demo',role:'coder'}),{code:'proxy-open'});
+ assert.equal(f.queueCalls(),0);assert.equal(f.state.queued.length,1);
+ await f.pollSettledAfterTick(t);assert.equal(f.queueCalls(),0);assert.equal(f.state.queued.length,1);
+ assert.equal(f.bus.broker.request(human,{verb:'usage'}).proxy.state,'unavailable');
+ }else{
+ assert.equal(f.queueCalls(),1);assert.equal(f.state.queued.length,0);
+ assert.equal(f.bus.broker.request(human,{verb:'usage'}).proxy.state,'available');
+ assert.equal(f.bus.credentials.status().some(r=>r.service==='model'&&r.keyId),false);
+ }
+});
+test('P5 R1 later sentinel refusal fences every subsequent queue poll while preserving human control',async t=>{
+ t.mock.timers.enable({apis:['Date','setInterval'],now:Date.now()});
+ const f=await telemetryFixture(t);await f.start();await f.settleInitial();assert.equal(f.queueCalls(),1);
+ f.state.keys=[f.other];
+ await assert.rejects(f.bus.modelPreflight({business:'demo',role:'coder'}),{code:'proxy-open'});
+ await f.pollSettledAfterTick(t);assert.equal(f.queueCalls(),1);
+ await f.pollSettledAfterTick(t);assert.equal(f.queueCalls(),1);
+ const human=f.human();assert.equal(f.bus.broker.request(human,{verb:'plugins'}).plugins.usage,'cliproxy-queue');
+ assert.equal(f.bus.broker.request(human,{verb:'usage'}).proxy.state,'unavailable');
+});
+
+test('P5 R1 every drain verifies fresh sentinel before consuming a changed listener',async t=>{
+ t.mock.timers.enable({apis:['Date','setInterval'],now:Date.now()});
+ const f=await telemetryFixture(t);await f.start();await f.settleInitial();assert.equal(f.queueCalls(),1);
+ f.state.keys=[f.other];await f.pollSettledAfterTick(t);assert.equal(f.queueCalls(),1);
+ await assert.rejects(f.bus.modelPreflight({business:'demo',role:'coder'}),{code:'proxy-open'});
+ const lists=f.state.calls.filter(p=>p==='/v8/management/config/access/api-keys').length;
+ f.state.keys=[f.own];await f.pollSettledAfterTick(t);assert.equal(f.queueCalls(),1);
+ assert.equal(f.state.calls.filter(p=>p==='/v8/management/config/access/api-keys').length,lists,'no retry around sticky identity refusal');
+});
diff --git a/packages/bus/tests/p5-key-compatibility.test.mjs b/packages/bus/tests/p5-key-compatibility.test.mjs
new file mode 100644
index 0000000000000000000000000000000000000000..331032ecb48644587057a9ec4799e69d5fa3cdc8
--- /dev/null
+++ b/packages/bus/tests/p5-key-compatibility.test.mjs
@@ -0,0 +1,68 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import { mkdtempSync, rmSync, readFileSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { Store } from '../src/store.mjs';
+import { createLimits, modelUsageKey } from '../src/limits.mjs';
+import * as token from '../../plugins/limit-check/token-limit/index.mjs';
+import * as daily from '../../plugins/limit-check/daily-quota/index.mjs';
+import { launchSettings } from '../../business/src/launch-settings.mjs';
+import { businessDoc, rolesCopy, writeJson, systemFor } from '../../business/tests/helpers.mjs';
+const key='abcdefabcdef',other='012345abcdef',since='2026-01-01T00:00:00.000Z';
+const quota={limit:10,since,reset:'00:00',timeZone:'UTC'};
+const native={at:'2026-10-26T12:00:00.000Z',run:'legacy-run',turn:'turn',account:key,modelKeyId:other,status:'known',input:10,output:0,cacheWrite:0,cacheRead:0};
+test('P5 R1 plain twelve-hex account leaves retain matching and original account report even with another model ID',()=>{
+ const a={limits:{tokens:{keys:{[key]:{limit:10,since}}}},subject:{account:key,modelKeyId:other},records:[native]};
+ assert.equal(token.mayLaunch(a).allow,false);assert.equal(token.mustStop(a).stop,true);
+ assert.equal(token.report(a)[0].count,10);assert.deepEqual(token.report(a)[0].path,['tokens','keys',key]);
+ assert.equal(token.mayLaunch({...a,records:[{...native,input:9}]}).allow,true);
+ assert.deepEqual(daily.report({...a,now:native.at}),[]);
+});
+for(const proxy of [false,true])test(`P5 R1 legacy account core lookup stays independent of ${proxy?'unrelated proxy metadata':'missing proxy metadata'}`,async t=>{
+ const root=mkdtempSync(join(tmpdir(),'p5-legacy-')),store=new Store(root);t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
+ let lookups=0;
+ const b={launch:{account:{name:key,credential:'FAKE_TOKEN_NAME'},limits:{tokens:{keys:{[key]:{limit:10,since}}}}},plugins:{'limit-check':['token-limit']}};
+ const limits=createLimits({store,read:()=>b,log:()=>{},keyForSubject:(...args)=>{lookups++;return proxy?modelUsageKey([{service:'model',instance:'demo/coder',keyId:other,retiring:[]}],new Map(),'demo',args[1]):null;}});
+ assert.deepEqual(await limits.mayLaunch('demo',{instance:'coder',account:key}),{allow:true});
+ store.run(`INSERT INTO usage_records(at,business,run,instance,account,turn,source,phase,status,cursor,input,output,cache_write,cache_read)
+ VALUES (?,'demo','legacy-run','coder',?,'turn','transcript','end','known',?,10,0,0,0)`,native.at,key,JSON.stringify({modelKeyId:other}));
+ const hit={path:['tokens','keys',key],limit:10,count:10,unknownTurns:0};
+ assert.deepEqual(await limits.mayLaunch('demo',{instance:'coder',account:key}),{allow:false,check:'token-limit',hit});
+ assert.deepEqual(await limits.mustStop('demo',{instance:'coder',account:key}),{stop:true,check:'token-limit',hit});
+ assert.equal(limits.report('demo')[0].count,10);assert.equal(lookups,0);
+});
+for(const leaf of [{limit:0,since},quota])test(`P5 R1 empty checks bypass model metadata for ${leaf.reset?'daily model':'legacy hex account'} leaves`,async t=>{
+ const root=mkdtempSync(join(tmpdir(),'p5-no-checks-')),store=new Store(root);t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
+ let lookups=0;const limits=createLimits({store,read:()=>({plugins:{'limit-check':[]},launch:{limits:{tokens:{keys:{[key]:leaf}}}}}),log:()=>{},keyForSubject:()=>{lookups++;throw Error('MUST-NOT-LOOK-UP');}});
+ assert.deepEqual(await limits.mayLaunch('demo',{instance:'coder',account:key}),{allow:true});
+ assert.deepEqual(await limits.mustStop('demo',{instance:'coder',account:key}),{stop:false});assert.equal(lookups,0);
+});
+test('P5 R1 legacy hex account chief resets stay allowed; daily model old/new/removal/reset transitions stay human-only',t=>{
+ const root=mkdtempSync(join(tmpdir(),'p5-fence-'));t.after(()=>rmSync(root,{recursive:true,force:true}));
+ const rolesDir=rolesCopy(root),doc=businessDoc(root,'demo'),file=join(root,'businesses/demo.json');
+ doc.launch.account={name:key,credential:'FAKE_TOKEN_NAME'};doc.launch.limits={tokens:{keys:{[key]:{limit:10,since}}}};writeJson(file,doc);
+ let now='2026-10-26T12:00:00.000Z';const settings=launchSettings({dir:root,rolesDir,system:systemFor(root),now:()=>now});let v=settings.read('demo');
+ v=settings.set('demo',{revision:v.revision,reset:[['tokens','keys',key]]},'chief');
+ assert.equal(JSON.parse(readFileSync(file,'utf8')).launch.limits.tokens.keys[key].since,now);
+ const dailyLeaf={limit:10,reset:'00:00',timeZone:'UTC'};
+ assert.throws(()=>settings.set('demo',{revision:v.revision,limits:{tokens:{keys:{[key]:dailyLeaf}}}},'chief'),{code:'organization-model-quota-human-only'});
+ v=settings.set('demo',{revision:v.revision,limits:{tokens:{keys:{[key]:dailyLeaf}}}},'jason');now='2026-10-26T13:00:00.000Z';
+ for(const args of [{reset:[['tokens','keys',key]]},{limits:{}},{limits:{tokens:{keys:{[key]:{limit:10}}}}}])
+ assert.throws(()=>settings.set('demo',{revision:v.revision,...args},'chief'),{code:'organization-model-quota-human-only'});
+ v=settings.set('demo',{revision:v.revision,limits:{tokens:{keys:{[key]:{limit:10}}}}},'jason');
+ v=settings.set('demo',{revision:v.revision,reset:[['tokens','keys',key]]},'chief');
+ assert.equal(JSON.parse(readFileSync(file,'utf8')).launch.limits.tokens.keys[key].since,now);
+});
+
+test('P5 R1 daily model matching/report is separate from legacy account and schema refuses partial or invalid daily shapes',async()=>{
+ const {checkTokenLimits}=await import('../../business/src/launch.mjs');
+ assert.deepEqual(checkTokenLimits({keys:{[key]:quota}}).keys[key],quota);
+ const args={limits:{tokens:{keys:{[key]:quota}}},records:[native],subject:{account:key,modelKeyId:other},now:native.at};
+ assert.deepEqual(token.report(args),[]);
+ assert.equal(daily.mayLaunch(args).allow,true);assert.equal(daily.report(args)[0].count,0);
+ const owned={...args,subject:{account:'other-account',modelKeyId:key},records:[{...native,account:'other-account',modelKeyId:key}]};
+ assert.equal(daily.mayLaunch(owned).allow,false);assert.equal(daily.mustStop(owned).stop,true);assert.equal(daily.report(owned)[0].count,10);
+ for(const leaf of [{...quota,reset:'25:00'},{...quota,timeZone:'Mars/Phobos'},{limit:10,since,reset:'00:00'},{limit:10,since,timeZone:'UTC'}])
+ assert.throws(()=>checkTokenLimits({keys:{[key]:leaf}}));
+});
diff --git a/packages/bus/tests/p5-telemetry-fixture.mjs b/packages/bus/tests/p5-telemetry-fixture.mjs
new file mode 100644
index 0000000000000000000000000000000000000000..99390f7d565a7d7db5344b574bc5a8623d5fa073
--- /dev/null
+++ b/packages/bus/tests/p5-telemetry-fixture.mjs
@@ -0,0 +1,66 @@
+// Fresh, made-up instance and local management listener only; no worker/provider.
+import http from 'node:http';
+import { createHash, randomBytes } from 'node:crypto';
+import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { startBroker } from '../src/runtime.mjs';
+import { Registry } from '../../seat/src/session.mjs';
+import { businessDoc, rolesCopy, systemFor, writeJson } from '../../business/tests/helpers.mjs';
+export async function telemetryFixture(t, { foreign = false, hold = false } = {}) {
+ const root = mkdtempSync(join(tmpdir(), 'p5-telemetry-')), config = join(root,'config'), data = join(root,'data');
+ mkdirSync(config,{mode:0o700}); mkdirSync(data,{mode:0o700});
+ const rolesDir = rolesCopy(config), doc = businessDoc(config,'demo');
+ doc.plugins = { usage:'cliproxy-queue', harness:['pi'], 'usage-source':['transcript'], 'limit-check':['token-limit'] };
+ doc.usage = { cliproxyQueue:{pollSeconds:1} };
+ writeJson(join(config,'businesses/demo.json'),doc);
+ mkdirSync(join(config,'secrets'),{recursive:true,mode:0o700});
+ writeFileSync(join(config,'secrets/proxy-management.key'),'p5-r1-made-up-management',{mode:0o600});
+ new Registry(data);
+ const tag = createHash('sha256').update(config).digest('hex').slice(0,12);
+ const own = `msk-${tag}-sentinel-${randomBytes(32).toString('base64url')}`;
+ const other = `msk-ffffffffffff-sentinel-${randomBytes(32).toString('base64url')}`;
+ const state = { keys:[foreign?other:own], calls:[], queued:[{api_key:'msk-r1-unknown-fake',source:'p5-r1-upstream-canary',failed:false,tokens:{input_tokens:1,output_tokens:2}}], held:[], hold };
+ const logs=[], waiters=[];
+ const stderr = process.stderr.write;
+ t.mock.method(process.stderr,'write',function(chunk,...args) {
+ const text=String(chunk);logs.push(text);
+ for(const waiter of [...waiters]) if(text.includes(waiter.fragment) && logs.length>waiter.from) { waiters.splice(waiters.indexOf(waiter),1);waiter.resolve(); }
+ return stderr.call(this,chunk,...args);
+ });
+ const waitLog=(fragment,from=0)=> {
+ if(logs.slice(from).some(line=>line.includes(fragment)))return Promise.resolve();
+ return new Promise(resolve=>waiters.push({fragment,from,resolve}));
+ };
+ let queueWaiters=[];
+ const waitQueue=(count)=> state.calls.filter(p=>p.includes('/usage/queue')).length>=count?Promise.resolve():new Promise(resolve=>queueWaiters.push({count,resolve}));
+ const answerQueue=res=>{res.end(JSON.stringify(state.queued));state.queued=[];};
+ const server=http.createServer(async(req,res)=>{
+ state.calls.push(req.url);
+ if(req.headers.authorization!=='Bearer p5-r1-made-up-management' && req.url.startsWith('/v8/management/')) {res.writeHead(401);res.end('{}');return;}
+ if(req.url==='/v8/management/config/access/api-keys') {
+ if(req.method==='PUT'){let body='';for await(const c of req)body+=c;state.keys=JSON.parse(body);res.end('{"status":"ok"}');}
+ else res.end(JSON.stringify(state.keys));return;
+ }
+ if(req.url==='/v8/management/observability/usage/queue?count=100') {
+ if(state.hold)state.held.push(res);else answerQueue(res);
+ const count=state.calls.filter(p=>p.includes('/usage/queue')).length;
+ for(const waiter of queueWaiters.filter(w=>count>=w.count))waiter.resolve();
+ queueWaiters=queueWaiters.filter(w=>count<w.count);return;
+ }
+ res.writeHead(state.keys.includes(req.headers.authorization?.slice(7))?200:401);res.end('{}');
+ });
+ await new Promise(resolve=>server.listen(0,'127.0.0.1',resolve));
+ let bus=null,startPromise=null,closePromise=null;
+ const start=()=>startPromise??=(startBroker({dataRoot:data,businesses:{demo:{id:'demo',human:'jason',plugins:doc.plugins,arbiters:{technical:'coder',delivery:'coder'},roles:{coder:{definition:'coder',authority:{withinRole:[],crossRole:[]}}}}},
+ organization:{dir:config,rolesDir,system:systemFor(config)},proxy:{port:server.address().port,binary:'/fixture-unused'}}).then(value=>(bus=value)));
+ const release=(fail=false)=>{state.hold=false;for(const res of state.held.splice(0)){if(res.destroyed)continue;if(fail){res.writeHead(503);res.end('{}');}else answerQueue(res);}};
+ const close=()=>bus?(closePromise??=bus.close()):Promise.resolve();
+ t.after(async()=>{release();await startPromise?.catch(()=>{});await close();server.closeAllConnections();await new Promise(r=>server.close(r));rmSync(root,{recursive:true,force:true});});
+ return {root,data,config,state,logs,own,other,start,waitLog,waitQueue,release,close,
+ settleInitial:()=>Promise.race([waitLog('proxy-usage-read-failed'),waitLog('proxy.usage.reconcile')]),
+ get bus(){return bus;},queueCalls:()=>state.calls.filter(p=>p.includes('/usage/queue')).length,
+ human:()=>bus.broker.bindHuman({business:'demo',human:'jason',via:'cli',outsideAgent:true}),
+ async pollSettledAfterTick(t){const from=logs.length,next=state.calls.filter(p=>p.includes('/usage/queue')).length+1;t.mock.timers.tick(1000);await Promise.race([waitQueue(next),waitLog('proxy-usage-read-failed',from)]);await new Promise(setImmediate);},
+ };
+}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,301 @@
8be7f2b7c210ff8ddf24d86c2e088da5827f5d7160326291f4750e4bb608e112 AGENTS.md
c4eb0d3a8ba06097c784ee6e9acf3bb24b4d01e93d7c5a596ace87b23ea30150 RELEASE
06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1 agents/codex/work/queue-333/trace-inputs.mjs
95e2c9568498cbe628d62f1ef981dfb6819fc9acad0337086b67adc8717208fd docs/plans/2026-10-24_model-proxy-rows.md
3038d65cd3e42c858445d92ac25675f7c5ae66babef1ef79799bd17ae59f0b17 docs/plans/2026-10-24_stack-model-proxy.md
84e80f3bdcad8bd433951b503ad087705ee74341b374901b1eb8b3cbd6c04333 package-lock.json
3baab27d3fe178da625a3bf48c87790d7fa7006098dd568131d5ee9944ac11cb package.json
4f8057266af34f6c70ade88fc9bde45e2aff5a58ab3ee3b8a568a532385fc1cf packages/bus/package.json
a2ba3a46f12e56139ecae9e55227d00847842aedec50c1d92aaae28844ca48e7 packages/bus/schema.sql
232a1c77c2f17011c53b55fc6052f70985598210769d41d7c2c0b535328aad23 packages/bus/src/address.mjs
c0144adade79c2cfc6b8247721393f0250b1d64f6c6c04d85738cb80939c42e5 packages/bus/src/broker.mjs
ff927da3cf22fbacc9ace77b2e8b803bffc2953fb58cf7ab4e5f6f6493732996 packages/bus/src/business.mjs
f3d483f61a24cbc9cce235e1e92889f09b8cecf513fcaf90c741f316f62262e2 packages/bus/src/client.mjs
8b8609ae224bd7ed8e01be5a12c24c05291c7536723d7de9b8c9d1a46d630f22 packages/bus/src/console-cli.mjs
86b4321dd436b97e389101873197dbab95b3d2202e5ef7da712c4978f4f9159f packages/bus/src/credential-verbs.mjs
10485afcf94c29ac9f3d5ba30b12248a2379efd69185ff9fb90e9fed25fe0678 packages/bus/src/credentials.mjs
27d7d5322c2f12641e350867d3ac6f838b33832951e69f057e3a7a28b8ac4d5b packages/bus/src/gitea-grant.mjs
48337cdbc41d503f17962d3e3ad014183b1286165f97da6fd88b4faa50be3949 packages/bus/src/host-grant.mjs
324c05b16253e0fcfc1a0299d1d8ab45850ea723fad1f67bcc07fc031f50d593 packages/bus/src/host-run.mjs
271b9781d73cf31cc562a56180e3ebcd725b5fde148a83347a201fdef2fc28af packages/bus/src/human-cli.mjs
bb13c146717cdc46d75d157177e400edac4d3e10f14fe511027a25fd44cec885 packages/bus/src/human.mjs
56bfc8dcba476886d7de61a1e798aae8e3041c2434c62d44fc40a168d22bb3bd packages/bus/src/interpreter.mjs
9919febc7679168e0a72c0ef51983120283e595fea290a5e8e948409bf5c911b packages/bus/src/landing.mjs
18c1aacd280ebf0f200d5e6fc1dd1a7e098a3046c1cb8427140bb2198ac81cd3 packages/bus/src/limits.mjs
b753f630301bf125e9e286b4156d0736930dd8fb9cd8eb2ebf316688f9191a07 packages/bus/src/migrations/3b-3c.sql
179ffe356d4ff19a49b5ebad39b6c6bfd7771deb8e1b7c55b5e746f039d69e65 packages/bus/src/migrations/3b.sql
0423832d05aa68f9191d7362827bd19310001165b895fb2de40b962fe68f9d56 packages/bus/src/migrations/3c-3d.sql
d9aacc974d5047790e65c30a90068259bb9396dc92d4904eae3b9c5dbbb2f077 packages/bus/src/migrations/3d-3e.sql
bf0b72c606b1a56a1610f09619b0c1118f1f300c636824ea13fd51a4ca6ac4b3 packages/bus/src/migrations/3e-3f.sql
82f54b264919e34282bc214e34e9849f701cd3723b9b2f0a0d107c16f939dc05 packages/bus/src/migrations/3f-3g.sql
76168e4f9f6b427286ddb8402fd833acadb01d6325a85f60e9ccf8d42fe2d1d0 packages/bus/src/migrations/3g-3h.sql
e058e6cea8da7b6e649f3e03f2b81dc5444ee940a64274d0e367124c93545035 packages/bus/src/migrations/3h-3i.sql
5ad122ca950e43e066f3d9ed215e73353e6b26de6687b961a8818d69c9465031 packages/bus/src/migrations/3i-3j.sql
2e2bb1fe70076f5e24406a18a923b9e55c4192178a0a704a1b9716032676f9d4 packages/bus/src/migrations/3j-3k.sql
eb2822c73e527697399691ae520092277ddbd4d2a9a42a0731b3c81cc3569e58 packages/bus/src/migrations/3k-3l.sql
791879f06a3e97d3cfbe6112e2fb6502457af30b3e0198e3da1192038906d156 packages/bus/src/migrations/3l-3m.sql
b40bc6a7bedc459d6827cbf0414619e48fc5dce2febdeff70a647345f2281c3a packages/bus/src/migrations/3m-3n.sql
b4e11975bd56db4c816ada297902f033b3db7754d4a05319f03d640e17374550 packages/bus/src/model-keys.mjs
29c88655e8b9aed8db604573c9213fd9f3c40ef35ff04f4eda8fbe8f1b8a32d7 packages/bus/src/peercred.mjs
d1536a8f472fa5b3773adb10555529ed049ad63b647c0b44c00ce5f25ce09f85 packages/bus/src/peercred.py
2b1e18be825e8264b16506d6294863acbba812956cfdf8e056f21faaa94f7137 packages/bus/src/principal.mjs
ed13afdce6359df31d35a79496ebb4afdefef82030a8326a76b2a25b37e98d9d packages/bus/src/process.mjs
cec059ea4bef5ef62f6181123bfe64bca21d8985d5357471da8c0a3199a877f9 packages/bus/src/proxy-page-vocabulary.mjs
af36aae674f46a4e5eacfe176fde8b58cd0b171a6d70e07ee6d479e0f558cce7 packages/bus/src/proxy-page.mjs
5a6c3707e6a64304cfd37f1875eb378c6eb58bf438cc40365fe913eaec7cee59 packages/bus/src/proxy-usage.mjs
969d04eb06b97093c7f9f0dfa6b51084c781e967e2668814083bbba84a2af7b6 packages/bus/src/runtime.mjs
8318bed9168ac3f58c09de40a139b68aacefd684e6c117406e181e2ca5ab4ec7 packages/bus/src/server.mjs
dd7fce9706402efd1c5a5b81f7d0fa3793de203e7a6aef4e118e934aebdc7c84 packages/bus/src/store.mjs
c04c434ec76252fbc93fb047e7a0c996225590e805f2c82a8d521c161cc9b80b packages/bus/src/tester-cli.mjs
5e9e08ca8069e1de35232f26d48a77792388128dda659893909f2d34b5af2346 packages/bus/src/tester.mjs
4ae57d053c4b217e1c1a22ada3ed1c5d4a3f0e61b8d2798e9db37997cd071a29 packages/bus/src/usage.mjs
38228759eb2030232811669ef44a3c89874c80baf1f6af1da933decc1621e21a packages/bus/src/user-cli.mjs
1f31aefa71984fba90c5390df5cc595d929681965f57485ad4972143d5c4b15f packages/bus/src/views.mjs
68efa3c9d0a72095f503208ed5c2e660ef9bca68d3ea15f0fc2f1826a68e09cc packages/bus/src/web.mjs
dbbfa80b4082fd44e2f08539b5455653fac062321b8f2106f638e2d8161fa3eb packages/bus/tests/daily-quota-runtime.test.mjs
45870a4903d1996915c0086a6beb4d0a4c75b38386b7c5e6d98b5bc811c3b541 packages/bus/tests/limit-checks.test.mjs
561d0950b788d08ad9a79ccd6572ad6976ba4b2e2b1c79d1e4d06827a84c131b packages/bus/tests/limit-stop.test.mjs
a2e553025edbe6e930c9d03b48289c53b51b153ac9ae49bb21bf721b725f1913 packages/bus/tests/limits-runtime.test.mjs
a8038fbad6fc666d5d033da4b35dffbf5f679eae6d1d6e042bea8d211c298360 packages/bus/tests/model-keys.test.mjs
8a7889bb9aacde4faced9ab97faf6603eb7c5f7e1b78df9e5b28279c3b5ebab1 packages/bus/tests/p5-background.test.mjs
1d57b286993b4fe7098433703462c1e5bea715c5e4e88c52f6676cc1757fd153 packages/bus/tests/p5-identity.test.mjs
0c55ced6c8f30dbdc6572705f831a5c1a3375116cc169ca3005d36eeda35e737 packages/bus/tests/p5-key-compatibility.test.mjs
e37114eab9c5f21015ea8e429f0574d3ea34b06263f1e42b83b31b8d2df222a7 packages/bus/tests/p5-key-context.test.mjs
241e779016ffd0b54c5646cb4fac7e21ea1167e77afbd652ff4e01f8d238f99c packages/bus/tests/p5-runtime.test.mjs
0ba3a1937cd58a907581426a5dfdcd3f6d0ebcec63ef0eeeaa333c625fbdcfab packages/bus/tests/p5-telemetry-fixture.mjs
895ffddbcca1b38fdaa17eefdeca9092a9b9a934d3a54a3bf7857f42fe99fba7 packages/bus/tests/plugins-verb.test.mjs
84c8351029272b6ee05e7fd81b4cc4453553ceeb7a5127a1333dae63d1336ad5 packages/bus/tests/proxy-usage.test.mjs
4b2149ea4219f49db19669ada9f88931f7691cdd73dd27dceec6e8fe1f76dd0c packages/bus/tests/usage-broker.test.mjs
5abe93fca8442f06ff68760623e91262d863e1191fa35a3d0c87d7b0e6c0a4c6 packages/bus/tests/usage-runtime.test.mjs
2613ba0561572a7d4f753066922fddc90cca812cb0ce2b3e0a9a4d249a15e340 packages/bus/tests/usage.test.mjs
0e15a5be600573ff7fa0b41c425ee6e57dad788be3d42991185c3a84d6090fe9 packages/business/package.json
af028c999a6ab4d42b321c3f047e683b226c7ad232a2ae9cfc623b7dd5a4dd5f packages/business/src/access.mjs
aaa4578fd4133f64119de6c8786a14759240a8910677529fdeae57173058b7d9 packages/business/src/business.mjs
c3422b1e144177f9dd3015ac036ee1d2cde02bd2b3be406364f3b3f45d8c9b73 packages/business/src/credentials.mjs
cd4eb5960c17ce32f26d1a49196866ce04efc42c1d90b18b046af5fda8b9ff0a packages/business/src/errors.mjs
e08b11b70b54f13e3b18996dd903f841e04fd6c64791e96063df8b164c663882 packages/business/src/hosts.mjs
a386ce5bd1d41d86f7b90641a423a2b651b491c8989d5085412c7d202ac1cb30 packages/business/src/index.mjs
09f2bde85a6d7a8f0b1d1c60ac589b845b0c95e991b2f807758878416b13c6bd packages/business/src/instance-settings.mjs
e14d73f719664499d809909962a6ecc16d4ffb9d824fcdee699e0778809d9e96 packages/business/src/launch-settings.mjs
0aa94dbd14acd379a4837cc3e70b9618b3fa797d74124314e7245a8a3070e98c packages/business/src/launch.mjs
93a7fddac9a08b5f740a0a277b29b8a3459e6f5a4fd33a37212437cb456b9b62 packages/business/src/library-seats.mjs
44fa089c9024934a2f9fb5ef99552eb18d616842210cbc0fc860ea32ce0b1524 packages/business/src/migrate-launch.mjs
fa4ba1ae878cd27287865fa12115f8a6c1175a2dfd1011d5f8aca11e46e669c7 packages/business/src/organization.mjs
9d2c68dd21c6c9553af75f4b137c4f169e95761f32528767e0518d0313311f50 packages/business/src/plugin-settings.mjs
9472996134c520c31971e66006d1c1683709f6df4f76fe3445bdc97a18637eff packages/business/src/project.mjs
712183465fee099606223d84423afc54e3386a0c8e468c68d5ac39c1e676d109 packages/business/src/resolve.mjs
b10af84d7422da4d0e8c0a4fea1064eebbc2fac6a838a1b3939b554e22dedfc9 packages/business/src/role.mjs
e1f0e70a4bbba8ae2ad6185ab61770b15acda403e90fc708e13027a1e9ec663c packages/business/src/util.mjs
f6b15ee8dad2d985c0ae66b1f106ca46cb56ec86ac8cd5dec8a05c887596a421 packages/business/src/vars.mjs
de1f04628e400084a46e77fd7e03c7a039f0f80c9e07bb486c9c012f187aa3eb packages/business/src/vocabulary.mjs
a6a9971b42ddf176d9415caee3efc2eb16791dead5f0f0557d28449a550aefa1 packages/business/tests/helpers.mjs
f0dfe004905dce31317d85d89a05802db878c3472e765e85dc9f1e04166e1df6 packages/business/tests/plugin-settings.test.mjs
bc6b3a31e8918d70aced7151b91ac4b39afec4081054024b162acb0e8f8fae07 packages/business/tests/token-limit-settings.test.mjs
6c9c952d8637206697bc3273f2ee247185cad624b3db84fe4d2ead0b5c1013b3 packages/cli/package.json
c4949a16173d11f9d32d10d3ddd58a181631848b259bef1998820a78f5694808 packages/cli/src/access.mjs
15a8ee212fc37cea28e389f60ddb8916f9e1509cdcfb2e522acfe548702a16dc packages/cli/src/app.mjs
147a17bbdcbc34efe20a88a4cabe796c101cb63dce621d28103f4de29def4cc2 packages/cli/src/boot-status.mjs
1e663b175e18e39ff68c9ac3a65ff71fc777a6c37ebca035fce6a2783d0aaac3 packages/cli/src/cli.mjs
d960c2a9df3f7c84deff22dad1f0ab120f95ee365984e390de98eba7292b65a1 packages/cli/src/config.mjs
19755f7bb002d8455990c5dc7c458e64aeb95252ec7231a2ed2fd9c638fcb511 packages/cli/src/credentials.mjs
c7bdd98a3ddeeb9bc4415d907b92555d723c566eba314075d91486da9b5e85dc packages/cli/src/errors.mjs
481d9956698df7765ca8556d57164fb78f131708a09900d5a55b9048b5638f5f packages/cli/src/format.mjs
3076a53b9891d4d0e084306567b88ded12c4de53a943c029646a424bf59d8e49 packages/cli/src/git-socket.mjs
b586907ca8f351f60dc19ec2683df75d2d70ddb12955d09fb14560c9d3bed3dc packages/cli/src/grants.mjs
a0936aee783ff47dd58fc907fefd86f63e571809a3ce5b0d6d931f71e756b15e packages/cli/src/host.mjs
60419503898f5e7f3046df5e749098728fbdfea76eb5c53b5dc9b909329abe2e packages/cli/src/hosts.mjs
8d6dab8da62b4458477572ca1956adad57bc0b0d308df6eae57477175c345d7a packages/cli/src/instances.mjs
373d4c028dfa6d85c748d56f56359789fe2b81987f522ac23747fd37bb5478ed packages/cli/src/launcher.mjs
2f291a71f490f2741edada7a3e3788500f8976a08eb8ab1411f6c5982f778260 packages/cli/src/limits.mjs
9a043f122e1d49103bab64716d0eb80cfc09da3c91f7e2eb014b0d8ff0b02f3d packages/cli/src/model-proxy.mjs
0bdc91dcaa096bd3dc9d08a1dea59893a21f6505c843e698ad9c8daa4b74364b packages/cli/src/model-stall.mjs
b325b4f5133d40f8b1288e666ef36c5890f7f3a3de20f1dfc1ca27ec172a6372 packages/cli/src/notifier-process.mjs
400f4af8c72915101e00f25c0817534a34e7fcf29f960f5cdd78ed9884707f3f packages/cli/src/notifier.mjs
f8d9fc24ccd71494fb2914914949cb08948ae93fb3180b9531eb807c921a6f53 packages/cli/src/plugins.mjs
6cfe7fd5086ddb59c5666060c6f8044c2852e0f3d5755b1fa206f7521173f300 packages/cli/src/project.mjs
9d03335628ae62e85c5fbc08c2e739ed0bd43b10d486faf397129a56a1b343e0 packages/cli/src/screens.mjs
1a30048032f5bb64419ae9716a1692978bc1a137220a094d1900298aca6ba1d7 packages/cli/src/session.mjs
58888b7731f8009d4c3f8be2caf4445f13dd8f534e1633f6e2720b259fcc3f92 packages/cli/src/thread.mjs
662642a8ce739fcb6c188ad07125a94e008c8a305eced127c8041d472c56e55b packages/cli/src/transport.mjs
f9e0c69849633ae36a7a6aa22729a690dc40292178ac3db43accbb131fd7b4ca packages/cli/src/usage.mjs
1e1aef2c74434e388d61b03407cd323336d20b7ef2106893d16a39638ee12a64 packages/control-board/package.json
8966f1f98ea81b4525345fc4889db5e0e5263ca41b5132ac8dd9bd99a2c88522 packages/control-board/src/discord.mjs
6d74b131af360268be748a1f8f7f2b3f5a9180365e7279426640883fc295a676 packages/control-board/src/scan.mjs
2eb25c46e85ddadd3bdbdbe605db54a6e09845155384a209622554d78307e583 packages/control-board/src/serve.mjs
2ed3790eb877414b8e985ca16031d8963adfb5c9555d415efb76288b76a5e1a6 packages/conversation/package.json
a45beb82438bb42d97d1e322010e175e785767664e548b90c4125e98b7660003 packages/conversation/src/client.mjs
eaf0772b60bb17fbf9548267c9cfeb0104f92f5cbafdfcb60c1633883eec6432 packages/conversation/src/framing.mjs
da336ed2a2a149ff56ac12af2440a8353d4573c33e9069381be60f1a0ca70151 packages/conversation/src/parts.mjs
20e781240846298fa65f9a8226b5e1ee1e81338b81229334666d845c17c99ac1 packages/conversation/src/pi.mjs
75d0cc982c36b0a81ff23f0da9da1b56906c496250a043f91d3a3b18ffa8e51b packages/conversation/src/reader.mjs
96f7b64c2e2c3493e270224542818fd14f042e3cf0ac14788b3f881010bc25b1 packages/conversation/src/records.mjs
62b0f7e9f798f584fcc0e4ead0522e44fd113bd0803f2bad92ffa480cadb7527 packages/conversation/src/safe-fs.mjs
c24d28a073659640b8b027eb12ad150ba895c3001091b892ecef2ec1da40d5cd packages/conversation/src/terminal.mjs
f834ee740e7149e7d2ed976112d0719ce0660270e3b61cf93e1774d112c992a2 packages/conversation/src/transcript.mjs
bdbfc8073d2073dd2ca4cb1460e3c376f087fff387d053d883932e5a67f85948 packages/discord/bin/git-credential.mjs
a52c6bfc9bd26a3b021d3a96bddb0f5c45845d752ca4579ef04ef60667f110f3 packages/discord/package.json
5ab69c4111dd9589a197172ffe6968bf414f41c552b7910e5478a27c446cfaec packages/discord/src/binding.mjs
917b0e6c4f100e93f056b925e38d97eacdd8b2596e39fbd3f88c0b62b973d8ed packages/discord/src/errors.mjs
c28e04a0055997ea0b34bea1ad2912adb248d5fd43713df1e6f5a661d87949b7 packages/discord/src/git.mjs
12684e926574c3fe7f693a03b60d1393df483f5feb4b47c9dd7c5a7ac050aec5 packages/discord/src/journal.mjs
aa7c1e328d6664b53e4d9cb5a1ab83c8ff71cc31deb9d3ce91a7dc6715c887aa packages/discord/src/notify.mjs
8fa9968862dff77fa6d8be5210c22d13712fd622a8cbc722d167be5be80d0783 packages/discord/src/processing.mjs
0b0b8f4dc25b8fbd4d948c962453c63084b0797b0ec5f0420e3f4f174837ccd5 packages/discord/src/rest.mjs
ba09d286e707860afa53300f8802ac8e6193ab2d2e7abe9d2b07cbdef3822387 packages/discord/src/setspark.mjs
975503616245bb6051f06ecbf47436ce7d030f21af23042df7f3341062df967f packages/discord/src/tools.mjs
e5a7b64720872b12b34223549537ace05ebf0ca8a29b2f844d2b7c5cc9ea41f7 packages/discord/src/web.mjs
34ef8212e27f052223443c66830839517f7a54ecb6ef7d85795b3e89c65b4d4c packages/harness/package.json
e944a4c7a26d1fe55e13ac1eca31dd86c302dc7c868224b8b000b27255976153 packages/harness/src/bundle.mjs
32b5090760c95eea0e1232ff36ec13a1d9b58335b2eade621196dec1ebdbe784 packages/harness/src/claude-gate.mjs
a74ef2db4093c0c797ba9e7e28e4e4df0ceac9040385f00e60a273f39af9610b packages/harness/src/gate.mjs
ce0107c3b21e07925b6543b6b925da8b8768823448d4fcf30b620883cfd2d39e packages/harness/src/mcp-server.mjs
fcba4b8dfd9dde947a79f88376d880f383e2a04ee3c0a9ba2fa5af641fe61b35 packages/harness/src/pi-extension.mjs
38fe84040a78c3f8a8dcde4339d88db3b5df9ef669d605ad1d92ff3e8b646b40 packages/harness/src/tools.mjs
5c9b528fd69a2493f04933fc84f352b1101d276d69d9982806975def614fd740 packages/library/bin/askpass
f6208a6b9e233baca38dd0ed9fd435cf2c7a3e34160c2c07cea1fea66893513b packages/library/package.json
f710d9600a17f6e2989a289cfe84e58f161d86c7306605946ce05fa71b364eb2 packages/library/src/guard.mjs
70c1fe75cb2149c9a074d55a6301d5b66157c2dc2e777b92bac338cce09d89c7 packages/library/src/index-build.mjs
98c2c2877549c3e2c5963ec4e49d99ab3b6d6ad54fb3bfae86cf98542207157e packages/library/src/index.mjs
98ef45ed61144aaea44d8aea1ac43082b6d340297e46846d01772da38728e530 packages/library/src/limits.mjs
def32a176cb70c86248e45908edde22f9c4c5f88575a4af0a396a05f617358bc packages/library/src/links.mjs
c83c626c7cdc2a00ba4217c34b889ca0517cd2022d1f8fc9e7d3a14a0293a802 packages/library/src/mapping.mjs
26b824d6885e5c6d1b8bd71e754a9fa333c26307693f7e6a0c6a8e6300ecb4ae packages/library/src/mirror.mjs
0c8764b03dae0150c56af74bcb113cf583dcbe1fa0c6f7386ef2d48d59a6bd31 packages/library/src/problems.mjs
bafe113bee70f17bd249876d6bdd1c08fa051223c2111955e5d5f275bd76bba0 packages/library/src/query.mjs
ea126533afb7e74b71419eb943febb6b242eb96fc6917d9df1019db3e7e6ce8d packages/library/src/reader.mjs
bfc3de029d3c8f0dcc96c90fde30d6da58bbb5b72d8f13e3f536c0d735c73ca5 packages/library/src/render.mjs
7b46f47b5e9d6b554b5d39bce2cd95c4610f5f35b8ab8fdc5a2864b3214be809 packages/library/src/reply-protocol.mjs
97e12255f52ad638eeacd152eb26822f9a2aa72cd30e2fed1193f51cd6e56192 packages/library/src/scope.mjs
6a3b4de2070e62b1cca1c0ab20f2883d3153fc61608d1bf7670cecea08765b4c packages/library/src/supporting.mjs
016bfa5c80572c0baf90ced39cb3d3ec66d395f0be15c2727b9552a9dd849093 packages/library/src/survey.mjs
a58f3aec5ed9b3530b363e2fdbd38bc9ded7635d261ab2fca3cb31c45dcd3dfa packages/library/src/sync.mjs
a301b7c7e3f42f66cb69d88991220f4e236f25a6e5951c61e79ec4ef2b714198 packages/library/src/write.mjs
889ac9589fadf7654d4dbb914f968cbafe4255ed215bd6a9ff3f331757c9017b packages/model-proxy/PIN
8fbfb3d1562e9ea824a1bd399b17cb2048c92b125e7699ccf27abdcc6e31e40b packages/model-proxy/package.json
f5f86cad661034f223a76352d877fa8d7883bfa921a7a01282347a9a03272441 packages/model-proxy/src/client.mjs
a6fb88352018b8f21593a0bb9311f87162c80d8b1e05e62b4d43b1e69af21b23 packages/model-proxy/src/common.mjs
00378d2ea95ac4945899696462f8ff4c70dc020cc58d93663d731d2f2f333783 packages/model-proxy/src/fetch.mjs
1eac4b5741b360a077bb1c871c008b64f7c7119afc64be4d6e4a0dcdb3a313bb packages/model-proxy/src/settings.mjs
e66453cf6662677cf28cbad1ae8f7509917d333e5b80404ab02c53f5cf75e9e1 packages/model-proxy/src/validation.mjs
77327681d6eb51f25d7aeffcc532b7e8269c1dc59139cb03adb4a3a1409f63e9 packages/model-proxy/tests/client-probe.test.mjs
790c6a50ec030a8b27a28fac7fd129bd9eabe79774adf11d6620c00df9b6ae86 packages/model-proxy/tests/client.test.mjs
95e39a519f7ac8b9592876e6157191169f9b14d002163867a6ff6ab808e42c14 packages/model-proxy/tests/management-key-encoding.test.mjs
f24e1d121a340cbcaa3f6cd6390eeb7d4b05f778dd498d76ba099cba5a719dea packages/model-proxy/tests/page-client.test.mjs
1ad66d56800a31cfbd387939e640653bc72150f4e73822d9e3c777b3bffbf1e1 packages/model-proxy/tests/usage-client.test.mjs
5e7e1ec169392ee3065f8f47d19732ebbe8bdd90f9193581425b956e66da6b73 packages/plugins/channel/cli/index.mjs
789132601745a94027f9e9184e7fef1f70cff0cba450afed5cca647f683591f4 packages/plugins/channel/webui/index.mjs
a317ac544359d321bb91b67cd87fc6ef431b72df9ac9f7f2a9ff291ed1a9109a packages/plugins/harness/claude-code/index.mjs
aabaf5c4602e28f025c18b2e2ddd6fa0d1648870101a5de0c4424d97b24472dd packages/plugins/harness/pi/compactions.mjs
39c225f157b8f66b416625bda689153505743ffcfdc32964bb1f3d2c6fcb73af packages/plugins/harness/pi/index.mjs
3749b9f6dd681ef424ee7d7e4d80ccee87b3655df8cd8fe9ccd0d505dcaaee9b packages/plugins/limit-check/daily-quota/index.mjs
4d0c6f5f87101f94608c02001a49d62cef113da48c539b2d2488dfbed1a4c524 packages/plugins/limit-check/token-limit/index.mjs
90a9ac59a9ea2287e9a3d4b2f4286d025e727f2a6ce149464f8d0420fd9a8ef1 packages/plugins/package.json
8be381a7e5dc7dd5ad18e89bb17f17d4b7074bbac490331fc61c65ac2b824057 packages/plugins/search-source/harness-builtin/index.mjs
92618d0cd2f1b79c7d0230ec0ecd80ff628744524847d6b5f33ddbae9d7a3a09 packages/plugins/search-source/searxng-bundled/index.mjs
fe4603b69596c3758ef8d7f794e403273e24e0fb950a92f15f8e651e193955ec packages/plugins/search-source/searxng-url/index.mjs
5fcecf8336ee247e8ac2f626b21e4c79b1edc49082eadfd536cd23016c6bb756 packages/plugins/src/channel.mjs
eaa258a1aadadb5a75450fa73fdbcea0b53636adb50ed9a508193d29d564ca78 packages/plugins/src/kinds.mjs
2e99f9222424cf9503253701568f0bb5ef579a22930f9f224e5b63ad6b4f745f packages/plugins/src/loader.mjs
3d4fab56fea4c45c6a317ef41121aa5b6da0502a6ef614b7931f91cafdfc1f71 packages/plugins/tests/daily-quota.test.mjs
5d5e5dccdae3f94b8540d187a8899ec36f9c9933cae3933249c2d8c400c75aa2 packages/plugins/tests/helpers.mjs
f3081e1dbdac20ade2246c743bcbb3934be686f79f378af21c365cd1451893ba packages/plugins/tests/kinds.test.mjs
8588ad7eee0c9ce5de3b53e3b88562812a155a3d791a2bd3413bb1754655d78b packages/plugins/tests/loader.test.mjs
6e96bb96278ec754ca1816a24f49ef677771615ab5cf186ae41969fc2f93d8cc packages/plugins/tests/token-limit.test.mjs
d09ae19db3eb69477783163559bd6a8e5b59a6f5af0eafd62d0e2e3bd325065e packages/plugins/usage-source/transcript/index.mjs
e9deb2504741f45645cd52ea6a1daee031cd2d3d44775a1221e76cec73c6b480 packages/plugins/usage/cliproxy-queue/README.md
6096a577cd5d7e8bf84fd6b98ab284e2f47d5facebd027548e07e6aeec442f96 packages/plugins/usage/cliproxy-queue/index.mjs
83aa9ed92f6ea3e1f68a6325ee61250a3167cefb360fd7154b89ed026b1aa8fa packages/processing-control/package.json
781973277c09133de15fc39be35b372a79066479097d46923c8ab7782f011dcd packages/processing-control/src/containers.mjs
ddc7318297abc4ec4dd03d425820b7323db609e554cfc5341cfdfa6934271e73 packages/processing-control/src/coordinator.mjs
3bc600649267f011e21ed8266fb16927b0ad3a0e2c49e4b54062d34c544d0c17 packages/processing-control/src/effects.mjs
7145420aa354180689a5c84423928fc60c8123476dcfed3364c9cf4542f8c7ea packages/processing-control/src/runtimes.mjs
ed834770fed863cb0c15b75062de1fd63dea940f3b42020b769a7e62b319c8ed packages/processing-control/src/state.mjs
13664e88d0f233bcf18f05e75946e70a1f2a7ba8d099248b73936230cefadd8d packages/project/package.json
925bb03ac99e5845e4bfa20b4561a331f034f88e187db82213df6602a7ceee4b packages/project/schemas/decision.schema.json
f069c012e9660d5d0491a21f98e936b725f6818e1c3136dfec61b3c800bd58de packages/project/schemas/project.schema.json
79a1e7b567af7162bb88ca69861075fc579a858e8aec4e49824ccdc370b690c3 packages/project/schemas/requirement.schema.json
af6865a4cace92ef27910098507ffedfc8dfe768cea088b1fee21d0876cc556e packages/project/src/git.mjs
3ab38cc40ce9ed1a714a59a1f2c336c3792a59431a6a9cc655ba6a2f47513899 packages/project/src/index.mjs
bd9debcf3f9bb92560e74f220a0b108dfe24154bc6d1fb03c5ec414356d451f9 packages/project/src/paths.mjs
42113cd20eb8f04dd252f9963a6f1a84806af9cae7beb6808c4d584a2548220c packages/project/src/read.mjs
e49ab5e825f0706da2f3c8dfcf33c1331a38d77ca2d35b03359ee68ea74652c5 packages/project/src/validate.mjs
24b7e3224dba45753e2d6139fcf05d2ed8c29d999752b02a637cfb8489fd9e0a packages/project/templates/north-star.md
26ee149f870ff56ad6d1c3d7c3b4b2301879c59f02d5840078c07e7964cc2175 packages/seat/package.json
5aca02491fe8df51487968ce62c776d493d0fe693cc41478b84bef7b49c8948d packages/seat/src/checkout.mjs
c5de99284b8fa61763b8dd30a58809bbc086529eeb10587586d52b0df2754774 packages/seat/src/compactions.mjs
6f7c938a32b349ee49ce95b89ad499e599f6016e5e9d7efd79a9ea4177b4d175 packages/seat/src/landing.mjs
382cbf7e0ff336911e288ce858bdbfbec693bc2b69879720d1f0b4c7d8455198 packages/seat/src/proc.mjs
0868f393f6fb117d430428ec390e435359737eae0792b4a4d1f54797c7a6c1bf packages/seat/src/sandbox.mjs
eec970961a667c9e614d1474d33c31a019b2cf1b0bf931a51458d874bca13a15 packages/seat/src/seat.mjs
c37a6ef6f6d2b4e61443e77d800656bf31e38913bf7dbdc4ca955f4a83b13a41 packages/seat/src/session.mjs
621f5c223811444336f0f5d6ad10bc7afce075491653c0527d6c26ca568b79c3 packages/seat/src/working.mjs
2018701876f26c0566307335eae992efb3551b75af200b7c249b615757bf311a packages/tasks/fields.json
269161444d253da7886d83f7b2f7bd79792b6c6b798c6e72f05f69bb99ad5295 packages/tasks/package.json
80b58323994d70e8bb496d81225aeb3d2cdfda464654b68b3b082e9af1fac5c1 packages/tasks/requirements.json
ff0f30ef6b2f4b758082913c34062d4749a71c157e994a06de692bb70dc8014b packages/tasks/src/adapter.mjs
b5580224e931198c7024326135db5bd4f660dfa42834f19e4cd3c08550845bc9 packages/tasks/src/digest.mjs
c9a883e9a1649277edce97adca40bca2874df7b5312c70e4ac6f6d4a1c860841 packages/tasks/src/fields.mjs
38e7b85650247759f06c09fce205b2970b8368bc81491f51dc6b3c90ba2a846d packages/tasks/src/requirements.mjs
c538cb5ac1c9bc96c50b8d6ca01136361369ec463606684a21d81e3b5c2e46a5 packages/tasks/src/startup.mjs
39887268258c3b651246b3596a866005fc193cd8ee5f151a02492967069f2d06 packages/tasks/src/sync.mjs
1c10dfcd37b0435e199aed2535b71909728ef358dc145ca9eec4f5beb37bfb87 packages/tasks/src/verbs.mjs
0d76911dac358d195be4293ae03ae53476ea4d1b0fff4fbdb1a2de33f46ef952 packages/tasks/src/vikunja.mjs
0bb346f598380c2bcdb39db92a006959442d3ce5dc645503ef76405aae53311c packages/webui/package.json
c521be48ddbc473c61431424838cb9c6d67a0086082141000882013bde62379f packages/webui/src/access.mjs
4ebf6c2b5d71c23d85cbde83f69aa671058dc2195c9ae4bdda624f6940729d1b packages/webui/src/bus.mjs
3a5321a5f492a98d342e4ddcc1e9da3522cfff89a4f9bc3f51d2ab1426d3de1b packages/webui/src/chat-http.mjs
fe2072a7198771a82f58dca5fc05aa4d697dd3db25a206fb2a24c8514010b069 packages/webui/src/chat.mjs
5988c015b7f03b56654311039874f8c42a1d93012b330ee389a42fb88af70279 packages/webui/src/cli.mjs
79cfb474308d148293b702c0132927acb31ac4f1400fde9a9ee78c99a7a558af packages/webui/src/console-bus.mjs
93d4d0c36d0b74eaace24bce4c3e7179b7418377eb4df6d0f6a9ca89d5eb8e39 packages/webui/src/decision-http.mjs
c3825a02c3b4f4e5537db4a945439d707e177e74c3e8b1fc2cb777515e610b64 packages/webui/src/processing-http.mjs
a09028cd5ca57367f597d0681e84926ca871fd4626769e9947927d949c2b6ab7 packages/webui/src/proxy-http.mjs
3c7a35e25b4c1cfda19ac9466d4b2fbc86c880761a1d04ad3ece8bc485f60f93 packages/webui/src/public/bus.js
46defeb3b4be0e1a22e4b89445872ad6b15cdee182076e9e6222219ae29997f4 packages/webui/src/reads.mjs
7b7bee91604b7bd973027b177de83205db9aed366e694072fc6343b46465b5ba packages/webui/src/serve.mjs
37b01ab0479d5f2a7ab9aac790931c6d88c790465392d9c0b65a105513f3e36b packages/webui/src/sso-config.mjs
9a3442739e95407deb0afe3e2a2aa77741d40f3eb899db985f45af49c38b34a0 packages/webui/src/sso.mjs
1c1fe0c795adac97f28502564a75f26d5666d9be5ae51169f7dd5bb7741fad16 packages/webui/src/tester-socket.mjs
b35d3f3471d6d83ef2d19d6102eaecce2ddec9330f337d7194f1d7be03cbd216 packages/webui/tests/fixture.mjs
39f50991578b98594183390a00efbca84fda90ef61617eea4215e2c75f90b82c packages/webui/tests/usage-render.test.mjs
f96d06974bc83051c0d5c9000e38161ea0cc231997410bcc6c42ed7f55718dfd packages/webui/tests/usage.test.mjs
5f63ff52aaccf06a0f2415ffdd9d1903c202679cf953bef5266a6841b5e39ab7 roles/assistant.json
7d2d50a1278c62daa4f6c4a5ac7809817409f2f1d0d75787802300739d3fba15 roles/assistant.md
314074c8081953923f962f2df045d4c14629010ea99d1f23449ed45294b46bcc roles/chief-executive-officer.json
a6bc3aad543cfb3a03f93efda60859221c56f78d0f1094da33afd458399b4ffa roles/chief-executive-officer.md
539d531a0f5744aebb933ca685b52022554e3e93ae54cc8b67e4de0eb27d3460 roles/chief-financial-officer.json
09347759baf8fdbf0a8105106e8d27b500f3d0b76dcaa91dc2cdc20b3b000b00 roles/chief-financial-officer.md
8ee8e7213d4c073e2d9ba7732fd84b3b3130d9bbb930d07595b7f692bb9fc5dc roles/chief-information-officer.json
0a7041dd3ae5f05ba6f37baa2aeeca35a430ed3e387a3e2407daae2c431efda2 roles/chief-information-officer.md
a550428603979f4342e57ad9ccddd4d2e44a5203a64f19027ce09a24f1dbfc0e roles/chief-information-security-officer.json
1da83baca46abb75c6b2e74df7a3fb9424e1556ce37ff5f8c7802e85100d6b16 roles/chief-information-security-officer.md
3cdd799159d3e676529efee01f467a4ed7d67920253cddba2e098566368a1e36 roles/chief-marketing-officer.json
4d414c02485b6a83f9d8fc2498a53d275019fd45e9ad948fdf61777a3a983bfa roles/chief-marketing-officer.md
c781c4108824db7f17cc4b514e3b0d446120dc1ad7c05e5bf5a72edcac70d054 roles/chief-of-staff.json
db16c358820e199910eabe06f885a53a4bde2502aeafa5444c12d9b29c74880c roles/chief-of-staff.md
13713c4e64ade3b1b1eedabed75f5f76fe65e73f6df336b771d1e34881d111f3 roles/coder.json
d29d469aaae2a97705dd0d5b057b6eef20c5f22d37791aaee9d886c8bb46700f roles/coder.md
962f1e8ca9d56d7ad7dd4f82a57b97b834bacdc72c3fe774f9a9afccf7dd72e9 roles/companion.json
cad0360c16db9b2659370e6363937a27d61e9f6c4fae711a2dfc5b89aadead81 roles/companion.md
42e751413a649e03c5e1eb87acdf59e0a0fcd54f519bca297463f88ee07e3043 roles/conductor-policy.json
031807451adfe5e4643da2ff59fab0a041fce519f4cb84d749ec6f10edff8f36 roles/continuity.json
75522c66ccd242971b4b00786112ef37b41c972af5b0d98c011697169fba7db2 roles/continuity.md
60b6482a29a578234b4e5bf0d4c9a123bd3a65a65dc6e488f474546cf4456bb2 roles/cto.json
b5603cbdfc1a79d4b986c97aa2a94e2c57164f9abfd5117b348086025dd50993 roles/cto.md
1dfc6629dc70dd8020483456db140751010e81a44fbd49308580f0c6356c2471 roles/fact-checker.json
2d01f771831d52a1d9ddde8c1183601051782efd39899605949761fdd5e07291 roles/fact-checker.md
2c69c26460574948584eae487e944b7240cfa37a0a0f3ddeaabd682815ebf6ed roles/ideas.json
bb403867a2ba33ea271d2d576165c6131e43446f2d5deb4eb86389398cb0592d roles/ideas.md
14dbbbaa98670ebab8612555e3f813793ff12caf6a3aaef3883c2007ebc9bfe8 roles/merge-gate.json
b8bbccbf7e10e090f3514664384cba44c86fbb514c79d182d31a209045fdcc1d roles/merge-gate.md
1af1cb70512163eb5c39ae942496a4cc309b0b1d47b9cb48253ac788862f0e9f roles/pm.json
d1016f8c34ee04601ab751c7514a20dfbeec0359d46dba8f94c44538dcc16133 roles/pm.md
3a55947b867241dd42b78588276f6f901d374b519f3964ba0acc4b782513224c roles/proofreader.json
054f6f888064eca4c6b7b1c0180bd2ad968b10429f045db7aaa92453cbddd1ab roles/proofreader.md
38d36d8cca7f4f7141af5469f0a17dd2a44a5ec26ef113ad9a01c9b013968501 roles/research.json
2a66291a7a8d21b9f587c6226d408667a775b2846bc9950606e73b210f4ac0d1 roles/research.md
3b5f0c39b72eb1ef1d546899ea5b02da6ce0c22a5d30d67058530b1bdc67964f roles/researcher.json
4d2b2ab1208aced3a82d7de1ace879574fae2930ac1bc684f76e1d16e58cec8f roles/reviewer.json
f7418c27a5b84f258041b87e87ccf9f441fcb9c638a322e50aafcfdb0ce7f364 roles/reviewer.md
d84bd99dda657fc44b6272cc35a89c490315117c7102d8936042ac1cf58978cb roles/security-reviewer.json
eb5ad42d4fcd98a2c89afb8b2286edc5eb666f993e21fbbda838e5c472f34dd8 roles/security-reviewer.md
@@ -0,0 +1,311 @@
diff --git a/packages/bus/src/limits.mjs b/packages/bus/src/limits.mjs
index cb47c5df6c97fad2a18cf6a482b6976376ea7fa7..c4bb3a75ecd47b94f83dcc4df28f11e252d5f460 100644
--- a/packages/bus/src/limits.mjs
+++ b/packages/bus/src/limits.mjs
@@ -12,7 +12,7 @@
//
// refresh, mayLaunch and mustStop are async: they re-read the file and reload first. report is
// sync, so the organization verbs stay sync; it uses the modules the last refresh loaded.
-import { createLoader } from '../../plugins/src/loader.mjs';
+import { createLoader, isDailyModelQuota } from '../../plugins/src/loader.mjs';
import { turnRecords } from './usage.mjs';
const KIND = 'limit-check';
@@ -122,8 +122,9 @@ export function createLimits({ store, read, log, makeLoader = createLoader, keyF
log({ event: 'limit-check-failed', business, check: st.missing, export: name, code: 'not-loaded' });
return halt({ check: st.missing, code: 'not-loaded' });
}
+ if (!st.checks.length) return { [key]: go };
const leaves = limitLeaves(st.limits);
- if (Object.keys(st.limits?.tokens?.keys ?? {}).some(k => /^[a-f0-9]{12}$/.test(k))) {
+ if (Object.entries(st.limits?.tokens?.keys ?? {}).some(([k, entry]) => isDailyModelQuota(k, entry))) {
let modelKeyId;
try {
if (name === 'mustStop' && (typeof context?.run !== 'string' || !context.run)) throw new Failure('proxy-key-refused');
diff --git a/packages/bus/src/model-keys.mjs b/packages/bus/src/model-keys.mjs
index 560c8474838ca69a88539ecbc44961c2f157a84b..a998576434fa604912732b0131b9e31ca62f08b4 100644
--- a/packages/bus/src/model-keys.mjs
+++ b/packages/bus/src/model-keys.mjs
@@ -36,6 +36,17 @@ export class ModelKeys {
if (this.#record(instance)?.state === 'revoking') fail('proxy-key-revoking');
if (!this.#ready) fail(this.#failure);
}
+ // P5's destructive queue read needs this instance's current identity, not
+ // an issued agent credential. A sentinel refusal stays closed until explicit
+ // reconcile; telemetry never retries around it or performs reconciliation.
+ verifyIdentity() {
+ return this.#exclusive(async () => {
+ if (!this.#ready) fail(this.#failure);
+ let keys;
+ try { keys = await this.#client.getKeys(); } catch { fail('proxy-down'); }
+ this.#sentinel(keys);
+ });
+ }
async #replace(before, after) {
this.#sentinel(before); this.#sentinel(after);
await this.#client.putKeys(after);
diff --git a/packages/bus/src/proxy-usage.mjs b/packages/bus/src/proxy-usage.mjs
index 71d9a72fa348cf24003e02d36ebe0c1280597f30..754c8c022185014c39183dae0456ac6235ff87a9 100644
--- a/packages/bus/src/proxy-usage.mjs
+++ b/packages/bus/src/proxy-usage.mjs
@@ -28,7 +28,7 @@ export function createProxyUsage({ store, read, client, records, log, now = Date
due = now() + Math.min(...enabled.map(b => b.pollSeconds)) * 1000;
try {
await loader.load({ usage: 'cliproxy-queue' });
- const module = loader.modules('usage')[0], management = client();
+ const module = loader.modules('usage')[0], management = await client();
if (!module || !management) throw Error('unavailable');
const events = await module.read({ client: management });
const owners = new Map();
diff --git a/packages/bus/src/runtime.mjs b/packages/bus/src/runtime.mjs
index c21103a447c2e77fa1b8e487fef1a7c4a0dba6b2..8bb0b0585df10f38d3bf563f3bb6b4dc15ef33ab 100644
--- a/packages/bus/src/runtime.mjs
+++ b/packages/bus/src/runtime.mjs
@@ -384,7 +384,11 @@ export async function startBroker({
const keyForRun = (business, run) => modelRuns.get(business + ':' + run)?.keyId ?? null;
const usage = await createUsage({ store, dataRoot, businesses, log: usageLog, keyForRun,
proxyView: business => proxyUsage?.view(business) ?? null });
- proxyUsage = createProxyUsage({ store, log: usageLog, client: () => modelProxyClient,
+ proxyUsage = createProxyUsage({ store, log: usageLog, client: async () => {
+ if (!modelKeys) return null;
+ await modelKeys.verifyIdentity();
+ return modelProxyClient;
+ },
records: () => credentials.status(),
read: () => Object.fromEntries(Object.keys(businesses).map(id => [id, settings ? settings.current(id) : businesses[id]])) });
// Row 125 (#1619, REQ-LIMIT-3, REQ-LIMIT-4): the limit checks read the organization file at
@@ -862,9 +866,10 @@ export async function startBroker({
}
// One bounded queue read at a time. The service applies the configured
// 1..59 second poll deadline; this tick only checks whether a read is due.
- usageTimer = setInterval(() => { proxyUsage.tick().catch(() => usageLog({ action: 'proxy.usage', code: 'proxy-usage-read-failed' })); }, 1000);
+ const usageTick = () => { proxyUsage.tick().catch(() => usageLog({ action: 'proxy.usage', code: 'proxy-usage-read-failed' })); };
+ usageTimer = setInterval(usageTick, 1000);
usageTimer.unref();
- await proxyUsage.tick();
+ usageTick(); // Optional telemetry never blocks the native ready answer.
return {
broker,
credentials,
diff --git a/packages/bus/tests/limit-checks.test.mjs b/packages/bus/tests/limit-checks.test.mjs
index b9b7660723e4e2fe115cc786b8af2121b23e2403..a0264cc77cb2f9802d42adf4df5dbb01165a5bcc 100644
--- a/packages/bus/tests/limit-checks.test.mjs
+++ b/packages/bus/tests/limit-checks.test.mjs
@@ -327,7 +327,7 @@ test('REQ-LIMIT-3 core reaches limit checks only through the plug-in loader', ()
test('P5 missing, ambiguous or invalid model key lookup fails closed without leaking a lookup error', async t => {
const root=mkdtempSync(join(tmpdir(),'p5-limit-')),store=new Store(root),log=[];t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
- const key='012345abcdef',doc={plugins:{'limit-check':['token-limit']},launch:{limits:{tokens:{keys:{[key]:{limit:5,since:SINCE}}}}}};
+ const key='012345abcdef',doc={plugins:{'limit-check':['daily-quota']},launch:{limits:{tokens:{keys:{[key]:{limit:5,since:SINCE,reset:'00:00',timeZone:'UTC'}}}}}};
for(const lookup of [()=>null,()=>['012345abcdef','abcdef012345'],()=> 'msk-private-lookup',()=>{throw Error('PRIVATE-LOOKUP-CANARY');}]) {
const l=createLimits({store,read:()=>doc,log:e=>log.push(e),keyForSubject:lookup});
assert.deepEqual(await l.mayLaunch('demo',SUBJECT),{allow:false,check:null,code:'proxy-key-refused'});
@@ -337,7 +337,7 @@ test('P5 missing, ambiguous or invalid model key lookup fails closed without lea
});
test('P5 trusted lookup uses the retiring run key rather than the agent current key',async t=>{
const root=mkdtempSync(join(tmpdir(),'p5-old-key-')),store=new Store(root);t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
- const old='012345abcdef',current='abcdef012345',doc={plugins:{'limit-check':['token-limit']},launch:{limits:{tokens:{keys:{[old]:{limit:0,since:SINCE}}}}}};
+ const old='012345abcdef',current='abcdef012345',doc={plugins:{'limit-check':['daily-quota']},launch:{limits:{tokens:{keys:{[old]:{limit:0,since:SINCE,reset:'00:00',timeZone:'UTC'}}}}}};
const l=createLimits({store,read:()=>doc,log:()=>{},keyForSubject:(_,s)=>s.run==='old-run'?old:current});
assert.equal((await l.mayLaunch('demo',SUBJECT)).allow,true);
assert.equal((await l.mustStop('demo',SUBJECT,{run:'old-run'})).stop,true);
diff --git a/packages/bus/tests/p5-key-context.test.mjs b/packages/bus/tests/p5-key-context.test.mjs
index 8b2ebe0947591589f83d5c89b49bbd8fcf261e10..46b7a87c8e9cbfe4515e35be768f619dffc4a2b6 100644
--- a/packages/bus/tests/p5-key-context.test.mjs
+++ b/packages/bus/tests/p5-key-context.test.mjs
@@ -22,7 +22,7 @@ test('P5 broker preserves original plugin subject and derives internal run conte
});
test('P5 configured key quotas never use a supplied safe-looking ID when trusted metadata lookup is missing',async t=>{
const root=mkdtempSync(join(tmpdir(),'p5-no-bypass-')),store=new Store(root);t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
- const doc={plugins:{'limit-check':['token-limit']},launch:{limits:{tokens:{keys:{[key]:{limit:10,since:'2026-01-01T00:00:00.000Z'}}}}}};
+ const doc={plugins:{'limit-check':['daily-quota']},launch:{limits:{tokens:{keys:{[key]:{limit:10,since:'2026-01-01T00:00:00.000Z',reset:'00:00',timeZone:'UTC'}}}}}};
const limits=createLimits({store,read:()=>doc,log:()=>{},keyForSubject:()=>null});
assert.deepEqual(await limits.mustStop('demo',{instance:'coder',modelKeyId:key},{run:'forged-run'}),{stop:true,check:null,code:'proxy-key-refused'});
});
@@ -38,7 +38,7 @@ test('P5 internal context resolves exactly current or retained generation; wrong
test('P5 model-key mustStop without native run context fails closed even when the current key resolves',async t=>{
const root=mkdtempSync(join(tmpdir(),'p5-missing-context-')),store=new Store(root);t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
- const doc={plugins:{'limit-check':['token-limit']},launch:{limits:{tokens:{keys:{[key]:{limit:10,since:'2026-01-01T00:00:00.000Z'}}}}}};
+ const doc={plugins:{'limit-check':['daily-quota']},launch:{limits:{tokens:{keys:{[key]:{limit:10,since:'2026-01-01T00:00:00.000Z',reset:'00:00',timeZone:'UTC'}}}}}};
const limits=createLimits({store,read:()=>doc,log:()=>{},keyForSubject:()=>key});
assert.deepEqual(await limits.mustStop('demo',{instance:'coder'}),{stop:true,check:null,code:'proxy-key-refused'});
});
diff --git a/packages/business/src/launch.mjs b/packages/business/src/launch.mjs
index 4ee37c5c6514bdf541b20e7001873fb5d8e878f3..7871fdda595d23c3645b417dbf96783faac9047e 100644
--- a/packages/business/src/launch.mjs
+++ b/packages/business/src/launch.mjs
@@ -1,5 +1,6 @@
// REQ-LIMIT-1: editable concurrency policy, never a compiled-in capacity ceiling.
import { requireObject, requireId, requireString, rejectUnknownKeys } from "./util.mjs";
+import { isDailyModelQuota } from "../../plugins/src/model-quota.mjs";
import { refuse } from "./errors.mjs";
const name = (value, at) => requireString(value, at, { max: 200 });
@@ -67,12 +68,16 @@ export function checkTokenLimits(value, where = "launch.limits.tokens") {
if (Object.hasOwn(value, "models")) {
out.models = tokenMap(value.models, `${where}.models`, name, (models, at) => tokenMap(models, at, name, tokenLimit));
}
- // P5: model key IDs are 12 hex characters (including digit-leading IDs).
- // A model key may use the daily quota shape; existing account limits retain theirs.
- if (Object.hasOwn(value, "keys")) out.keys = tokenMap(value.keys, `${where}.keys`,
- (key, at) => /^[a-f0-9]{12}$/.test(key) ? key : requireId(key, at),
- (entry, at) => Object.hasOwn(entry ?? {}, "reset") && /^[a-f0-9]{12}$/.test(at.split('.').at(-1))
- ? dailyQuota(entry, at) : tokenLimit(entry, at));
+ // P5 adds daily model leaves, including digit-leading IDs; plain keys keep
+ // their existing account-name schema and cumulative account semantics.
+ if (Object.hasOwn(value, "keys")) {
+ requireObject(value.keys, `${where}.keys`);
+ out.keys = Object.fromEntries(Object.entries(value.keys).map(([key, entry]) => {
+ const at = `${where}.keys.${key}`;
+ if (isDailyModelQuota(key, entry)) return [key, dailyQuota(entry, at)];
+ return [requireId(key, `${where}.keys`), tokenLimit(entry, at)];
+ }));
+ }
// One quota per account; the business read checks each key names launch.account.
if (Object.hasOwn(value, "daily")) out.daily = tokenMap(value.daily, `${where}.daily`, requireId, dailyQuota);
return out;
diff --git a/packages/business/src/organization.mjs b/packages/business/src/organization.mjs
index 6d358631d81464dcac98ec0db2388f08e9eceb39..2acb92e417f32f9080396b41d1a2f565272a01d4 100644
--- a/packages/business/src/organization.mjs
+++ b/packages/business/src/organization.mjs
@@ -8,6 +8,7 @@ import { join, dirname } from "node:path";
import { randomUUID } from "node:crypto";
import { businessFilePath, validateBusinessDocument } from "./business.mjs";
import { requireId, sha256, canonicalJson } from "./util.mjs";
+import { isDailyModelQuota } from "../../plugins/src/model-quota.mjs";
import { checkReplyLimits } from "../../library/src/limits.mjs";
export class OrganizationError extends Error {
@@ -84,7 +85,7 @@ function changes(old, next, path = "") {
// P5/Q222: every writer protects per-model-key quotas, including removal/reset.
function modelQuotaFence(old, document, actor) {
const keys = doc => Object.fromEntries(Object.entries(doc?.launch?.limits?.tokens?.keys ?? {})
- .filter(([key]) => /^[a-f0-9]{12}$/.test(key)));
+ .filter(([key, entry]) => isDailyModelQuota(key, entry)));
if (canonicalJson(keys(old)) === canonicalJson(keys(document))) return;
const agents = Object.entries(old.roles ?? {}).flatMap(([instance, entry]) => [instance, `${entry?.definition}.${instance}`]);
if (actor === old.human && actor !== "tester" && !agents.includes(actor)) return;
diff --git a/packages/plugins/limit-check/daily-quota/index.mjs b/packages/plugins/limit-check/daily-quota/index.mjs
index 38b445803d13a05803ec91e11556346e868a2437..096aa2ead37a18cfa17b2e2d43e19fb5604350f6 100644
--- a/packages/plugins/limit-check/daily-quota/index.mjs
+++ b/packages/plugins/limit-check/daily-quota/index.mjs
@@ -4,6 +4,7 @@
// timeZone}. A count is every kind summed over the account's known records since the later of the
// day's reset and the leaf's `since`; an unknown turn adds nothing and is counted on its own.
// It copies token-limit's tally helpers rather than importing a sibling check, so each loads alone.
+import { isDailyModelQuota } from '../../src/model-quota.mjs';
export const interfaceVersion = 2;
const KINDS = ['input', 'output', 'cacheWrite', 'cacheRead'];
@@ -63,7 +64,7 @@ function windowStart(entry, now) {
function leaves(limits) {
const daily = limits?.tokens?.daily ?? {};
const entries = [...Object.entries(daily).map(([account, entry]) => ({ path: ['tokens', 'daily', account], entry, match: x => x.account === account })),
- ...Object.entries(limits?.tokens?.keys ?? {}).filter(([key, entry]) => /^[a-f0-9]{12}$/.test(key) && Object.hasOwn(entry, 'reset'))
+ ...Object.entries(limits?.tokens?.keys ?? {}).filter(([key, entry]) => isDailyModelQuota(key, entry))
.map(([key, entry]) => ({ path: ['tokens', 'keys', key], entry, match: x => x.modelKeyId === key }))];
return entries.map(({ path, entry, match }) => {
if (!Number.isSafeInteger(entry?.limit) || entry.limit < 0 || typeof entry.reset !== 'string' || !RESET.test(entry.reset) ||
diff --git a/packages/plugins/limit-check/token-limit/index.mjs b/packages/plugins/limit-check/token-limit/index.mjs
index 8f26fcb9c7cbcae4c6cf953a6827af53590771be..b20cea356ca7081a6cf571949a0f6aa31dfec89d 100644
--- a/packages/plugins/limit-check/token-limit/index.mjs
+++ b/packages/plugins/limit-check/token-limit/index.mjs
@@ -3,6 +3,7 @@
// launch limits and its per-turn usage records, and nothing here reads a file
// or a store. A count is every kind summed over the known records since the
// limit's `since`; an unknown turn adds nothing and is counted on its own.
+import { isDailyModelQuota } from '../../src/model-quota.mjs';
export const interfaceVersion = 2;
const KINDS = ['input', 'output', 'cacheWrite', 'cacheRead'];
@@ -31,8 +32,8 @@ function leaves(limits) {
// A key is the record's account. Accounts are null until row 126 names them,
// so a key limit matches nothing until then.
for (const [k, entry] of Object.entries(tokens.keys ?? {}))
- if (!Object.hasOwn(entry, 'reset')) out.push({ path: ['tokens', 'keys', k], entry,
- match: x => /^[a-f0-9]{12}$/.test(k) ? x.modelKeyId === k : x.account === k, key: true });
+ if (!isDailyModelQuota(k, entry)) out.push({ path: ['tokens', 'keys', k], entry,
+ match: x => x.account === k, key: true });
return out;
}
@@ -73,7 +74,7 @@ export function mustStop(args) {
// while no record names an account (lead decision 150, Q1).
export function report({ limits, records }) {
if (!Array.isArray(records)) refuse('bad-records');
- const named = records.some(r => r.account != null || r.modelKeyId != null);
+ const named = records.some(r => r.account != null);
return leaves(limits).map(leaf => {
const { path, entry: { limit, since } } = leaf;
if (leaf.key && !named) return { path, limit, since, notEnforced: 'no records name a key' };
diff --git a/packages/plugins/src/loader.mjs b/packages/plugins/src/loader.mjs
index 04731ee91b04329a3956fd751f4d7fb215f845c3..5634a90664ea98022074cd9fff9bbfbd279692e8 100644
--- a/packages/plugins/src/loader.mjs
+++ b/packages/plugins/src/loader.mjs
@@ -162,3 +162,6 @@ export function createLoader({ log, barrier = () => {} }) {
return { load, loaded, modules, snapshot };
}
+
+// Shared pure plug-in setting classification; no check implementation is loaded.
+export { isDailyModelQuota } from "./model-quota.mjs";
diff --git a/packages/plugins/src/model-quota.mjs b/packages/plugins/src/model-quota.mjs
new file mode 100644
index 0000000000000000000000000000000000000000..1350eb56b5947e759ec8d32f0c429813c352f2a9
--- /dev/null
+++ b/packages/plugins/src/model-quota.mjs
@@ -0,0 +1,17 @@
+// The new P5 namespace is the validated DAILY leaf, never a twelve-hex name
+// alone. Plain {limit,since} keys remain legacy account limits.
+const ID = /^[a-f0-9]{12}$/;
+const RESET = /^([01]\d|2[0-3]):[0-5]\d$/;
+const ZONE = /^[A-Za-z][A-Za-z0-9_+-]*(\/[A-Za-z0-9_+-]+)*$/;
+const SINCE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
+export function isDailyModelQuota(key, value) {
+ if (typeof key !== 'string' || !ID.test(key) || !value || typeof value !== 'object' || Array.isArray(value)
+ || Object.keys(value).some(k => !['limit','since','reset','timeZone'].includes(k))
+ || !Number.isSafeInteger(value.limit) || value.limit < 0
+ || typeof value.since !== 'string' || !SINCE.test(value.since) || Number.isNaN(Date.parse(value.since))
+ || new Date(value.since).toISOString() !== value.since
+ || typeof value.reset !== 'string' || !RESET.test(value.reset)
+ || typeof value.timeZone !== 'string' || !ZONE.test(value.timeZone)) return false;
+ try { new Intl.DateTimeFormat('en-US', { timeZone:value.timeZone }); return true; }
+ catch { return false; }
+}
diff --git a/packages/plugins/tests/token-limit.test.mjs b/packages/plugins/tests/token-limit.test.mjs
index d8f8d3db7928f034d7126d479f4255637d0f8646..2c08be007564e5d4b223a7f93bcf4b36535fe739 100644
--- a/packages/plugins/tests/token-limit.test.mjs
+++ b/packages/plugins/tests/token-limit.test.mjs
@@ -150,11 +150,11 @@ test("REQ-LIMIT-3 token-limit ignores tokens.daily, which the daily-quota check
assert.deepEqual(check.report(a), []);
});
-test('P5 a model key ID limit counts stack records by key ID without an account', () => {
- const keyId = '012345abcdef';
+test('P5 plain twelve-hex keys keep legacy account matching rather than cumulative model matching', () => {
+ const keyId = 'abcdef012345';
const args = { business: 'demo', limits: { tokens: { keys: { [keyId]: { limit: 5, since: '2026-10-18T00:00:00.000Z' } } } },
- subject: { instance: 'coder', modelKeyId: keyId, account: null }, records: [{ at: '2026-10-18T01:00:00.000Z',
- run: 'run', turn: 'turn', modelKeyId: keyId, account: null, status: 'known', input: 5, output: 0, cacheWrite: 0, cacheRead: 0 }] };
+ subject: { instance: 'coder', modelKeyId: '012345abcdef', account: keyId }, records: [{ at: '2026-10-18T01:00:00.000Z',
+ run: 'run', turn: 'turn', modelKeyId: '012345abcdef', account: keyId, status: 'known', input: 5, output: 0, cacheWrite: 0, cacheRead: 0 }] };
assert.equal(check.mayLaunch(args).allow, false);
assert.equal(check.report(args)[0].count, 5);
});
diff --git a/packages/plugins/usage/cliproxy-queue/README.md b/packages/plugins/usage/cliproxy-queue/README.md
index 98aa6e8a2757e170dc2a27752e0b474a9fb3fab3..7e1b0c1996b536deb0013d4d58c8ee1d2697ad8e 100644
--- a/packages/plugins/usage/cliproxy-queue/README.md
+++ b/packages/plugins/usage/cliproxy-queue/README.md
@@ -35,8 +35,9 @@ usage cursor, preserved at turn begin and end. The Console exposes `byKey`.
A business can set a daily per-key quota at
`launch.limits.tokens.keys.<12-hex-key-id>` with `{limit, since, reset, timeZone}`;
the human writer stamps `since`. Enable `limit-check: ["daily-quota"]` to apply
-that quota. Cumulative model-key limits retain `{limit,since}` and use
-`token-limit`. Omitting a limit means no quota. Existing named account keys and
+that quota. Plain `{limit,since}` keys leaves remain cumulative legacy account limits, even
+when the name is twelve hex characters. They use `token-limit` and never resolve
+model metadata. Omitting a limit means no quota. Existing named account keys and
`tokens.daily.<account>` retain their existing behavior. Model-key limits and
resets are human-only through every organization writer. Missing, ambiguous or
foreign run-key metadata fails closed with `proxy-key-refused`; a retiring run
@@ -0,0 +1,128 @@
[
{
"bytes": 12448,
"git_blob": "c4bb3a75ecd47b94f83dcc4df28f11e252d5f460",
"head_git_blob": "cb47c5df6c97fad2a18cf6a482b6976376ea7fa7",
"path": "packages/bus/src/limits.mjs",
"sha256": "83f6538a40d6b2a341e5755fa19992f091544746db47f1a25ae8d5794ba83547"
},
{
"bytes": 17664,
"git_blob": "a998576434fa604912732b0131b9e31ca62f08b4",
"head_git_blob": "560c8474838ca69a88539ecbc44961c2f157a84b",
"path": "packages/bus/src/model-keys.mjs",
"sha256": "ef2711a80200686496ef42b6f154ffd44e3b5b9a983c38e20c19a5cd1a6bb4b8"
},
{
"bytes": 5748,
"git_blob": "754c8c022185014c39183dae0456ac6235ff87a9",
"head_git_blob": "71d9a72fa348cf24003e02d36ebe0c1280597f30",
"path": "packages/bus/src/proxy-usage.mjs",
"sha256": "f673bc899f1eea07bb016e77203abfbbf19890079913a52e6c16bf737d25e44f"
},
{
"bytes": 57938,
"git_blob": "8bb0b0585df10f38d3bf563f3bb6b4dc15ef33ab",
"head_git_blob": "c21103a447c2e77fa1b8e487fef1a7c4a0dba6b2",
"path": "packages/bus/src/runtime.mjs",
"sha256": "311e722440e1ea6a255b0b2c3788a66299e1f27ed379e41463e4447b659df553"
},
{
"bytes": 23179,
"git_blob": "a0264cc77cb2f9802d42adf4df5dbb01165a5bcc",
"head_git_blob": "b9b7660723e4e2fe115cc786b8af2121b23e2403",
"path": "packages/bus/tests/limit-checks.test.mjs",
"sha256": "da07fe8a464e636040eaf676131b2482732f40fa9d0e89d4a413252d9bba4193"
},
{
"bytes": 3776,
"git_blob": "bb51ad3527280f0db0449c27eb42474dd8b9e894",
"head_git_blob": null,
"path": "packages/bus/tests/p5-background.test.mjs",
"sha256": "8a7889bb9aacde4faced9ab97faf6603eb7c5f7e1b78df9e5b28279c3b5ebab1"
},
{
"bytes": 2772,
"git_blob": "4ee111f7c9ec75dbae24c184c3310b71973fc7c2",
"head_git_blob": null,
"path": "packages/bus/tests/p5-identity.test.mjs",
"sha256": "1d57b286993b4fe7098433703462c1e5bea715c5e4e88c52f6676cc1757fd153"
},
{
"bytes": 6406,
"git_blob": "331032ecb48644587057a9ec4799e69d5fa3cdc8",
"head_git_blob": null,
"path": "packages/bus/tests/p5-key-compatibility.test.mjs",
"sha256": "0c55ced6c8f30dbdc6572705f831a5c1a3375116cc169ca3005d36eeda35e737"
},
{
"bytes": 3922,
"git_blob": "46b7a87c8e9cbfe4515e35be768f619dffc4a2b6",
"head_git_blob": "8b2ebe0947591589f83d5c89b49bbd8fcf261e10",
"path": "packages/bus/tests/p5-key-context.test.mjs",
"sha256": "6326f25430a4185e7031b5ae9893fc1ab20caa78f89b92e10266a93f165ab0f6"
},
{
"bytes": 5146,
"git_blob": "99390f7d565a7d7db5344b574bc5a8623d5fa073",
"head_git_blob": null,
"path": "packages/bus/tests/p5-telemetry-fixture.mjs",
"sha256": "0ba3a1937cd58a907581426a5dfdcd3f6d0ebcec63ef0eeeaa333c625fbdcfab"
},
{
"bytes": 8036,
"git_blob": "7871fdda595d23c3645b417dbf96783faac9047e",
"head_git_blob": "4ee37c5c6514bdf541b20e7001873fb5d8e878f3",
"path": "packages/business/src/launch.mjs",
"sha256": "2fbc6643133110236814ba403ac3efb5782b1e5f3c305b71aedd582adab6f9b6"
},
{
"bytes": 14358,
"git_blob": "2acb92e417f32f9080396b41d1a2f565272a01d4",
"head_git_blob": "6d358631d81464dcac98ec0db2388f08e9eceb39",
"path": "packages/business/src/organization.mjs",
"sha256": "63ed59a21ed03514c2ea1b51db2e730831dc6a0cf38608156a92e6534f2495b4"
},
{
"bytes": 5708,
"git_blob": "096aa2ead37a18cfa17b2e2d43e19fb5604350f6",
"head_git_blob": "38b445803d13a05803ec91e11556346e868a2437",
"path": "packages/plugins/limit-check/daily-quota/index.mjs",
"sha256": "3dc8244502eb42b9d5b94d66bda7cb10f75fde0f83683e9795feb768bdd7072f"
},
{
"bytes": 3944,
"git_blob": "b20cea356ca7081a6cf571949a0f6aa31dfec89d",
"head_git_blob": "8f26fcb9c7cbcae4c6cf953a6827af53590771be",
"path": "packages/plugins/limit-check/token-limit/index.mjs",
"sha256": "a40c456dbbbfa010ca23b7c008132958e463f0b9d04088314db2a6a2a4e01895"
},
{
"bytes": 6826,
"git_blob": "5634a90664ea98022074cd9fff9bbfbd279692e8",
"head_git_blob": "04731ee91b04329a3956fd751f4d7fb215f845c3",
"path": "packages/plugins/src/loader.mjs",
"sha256": "49346a27e6b5487ba28770c5d983355f9fbe1e2e7921b0bcc50f2b4ed674eaf2"
},
{
"bytes": 1092,
"git_blob": "1350eb56b5947e759ec8d32f0c429813c352f2a9",
"head_git_blob": null,
"path": "packages/plugins/src/model-quota.mjs",
"sha256": "127fc77d461ef1d8f62d0686608ad954d96a8763bee3d5c4a0fc14831afd9d67"
},
{
"bytes": 10609,
"git_blob": "2c08be007564e5d4b223a7f93bcf4b36535fe739",
"head_git_blob": "d8f8d3db7928f034d7126d479f4255637d0f8646",
"path": "packages/plugins/tests/token-limit.test.mjs",
"sha256": "cf2da1bd44a1591a48a2e5daa690286fd3f9419bf4206703234f3280838ed021"
},
{
"bytes": 2827,
"git_blob": "7e1b0c1996b536deb0013d4d58c8ee1d2697ad8e",
"head_git_blob": "98aa6e8a2757e170dc2a27752e0b474a9fb3fab3",
"path": "packages/plugins/usage/cliproxy-queue/README.md",
"sha256": "06a8f869c90e0d5164a025a485a1e40cdef84dfe47926c5a3c38709494535c1b"
}
]
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,312 @@
8be7f2b7c210ff8ddf24d86c2e088da5827f5d7160326291f4750e4bb608e112 AGENTS.md
c4eb0d3a8ba06097c784ee6e9acf3bb24b4d01e93d7c5a596ace87b23ea30150 RELEASE
db1ff3fb9f411012d49796039eb0a967918a756f1d7fe962c1d808a2385d26e1 agents/codex/work/queue-333/r1-repair/CONTROL-MAP.md
e89c8ce76419b2858b698031ee138b7209f1132fd0d649138661f69d8cdacaee agents/codex/work/queue-333/r1-repair/GATE-ENTRY.md
0ea528625b42b31822b12987c46c761d9bf881f38904bc78a5365464115e102f agents/codex/work/queue-333/r1-repair/RESPONSE.md
7c95672a30c0d5c39189c7c7d610ada89cd539dcb9413617071fbb81200fd008 agents/codex/work/queue-333/r1-repair/REVIEW-R1.md
7f74eba656d8380410cd500af951832377681b21027a92d7c2bbcfbd8a9cb181 agents/codex/work/queue-333/r1-repair/build-static-packet.py
9a2673cc530a2ed046273ac351779e5fc5748ccd003581b7e8ef2eaa73b7597c agents/codex/work/queue-333/r1-repair/priority-guard.mjs
4888024bd2945787bd107c677e5791d4836770c1b8c135f3cf6f52dafcf9eadc agents/codex/work/queue-333/r1-repair/run-light.sh
0b1d09ce0b5d9cd7fddb5653574b3f582392367762d8185b994b689daff44754 agents/codex/work/queue-333/r1-repair/run-priority.mjs
6a86f7c1e32cf8b8bd176608fe1c8ae2f5b2c91e4676cc0dbd9bd452a58cdb0e agents/codex/work/queue-333/r1-repair/run-strict19.sh
c32f33ebc78f09a0549b0b0ba185771bf1cdb3149e9579204147f4b827a66a56 agents/codex/work/queue-333/r1-repair/whole-files.txt
06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1 agents/codex/work/queue-333/trace-inputs.mjs
95e2c9568498cbe628d62f1ef981dfb6819fc9acad0337086b67adc8717208fd docs/plans/2026-10-24_model-proxy-rows.md
3038d65cd3e42c858445d92ac25675f7c5ae66babef1ef79799bd17ae59f0b17 docs/plans/2026-10-24_stack-model-proxy.md
84e80f3bdcad8bd433951b503ad087705ee74341b374901b1eb8b3cbd6c04333 package-lock.json
3baab27d3fe178da625a3bf48c87790d7fa7006098dd568131d5ee9944ac11cb package.json
4f8057266af34f6c70ade88fc9bde45e2aff5a58ab3ee3b8a568a532385fc1cf packages/bus/package.json
a2ba3a46f12e56139ecae9e55227d00847842aedec50c1d92aaae28844ca48e7 packages/bus/schema.sql
232a1c77c2f17011c53b55fc6052f70985598210769d41d7c2c0b535328aad23 packages/bus/src/address.mjs
c0144adade79c2cfc6b8247721393f0250b1d64f6c6c04d85738cb80939c42e5 packages/bus/src/broker.mjs
ff927da3cf22fbacc9ace77b2e8b803bffc2953fb58cf7ab4e5f6f6493732996 packages/bus/src/business.mjs
f3d483f61a24cbc9cce235e1e92889f09b8cecf513fcaf90c741f316f62262e2 packages/bus/src/client.mjs
8b8609ae224bd7ed8e01be5a12c24c05291c7536723d7de9b8c9d1a46d630f22 packages/bus/src/console-cli.mjs
86b4321dd436b97e389101873197dbab95b3d2202e5ef7da712c4978f4f9159f packages/bus/src/credential-verbs.mjs
10485afcf94c29ac9f3d5ba30b12248a2379efd69185ff9fb90e9fed25fe0678 packages/bus/src/credentials.mjs
27d7d5322c2f12641e350867d3ac6f838b33832951e69f057e3a7a28b8ac4d5b packages/bus/src/gitea-grant.mjs
48337cdbc41d503f17962d3e3ad014183b1286165f97da6fd88b4faa50be3949 packages/bus/src/host-grant.mjs
324c05b16253e0fcfc1a0299d1d8ab45850ea723fad1f67bcc07fc031f50d593 packages/bus/src/host-run.mjs
271b9781d73cf31cc562a56180e3ebcd725b5fde148a83347a201fdef2fc28af packages/bus/src/human-cli.mjs
bb13c146717cdc46d75d157177e400edac4d3e10f14fe511027a25fd44cec885 packages/bus/src/human.mjs
56bfc8dcba476886d7de61a1e798aae8e3041c2434c62d44fc40a168d22bb3bd packages/bus/src/interpreter.mjs
9919febc7679168e0a72c0ef51983120283e595fea290a5e8e948409bf5c911b packages/bus/src/landing.mjs
83f6538a40d6b2a341e5755fa19992f091544746db47f1a25ae8d5794ba83547 packages/bus/src/limits.mjs
b753f630301bf125e9e286b4156d0736930dd8fb9cd8eb2ebf316688f9191a07 packages/bus/src/migrations/3b-3c.sql
179ffe356d4ff19a49b5ebad39b6c6bfd7771deb8e1b7c55b5e746f039d69e65 packages/bus/src/migrations/3b.sql
0423832d05aa68f9191d7362827bd19310001165b895fb2de40b962fe68f9d56 packages/bus/src/migrations/3c-3d.sql
d9aacc974d5047790e65c30a90068259bb9396dc92d4904eae3b9c5dbbb2f077 packages/bus/src/migrations/3d-3e.sql
bf0b72c606b1a56a1610f09619b0c1118f1f300c636824ea13fd51a4ca6ac4b3 packages/bus/src/migrations/3e-3f.sql
82f54b264919e34282bc214e34e9849f701cd3723b9b2f0a0d107c16f939dc05 packages/bus/src/migrations/3f-3g.sql
76168e4f9f6b427286ddb8402fd833acadb01d6325a85f60e9ccf8d42fe2d1d0 packages/bus/src/migrations/3g-3h.sql
e058e6cea8da7b6e649f3e03f2b81dc5444ee940a64274d0e367124c93545035 packages/bus/src/migrations/3h-3i.sql
5ad122ca950e43e066f3d9ed215e73353e6b26de6687b961a8818d69c9465031 packages/bus/src/migrations/3i-3j.sql
2e2bb1fe70076f5e24406a18a923b9e55c4192178a0a704a1b9716032676f9d4 packages/bus/src/migrations/3j-3k.sql
eb2822c73e527697399691ae520092277ddbd4d2a9a42a0731b3c81cc3569e58 packages/bus/src/migrations/3k-3l.sql
791879f06a3e97d3cfbe6112e2fb6502457af30b3e0198e3da1192038906d156 packages/bus/src/migrations/3l-3m.sql
b40bc6a7bedc459d6827cbf0414619e48fc5dce2febdeff70a647345f2281c3a packages/bus/src/migrations/3m-3n.sql
ef2711a80200686496ef42b6f154ffd44e3b5b9a983c38e20c19a5cd1a6bb4b8 packages/bus/src/model-keys.mjs
29c88655e8b9aed8db604573c9213fd9f3c40ef35ff04f4eda8fbe8f1b8a32d7 packages/bus/src/peercred.mjs
d1536a8f472fa5b3773adb10555529ed049ad63b647c0b44c00ce5f25ce09f85 packages/bus/src/peercred.py
2b1e18be825e8264b16506d6294863acbba812956cfdf8e056f21faaa94f7137 packages/bus/src/principal.mjs
ed13afdce6359df31d35a79496ebb4afdefef82030a8326a76b2a25b37e98d9d packages/bus/src/process.mjs
cec059ea4bef5ef62f6181123bfe64bca21d8985d5357471da8c0a3199a877f9 packages/bus/src/proxy-page-vocabulary.mjs
af36aae674f46a4e5eacfe176fde8b58cd0b171a6d70e07ee6d479e0f558cce7 packages/bus/src/proxy-page.mjs
f673bc899f1eea07bb016e77203abfbbf19890079913a52e6c16bf737d25e44f packages/bus/src/proxy-usage.mjs
311e722440e1ea6a255b0b2c3788a66299e1f27ed379e41463e4447b659df553 packages/bus/src/runtime.mjs
8318bed9168ac3f58c09de40a139b68aacefd684e6c117406e181e2ca5ab4ec7 packages/bus/src/server.mjs
dd7fce9706402efd1c5a5b81f7d0fa3793de203e7a6aef4e118e934aebdc7c84 packages/bus/src/store.mjs
c04c434ec76252fbc93fb047e7a0c996225590e805f2c82a8d521c161cc9b80b packages/bus/src/tester-cli.mjs
5e9e08ca8069e1de35232f26d48a77792388128dda659893909f2d34b5af2346 packages/bus/src/tester.mjs
4ae57d053c4b217e1c1a22ada3ed1c5d4a3f0e61b8d2798e9db37997cd071a29 packages/bus/src/usage.mjs
38228759eb2030232811669ef44a3c89874c80baf1f6af1da933decc1621e21a packages/bus/src/user-cli.mjs
1f31aefa71984fba90c5390df5cc595d929681965f57485ad4972143d5c4b15f packages/bus/src/views.mjs
68efa3c9d0a72095f503208ed5c2e660ef9bca68d3ea15f0fc2f1826a68e09cc packages/bus/src/web.mjs
dbbfa80b4082fd44e2f08539b5455653fac062321b8f2106f638e2d8161fa3eb packages/bus/tests/daily-quota-runtime.test.mjs
da07fe8a464e636040eaf676131b2482732f40fa9d0e89d4a413252d9bba4193 packages/bus/tests/limit-checks.test.mjs
561d0950b788d08ad9a79ccd6572ad6976ba4b2e2b1c79d1e4d06827a84c131b packages/bus/tests/limit-stop.test.mjs
a2e553025edbe6e930c9d03b48289c53b51b153ac9ae49bb21bf721b725f1913 packages/bus/tests/limits-runtime.test.mjs
a8038fbad6fc666d5d033da4b35dffbf5f679eae6d1d6e042bea8d211c298360 packages/bus/tests/model-keys.test.mjs
8a7889bb9aacde4faced9ab97faf6603eb7c5f7e1b78df9e5b28279c3b5ebab1 packages/bus/tests/p5-background.test.mjs
1d57b286993b4fe7098433703462c1e5bea715c5e4e88c52f6676cc1757fd153 packages/bus/tests/p5-identity.test.mjs
0c55ced6c8f30dbdc6572705f831a5c1a3375116cc169ca3005d36eeda35e737 packages/bus/tests/p5-key-compatibility.test.mjs
6326f25430a4185e7031b5ae9893fc1ab20caa78f89b92e10266a93f165ab0f6 packages/bus/tests/p5-key-context.test.mjs
241e779016ffd0b54c5646cb4fac7e21ea1167e77afbd652ff4e01f8d238f99c packages/bus/tests/p5-runtime.test.mjs
0ba3a1937cd58a907581426a5dfdcd3f6d0ebcec63ef0eeeaa333c625fbdcfab packages/bus/tests/p5-telemetry-fixture.mjs
895ffddbcca1b38fdaa17eefdeca9092a9b9a934d3a54a3bf7857f42fe99fba7 packages/bus/tests/plugins-verb.test.mjs
84c8351029272b6ee05e7fd81b4cc4453553ceeb7a5127a1333dae63d1336ad5 packages/bus/tests/proxy-usage.test.mjs
4b2149ea4219f49db19669ada9f88931f7691cdd73dd27dceec6e8fe1f76dd0c packages/bus/tests/usage-broker.test.mjs
5abe93fca8442f06ff68760623e91262d863e1191fa35a3d0c87d7b0e6c0a4c6 packages/bus/tests/usage-runtime.test.mjs
2613ba0561572a7d4f753066922fddc90cca812cb0ce2b3e0a9a4d249a15e340 packages/bus/tests/usage.test.mjs
0e15a5be600573ff7fa0b41c425ee6e57dad788be3d42991185c3a84d6090fe9 packages/business/package.json
af028c999a6ab4d42b321c3f047e683b226c7ad232a2ae9cfc623b7dd5a4dd5f packages/business/src/access.mjs
aaa4578fd4133f64119de6c8786a14759240a8910677529fdeae57173058b7d9 packages/business/src/business.mjs
c3422b1e144177f9dd3015ac036ee1d2cde02bd2b3be406364f3b3f45d8c9b73 packages/business/src/credentials.mjs
cd4eb5960c17ce32f26d1a49196866ce04efc42c1d90b18b046af5fda8b9ff0a packages/business/src/errors.mjs
e08b11b70b54f13e3b18996dd903f841e04fd6c64791e96063df8b164c663882 packages/business/src/hosts.mjs
a386ce5bd1d41d86f7b90641a423a2b651b491c8989d5085412c7d202ac1cb30 packages/business/src/index.mjs
09f2bde85a6d7a8f0b1d1c60ac589b845b0c95e991b2f807758878416b13c6bd packages/business/src/instance-settings.mjs
e14d73f719664499d809909962a6ecc16d4ffb9d824fcdee699e0778809d9e96 packages/business/src/launch-settings.mjs
2fbc6643133110236814ba403ac3efb5782b1e5f3c305b71aedd582adab6f9b6 packages/business/src/launch.mjs
93a7fddac9a08b5f740a0a277b29b8a3459e6f5a4fd33a37212437cb456b9b62 packages/business/src/library-seats.mjs
44fa089c9024934a2f9fb5ef99552eb18d616842210cbc0fc860ea32ce0b1524 packages/business/src/migrate-launch.mjs
63ed59a21ed03514c2ea1b51db2e730831dc6a0cf38608156a92e6534f2495b4 packages/business/src/organization.mjs
9d2c68dd21c6c9553af75f4b137c4f169e95761f32528767e0518d0313311f50 packages/business/src/plugin-settings.mjs
9472996134c520c31971e66006d1c1683709f6df4f76fe3445bdc97a18637eff packages/business/src/project.mjs
712183465fee099606223d84423afc54e3386a0c8e468c68d5ac39c1e676d109 packages/business/src/resolve.mjs
b10af84d7422da4d0e8c0a4fea1064eebbc2fac6a838a1b3939b554e22dedfc9 packages/business/src/role.mjs
e1f0e70a4bbba8ae2ad6185ab61770b15acda403e90fc708e13027a1e9ec663c packages/business/src/util.mjs
f6b15ee8dad2d985c0ae66b1f106ca46cb56ec86ac8cd5dec8a05c887596a421 packages/business/src/vars.mjs
de1f04628e400084a46e77fd7e03c7a039f0f80c9e07bb486c9c012f187aa3eb packages/business/src/vocabulary.mjs
a6a9971b42ddf176d9415caee3efc2eb16791dead5f0f0557d28449a550aefa1 packages/business/tests/helpers.mjs
f0dfe004905dce31317d85d89a05802db878c3472e765e85dc9f1e04166e1df6 packages/business/tests/plugin-settings.test.mjs
bc6b3a31e8918d70aced7151b91ac4b39afec4081054024b162acb0e8f8fae07 packages/business/tests/token-limit-settings.test.mjs
6c9c952d8637206697bc3273f2ee247185cad624b3db84fe4d2ead0b5c1013b3 packages/cli/package.json
c4949a16173d11f9d32d10d3ddd58a181631848b259bef1998820a78f5694808 packages/cli/src/access.mjs
15a8ee212fc37cea28e389f60ddb8916f9e1509cdcfb2e522acfe548702a16dc packages/cli/src/app.mjs
147a17bbdcbc34efe20a88a4cabe796c101cb63dce621d28103f4de29def4cc2 packages/cli/src/boot-status.mjs
1e663b175e18e39ff68c9ac3a65ff71fc777a6c37ebca035fce6a2783d0aaac3 packages/cli/src/cli.mjs
d960c2a9df3f7c84deff22dad1f0ab120f95ee365984e390de98eba7292b65a1 packages/cli/src/config.mjs
19755f7bb002d8455990c5dc7c458e64aeb95252ec7231a2ed2fd9c638fcb511 packages/cli/src/credentials.mjs
c7bdd98a3ddeeb9bc4415d907b92555d723c566eba314075d91486da9b5e85dc packages/cli/src/errors.mjs
481d9956698df7765ca8556d57164fb78f131708a09900d5a55b9048b5638f5f packages/cli/src/format.mjs
3076a53b9891d4d0e084306567b88ded12c4de53a943c029646a424bf59d8e49 packages/cli/src/git-socket.mjs
b586907ca8f351f60dc19ec2683df75d2d70ddb12955d09fb14560c9d3bed3dc packages/cli/src/grants.mjs
a0936aee783ff47dd58fc907fefd86f63e571809a3ce5b0d6d931f71e756b15e packages/cli/src/host.mjs
60419503898f5e7f3046df5e749098728fbdfea76eb5c53b5dc9b909329abe2e packages/cli/src/hosts.mjs
8d6dab8da62b4458477572ca1956adad57bc0b0d308df6eae57477175c345d7a packages/cli/src/instances.mjs
373d4c028dfa6d85c748d56f56359789fe2b81987f522ac23747fd37bb5478ed packages/cli/src/launcher.mjs
2f291a71f490f2741edada7a3e3788500f8976a08eb8ab1411f6c5982f778260 packages/cli/src/limits.mjs
9a043f122e1d49103bab64716d0eb80cfc09da3c91f7e2eb014b0d8ff0b02f3d packages/cli/src/model-proxy.mjs
0bdc91dcaa096bd3dc9d08a1dea59893a21f6505c843e698ad9c8daa4b74364b packages/cli/src/model-stall.mjs
b325b4f5133d40f8b1288e666ef36c5890f7f3a3de20f1dfc1ca27ec172a6372 packages/cli/src/notifier-process.mjs
400f4af8c72915101e00f25c0817534a34e7fcf29f960f5cdd78ed9884707f3f packages/cli/src/notifier.mjs
f8d9fc24ccd71494fb2914914949cb08948ae93fb3180b9531eb807c921a6f53 packages/cli/src/plugins.mjs
6cfe7fd5086ddb59c5666060c6f8044c2852e0f3d5755b1fa206f7521173f300 packages/cli/src/project.mjs
9d03335628ae62e85c5fbc08c2e739ed0bd43b10d486faf397129a56a1b343e0 packages/cli/src/screens.mjs
1a30048032f5bb64419ae9716a1692978bc1a137220a094d1900298aca6ba1d7 packages/cli/src/session.mjs
58888b7731f8009d4c3f8be2caf4445f13dd8f534e1633f6e2720b259fcc3f92 packages/cli/src/thread.mjs
662642a8ce739fcb6c188ad07125a94e008c8a305eced127c8041d472c56e55b packages/cli/src/transport.mjs
f9e0c69849633ae36a7a6aa22729a690dc40292178ac3db43accbb131fd7b4ca packages/cli/src/usage.mjs
1e1aef2c74434e388d61b03407cd323336d20b7ef2106893d16a39638ee12a64 packages/control-board/package.json
8966f1f98ea81b4525345fc4889db5e0e5263ca41b5132ac8dd9bd99a2c88522 packages/control-board/src/discord.mjs
6d74b131af360268be748a1f8f7f2b3f5a9180365e7279426640883fc295a676 packages/control-board/src/scan.mjs
2eb25c46e85ddadd3bdbdbe605db54a6e09845155384a209622554d78307e583 packages/control-board/src/serve.mjs
2ed3790eb877414b8e985ca16031d8963adfb5c9555d415efb76288b76a5e1a6 packages/conversation/package.json
a45beb82438bb42d97d1e322010e175e785767664e548b90c4125e98b7660003 packages/conversation/src/client.mjs
eaf0772b60bb17fbf9548267c9cfeb0104f92f5cbafdfcb60c1633883eec6432 packages/conversation/src/framing.mjs
da336ed2a2a149ff56ac12af2440a8353d4573c33e9069381be60f1a0ca70151 packages/conversation/src/parts.mjs
20e781240846298fa65f9a8226b5e1ee1e81338b81229334666d845c17c99ac1 packages/conversation/src/pi.mjs
75d0cc982c36b0a81ff23f0da9da1b56906c496250a043f91d3a3b18ffa8e51b packages/conversation/src/reader.mjs
96f7b64c2e2c3493e270224542818fd14f042e3cf0ac14788b3f881010bc25b1 packages/conversation/src/records.mjs
62b0f7e9f798f584fcc0e4ead0522e44fd113bd0803f2bad92ffa480cadb7527 packages/conversation/src/safe-fs.mjs
c24d28a073659640b8b027eb12ad150ba895c3001091b892ecef2ec1da40d5cd packages/conversation/src/terminal.mjs
f834ee740e7149e7d2ed976112d0719ce0660270e3b61cf93e1774d112c992a2 packages/conversation/src/transcript.mjs
bdbfc8073d2073dd2ca4cb1460e3c376f087fff387d053d883932e5a67f85948 packages/discord/bin/git-credential.mjs
a52c6bfc9bd26a3b021d3a96bddb0f5c45845d752ca4579ef04ef60667f110f3 packages/discord/package.json
5ab69c4111dd9589a197172ffe6968bf414f41c552b7910e5478a27c446cfaec packages/discord/src/binding.mjs
917b0e6c4f100e93f056b925e38d97eacdd8b2596e39fbd3f88c0b62b973d8ed packages/discord/src/errors.mjs
c28e04a0055997ea0b34bea1ad2912adb248d5fd43713df1e6f5a661d87949b7 packages/discord/src/git.mjs
12684e926574c3fe7f693a03b60d1393df483f5feb4b47c9dd7c5a7ac050aec5 packages/discord/src/journal.mjs
aa7c1e328d6664b53e4d9cb5a1ab83c8ff71cc31deb9d3ce91a7dc6715c887aa packages/discord/src/notify.mjs
8fa9968862dff77fa6d8be5210c22d13712fd622a8cbc722d167be5be80d0783 packages/discord/src/processing.mjs
0b0b8f4dc25b8fbd4d948c962453c63084b0797b0ec5f0420e3f4f174837ccd5 packages/discord/src/rest.mjs
ba09d286e707860afa53300f8802ac8e6193ab2d2e7abe9d2b07cbdef3822387 packages/discord/src/setspark.mjs
975503616245bb6051f06ecbf47436ce7d030f21af23042df7f3341062df967f packages/discord/src/tools.mjs
e5a7b64720872b12b34223549537ace05ebf0ca8a29b2f844d2b7c5cc9ea41f7 packages/discord/src/web.mjs
34ef8212e27f052223443c66830839517f7a54ecb6ef7d85795b3e89c65b4d4c packages/harness/package.json
e944a4c7a26d1fe55e13ac1eca31dd86c302dc7c868224b8b000b27255976153 packages/harness/src/bundle.mjs
32b5090760c95eea0e1232ff36ec13a1d9b58335b2eade621196dec1ebdbe784 packages/harness/src/claude-gate.mjs
a74ef2db4093c0c797ba9e7e28e4e4df0ceac9040385f00e60a273f39af9610b packages/harness/src/gate.mjs
ce0107c3b21e07925b6543b6b925da8b8768823448d4fcf30b620883cfd2d39e packages/harness/src/mcp-server.mjs
fcba4b8dfd9dde947a79f88376d880f383e2a04ee3c0a9ba2fa5af641fe61b35 packages/harness/src/pi-extension.mjs
38fe84040a78c3f8a8dcde4339d88db3b5df9ef669d605ad1d92ff3e8b646b40 packages/harness/src/tools.mjs
5c9b528fd69a2493f04933fc84f352b1101d276d69d9982806975def614fd740 packages/library/bin/askpass
f6208a6b9e233baca38dd0ed9fd435cf2c7a3e34160c2c07cea1fea66893513b packages/library/package.json
f710d9600a17f6e2989a289cfe84e58f161d86c7306605946ce05fa71b364eb2 packages/library/src/guard.mjs
70c1fe75cb2149c9a074d55a6301d5b66157c2dc2e777b92bac338cce09d89c7 packages/library/src/index-build.mjs
98c2c2877549c3e2c5963ec4e49d99ab3b6d6ad54fb3bfae86cf98542207157e packages/library/src/index.mjs
98ef45ed61144aaea44d8aea1ac43082b6d340297e46846d01772da38728e530 packages/library/src/limits.mjs
def32a176cb70c86248e45908edde22f9c4c5f88575a4af0a396a05f617358bc packages/library/src/links.mjs
c83c626c7cdc2a00ba4217c34b889ca0517cd2022d1f8fc9e7d3a14a0293a802 packages/library/src/mapping.mjs
26b824d6885e5c6d1b8bd71e754a9fa333c26307693f7e6a0c6a8e6300ecb4ae packages/library/src/mirror.mjs
0c8764b03dae0150c56af74bcb113cf583dcbe1fa0c6f7386ef2d48d59a6bd31 packages/library/src/problems.mjs
bafe113bee70f17bd249876d6bdd1c08fa051223c2111955e5d5f275bd76bba0 packages/library/src/query.mjs
ea126533afb7e74b71419eb943febb6b242eb96fc6917d9df1019db3e7e6ce8d packages/library/src/reader.mjs
bfc3de029d3c8f0dcc96c90fde30d6da58bbb5b72d8f13e3f536c0d735c73ca5 packages/library/src/render.mjs
7b46f47b5e9d6b554b5d39bce2cd95c4610f5f35b8ab8fdc5a2864b3214be809 packages/library/src/reply-protocol.mjs
97e12255f52ad638eeacd152eb26822f9a2aa72cd30e2fed1193f51cd6e56192 packages/library/src/scope.mjs
6a3b4de2070e62b1cca1c0ab20f2883d3153fc61608d1bf7670cecea08765b4c packages/library/src/supporting.mjs
016bfa5c80572c0baf90ced39cb3d3ec66d395f0be15c2727b9552a9dd849093 packages/library/src/survey.mjs
a58f3aec5ed9b3530b363e2fdbd38bc9ded7635d261ab2fca3cb31c45dcd3dfa packages/library/src/sync.mjs
a301b7c7e3f42f66cb69d88991220f4e236f25a6e5951c61e79ec4ef2b714198 packages/library/src/write.mjs
889ac9589fadf7654d4dbb914f968cbafe4255ed215bd6a9ff3f331757c9017b packages/model-proxy/PIN
8fbfb3d1562e9ea824a1bd399b17cb2048c92b125e7699ccf27abdcc6e31e40b packages/model-proxy/package.json
f5f86cad661034f223a76352d877fa8d7883bfa921a7a01282347a9a03272441 packages/model-proxy/src/client.mjs
a6fb88352018b8f21593a0bb9311f87162c80d8b1e05e62b4d43b1e69af21b23 packages/model-proxy/src/common.mjs
00378d2ea95ac4945899696462f8ff4c70dc020cc58d93663d731d2f2f333783 packages/model-proxy/src/fetch.mjs
1eac4b5741b360a077bb1c871c008b64f7c7119afc64be4d6e4a0dcdb3a313bb packages/model-proxy/src/settings.mjs
e66453cf6662677cf28cbad1ae8f7509917d333e5b80404ab02c53f5cf75e9e1 packages/model-proxy/src/validation.mjs
77327681d6eb51f25d7aeffcc532b7e8269c1dc59139cb03adb4a3a1409f63e9 packages/model-proxy/tests/client-probe.test.mjs
790c6a50ec030a8b27a28fac7fd129bd9eabe79774adf11d6620c00df9b6ae86 packages/model-proxy/tests/client.test.mjs
95e39a519f7ac8b9592876e6157191169f9b14d002163867a6ff6ab808e42c14 packages/model-proxy/tests/management-key-encoding.test.mjs
f24e1d121a340cbcaa3f6cd6390eeb7d4b05f778dd498d76ba099cba5a719dea packages/model-proxy/tests/page-client.test.mjs
1ad66d56800a31cfbd387939e640653bc72150f4e73822d9e3c777b3bffbf1e1 packages/model-proxy/tests/usage-client.test.mjs
5e7e1ec169392ee3065f8f47d19732ebbe8bdd90f9193581425b956e66da6b73 packages/plugins/channel/cli/index.mjs
789132601745a94027f9e9184e7fef1f70cff0cba450afed5cca647f683591f4 packages/plugins/channel/webui/index.mjs
a317ac544359d321bb91b67cd87fc6ef431b72df9ac9f7f2a9ff291ed1a9109a packages/plugins/harness/claude-code/index.mjs
aabaf5c4602e28f025c18b2e2ddd6fa0d1648870101a5de0c4424d97b24472dd packages/plugins/harness/pi/compactions.mjs
39c225f157b8f66b416625bda689153505743ffcfdc32964bb1f3d2c6fcb73af packages/plugins/harness/pi/index.mjs
3dc8244502eb42b9d5b94d66bda7cb10f75fde0f83683e9795feb768bdd7072f packages/plugins/limit-check/daily-quota/index.mjs
a40c456dbbbfa010ca23b7c008132958e463f0b9d04088314db2a6a2a4e01895 packages/plugins/limit-check/token-limit/index.mjs
90a9ac59a9ea2287e9a3d4b2f4286d025e727f2a6ce149464f8d0420fd9a8ef1 packages/plugins/package.json
8be381a7e5dc7dd5ad18e89bb17f17d4b7074bbac490331fc61c65ac2b824057 packages/plugins/search-source/harness-builtin/index.mjs
92618d0cd2f1b79c7d0230ec0ecd80ff628744524847d6b5f33ddbae9d7a3a09 packages/plugins/search-source/searxng-bundled/index.mjs
fe4603b69596c3758ef8d7f794e403273e24e0fb950a92f15f8e651e193955ec packages/plugins/search-source/searxng-url/index.mjs
5fcecf8336ee247e8ac2f626b21e4c79b1edc49082eadfd536cd23016c6bb756 packages/plugins/src/channel.mjs
eaa258a1aadadb5a75450fa73fdbcea0b53636adb50ed9a508193d29d564ca78 packages/plugins/src/kinds.mjs
49346a27e6b5487ba28770c5d983355f9fbe1e2e7921b0bcc50f2b4ed674eaf2 packages/plugins/src/loader.mjs
127fc77d461ef1d8f62d0686608ad954d96a8763bee3d5c4a0fc14831afd9d67 packages/plugins/src/model-quota.mjs
3d4fab56fea4c45c6a317ef41121aa5b6da0502a6ef614b7931f91cafdfc1f71 packages/plugins/tests/daily-quota.test.mjs
5d5e5dccdae3f94b8540d187a8899ec36f9c9933cae3933249c2d8c400c75aa2 packages/plugins/tests/helpers.mjs
f3081e1dbdac20ade2246c743bcbb3934be686f79f378af21c365cd1451893ba packages/plugins/tests/kinds.test.mjs
8588ad7eee0c9ce5de3b53e3b88562812a155a3d791a2bd3413bb1754655d78b packages/plugins/tests/loader.test.mjs
cf2da1bd44a1591a48a2e5daa690286fd3f9419bf4206703234f3280838ed021 packages/plugins/tests/token-limit.test.mjs
d09ae19db3eb69477783163559bd6a8e5b59a6f5af0eafd62d0e2e3bd325065e packages/plugins/usage-source/transcript/index.mjs
06a8f869c90e0d5164a025a485a1e40cdef84dfe47926c5a3c38709494535c1b packages/plugins/usage/cliproxy-queue/README.md
6096a577cd5d7e8bf84fd6b98ab284e2f47d5facebd027548e07e6aeec442f96 packages/plugins/usage/cliproxy-queue/index.mjs
83aa9ed92f6ea3e1f68a6325ee61250a3167cefb360fd7154b89ed026b1aa8fa packages/processing-control/package.json
781973277c09133de15fc39be35b372a79066479097d46923c8ab7782f011dcd packages/processing-control/src/containers.mjs
ddc7318297abc4ec4dd03d425820b7323db609e554cfc5341cfdfa6934271e73 packages/processing-control/src/coordinator.mjs
3bc600649267f011e21ed8266fb16927b0ad3a0e2c49e4b54062d34c544d0c17 packages/processing-control/src/effects.mjs
7145420aa354180689a5c84423928fc60c8123476dcfed3364c9cf4542f8c7ea packages/processing-control/src/runtimes.mjs
ed834770fed863cb0c15b75062de1fd63dea940f3b42020b769a7e62b319c8ed packages/processing-control/src/state.mjs
13664e88d0f233bcf18f05e75946e70a1f2a7ba8d099248b73936230cefadd8d packages/project/package.json
925bb03ac99e5845e4bfa20b4561a331f034f88e187db82213df6602a7ceee4b packages/project/schemas/decision.schema.json
f069c012e9660d5d0491a21f98e936b725f6818e1c3136dfec61b3c800bd58de packages/project/schemas/project.schema.json
79a1e7b567af7162bb88ca69861075fc579a858e8aec4e49824ccdc370b690c3 packages/project/schemas/requirement.schema.json
af6865a4cace92ef27910098507ffedfc8dfe768cea088b1fee21d0876cc556e packages/project/src/git.mjs
3ab38cc40ce9ed1a714a59a1f2c336c3792a59431a6a9cc655ba6a2f47513899 packages/project/src/index.mjs
bd9debcf3f9bb92560e74f220a0b108dfe24154bc6d1fb03c5ec414356d451f9 packages/project/src/paths.mjs
42113cd20eb8f04dd252f9963a6f1a84806af9cae7beb6808c4d584a2548220c packages/project/src/read.mjs
e49ab5e825f0706da2f3c8dfcf33c1331a38d77ca2d35b03359ee68ea74652c5 packages/project/src/validate.mjs
24b7e3224dba45753e2d6139fcf05d2ed8c29d999752b02a637cfb8489fd9e0a packages/project/templates/north-star.md
26ee149f870ff56ad6d1c3d7c3b4b2301879c59f02d5840078c07e7964cc2175 packages/seat/package.json
5aca02491fe8df51487968ce62c776d493d0fe693cc41478b84bef7b49c8948d packages/seat/src/checkout.mjs
c5de99284b8fa61763b8dd30a58809bbc086529eeb10587586d52b0df2754774 packages/seat/src/compactions.mjs
6f7c938a32b349ee49ce95b89ad499e599f6016e5e9d7efd79a9ea4177b4d175 packages/seat/src/landing.mjs
382cbf7e0ff336911e288ce858bdbfbec693bc2b69879720d1f0b4c7d8455198 packages/seat/src/proc.mjs
0868f393f6fb117d430428ec390e435359737eae0792b4a4d1f54797c7a6c1bf packages/seat/src/sandbox.mjs
eec970961a667c9e614d1474d33c31a019b2cf1b0bf931a51458d874bca13a15 packages/seat/src/seat.mjs
c37a6ef6f6d2b4e61443e77d800656bf31e38913bf7dbdc4ca955f4a83b13a41 packages/seat/src/session.mjs
621f5c223811444336f0f5d6ad10bc7afce075491653c0527d6c26ca568b79c3 packages/seat/src/working.mjs
2018701876f26c0566307335eae992efb3551b75af200b7c249b615757bf311a packages/tasks/fields.json
269161444d253da7886d83f7b2f7bd79792b6c6b798c6e72f05f69bb99ad5295 packages/tasks/package.json
80b58323994d70e8bb496d81225aeb3d2cdfda464654b68b3b082e9af1fac5c1 packages/tasks/requirements.json
ff0f30ef6b2f4b758082913c34062d4749a71c157e994a06de692bb70dc8014b packages/tasks/src/adapter.mjs
b5580224e931198c7024326135db5bd4f660dfa42834f19e4cd3c08550845bc9 packages/tasks/src/digest.mjs
c9a883e9a1649277edce97adca40bca2874df7b5312c70e4ac6f6d4a1c860841 packages/tasks/src/fields.mjs
38e7b85650247759f06c09fce205b2970b8368bc81491f51dc6b3c90ba2a846d packages/tasks/src/requirements.mjs
c538cb5ac1c9bc96c50b8d6ca01136361369ec463606684a21d81e3b5c2e46a5 packages/tasks/src/startup.mjs
39887268258c3b651246b3596a866005fc193cd8ee5f151a02492967069f2d06 packages/tasks/src/sync.mjs
1c10dfcd37b0435e199aed2535b71909728ef358dc145ca9eec4f5beb37bfb87 packages/tasks/src/verbs.mjs
0d76911dac358d195be4293ae03ae53476ea4d1b0fff4fbdb1a2de33f46ef952 packages/tasks/src/vikunja.mjs
0bb346f598380c2bcdb39db92a006959442d3ce5dc645503ef76405aae53311c packages/webui/package.json
c521be48ddbc473c61431424838cb9c6d67a0086082141000882013bde62379f packages/webui/src/access.mjs
4ebf6c2b5d71c23d85cbde83f69aa671058dc2195c9ae4bdda624f6940729d1b packages/webui/src/bus.mjs
3a5321a5f492a98d342e4ddcc1e9da3522cfff89a4f9bc3f51d2ab1426d3de1b packages/webui/src/chat-http.mjs
fe2072a7198771a82f58dca5fc05aa4d697dd3db25a206fb2a24c8514010b069 packages/webui/src/chat.mjs
5988c015b7f03b56654311039874f8c42a1d93012b330ee389a42fb88af70279 packages/webui/src/cli.mjs
79cfb474308d148293b702c0132927acb31ac4f1400fde9a9ee78c99a7a558af packages/webui/src/console-bus.mjs
93d4d0c36d0b74eaace24bce4c3e7179b7418377eb4df6d0f6a9ca89d5eb8e39 packages/webui/src/decision-http.mjs
c3825a02c3b4f4e5537db4a945439d707e177e74c3e8b1fc2cb777515e610b64 packages/webui/src/processing-http.mjs
a09028cd5ca57367f597d0681e84926ca871fd4626769e9947927d949c2b6ab7 packages/webui/src/proxy-http.mjs
3c7a35e25b4c1cfda19ac9466d4b2fbc86c880761a1d04ad3ece8bc485f60f93 packages/webui/src/public/bus.js
46defeb3b4be0e1a22e4b89445872ad6b15cdee182076e9e6222219ae29997f4 packages/webui/src/reads.mjs
7b7bee91604b7bd973027b177de83205db9aed366e694072fc6343b46465b5ba packages/webui/src/serve.mjs
37b01ab0479d5f2a7ab9aac790931c6d88c790465392d9c0b65a105513f3e36b packages/webui/src/sso-config.mjs
9a3442739e95407deb0afe3e2a2aa77741d40f3eb899db985f45af49c38b34a0 packages/webui/src/sso.mjs
1c1fe0c795adac97f28502564a75f26d5666d9be5ae51169f7dd5bb7741fad16 packages/webui/src/tester-socket.mjs
b35d3f3471d6d83ef2d19d6102eaecce2ddec9330f337d7194f1d7be03cbd216 packages/webui/tests/fixture.mjs
39f50991578b98594183390a00efbca84fda90ef61617eea4215e2c75f90b82c packages/webui/tests/usage-render.test.mjs
f96d06974bc83051c0d5c9000e38161ea0cc231997410bcc6c42ed7f55718dfd packages/webui/tests/usage.test.mjs
5f63ff52aaccf06a0f2415ffdd9d1903c202679cf953bef5266a6841b5e39ab7 roles/assistant.json
7d2d50a1278c62daa4f6c4a5ac7809817409f2f1d0d75787802300739d3fba15 roles/assistant.md
314074c8081953923f962f2df045d4c14629010ea99d1f23449ed45294b46bcc roles/chief-executive-officer.json
a6bc3aad543cfb3a03f93efda60859221c56f78d0f1094da33afd458399b4ffa roles/chief-executive-officer.md
539d531a0f5744aebb933ca685b52022554e3e93ae54cc8b67e4de0eb27d3460 roles/chief-financial-officer.json
09347759baf8fdbf0a8105106e8d27b500f3d0b76dcaa91dc2cdc20b3b000b00 roles/chief-financial-officer.md
8ee8e7213d4c073e2d9ba7732fd84b3b3130d9bbb930d07595b7f692bb9fc5dc roles/chief-information-officer.json
0a7041dd3ae5f05ba6f37baa2aeeca35a430ed3e387a3e2407daae2c431efda2 roles/chief-information-officer.md
a550428603979f4342e57ad9ccddd4d2e44a5203a64f19027ce09a24f1dbfc0e roles/chief-information-security-officer.json
1da83baca46abb75c6b2e74df7a3fb9424e1556ce37ff5f8c7802e85100d6b16 roles/chief-information-security-officer.md
3cdd799159d3e676529efee01f467a4ed7d67920253cddba2e098566368a1e36 roles/chief-marketing-officer.json
4d414c02485b6a83f9d8fc2498a53d275019fd45e9ad948fdf61777a3a983bfa roles/chief-marketing-officer.md
c781c4108824db7f17cc4b514e3b0d446120dc1ad7c05e5bf5a72edcac70d054 roles/chief-of-staff.json
db16c358820e199910eabe06f885a53a4bde2502aeafa5444c12d9b29c74880c roles/chief-of-staff.md
13713c4e64ade3b1b1eedabed75f5f76fe65e73f6df336b771d1e34881d111f3 roles/coder.json
d29d469aaae2a97705dd0d5b057b6eef20c5f22d37791aaee9d886c8bb46700f roles/coder.md
962f1e8ca9d56d7ad7dd4f82a57b97b834bacdc72c3fe774f9a9afccf7dd72e9 roles/companion.json
cad0360c16db9b2659370e6363937a27d61e9f6c4fae711a2dfc5b89aadead81 roles/companion.md
42e751413a649e03c5e1eb87acdf59e0a0fcd54f519bca297463f88ee07e3043 roles/conductor-policy.json
031807451adfe5e4643da2ff59fab0a041fce519f4cb84d749ec6f10edff8f36 roles/continuity.json
75522c66ccd242971b4b00786112ef37b41c972af5b0d98c011697169fba7db2 roles/continuity.md
60b6482a29a578234b4e5bf0d4c9a123bd3a65a65dc6e488f474546cf4456bb2 roles/cto.json
b5603cbdfc1a79d4b986c97aa2a94e2c57164f9abfd5117b348086025dd50993 roles/cto.md
1dfc6629dc70dd8020483456db140751010e81a44fbd49308580f0c6356c2471 roles/fact-checker.json
2d01f771831d52a1d9ddde8c1183601051782efd39899605949761fdd5e07291 roles/fact-checker.md
2c69c26460574948584eae487e944b7240cfa37a0a0f3ddeaabd682815ebf6ed roles/ideas.json
bb403867a2ba33ea271d2d576165c6131e43446f2d5deb4eb86389398cb0592d roles/ideas.md
14dbbbaa98670ebab8612555e3f813793ff12caf6a3aaef3883c2007ebc9bfe8 roles/merge-gate.json
b8bbccbf7e10e090f3514664384cba44c86fbb514c79d182d31a209045fdcc1d roles/merge-gate.md
1af1cb70512163eb5c39ae942496a4cc309b0b1d47b9cb48253ac788862f0e9f roles/pm.json
d1016f8c34ee04601ab751c7514a20dfbeec0359d46dba8f94c44538dcc16133 roles/pm.md
3a55947b867241dd42b78588276f6f901d374b519f3964ba0acc4b782513224c roles/proofreader.json
054f6f888064eca4c6b7b1c0180bd2ad968b10429f045db7aaa92453cbddd1ab roles/proofreader.md
38d36d8cca7f4f7141af5469f0a17dd2a44a5ec26ef113ad9a01c9b013968501 roles/research.json
2a66291a7a8d21b9f587c6226d408667a775b2846bc9950606e73b210f4ac0d1 roles/research.md
3b5f0c39b72eb1ef1d546899ea5b02da6ce0c22a5d30d67058530b1bdc67964f roles/researcher.json
4d2b2ab1208aced3a82d7de1ace879574fae2930ac1bc684f76e1d16e58cec8f roles/reviewer.json
f7418c27a5b84f258041b87e87ccf9f441fcb9c638a322e50aafcfdb0ce7f364 roles/reviewer.md
d84bd99dda657fc44b6272cc35a89c490315117c7102d8936042ac1cf58978cb roles/security-reviewer.json
eb5ad42d4fcd98a2c89afb8b2286edc5eb666f993e21fbbda838e5c472f34dd8 roles/security-reviewer.md
@@ -0,0 +1,17 @@
3eb9b8d10445aa328be3b854385e4792dda2c5712b19d443d485d1b00a18d0f8 INDEX.json
9b64bfe45f20f59ae62812529c5f4ef4a41f29ea9124cf42dd6e9c32f5089711 baseline-controls.patch
add6f177692f774a0a4370c95d28d3e72a3aa4e76adab886ed6bdcc01a965e2b baseline-input-bytes.tar.gz
9f18698d9b327c8664461decf939e7fcbb6a756e81f93e88dc1d2d51511a7ea8 baseline-inputs.json
a287f6218039b825bb84c5902d68f0659cbedc9c89d5c2cff6e63fd0a64dfeed baseline-inputs.sha256
f3808e3a13fc9244f2301a8f6237fd07d5ed62f496765ef6c281f245713b7e68 baseline-to-fixed.patch
42f770fc3e2384362efd1e416091355c064b6cca22dd40f3b5ef8f7b67e43a52 changed-source-tests.json
ce03510187334794f10c57b3ce022cbb31fb0324a50e9a225a1c8bb9a06540c4 fixed-input-bytes.tar.gz
505c022b46d0871d979c1dc9455a5d0a34ba5442fdeb5bc6195509e56a06b3b2 fixed-inputs.json
8f47fbe78ca155f2bc45f5c76e0cc2204af655b5485fc4bb55db5b21f2f7095f fixed-inputs.sha256
fcbb8633c9cf0bdee9aeb1bfa8026c868c880cdbeea5369fa35928a9e87daacb preserved-base-test-prefixes.json
e7edd87316c9617caf2d30f7f8fc2ef38a6e918a781173bd40b251a81f878f6d r1-raw-evidence-bytes.tar.gz
e2d81fd97a93d13805fe009428dcab77cafd2e99f6f9330b8ae08bc56af06306 r1-raw-evidence.json
a78bc385801b64be270fb9d6e84672c443738a5fce8eb68f7d2a01359a57a770 source-tests.patch
3a1878a64719ad3c733c4e6a7b3fee091fb97be5591e126a6d2cb971262fc8b1 static-dependencies.json
521a779bb862349c137bd3cce0e319e7565c80657c437cc794bf3f9848689319 static-overlay-check.json
c32f33ebc78f09a0549b0b0ba185771bf1cdb3149e9579204147f4b827a66a56 whole-files.txt
@@ -0,0 +1,4 @@
[
"packages/bus/tests/limit-checks.test.mjs",
"packages/plugins/tests/token-limit.test.mjs"
]
@@ -0,0 +1,72 @@
[
{
"bytes": 3307,
"git_blob": "00f2b35bb3b5187909e724f042062feb057a6d7a",
"head_git_blob": null,
"path": "agents/codex/work/queue-333/r1-repair/receipts/01-identity-red.txt",
"sha256": "ec0fb03d34a3fa31bfa8305676fb932cb3ca3c52fc3ed663b7ae56d946585b77"
},
{
"bytes": 4537,
"git_blob": "f10567852cfd3ff9adb288b73c0e0b6d37eb391d",
"head_git_blob": null,
"path": "agents/codex/work/queue-333/r1-repair/receipts/02-fresh-identity-red.txt",
"sha256": "6693e5e29d26c789c3469664c70d1c77246456774641985bc07737c960f9042f"
},
{
"bytes": 5219,
"git_blob": "296f6ece0dbb17f656a3fbe07be71197fd0dd3e1",
"head_git_blob": null,
"path": "agents/codex/work/queue-333/r1-repair/receipts/03-identity-green.txt",
"sha256": "06c7727d4058447e299a4110ae24d71c390e5ef4851231ddb2c725737738c645"
},
{
"bytes": 6536,
"git_blob": "0f41601f8893466afd3853c4cfe5a0eead00341f",
"head_git_blob": null,
"path": "agents/codex/work/queue-333/r1-repair/receipts/04-legacy-account-red.txt",
"sha256": "76d8a88b81caef26568191b8b9b76447e881b8073907b3bdabb986b929a2dd51"
},
{
"bytes": 6757,
"git_blob": "ee3b3cb6b042306c62c7d89861b78a13e28c13be",
"head_git_blob": null,
"path": "agents/codex/work/queue-333/r1-repair/receipts/05-legacy-fence-behavior-red.txt",
"sha256": "a8dabd0f59035d90de5bcc4680d9c9c5dee867e7e0edf521331c41544e54079a"
},
{
"bytes": 839,
"git_blob": "2fbd8bad453f3ab8893afb2951fc2a2b78a524fc",
"head_git_blob": null,
"path": "agents/codex/work/queue-333/r1-repair/receipts/06-legacy-account-green.txt",
"sha256": "be88ca17efc4fc18f5d011afc5ab6f519f26fe0da496631558204c0db81cc655"
},
{
"bytes": 1046,
"git_blob": "4d24f1b251ffdba83a19bbddd99f9258b187acb8",
"head_git_blob": null,
"path": "agents/codex/work/queue-333/r1-repair/receipts/07-legacy-strict19.txt",
"sha256": "198c1d8b28df8c9f301fd99f559ff222515de4fbff346ba36c717c366339f0df"
},
{
"bytes": 308,
"git_blob": "b178ce53cd6ee0d645d4b8997a4b6fd87843e1d0",
"head_git_blob": null,
"path": "agents/codex/work/queue-333/r1-repair/receipts/07-priority-native.jsonl",
"sha256": "cf338f68c02eb89ca1722aa32a529ece28c7e8c341585d47cae53a2adfa296b3"
},
{
"bytes": 14879,
"git_blob": "65fb63c1351da0bc799eb7ea410007ab7d7c7197",
"head_git_blob": null,
"path": "agents/codex/work/queue-333/r1-repair/REVIEW-R1.md",
"sha256": "7c95672a30c0d5c39189c7c7d610ada89cd539dcb9413617071fbb81200fd008"
},
{
"bytes": 57857,
"git_blob": "3c032a8c18da6645abf0e8fc80b157b3bdc40efd",
"head_git_blob": null,
"path": "agents/codex/work/queue-333/r1-repair/baselines/runtime-before-background-fix.mjs",
"sha256": "b493137828a70fbb7eeece7d4fe5628ebc8f98a9997882bb3be010b2ae7eed4f"
}
]
@@ -0,0 +1,558 @@
diff --git a/packages/bus/src/limits.mjs b/packages/bus/src/limits.mjs
index cb47c5df6c97fad2a18cf6a482b6976376ea7fa7..c4bb3a75ecd47b94f83dcc4df28f11e252d5f460 100644
--- a/packages/bus/src/limits.mjs
+++ b/packages/bus/src/limits.mjs
@@ -12,7 +12,7 @@
//
// refresh, mayLaunch and mustStop are async: they re-read the file and reload first. report is
// sync, so the organization verbs stay sync; it uses the modules the last refresh loaded.
-import { createLoader } from '../../plugins/src/loader.mjs';
+import { createLoader, isDailyModelQuota } from '../../plugins/src/loader.mjs';
import { turnRecords } from './usage.mjs';
const KIND = 'limit-check';
@@ -122,8 +122,9 @@ export function createLimits({ store, read, log, makeLoader = createLoader, keyF
log({ event: 'limit-check-failed', business, check: st.missing, export: name, code: 'not-loaded' });
return halt({ check: st.missing, code: 'not-loaded' });
}
+ if (!st.checks.length) return { [key]: go };
const leaves = limitLeaves(st.limits);
- if (Object.keys(st.limits?.tokens?.keys ?? {}).some(k => /^[a-f0-9]{12}$/.test(k))) {
+ if (Object.entries(st.limits?.tokens?.keys ?? {}).some(([k, entry]) => isDailyModelQuota(k, entry))) {
let modelKeyId;
try {
if (name === 'mustStop' && (typeof context?.run !== 'string' || !context.run)) throw new Failure('proxy-key-refused');
diff --git a/packages/bus/src/model-keys.mjs b/packages/bus/src/model-keys.mjs
index 560c8474838ca69a88539ecbc44961c2f157a84b..a998576434fa604912732b0131b9e31ca62f08b4 100644
--- a/packages/bus/src/model-keys.mjs
+++ b/packages/bus/src/model-keys.mjs
@@ -36,6 +36,17 @@ export class ModelKeys {
if (this.#record(instance)?.state === 'revoking') fail('proxy-key-revoking');
if (!this.#ready) fail(this.#failure);
}
+ // P5's destructive queue read needs this instance's current identity, not
+ // an issued agent credential. A sentinel refusal stays closed until explicit
+ // reconcile; telemetry never retries around it or performs reconciliation.
+ verifyIdentity() {
+ return this.#exclusive(async () => {
+ if (!this.#ready) fail(this.#failure);
+ let keys;
+ try { keys = await this.#client.getKeys(); } catch { fail('proxy-down'); }
+ this.#sentinel(keys);
+ });
+ }
async #replace(before, after) {
this.#sentinel(before); this.#sentinel(after);
await this.#client.putKeys(after);
diff --git a/packages/bus/src/proxy-usage.mjs b/packages/bus/src/proxy-usage.mjs
index 71d9a72fa348cf24003e02d36ebe0c1280597f30..754c8c022185014c39183dae0456ac6235ff87a9 100644
--- a/packages/bus/src/proxy-usage.mjs
+++ b/packages/bus/src/proxy-usage.mjs
@@ -28,7 +28,7 @@ export function createProxyUsage({ store, read, client, records, log, now = Date
due = now() + Math.min(...enabled.map(b => b.pollSeconds)) * 1000;
try {
await loader.load({ usage: 'cliproxy-queue' });
- const module = loader.modules('usage')[0], management = client();
+ const module = loader.modules('usage')[0], management = await client();
if (!module || !management) throw Error('unavailable');
const events = await module.read({ client: management });
const owners = new Map();
diff --git a/packages/bus/src/runtime.mjs b/packages/bus/src/runtime.mjs
index c21103a447c2e77fa1b8e487fef1a7c4a0dba6b2..8bb0b0585df10f38d3bf563f3bb6b4dc15ef33ab 100644
--- a/packages/bus/src/runtime.mjs
+++ b/packages/bus/src/runtime.mjs
@@ -384,7 +384,11 @@ export async function startBroker({
const keyForRun = (business, run) => modelRuns.get(business + ':' + run)?.keyId ?? null;
const usage = await createUsage({ store, dataRoot, businesses, log: usageLog, keyForRun,
proxyView: business => proxyUsage?.view(business) ?? null });
- proxyUsage = createProxyUsage({ store, log: usageLog, client: () => modelProxyClient,
+ proxyUsage = createProxyUsage({ store, log: usageLog, client: async () => {
+ if (!modelKeys) return null;
+ await modelKeys.verifyIdentity();
+ return modelProxyClient;
+ },
records: () => credentials.status(),
read: () => Object.fromEntries(Object.keys(businesses).map(id => [id, settings ? settings.current(id) : businesses[id]])) });
// Row 125 (#1619, REQ-LIMIT-3, REQ-LIMIT-4): the limit checks read the organization file at
@@ -862,9 +866,10 @@ export async function startBroker({
}
// One bounded queue read at a time. The service applies the configured
// 1..59 second poll deadline; this tick only checks whether a read is due.
- usageTimer = setInterval(() => { proxyUsage.tick().catch(() => usageLog({ action: 'proxy.usage', code: 'proxy-usage-read-failed' })); }, 1000);
+ const usageTick = () => { proxyUsage.tick().catch(() => usageLog({ action: 'proxy.usage', code: 'proxy-usage-read-failed' })); };
+ usageTimer = setInterval(usageTick, 1000);
usageTimer.unref();
- await proxyUsage.tick();
+ usageTick(); // Optional telemetry never blocks the native ready answer.
return {
broker,
credentials,
diff --git a/packages/bus/tests/limit-checks.test.mjs b/packages/bus/tests/limit-checks.test.mjs
index b9b7660723e4e2fe115cc786b8af2121b23e2403..a0264cc77cb2f9802d42adf4df5dbb01165a5bcc 100644
--- a/packages/bus/tests/limit-checks.test.mjs
+++ b/packages/bus/tests/limit-checks.test.mjs
@@ -327,7 +327,7 @@ test('REQ-LIMIT-3 core reaches limit checks only through the plug-in loader', ()
test('P5 missing, ambiguous or invalid model key lookup fails closed without leaking a lookup error', async t => {
const root=mkdtempSync(join(tmpdir(),'p5-limit-')),store=new Store(root),log=[];t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
- const key='012345abcdef',doc={plugins:{'limit-check':['token-limit']},launch:{limits:{tokens:{keys:{[key]:{limit:5,since:SINCE}}}}}};
+ const key='012345abcdef',doc={plugins:{'limit-check':['daily-quota']},launch:{limits:{tokens:{keys:{[key]:{limit:5,since:SINCE,reset:'00:00',timeZone:'UTC'}}}}}};
for(const lookup of [()=>null,()=>['012345abcdef','abcdef012345'],()=> 'msk-private-lookup',()=>{throw Error('PRIVATE-LOOKUP-CANARY');}]) {
const l=createLimits({store,read:()=>doc,log:e=>log.push(e),keyForSubject:lookup});
assert.deepEqual(await l.mayLaunch('demo',SUBJECT),{allow:false,check:null,code:'proxy-key-refused'});
@@ -337,7 +337,7 @@ test('P5 missing, ambiguous or invalid model key lookup fails closed without lea
});
test('P5 trusted lookup uses the retiring run key rather than the agent current key',async t=>{
const root=mkdtempSync(join(tmpdir(),'p5-old-key-')),store=new Store(root);t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
- const old='012345abcdef',current='abcdef012345',doc={plugins:{'limit-check':['token-limit']},launch:{limits:{tokens:{keys:{[old]:{limit:0,since:SINCE}}}}}};
+ const old='012345abcdef',current='abcdef012345',doc={plugins:{'limit-check':['daily-quota']},launch:{limits:{tokens:{keys:{[old]:{limit:0,since:SINCE,reset:'00:00',timeZone:'UTC'}}}}}};
const l=createLimits({store,read:()=>doc,log:()=>{},keyForSubject:(_,s)=>s.run==='old-run'?old:current});
assert.equal((await l.mayLaunch('demo',SUBJECT)).allow,true);
assert.equal((await l.mustStop('demo',SUBJECT,{run:'old-run'})).stop,true);
diff --git a/packages/bus/tests/p5-background.test.mjs b/packages/bus/tests/p5-background.test.mjs
new file mode 100644
index 0000000000000000000000000000000000000000..bb51ad3527280f0db0449c27eb42474dd8b9e894
--- /dev/null
+++ b/packages/bus/tests/p5-background.test.mjs
@@ -0,0 +1,51 @@
+// Prepared after Mos1971 STOP. These controls have NOT been executed locally.
+// Only fake loopback HTTP, explicit event barriers and virtual existing timers.
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import { mkdirSync, writeFileSync } from 'node:fs';
+import { join } from 'node:path';
+import { startTimeOf } from '../../seat/src/proc.mjs';
+import { telemetryFixture } from './p5-telemetry-fixture.mjs';
+async function nativeTurn(f) {
+ const model=await f.bus.modelPreflight({business:'demo',role:'coder'});
+ const keyId=createHash('sha256').update(model.key).digest('hex').slice(0,12),dir=join(f.root,'native-transcript');mkdirSync(dir);
+ const {cap}=f.bus.bindLaunch({business:'demo',role:'coder',run:'held-poll-native',harness:'pi',modelKeyId:keyId,transcript:dir,
+ pid:process.pid,startTime:startTimeOf(process.pid)});
+ f.bus.broker.request(cap,{verb:'role.claim'});
+ assert.deepEqual(await f.bus.mayLaunch({business:'demo',instance:'coder',provider:'fixture',model:'fake'}),{allow:true});
+ const human=f.human(),{id}=f.bus.broker.request(human,{verb:'message.send',args:{to:'coder',body:'native work while optional queue is held'}});
+ f.bus.broker.request(cap,{verb:'message.receive'});
+ await f.bus.broker.request(cap,{verb:'usage.begin',args:{turn:id}});
+ writeFileSync(join(dir,'native.jsonl'),JSON.stringify({type:'message',id:'native',message:{role:'assistant',usage:{input:2,output:1,cacheRead:0,cacheWrite:0}}})+'\n');
+ await f.bus.broker.request(cap,{verb:'usage.end',args:{turn:id}});
+ const view=f.bus.broker.request(human,{verb:'usage'});
+ assert.equal(view.total.input,2);assert.equal(view.byKey[0].modelKeyId,keyId);
+ assert.deepEqual(f.bus.broker.request(cap,{verb:'message.receive'}),[]);
+}
+for(const fail of [false,true])test(`P5 R1 held first optional poll does not delay native startup or work; ${fail?'failure':'release'} settles safely`,async t=>{
+ t.mock.timers.enable({apis:['Date','setInterval'],now:Date.now()});
+ const f=await telemetryFixture(t,{hold:true});const started=f.start();
+ await f.waitQueue(1);await new Promise(setImmediate);
+ // Causal first guard: the queue is still held, so a ready runtime cannot
+ // have depended on its response. No racing timeout or longer budget.
+ assert.notEqual(f.bus,null,'startBroker must resolve while the first queue response is held');
+ await started;assert.equal(f.state.held.length,1);
+ assert.equal(f.bus.broker.request(f.human(),{verb:'plugins'}).plugins.usage,'cliproxy-queue');
+ await nativeTurn(f);assert.equal(f.queueCalls(),1);
+ t.mock.timers.tick(1000);await new Promise(setImmediate);assert.equal(f.queueCalls(),1,'scheduled ticks share the held first read');
+ const from=f.logs.length;f.release(fail);
+ await f.waitLog(fail?'proxy-usage-read-failed':'proxy.usage.reconcile',from);
+ assert.equal(f.bus.broker.request(f.human(),{verb:'usage'}).proxy.state,fail?'unavailable':'available');
+ await f.close();assert.equal(f.queueCalls(),1);
+});
+test('P5 R1 close bounds an outstanding first poll by the unchanged five-second client deadline',async t=>{
+ t.mock.timers.enable({apis:['Date','setInterval','setTimeout'],now:Date.now()});
+ const f=await telemetryFixture(t,{hold:true});const started=f.start();await f.waitQueue(1);await new Promise(setImmediate);
+ assert.notEqual(f.bus,null,'native readiness precedes the held optional poll');await started;
+ let closed=false;const closing=f.close().then(()=>{closed=true;});
+ t.mock.timers.tick(4999);await new Promise(setImmediate);assert.equal(closed,false);
+ t.mock.timers.tick(1);await closing;
+ assert.equal(closed,true);assert.equal(f.queueCalls(),1);
+ assert.ok(f.logs.some(line=>line.includes('proxy-usage-read-failed')));
+});
diff --git a/packages/bus/tests/p5-identity.test.mjs b/packages/bus/tests/p5-identity.test.mjs
new file mode 100644
index 0000000000000000000000000000000000000000..4ee111f7c9ec75dbae24c184c3310b71973fc7c2
--- /dev/null
+++ b/packages/bus/tests/p5-identity.test.mjs
@@ -0,0 +1,38 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import { telemetryFixture } from './p5-telemetry-fixture.mjs';
+for(const foreign of [true,false])test(`P5 R1 boot identity ${foreign?'refusal prevents queue consumption':'matching sentinel permits telemetry without an agent key'}`,async t=>{
+ t.mock.timers.enable({apis:['Date','setInterval'],now:Date.now()});
+ const f=await telemetryFixture(t,{foreign});await f.start();await f.settleInitial();
+ const human=f.human();assert.equal(f.bus.broker.request(human,{verb:'plugins'}).plugins.usage,'cliproxy-queue');
+ if(foreign){
+ await assert.rejects(f.bus.modelPreflight({business:'demo',role:'coder'}),{code:'proxy-open'});
+ assert.equal(f.queueCalls(),0);assert.equal(f.state.queued.length,1);
+ await f.pollSettledAfterTick(t);assert.equal(f.queueCalls(),0);assert.equal(f.state.queued.length,1);
+ assert.equal(f.bus.broker.request(human,{verb:'usage'}).proxy.state,'unavailable');
+ }else{
+ assert.equal(f.queueCalls(),1);assert.equal(f.state.queued.length,0);
+ assert.equal(f.bus.broker.request(human,{verb:'usage'}).proxy.state,'available');
+ assert.equal(f.bus.credentials.status().some(r=>r.service==='model'&&r.keyId),false);
+ }
+});
+test('P5 R1 later sentinel refusal fences every subsequent queue poll while preserving human control',async t=>{
+ t.mock.timers.enable({apis:['Date','setInterval'],now:Date.now()});
+ const f=await telemetryFixture(t);await f.start();await f.settleInitial();assert.equal(f.queueCalls(),1);
+ f.state.keys=[f.other];
+ await assert.rejects(f.bus.modelPreflight({business:'demo',role:'coder'}),{code:'proxy-open'});
+ await f.pollSettledAfterTick(t);assert.equal(f.queueCalls(),1);
+ await f.pollSettledAfterTick(t);assert.equal(f.queueCalls(),1);
+ const human=f.human();assert.equal(f.bus.broker.request(human,{verb:'plugins'}).plugins.usage,'cliproxy-queue');
+ assert.equal(f.bus.broker.request(human,{verb:'usage'}).proxy.state,'unavailable');
+});
+
+test('P5 R1 every drain verifies fresh sentinel before consuming a changed listener',async t=>{
+ t.mock.timers.enable({apis:['Date','setInterval'],now:Date.now()});
+ const f=await telemetryFixture(t);await f.start();await f.settleInitial();assert.equal(f.queueCalls(),1);
+ f.state.keys=[f.other];await f.pollSettledAfterTick(t);assert.equal(f.queueCalls(),1);
+ await assert.rejects(f.bus.modelPreflight({business:'demo',role:'coder'}),{code:'proxy-open'});
+ const lists=f.state.calls.filter(p=>p==='/v8/management/config/access/api-keys').length;
+ f.state.keys=[f.own];await f.pollSettledAfterTick(t);assert.equal(f.queueCalls(),1);
+ assert.equal(f.state.calls.filter(p=>p==='/v8/management/config/access/api-keys').length,lists,'no retry around sticky identity refusal');
+});
diff --git a/packages/bus/tests/p5-key-compatibility.test.mjs b/packages/bus/tests/p5-key-compatibility.test.mjs
new file mode 100644
index 0000000000000000000000000000000000000000..331032ecb48644587057a9ec4799e69d5fa3cdc8
--- /dev/null
+++ b/packages/bus/tests/p5-key-compatibility.test.mjs
@@ -0,0 +1,68 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import { mkdtempSync, rmSync, readFileSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { Store } from '../src/store.mjs';
+import { createLimits, modelUsageKey } from '../src/limits.mjs';
+import * as token from '../../plugins/limit-check/token-limit/index.mjs';
+import * as daily from '../../plugins/limit-check/daily-quota/index.mjs';
+import { launchSettings } from '../../business/src/launch-settings.mjs';
+import { businessDoc, rolesCopy, writeJson, systemFor } from '../../business/tests/helpers.mjs';
+const key='abcdefabcdef',other='012345abcdef',since='2026-01-01T00:00:00.000Z';
+const quota={limit:10,since,reset:'00:00',timeZone:'UTC'};
+const native={at:'2026-10-26T12:00:00.000Z',run:'legacy-run',turn:'turn',account:key,modelKeyId:other,status:'known',input:10,output:0,cacheWrite:0,cacheRead:0};
+test('P5 R1 plain twelve-hex account leaves retain matching and original account report even with another model ID',()=>{
+ const a={limits:{tokens:{keys:{[key]:{limit:10,since}}}},subject:{account:key,modelKeyId:other},records:[native]};
+ assert.equal(token.mayLaunch(a).allow,false);assert.equal(token.mustStop(a).stop,true);
+ assert.equal(token.report(a)[0].count,10);assert.deepEqual(token.report(a)[0].path,['tokens','keys',key]);
+ assert.equal(token.mayLaunch({...a,records:[{...native,input:9}]}).allow,true);
+ assert.deepEqual(daily.report({...a,now:native.at}),[]);
+});
+for(const proxy of [false,true])test(`P5 R1 legacy account core lookup stays independent of ${proxy?'unrelated proxy metadata':'missing proxy metadata'}`,async t=>{
+ const root=mkdtempSync(join(tmpdir(),'p5-legacy-')),store=new Store(root);t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
+ let lookups=0;
+ const b={launch:{account:{name:key,credential:'FAKE_TOKEN_NAME'},limits:{tokens:{keys:{[key]:{limit:10,since}}}}},plugins:{'limit-check':['token-limit']}};
+ const limits=createLimits({store,read:()=>b,log:()=>{},keyForSubject:(...args)=>{lookups++;return proxy?modelUsageKey([{service:'model',instance:'demo/coder',keyId:other,retiring:[]}],new Map(),'demo',args[1]):null;}});
+ assert.deepEqual(await limits.mayLaunch('demo',{instance:'coder',account:key}),{allow:true});
+ store.run(`INSERT INTO usage_records(at,business,run,instance,account,turn,source,phase,status,cursor,input,output,cache_write,cache_read)
+ VALUES (?,'demo','legacy-run','coder',?,'turn','transcript','end','known',?,10,0,0,0)`,native.at,key,JSON.stringify({modelKeyId:other}));
+ const hit={path:['tokens','keys',key],limit:10,count:10,unknownTurns:0};
+ assert.deepEqual(await limits.mayLaunch('demo',{instance:'coder',account:key}),{allow:false,check:'token-limit',hit});
+ assert.deepEqual(await limits.mustStop('demo',{instance:'coder',account:key}),{stop:true,check:'token-limit',hit});
+ assert.equal(limits.report('demo')[0].count,10);assert.equal(lookups,0);
+});
+for(const leaf of [{limit:0,since},quota])test(`P5 R1 empty checks bypass model metadata for ${leaf.reset?'daily model':'legacy hex account'} leaves`,async t=>{
+ const root=mkdtempSync(join(tmpdir(),'p5-no-checks-')),store=new Store(root);t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
+ let lookups=0;const limits=createLimits({store,read:()=>({plugins:{'limit-check':[]},launch:{limits:{tokens:{keys:{[key]:leaf}}}}}),log:()=>{},keyForSubject:()=>{lookups++;throw Error('MUST-NOT-LOOK-UP');}});
+ assert.deepEqual(await limits.mayLaunch('demo',{instance:'coder',account:key}),{allow:true});
+ assert.deepEqual(await limits.mustStop('demo',{instance:'coder',account:key}),{stop:false});assert.equal(lookups,0);
+});
+test('P5 R1 legacy hex account chief resets stay allowed; daily model old/new/removal/reset transitions stay human-only',t=>{
+ const root=mkdtempSync(join(tmpdir(),'p5-fence-'));t.after(()=>rmSync(root,{recursive:true,force:true}));
+ const rolesDir=rolesCopy(root),doc=businessDoc(root,'demo'),file=join(root,'businesses/demo.json');
+ doc.launch.account={name:key,credential:'FAKE_TOKEN_NAME'};doc.launch.limits={tokens:{keys:{[key]:{limit:10,since}}}};writeJson(file,doc);
+ let now='2026-10-26T12:00:00.000Z';const settings=launchSettings({dir:root,rolesDir,system:systemFor(root),now:()=>now});let v=settings.read('demo');
+ v=settings.set('demo',{revision:v.revision,reset:[['tokens','keys',key]]},'chief');
+ assert.equal(JSON.parse(readFileSync(file,'utf8')).launch.limits.tokens.keys[key].since,now);
+ const dailyLeaf={limit:10,reset:'00:00',timeZone:'UTC'};
+ assert.throws(()=>settings.set('demo',{revision:v.revision,limits:{tokens:{keys:{[key]:dailyLeaf}}}},'chief'),{code:'organization-model-quota-human-only'});
+ v=settings.set('demo',{revision:v.revision,limits:{tokens:{keys:{[key]:dailyLeaf}}}},'jason');now='2026-10-26T13:00:00.000Z';
+ for(const args of [{reset:[['tokens','keys',key]]},{limits:{}},{limits:{tokens:{keys:{[key]:{limit:10}}}}}])
+ assert.throws(()=>settings.set('demo',{revision:v.revision,...args},'chief'),{code:'organization-model-quota-human-only'});
+ v=settings.set('demo',{revision:v.revision,limits:{tokens:{keys:{[key]:{limit:10}}}}},'jason');
+ v=settings.set('demo',{revision:v.revision,reset:[['tokens','keys',key]]},'chief');
+ assert.equal(JSON.parse(readFileSync(file,'utf8')).launch.limits.tokens.keys[key].since,now);
+});
+
+test('P5 R1 daily model matching/report is separate from legacy account and schema refuses partial or invalid daily shapes',async()=>{
+ const {checkTokenLimits}=await import('../../business/src/launch.mjs');
+ assert.deepEqual(checkTokenLimits({keys:{[key]:quota}}).keys[key],quota);
+ const args={limits:{tokens:{keys:{[key]:quota}}},records:[native],subject:{account:key,modelKeyId:other},now:native.at};
+ assert.deepEqual(token.report(args),[]);
+ assert.equal(daily.mayLaunch(args).allow,true);assert.equal(daily.report(args)[0].count,0);
+ const owned={...args,subject:{account:'other-account',modelKeyId:key},records:[{...native,account:'other-account',modelKeyId:key}]};
+ assert.equal(daily.mayLaunch(owned).allow,false);assert.equal(daily.mustStop(owned).stop,true);assert.equal(daily.report(owned)[0].count,10);
+ for(const leaf of [{...quota,reset:'25:00'},{...quota,timeZone:'Mars/Phobos'},{limit:10,since,reset:'00:00'},{limit:10,since,timeZone:'UTC'}])
+ assert.throws(()=>checkTokenLimits({keys:{[key]:leaf}}));
+});
diff --git a/packages/bus/tests/p5-key-context.test.mjs b/packages/bus/tests/p5-key-context.test.mjs
index 8b2ebe0947591589f83d5c89b49bbd8fcf261e10..46b7a87c8e9cbfe4515e35be768f619dffc4a2b6 100644
--- a/packages/bus/tests/p5-key-context.test.mjs
+++ b/packages/bus/tests/p5-key-context.test.mjs
@@ -22,7 +22,7 @@ test('P5 broker preserves original plugin subject and derives internal run conte
});
test('P5 configured key quotas never use a supplied safe-looking ID when trusted metadata lookup is missing',async t=>{
const root=mkdtempSync(join(tmpdir(),'p5-no-bypass-')),store=new Store(root);t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
- const doc={plugins:{'limit-check':['token-limit']},launch:{limits:{tokens:{keys:{[key]:{limit:10,since:'2026-01-01T00:00:00.000Z'}}}}}};
+ const doc={plugins:{'limit-check':['daily-quota']},launch:{limits:{tokens:{keys:{[key]:{limit:10,since:'2026-01-01T00:00:00.000Z',reset:'00:00',timeZone:'UTC'}}}}}};
const limits=createLimits({store,read:()=>doc,log:()=>{},keyForSubject:()=>null});
assert.deepEqual(await limits.mustStop('demo',{instance:'coder',modelKeyId:key},{run:'forged-run'}),{stop:true,check:null,code:'proxy-key-refused'});
});
@@ -38,7 +38,7 @@ test('P5 internal context resolves exactly current or retained generation; wrong
test('P5 model-key mustStop without native run context fails closed even when the current key resolves',async t=>{
const root=mkdtempSync(join(tmpdir(),'p5-missing-context-')),store=new Store(root);t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
- const doc={plugins:{'limit-check':['token-limit']},launch:{limits:{tokens:{keys:{[key]:{limit:10,since:'2026-01-01T00:00:00.000Z'}}}}}};
+ const doc={plugins:{'limit-check':['daily-quota']},launch:{limits:{tokens:{keys:{[key]:{limit:10,since:'2026-01-01T00:00:00.000Z',reset:'00:00',timeZone:'UTC'}}}}}};
const limits=createLimits({store,read:()=>doc,log:()=>{},keyForSubject:()=>key});
assert.deepEqual(await limits.mustStop('demo',{instance:'coder'}),{stop:true,check:null,code:'proxy-key-refused'});
});
diff --git a/packages/bus/tests/p5-telemetry-fixture.mjs b/packages/bus/tests/p5-telemetry-fixture.mjs
new file mode 100644
index 0000000000000000000000000000000000000000..99390f7d565a7d7db5344b574bc5a8623d5fa073
--- /dev/null
+++ b/packages/bus/tests/p5-telemetry-fixture.mjs
@@ -0,0 +1,66 @@
+// Fresh, made-up instance and local management listener only; no worker/provider.
+import http from 'node:http';
+import { createHash, randomBytes } from 'node:crypto';
+import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { startBroker } from '../src/runtime.mjs';
+import { Registry } from '../../seat/src/session.mjs';
+import { businessDoc, rolesCopy, systemFor, writeJson } from '../../business/tests/helpers.mjs';
+export async function telemetryFixture(t, { foreign = false, hold = false } = {}) {
+ const root = mkdtempSync(join(tmpdir(), 'p5-telemetry-')), config = join(root,'config'), data = join(root,'data');
+ mkdirSync(config,{mode:0o700}); mkdirSync(data,{mode:0o700});
+ const rolesDir = rolesCopy(config), doc = businessDoc(config,'demo');
+ doc.plugins = { usage:'cliproxy-queue', harness:['pi'], 'usage-source':['transcript'], 'limit-check':['token-limit'] };
+ doc.usage = { cliproxyQueue:{pollSeconds:1} };
+ writeJson(join(config,'businesses/demo.json'),doc);
+ mkdirSync(join(config,'secrets'),{recursive:true,mode:0o700});
+ writeFileSync(join(config,'secrets/proxy-management.key'),'p5-r1-made-up-management',{mode:0o600});
+ new Registry(data);
+ const tag = createHash('sha256').update(config).digest('hex').slice(0,12);
+ const own = `msk-${tag}-sentinel-${randomBytes(32).toString('base64url')}`;
+ const other = `msk-ffffffffffff-sentinel-${randomBytes(32).toString('base64url')}`;
+ const state = { keys:[foreign?other:own], calls:[], queued:[{api_key:'msk-r1-unknown-fake',source:'p5-r1-upstream-canary',failed:false,tokens:{input_tokens:1,output_tokens:2}}], held:[], hold };
+ const logs=[], waiters=[];
+ const stderr = process.stderr.write;
+ t.mock.method(process.stderr,'write',function(chunk,...args) {
+ const text=String(chunk);logs.push(text);
+ for(const waiter of [...waiters]) if(text.includes(waiter.fragment) && logs.length>waiter.from) { waiters.splice(waiters.indexOf(waiter),1);waiter.resolve(); }
+ return stderr.call(this,chunk,...args);
+ });
+ const waitLog=(fragment,from=0)=> {
+ if(logs.slice(from).some(line=>line.includes(fragment)))return Promise.resolve();
+ return new Promise(resolve=>waiters.push({fragment,from,resolve}));
+ };
+ let queueWaiters=[];
+ const waitQueue=(count)=> state.calls.filter(p=>p.includes('/usage/queue')).length>=count?Promise.resolve():new Promise(resolve=>queueWaiters.push({count,resolve}));
+ const answerQueue=res=>{res.end(JSON.stringify(state.queued));state.queued=[];};
+ const server=http.createServer(async(req,res)=>{
+ state.calls.push(req.url);
+ if(req.headers.authorization!=='Bearer p5-r1-made-up-management' && req.url.startsWith('/v8/management/')) {res.writeHead(401);res.end('{}');return;}
+ if(req.url==='/v8/management/config/access/api-keys') {
+ if(req.method==='PUT'){let body='';for await(const c of req)body+=c;state.keys=JSON.parse(body);res.end('{"status":"ok"}');}
+ else res.end(JSON.stringify(state.keys));return;
+ }
+ if(req.url==='/v8/management/observability/usage/queue?count=100') {
+ if(state.hold)state.held.push(res);else answerQueue(res);
+ const count=state.calls.filter(p=>p.includes('/usage/queue')).length;
+ for(const waiter of queueWaiters.filter(w=>count>=w.count))waiter.resolve();
+ queueWaiters=queueWaiters.filter(w=>count<w.count);return;
+ }
+ res.writeHead(state.keys.includes(req.headers.authorization?.slice(7))?200:401);res.end('{}');
+ });
+ await new Promise(resolve=>server.listen(0,'127.0.0.1',resolve));
+ let bus=null,startPromise=null,closePromise=null;
+ const start=()=>startPromise??=(startBroker({dataRoot:data,businesses:{demo:{id:'demo',human:'jason',plugins:doc.plugins,arbiters:{technical:'coder',delivery:'coder'},roles:{coder:{definition:'coder',authority:{withinRole:[],crossRole:[]}}}}},
+ organization:{dir:config,rolesDir,system:systemFor(config)},proxy:{port:server.address().port,binary:'/fixture-unused'}}).then(value=>(bus=value)));
+ const release=(fail=false)=>{state.hold=false;for(const res of state.held.splice(0)){if(res.destroyed)continue;if(fail){res.writeHead(503);res.end('{}');}else answerQueue(res);}};
+ const close=()=>bus?(closePromise??=bus.close()):Promise.resolve();
+ t.after(async()=>{release();await startPromise?.catch(()=>{});await close();server.closeAllConnections();await new Promise(r=>server.close(r));rmSync(root,{recursive:true,force:true});});
+ return {root,data,config,state,logs,own,other,start,waitLog,waitQueue,release,close,
+ settleInitial:()=>Promise.race([waitLog('proxy-usage-read-failed'),waitLog('proxy.usage.reconcile')]),
+ get bus(){return bus;},queueCalls:()=>state.calls.filter(p=>p.includes('/usage/queue')).length,
+ human:()=>bus.broker.bindHuman({business:'demo',human:'jason',via:'cli',outsideAgent:true}),
+ async pollSettledAfterTick(t){const from=logs.length,next=state.calls.filter(p=>p.includes('/usage/queue')).length+1;t.mock.timers.tick(1000);await Promise.race([waitQueue(next),waitLog('proxy-usage-read-failed',from)]);await new Promise(setImmediate);},
+ };
+}
diff --git a/packages/business/src/launch.mjs b/packages/business/src/launch.mjs
index 4ee37c5c6514bdf541b20e7001873fb5d8e878f3..7871fdda595d23c3645b417dbf96783faac9047e 100644
--- a/packages/business/src/launch.mjs
+++ b/packages/business/src/launch.mjs
@@ -1,5 +1,6 @@
// REQ-LIMIT-1: editable concurrency policy, never a compiled-in capacity ceiling.
import { requireObject, requireId, requireString, rejectUnknownKeys } from "./util.mjs";
+import { isDailyModelQuota } from "../../plugins/src/model-quota.mjs";
import { refuse } from "./errors.mjs";
const name = (value, at) => requireString(value, at, { max: 200 });
@@ -67,12 +68,16 @@ export function checkTokenLimits(value, where = "launch.limits.tokens") {
if (Object.hasOwn(value, "models")) {
out.models = tokenMap(value.models, `${where}.models`, name, (models, at) => tokenMap(models, at, name, tokenLimit));
}
- // P5: model key IDs are 12 hex characters (including digit-leading IDs).
- // A model key may use the daily quota shape; existing account limits retain theirs.
- if (Object.hasOwn(value, "keys")) out.keys = tokenMap(value.keys, `${where}.keys`,
- (key, at) => /^[a-f0-9]{12}$/.test(key) ? key : requireId(key, at),
- (entry, at) => Object.hasOwn(entry ?? {}, "reset") && /^[a-f0-9]{12}$/.test(at.split('.').at(-1))
- ? dailyQuota(entry, at) : tokenLimit(entry, at));
+ // P5 adds daily model leaves, including digit-leading IDs; plain keys keep
+ // their existing account-name schema and cumulative account semantics.
+ if (Object.hasOwn(value, "keys")) {
+ requireObject(value.keys, `${where}.keys`);
+ out.keys = Object.fromEntries(Object.entries(value.keys).map(([key, entry]) => {
+ const at = `${where}.keys.${key}`;
+ if (isDailyModelQuota(key, entry)) return [key, dailyQuota(entry, at)];
+ return [requireId(key, `${where}.keys`), tokenLimit(entry, at)];
+ }));
+ }
// One quota per account; the business read checks each key names launch.account.
if (Object.hasOwn(value, "daily")) out.daily = tokenMap(value.daily, `${where}.daily`, requireId, dailyQuota);
return out;
diff --git a/packages/business/src/organization.mjs b/packages/business/src/organization.mjs
index 6d358631d81464dcac98ec0db2388f08e9eceb39..2acb92e417f32f9080396b41d1a2f565272a01d4 100644
--- a/packages/business/src/organization.mjs
+++ b/packages/business/src/organization.mjs
@@ -8,6 +8,7 @@ import { join, dirname } from "node:path";
import { randomUUID } from "node:crypto";
import { businessFilePath, validateBusinessDocument } from "./business.mjs";
import { requireId, sha256, canonicalJson } from "./util.mjs";
+import { isDailyModelQuota } from "../../plugins/src/model-quota.mjs";
import { checkReplyLimits } from "../../library/src/limits.mjs";
export class OrganizationError extends Error {
@@ -84,7 +85,7 @@ function changes(old, next, path = "") {
// P5/Q222: every writer protects per-model-key quotas, including removal/reset.
function modelQuotaFence(old, document, actor) {
const keys = doc => Object.fromEntries(Object.entries(doc?.launch?.limits?.tokens?.keys ?? {})
- .filter(([key]) => /^[a-f0-9]{12}$/.test(key)));
+ .filter(([key, entry]) => isDailyModelQuota(key, entry)));
if (canonicalJson(keys(old)) === canonicalJson(keys(document))) return;
const agents = Object.entries(old.roles ?? {}).flatMap(([instance, entry]) => [instance, `${entry?.definition}.${instance}`]);
if (actor === old.human && actor !== "tester" && !agents.includes(actor)) return;
diff --git a/packages/plugins/limit-check/daily-quota/index.mjs b/packages/plugins/limit-check/daily-quota/index.mjs
index 38b445803d13a05803ec91e11556346e868a2437..096aa2ead37a18cfa17b2e2d43e19fb5604350f6 100644
--- a/packages/plugins/limit-check/daily-quota/index.mjs
+++ b/packages/plugins/limit-check/daily-quota/index.mjs
@@ -4,6 +4,7 @@
// timeZone}. A count is every kind summed over the account's known records since the later of the
// day's reset and the leaf's `since`; an unknown turn adds nothing and is counted on its own.
// It copies token-limit's tally helpers rather than importing a sibling check, so each loads alone.
+import { isDailyModelQuota } from '../../src/model-quota.mjs';
export const interfaceVersion = 2;
const KINDS = ['input', 'output', 'cacheWrite', 'cacheRead'];
@@ -63,7 +64,7 @@ function windowStart(entry, now) {
function leaves(limits) {
const daily = limits?.tokens?.daily ?? {};
const entries = [...Object.entries(daily).map(([account, entry]) => ({ path: ['tokens', 'daily', account], entry, match: x => x.account === account })),
- ...Object.entries(limits?.tokens?.keys ?? {}).filter(([key, entry]) => /^[a-f0-9]{12}$/.test(key) && Object.hasOwn(entry, 'reset'))
+ ...Object.entries(limits?.tokens?.keys ?? {}).filter(([key, entry]) => isDailyModelQuota(key, entry))
.map(([key, entry]) => ({ path: ['tokens', 'keys', key], entry, match: x => x.modelKeyId === key }))];
return entries.map(({ path, entry, match }) => {
if (!Number.isSafeInteger(entry?.limit) || entry.limit < 0 || typeof entry.reset !== 'string' || !RESET.test(entry.reset) ||
diff --git a/packages/plugins/limit-check/token-limit/index.mjs b/packages/plugins/limit-check/token-limit/index.mjs
index 8f26fcb9c7cbcae4c6cf953a6827af53590771be..b20cea356ca7081a6cf571949a0f6aa31dfec89d 100644
--- a/packages/plugins/limit-check/token-limit/index.mjs
+++ b/packages/plugins/limit-check/token-limit/index.mjs
@@ -3,6 +3,7 @@
// launch limits and its per-turn usage records, and nothing here reads a file
// or a store. A count is every kind summed over the known records since the
// limit's `since`; an unknown turn adds nothing and is counted on its own.
+import { isDailyModelQuota } from '../../src/model-quota.mjs';
export const interfaceVersion = 2;
const KINDS = ['input', 'output', 'cacheWrite', 'cacheRead'];
@@ -31,8 +32,8 @@ function leaves(limits) {
// A key is the record's account. Accounts are null until row 126 names them,
// so a key limit matches nothing until then.
for (const [k, entry] of Object.entries(tokens.keys ?? {}))
- if (!Object.hasOwn(entry, 'reset')) out.push({ path: ['tokens', 'keys', k], entry,
- match: x => /^[a-f0-9]{12}$/.test(k) ? x.modelKeyId === k : x.account === k, key: true });
+ if (!isDailyModelQuota(k, entry)) out.push({ path: ['tokens', 'keys', k], entry,
+ match: x => x.account === k, key: true });
return out;
}
@@ -73,7 +74,7 @@ export function mustStop(args) {
// while no record names an account (lead decision 150, Q1).
export function report({ limits, records }) {
if (!Array.isArray(records)) refuse('bad-records');
- const named = records.some(r => r.account != null || r.modelKeyId != null);
+ const named = records.some(r => r.account != null);
return leaves(limits).map(leaf => {
const { path, entry: { limit, since } } = leaf;
if (leaf.key && !named) return { path, limit, since, notEnforced: 'no records name a key' };
diff --git a/packages/plugins/src/loader.mjs b/packages/plugins/src/loader.mjs
index 04731ee91b04329a3956fd751f4d7fb215f845c3..5634a90664ea98022074cd9fff9bbfbd279692e8 100644
--- a/packages/plugins/src/loader.mjs
+++ b/packages/plugins/src/loader.mjs
@@ -162,3 +162,6 @@ export function createLoader({ log, barrier = () => {} }) {
return { load, loaded, modules, snapshot };
}
+
+// Shared pure plug-in setting classification; no check implementation is loaded.
+export { isDailyModelQuota } from "./model-quota.mjs";
diff --git a/packages/plugins/src/model-quota.mjs b/packages/plugins/src/model-quota.mjs
new file mode 100644
index 0000000000000000000000000000000000000000..1350eb56b5947e759ec8d32f0c429813c352f2a9
--- /dev/null
+++ b/packages/plugins/src/model-quota.mjs
@@ -0,0 +1,17 @@
+// The new P5 namespace is the validated DAILY leaf, never a twelve-hex name
+// alone. Plain {limit,since} keys remain legacy account limits.
+const ID = /^[a-f0-9]{12}$/;
+const RESET = /^([01]\d|2[0-3]):[0-5]\d$/;
+const ZONE = /^[A-Za-z][A-Za-z0-9_+-]*(\/[A-Za-z0-9_+-]+)*$/;
+const SINCE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
+export function isDailyModelQuota(key, value) {
+ if (typeof key !== 'string' || !ID.test(key) || !value || typeof value !== 'object' || Array.isArray(value)
+ || Object.keys(value).some(k => !['limit','since','reset','timeZone'].includes(k))
+ || !Number.isSafeInteger(value.limit) || value.limit < 0
+ || typeof value.since !== 'string' || !SINCE.test(value.since) || Number.isNaN(Date.parse(value.since))
+ || new Date(value.since).toISOString() !== value.since
+ || typeof value.reset !== 'string' || !RESET.test(value.reset)
+ || typeof value.timeZone !== 'string' || !ZONE.test(value.timeZone)) return false;
+ try { new Intl.DateTimeFormat('en-US', { timeZone:value.timeZone }); return true; }
+ catch { return false; }
+}
diff --git a/packages/plugins/tests/token-limit.test.mjs b/packages/plugins/tests/token-limit.test.mjs
index d8f8d3db7928f034d7126d479f4255637d0f8646..2c08be007564e5d4b223a7f93bcf4b36535fe739 100644
--- a/packages/plugins/tests/token-limit.test.mjs
+++ b/packages/plugins/tests/token-limit.test.mjs
@@ -150,11 +150,11 @@ test("REQ-LIMIT-3 token-limit ignores tokens.daily, which the daily-quota check
assert.deepEqual(check.report(a), []);
});
-test('P5 a model key ID limit counts stack records by key ID without an account', () => {
- const keyId = '012345abcdef';
+test('P5 plain twelve-hex keys keep legacy account matching rather than cumulative model matching', () => {
+ const keyId = 'abcdef012345';
const args = { business: 'demo', limits: { tokens: { keys: { [keyId]: { limit: 5, since: '2026-10-18T00:00:00.000Z' } } } },
- subject: { instance: 'coder', modelKeyId: keyId, account: null }, records: [{ at: '2026-10-18T01:00:00.000Z',
- run: 'run', turn: 'turn', modelKeyId: keyId, account: null, status: 'known', input: 5, output: 0, cacheWrite: 0, cacheRead: 0 }] };
+ subject: { instance: 'coder', modelKeyId: '012345abcdef', account: keyId }, records: [{ at: '2026-10-18T01:00:00.000Z',
+ run: 'run', turn: 'turn', modelKeyId: '012345abcdef', account: keyId, status: 'known', input: 5, output: 0, cacheWrite: 0, cacheRead: 0 }] };
assert.equal(check.mayLaunch(args).allow, false);
assert.equal(check.report(args)[0].count, 5);
});
diff --git a/packages/plugins/usage/cliproxy-queue/README.md b/packages/plugins/usage/cliproxy-queue/README.md
index 98aa6e8a2757e170dc2a27752e0b474a9fb3fab3..7e1b0c1996b536deb0013d4d58c8ee1d2697ad8e 100644
--- a/packages/plugins/usage/cliproxy-queue/README.md
+++ b/packages/plugins/usage/cliproxy-queue/README.md
@@ -35,8 +35,9 @@ usage cursor, preserved at turn begin and end. The Console exposes `byKey`.
A business can set a daily per-key quota at
`launch.limits.tokens.keys.<12-hex-key-id>` with `{limit, since, reset, timeZone}`;
the human writer stamps `since`. Enable `limit-check: ["daily-quota"]` to apply
-that quota. Cumulative model-key limits retain `{limit,since}` and use
-`token-limit`. Omitting a limit means no quota. Existing named account keys and
+that quota. Plain `{limit,since}` keys leaves remain cumulative legacy account limits, even
+when the name is twelve hex characters. They use `token-limit` and never resolve
+model metadata. Omitting a limit means no quota. Existing named account keys and
`tokens.daily.<account>` retain their existing behavior. Model-key limits and
resets are human-only through every organization writer. Missing, ambiguous or
foreign run-key metadata fails closed with `proxy-key-refused`; a retiring run
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,6 @@
{
"changed_package_files": 18,
"source_patch_equals_controls_then_remainder": true,
"status": "byte-application-verified-no-product-execution",
"temporary_trees_removed": true
}
@@ -0,0 +1,28 @@
packages/model-proxy/tests/usage-client.test.mjs
packages/model-proxy/tests/client.test.mjs
packages/model-proxy/tests/client-probe.test.mjs
packages/model-proxy/tests/page-client.test.mjs
packages/model-proxy/tests/management-key-encoding.test.mjs
packages/plugins/tests/kinds.test.mjs
packages/plugins/tests/loader.test.mjs
packages/plugins/tests/token-limit.test.mjs
packages/plugins/tests/daily-quota.test.mjs
packages/business/tests/plugin-settings.test.mjs
packages/business/tests/token-limit-settings.test.mjs
packages/bus/tests/usage.test.mjs
packages/bus/tests/proxy-usage.test.mjs
packages/bus/tests/p5-runtime.test.mjs
packages/bus/tests/p5-key-context.test.mjs
packages/bus/tests/limit-checks.test.mjs
packages/bus/tests/usage-runtime.test.mjs
packages/bus/tests/usage-broker.test.mjs
packages/bus/tests/daily-quota-runtime.test.mjs
packages/bus/tests/limits-runtime.test.mjs
packages/bus/tests/limit-stop.test.mjs
packages/bus/tests/plugins-verb.test.mjs
packages/webui/tests/usage.test.mjs
packages/webui/tests/usage-render.test.mjs
packages/bus/tests/p5-identity.test.mjs
packages/bus/tests/p5-key-compatibility.test.mjs
packages/bus/tests/p5-background.test.mjs
packages/bus/tests/model-keys.test.mjs
@@ -0,0 +1,20 @@
// Own-process priority only. A drift is evidence failure, never a behavior RED.
import { setPriority, getPriority } from 'node:os';
import { appendFileSync } from 'node:fs';
const file=process.env.P5_PRIORITY_TRACE;
const capture=phase=>{let priority=null;try{priority=getPriority(0);}catch{};const row={phase,pid:process.pid,ppid:process.ppid,priority};appendFileSync(file,JSON.stringify(row)+'\n');if(priority!==19)process.exitCode=78;return row;};
try{setPriority(0,19);}catch{appendFileSync(file,JSON.stringify({phase:'setup-failed',pid:process.pid})+'\n');process.exit(78);}
const enter=capture('before-modules');if(enter.priority!==19)process.exit(78);
const direct=process.ppid===Number(process.env.P5_PRIORITY_PARENT) && typeof process.send==='function';
if(direct){
await new Promise(resolve=>{process.once('message',msg=>{if(msg?.p5Priority!=='before-ack'||msg.priority!==19)process.exit(78);resolve();});process.send({p5Priority:'before',...enter});});
if(capture('before-modules-acked').priority!==19)process.exit(78);
process.channel.unref();
}
let sampled=false;
process.on('beforeExit',()=>{
if(sampled)return;sampled=true;
const after=capture('after-modules');
if(direct&&process.connected){process.channel.ref();process.once('message',msg=>{if(msg?.p5Priority!=='after-ack'||msg.priority!==19)process.exitCode=78;process.disconnect();});process.send({p5Priority:'after',...after});}
});
process.on('exit',()=>capture('exit'));
@@ -0,0 +1,64 @@
serial nice19/private HOME/XDG_CONFIG_HOME/TMPDIR/MOSAIC_CONFIG; current whole files; original budgets
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["70a0d738f730"]}
model-proxy: {"action":"proxy.reconcile","code":"proxy-open"}
model-proxy: {"action":"proxy.boot-refused","code":"proxy-open"}
model-proxy: {"call":"GET /v8/management/observability/usage/queue","status":200,"keyIds":[]}
usage: {"action":"proxy.usage.reconcile","keyId":"2d76a74ee538","code":"proxy-usage-unknown-key"}
✖ P5 R1 boot identity refusal prevents queue consumption (125.800633ms)
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["ef88c818311e"]}
model-proxy: {"action":"proxy.reconcile","addedKeyIds":[],"removedKeyIds":[]}
model-proxy: {"call":"GET /v8/management/observability/usage/queue","status":200,"keyIds":[]}
usage: {"action":"proxy.usage.reconcile","keyId":"2d76a74ee538","code":"proxy-usage-unknown-key"}
✔ P5 R1 boot identity matching sentinel permits telemetry without an agent key (97.002793ms)
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["e2be6c3cd8a1"]}
model-proxy: {"action":"proxy.reconcile","addedKeyIds":[],"removedKeyIds":[]}
model-proxy: {"call":"GET /v8/management/observability/usage/queue","status":200,"keyIds":[]}
usage: {"action":"proxy.usage.reconcile","keyId":"2d76a74ee538","code":"proxy-usage-unknown-key"}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["56754da18bfc"]}
model-proxy: {"call":"GET /v8/management/observability/usage/queue","status":200,"keyIds":[]}
✖ P5 R1 later sentinel refusal fences every subsequent queue poll while preserving human control (91.983417ms)
ℹ tests 3
ℹ suites 0
ℹ pass 1
ℹ fail 2
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 449.925938
✖ failing tests:
test at packages/bus/tests/p5-identity.test.mjs:4:35
✖ P5 R1 boot identity refusal prevents queue consumption (125.800633ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
1 !== 0
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-identity.test.mjs:10:12)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async Test.run (node:internal/test_runner/test:1409:7)
at async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: 1,
expected: 0,
operator: 'strictEqual',
diff: 'simple'
}
test at packages/bus/tests/p5-identity.test.mjs:19:1
✖ P5 R1 later sentinel refusal fences every subsequent queue poll while preserving human control (91.983417ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
2 !== 1
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-identity.test.mjs:24:42)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: 2,
expected: 1,
operator: 'strictEqual',
diff: 'simple'
}
@@ -0,0 +1,87 @@
serial nice19/private HOME/XDG_CONFIG_HOME/TMPDIR/MOSAIC_CONFIG; current whole files; original budgets
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["f5a3100515d0"]}
model-proxy: {"action":"proxy.reconcile","code":"proxy-open"}
model-proxy: {"action":"proxy.boot-refused","code":"proxy-open"}
model-proxy: {"call":"GET /v8/management/observability/usage/queue","status":200,"keyIds":[]}
usage: {"action":"proxy.usage.reconcile","keyId":"2d76a74ee538","code":"proxy-usage-unknown-key"}
✖ P5 R1 boot identity refusal prevents queue consumption (128.483916ms)
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["7a3cb88227a1"]}
model-proxy: {"action":"proxy.reconcile","addedKeyIds":[],"removedKeyIds":[]}
model-proxy: {"call":"GET /v8/management/observability/usage/queue","status":200,"keyIds":[]}
usage: {"action":"proxy.usage.reconcile","keyId":"2d76a74ee538","code":"proxy-usage-unknown-key"}
✔ P5 R1 boot identity matching sentinel permits telemetry without an agent key (92.549175ms)
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["d65bc75c34be"]}
model-proxy: {"action":"proxy.reconcile","addedKeyIds":[],"removedKeyIds":[]}
model-proxy: {"call":"GET /v8/management/observability/usage/queue","status":200,"keyIds":[]}
usage: {"action":"proxy.usage.reconcile","keyId":"2d76a74ee538","code":"proxy-usage-unknown-key"}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["4ebc52a66f1f"]}
model-proxy: {"call":"GET /v8/management/observability/usage/queue","status":200,"keyIds":[]}
✖ P5 R1 later sentinel refusal fences every subsequent queue poll while preserving human control (89.288341ms)
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["381e8696a4aa"]}
model-proxy: {"action":"proxy.reconcile","addedKeyIds":[],"removedKeyIds":[]}
model-proxy: {"call":"GET /v8/management/observability/usage/queue","status":200,"keyIds":[]}
usage: {"action":"proxy.usage.reconcile","keyId":"2d76a74ee538","code":"proxy-usage-unknown-key"}
model-proxy: {"call":"GET /v8/management/observability/usage/queue","status":200,"keyIds":[]}
✖ P5 R1 every drain verifies fresh sentinel before consuming a changed listener (86.240495ms)
ℹ tests 4
ℹ suites 0
ℹ pass 1
ℹ fail 3
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 510.10727
✖ failing tests:
test at packages/bus/tests/p5-identity.test.mjs:4:35
✖ P5 R1 boot identity refusal prevents queue consumption (128.483916ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
1 !== 0
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-identity.test.mjs:10:12)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async Test.run (node:internal/test_runner/test:1409:7)
at async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: 1,
expected: 0,
operator: 'strictEqual',
diff: 'simple'
}
test at packages/bus/tests/p5-identity.test.mjs:19:1
✖ P5 R1 later sentinel refusal fences every subsequent queue poll while preserving human control (89.288341ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
2 !== 1
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-identity.test.mjs:24:42)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: 2,
expected: 1,
operator: 'strictEqual',
diff: 'simple'
}
test at packages/bus/tests/p5-identity.test.mjs:30:1
✖ P5 R1 every drain verifies fresh sentinel before consuming a changed listener (86.240495ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
2 !== 1
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-identity.test.mjs:33:65)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: 2,
expected: 1,
operator: 'strictEqual',
diff: 'simple'
}
@@ -0,0 +1,58 @@
serial nice19/private HOME/XDG_CONFIG_HOME/TMPDIR/MOSAIC_CONFIG; current whole files; original budgets
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["86c48fc677b6"]}
model-proxy: {"action":"proxy.reconcile","code":"proxy-open"}
model-proxy: {"action":"proxy.boot-refused","code":"proxy-open"}
usage: {"action":"proxy.usage","code":"proxy-usage-read-failed"}
usage: {"action":"proxy.usage","code":"proxy-usage-read-failed"}
✔ P5 R1 boot identity refusal prevents queue consumption (130.508163ms)
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["bd046882d09b"]}
model-proxy: {"action":"proxy.reconcile","addedKeyIds":[],"removedKeyIds":[]}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["bd046882d09b"]}
model-proxy: {"call":"GET /v8/management/observability/usage/queue","status":200,"keyIds":[]}
usage: {"action":"proxy.usage.reconcile","keyId":"2d76a74ee538","code":"proxy-usage-unknown-key"}
✔ P5 R1 boot identity matching sentinel permits telemetry without an agent key (88.658667ms)
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["4b34617e0395"]}
model-proxy: {"action":"proxy.reconcile","addedKeyIds":[],"removedKeyIds":[]}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["4b34617e0395"]}
model-proxy: {"call":"GET /v8/management/observability/usage/queue","status":200,"keyIds":[]}
usage: {"action":"proxy.usage.reconcile","keyId":"2d76a74ee538","code":"proxy-usage-unknown-key"}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["7dffb1f98321"]}
usage: {"action":"proxy.usage","code":"proxy-usage-read-failed"}
usage: {"action":"proxy.usage","code":"proxy-usage-read-failed"}
✔ P5 R1 later sentinel refusal fences every subsequent queue poll while preserving human control (90.624642ms)
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["214865151ff7"]}
model-proxy: {"action":"proxy.reconcile","addedKeyIds":[],"removedKeyIds":[]}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["214865151ff7"]}
model-proxy: {"call":"GET /v8/management/observability/usage/queue","status":200,"keyIds":[]}
usage: {"action":"proxy.usage.reconcile","keyId":"2d76a74ee538","code":"proxy-usage-unknown-key"}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["05c20c828aab"]}
usage: {"action":"proxy.usage","code":"proxy-usage-read-failed"}
usage: {"action":"proxy.usage","code":"proxy-usage-read-failed"}
✔ P5 R1 every drain verifies fresh sentinel before consuming a changed listener (89.507433ms)
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["3c2be7b3eafc"]}
model-proxy: {"action":"proxy.reconcile","addedKeyIds":[],"removedKeyIds":[]}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["3c2be7b3eafc"]}
model-proxy: {"call":"PUT /v8/management/config/access/api-keys","status":200,"keyIds":["3c2be7b3eafc","59588bcfb072"]}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["3c2be7b3eafc","59588bcfb072"]}
model-proxy: {"action":"proxy.key.issued","keyIds":["59588bcfb072"],"instance":"demo/coder"}
model-proxy: {"call":"GET /v1/models","status":200,"keyIds":["59588bcfb072"]}
organization: {"event":"reload-needs-restart","business":"demo"}
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mustStop","subject":{"instance":"coder","provider":null,"model":null,"account":null,"modelKeyId":"59588bcfb072"},"path":["tokens","keys","59588bcfb072"],"limit":2,"count":2,"unknownTurns":0}
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mayLaunch","subject":{"instance":"coder","provider":"fixture","model":"fake","account":null,"modelKeyId":"59588bcfb072"},"path":["tokens","keys","59588bcfb072"],"limit":2,"count":2,"unknownTurns":0}
organization: {"event":"reload-needs-restart","business":"demo"}
✔ P5 real runtime binds stack usage to issued key, daily stops at stack count and human-only telemetry settings pass broker contract (307.634061ms)
✔ P5 usage plugin off by default, default poll is 15 seconds and configured polls skip early ticks (59.231552ms)
✔ P5 safe telemetry stores failures per key and proxy-labelled accounts; no client/upstream value enters store/log/view or quota records (51.73727ms)
✔ P5 unknown msk key goes only to value-free reconcile log and other businesses stay isolated (41.741296ms)
✔ P5 queue failure is safe, does not enforce and does not retry before poll deadline (41.631253ms)
✔ P5 retiring key keeps attribution and telemetry rows remain append-only across reader restart (45.675917ms)
✔ P5 malformed queue batch is atomic: no valid prefix, body or credential can reach store/log/view (40.836614ms)
✔ P5 concurrent ticks issue one bounded queue read and a closed collector never polls again (41.649306ms)
ℹ tests 12
ℹ suites 0
ℹ pass 12
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1339.356951
@@ -0,0 +1,151 @@
serial nice19/private HOME/XDG_CONFIG_HOME/TMPDIR/MOSAIC_CONFIG; current whole files; original budgets
✖ P5 R1 plain twelve-hex account leaves retain matching and original account report even with another model ID (1.287351ms)
✖ P5 R1 legacy account core lookup stays independent of missing proxy metadata (44.846563ms)
✖ P5 R1 legacy account core lookup stays independent of unrelated proxy metadata (75.574178ms)
✖ P5 R1 empty checks bypass model metadata for legacy hex account leaves (40.99232ms)
✖ P5 R1 empty checks bypass model metadata for daily model leaves (39.708938ms)
✖ P5 R1 legacy hex account chief resets stay allowed; daily model old/new/removal/reset transitions stay human-only (6.300602ms)
ℹ tests 6
ℹ suites 0
ℹ pass 0
ℹ fail 6
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 286.933279
✖ failing tests:
test at packages/bus/tests/p5-key-compatibility.test.mjs:15:1
✖ P5 R1 plain twelve-hex account leaves retain matching and original account report even with another model ID (1.287351ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
true !== false
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-key-compatibility.test.mjs:17:9)
at Test.runInAsyncScope (node:async_hooks:226:14)
at Test.run (node:internal/test_runner/test:1402:25)
at Test.start (node:internal/test_runner/test:1262:17)
at startSubtestAfterBootstrap (node:internal/test_runner/harness:387:17) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: true,
expected: false,
operator: 'strictEqual',
diff: 'simple'
}
test at packages/bus/tests/p5-key-compatibility.test.mjs:22:33
✖ P5 R1 legacy account core lookup stays independent of missing proxy metadata (44.846563ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected
{
+ allow: false,
+ check: null,
+ code: 'proxy-key-refused'
- allow: true
}
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-key-compatibility.test.mjs:27:9)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: { allow: false, check: null, code: 'proxy-key-refused' },
expected: { allow: true },
operator: 'deepStrictEqual',
diff: 'simple'
}
test at packages/bus/tests/p5-key-compatibility.test.mjs:22:33
✖ P5 R1 legacy account core lookup stays independent of unrelated proxy metadata (75.574178ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected
{
+ allow: true
- allow: false,
- check: 'token-limit',
- hit: {
- count: 10,
- limit: 10,
- path: [
- 'tokens',
- 'keys',
- 'abcdefabcdef'
- ],
- unknownTurns: 0
- }
}
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-key-compatibility.test.mjs:31:9)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: { allow: true },
expected: { allow: false, check: 'token-limit', hit: { path: [Array], limit: 10, count: 10, unknownTurns: 0 } },
operator: 'deepStrictEqual',
diff: 'simple'
}
test at packages/bus/tests/p5-key-compatibility.test.mjs:35:43
✖ P5 R1 empty checks bypass model metadata for legacy hex account leaves (40.99232ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected
{
+ allow: false,
+ check: null,
+ code: 'proxy-key-refused'
- allow: true
}
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-key-compatibility.test.mjs:38:9)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: { allow: false, check: null, code: 'proxy-key-refused' },
expected: { allow: true },
operator: 'deepStrictEqual',
diff: 'simple'
}
test at packages/bus/tests/p5-key-compatibility.test.mjs:35:43
✖ P5 R1 empty checks bypass model metadata for daily model leaves (39.708938ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected
{
+ allow: false,
+ check: null,
+ code: 'proxy-key-refused'
- allow: true
}
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-key-compatibility.test.mjs:38:9)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: { allow: false, check: null, code: 'proxy-key-refused' },
expected: { allow: true },
operator: 'deepStrictEqual',
diff: 'simple'
}
test at packages/bus/tests/p5-key-compatibility.test.mjs:41:1
✖ P5 R1 legacy hex account chief resets stay allowed; daily model old/new/removal/reset transitions stay human-only (6.300602ms)
TypeError: Cannot convert undefined or null to object
at Object.entries (<anonymous>)
at mergeVars (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/src/vars.mjs:208:39)
at resolveInstance (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/src/resolve.mjs:58:32)
at file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/src/launch-settings.mjs:149:20
at Array.map (<anonymous>)
at Object.view [as read] (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/src/launch-settings.mjs:148:70)
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-key-compatibility.test.mjs:45:115)
at Test.runInAsyncScope (node:async_hooks:226:14)
at Test.run (node:internal/test_runner/test:1402:25)
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
@@ -0,0 +1,153 @@
serial nice19/private HOME/XDG_CONFIG_HOME/TMPDIR/MOSAIC_CONFIG; current whole files; original budgets
✖ P5 R1 plain twelve-hex account leaves retain matching and original account report even with another model ID (1.240436ms)
✖ P5 R1 legacy account core lookup stays independent of missing proxy metadata (39.542498ms)
✖ P5 R1 legacy account core lookup stays independent of unrelated proxy metadata (41.657463ms)
✖ P5 R1 empty checks bypass model metadata for legacy hex account leaves (42.329077ms)
✖ P5 R1 empty checks bypass model metadata for daily model leaves (38.400191ms)
✖ P5 R1 legacy hex account chief resets stay allowed; daily model old/new/removal/reset transitions stay human-only (28.304788ms)
ℹ tests 6
ℹ suites 0
ℹ pass 0
ℹ fail 6
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 266.994555
✖ failing tests:
test at packages/bus/tests/p5-key-compatibility.test.mjs:15:1
✖ P5 R1 plain twelve-hex account leaves retain matching and original account report even with another model ID (1.240436ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
true !== false
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-key-compatibility.test.mjs:17:9)
at Test.runInAsyncScope (node:async_hooks:226:14)
at Test.run (node:internal/test_runner/test:1402:25)
at Test.start (node:internal/test_runner/test:1262:17)
at startSubtestAfterBootstrap (node:internal/test_runner/harness:387:17) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: true,
expected: false,
operator: 'strictEqual',
diff: 'simple'
}
test at packages/bus/tests/p5-key-compatibility.test.mjs:22:33
✖ P5 R1 legacy account core lookup stays independent of missing proxy metadata (39.542498ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected
{
+ allow: false,
+ check: null,
+ code: 'proxy-key-refused'
- allow: true
}
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-key-compatibility.test.mjs:27:9)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: { allow: false, check: null, code: 'proxy-key-refused' },
expected: { allow: true },
operator: 'deepStrictEqual',
diff: 'simple'
}
test at packages/bus/tests/p5-key-compatibility.test.mjs:22:33
✖ P5 R1 legacy account core lookup stays independent of unrelated proxy metadata (41.657463ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected
{
+ allow: true
- allow: false,
- check: 'token-limit',
- hit: {
- count: 10,
- limit: 10,
- path: [
- 'tokens',
- 'keys',
- 'abcdefabcdef'
- ],
- unknownTurns: 0
- }
}
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-key-compatibility.test.mjs:31:9)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: { allow: true },
expected: { allow: false, check: 'token-limit', hit: { path: [Array], limit: 10, count: 10, unknownTurns: 0 } },
operator: 'deepStrictEqual',
diff: 'simple'
}
test at packages/bus/tests/p5-key-compatibility.test.mjs:35:43
✖ P5 R1 empty checks bypass model metadata for legacy hex account leaves (42.329077ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected
{
+ allow: false,
+ check: null,
+ code: 'proxy-key-refused'
- allow: true
}
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-key-compatibility.test.mjs:38:9)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: { allow: false, check: null, code: 'proxy-key-refused' },
expected: { allow: true },
operator: 'deepStrictEqual',
diff: 'simple'
}
test at packages/bus/tests/p5-key-compatibility.test.mjs:35:43
✖ P5 R1 empty checks bypass model metadata for daily model leaves (38.400191ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected
{
+ allow: false,
+ check: null,
+ code: 'proxy-key-refused'
- allow: true
}
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-key-compatibility.test.mjs:38:9)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: { allow: false, check: null, code: 'proxy-key-refused' },
expected: { allow: true },
operator: 'deepStrictEqual',
diff: 'simple'
}
test at packages/bus/tests/p5-key-compatibility.test.mjs:41:1
✖ P5 R1 legacy hex account chief resets stay allowed; daily model old/new/removal/reset transitions stay human-only (28.304788ms)
Error: organization-model-quota-human-only
at fail (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/src/organization.mjs:21:9)
at modelQuotaFence (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/src/organization.mjs:91:3)
at file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/src/organization.mjs:263:9
at withLock (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/src/organization.mjs:189:14)
at Object.write (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/src/organization.mjs:251:14)
at Object.set (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/src/launch-settings.mjs:247:28)
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-key-compatibility.test.mjs:46:13)
at Test.runInAsyncScope (node:async_hooks:226:14)
at Test.run (node:internal/test_runner/test:1402:25)
at Test.processPendingSubtests (node:internal/test_runner/test:974:18) {
code: 'organization-model-quota-human-only'
}
@@ -0,0 +1,15 @@
serial nice19/private HOME/XDG_CONFIG_HOME/TMPDIR/MOSAIC_CONFIG; current whole files; original budgets
✔ P5 R1 plain twelve-hex account leaves retain matching and original account report even with another model ID (2.200722ms)
✔ P5 R1 legacy account core lookup stays independent of missing proxy metadata (66.048932ms)
✔ P5 R1 legacy account core lookup stays independent of unrelated proxy metadata (44.314633ms)
✔ P5 R1 empty checks bypass model metadata for legacy hex account leaves (42.37751ms)
✔ P5 R1 empty checks bypass model metadata for daily model leaves (43.039529ms)
✔ P5 R1 legacy hex account chief resets stay allowed; daily model old/new/removal/reset transitions stay human-only (249.560024ms)
ℹ tests 6
ℹ suites 0
ℹ pass 6
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 523.899686
@@ -0,0 +1,22 @@
✔ P5 R1 plain twelve-hex account leaves retain matching and original account report even with another model ID (1.786896ms)
✔ P5 R1 legacy account core lookup stays independent of missing proxy metadata (52.50413ms)
✔ P5 R1 legacy account core lookup stays independent of unrelated proxy metadata (45.531998ms)
✔ P5 R1 empty checks bypass model metadata for legacy hex account leaves (39.386516ms)
✔ P5 R1 empty checks bypass model metadata for daily model leaves (41.470824ms)
✔ P5 R1 legacy hex account chief resets stay allowed; daily model old/new/removal/reset transitions stay human-only (246.297869ms)
✖ packages/bus/tests/p5-key-compatibility.test.mjs (498.329508ms)
ℹ tests 7
ℹ suites 0
ℹ pass 6
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 503.700106
✖ failing tests:
test at packages/bus/tests/p5-key-compatibility.test.mjs:1:1
✖ packages/bus/tests/p5-key-compatibility.test.mjs (498.329508ms)
'test failed'
UNVERIFIED/STOP: priority drift or incomplete capture; child=1, signal=null
@@ -0,0 +1,5 @@
{"phase":"wrapper-before","pid":2643577,"priority":19}
{"phase":"before-modules","pid":2643590,"ppid":2643584,"priority":19}
{"phase":"after-modules","pid":2643590,"ppid":2643584,"priority":16}
{"phase":"exit","pid":2643590,"ppid":2643584,"priority":16}
{"phase":"wrapper-after","pid":2643577,"priority":16}
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
p5root=$(mktemp -d /tmp/p5-r1-light-XXXXXX)
trap 'rm -rf "$p5root"' EXIT
mkdir "$p5root/home" "$p5root/config" "$p5root/tmp"
export HOME="$p5root/home" XDG_CONFIG_HOME="$p5root/config" TMPDIR="$p5root/tmp" MOSAIC_CONFIG="$p5root/config/absent.json"
printf '%s\n' 'serial nice19/private HOME/XDG_CONFIG_HOME/TMPDIR/MOSAIC_CONFIG; current whole files; original budgets'
nice -n 19 node --test --test-concurrency=1 "$@"
@@ -0,0 +1,26 @@
import { setPriority, getPriority } from 'node:os';
import { spawn } from 'node:child_process';
import { appendFileSync, readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
const file=process.env.P5_PRIORITY_TRACE;
const capture=(phase,pid=0)=>{let priority=null;try{priority=getPriority(pid);}catch{};const row={phase,pid:pid||process.pid,priority};appendFileSync(file,JSON.stringify(row)+'\n');return priority;};
try{setPriority(0,19);}catch{process.stderr.write('UNVERIFIED/STOP: own wrapper priority setup failed\n');process.exit(78);}
if(capture('wrapper-before')!==19)process.exit(78);
const child=spawn(process.execPath,['--import',fileURLToPath(new URL('./priority-guard.mjs',import.meta.url)),'--test','--test-concurrency=1',...process.argv.slice(2)],{
env:{...process.env,P5_PRIORITY_PARENT:String(process.pid)},stdio:['ignore','inherit','inherit','ipc'],
});
child.on('message',msg=>{
if(!['before','after'].includes(msg?.p5Priority))return;
const priority=capture(`direct-child-${msg.p5Priority}`,child.pid);
child.send({p5Priority:`${msg.p5Priority}-ack`,priority});
});
child.on('error',()=>{process.stderr.write('UNVERIFIED/STOP: native child setup failed\n');process.exitCode=78;});
child.on('close',(code,signal)=>{
capture('wrapper-after');
const rows=readFileSync(file,'utf8').trim().split('\n').map(JSON.parse);
const drift=rows.some(r=>r.priority!==19);
const before=rows.filter(r=>r.phase==='before-modules');
const complete=before.length>0&&before.every(r=>rows.some(x=>x.pid===r.pid&&x.phase==='exit'));
if(drift||!complete||signal){process.stderr.write(`UNVERIFIED/STOP: priority drift or incomplete capture; child=${code}, signal=${signal}\n`);process.exitCode=78;}
else{process.stderr.write(`native strict19 verified: ${before.length} Node processes; direct-child before/after readbacks=19; behavior exit=${code}\n`);process.exitCode=code??78;}
});
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -euo pipefail
p5root=$(mktemp -d /tmp/p5-r1-strict-XXXXXX)
trap 'rm -rf "$p5root"' EXIT
mkdir "$p5root/home" "$p5root/config" "$p5root/tmp"
export HOME="$p5root/home" XDG_CONFIG_HOME="$p5root/config" TMPDIR="$p5root/tmp" MOSAIC_CONFIG="$p5root/config/absent.json"
: "${P5_PRIORITY_TRACE:?caller must name a new priority evidence file}"
: > "$P5_PRIORITY_TRACE"
node agents/codex/work/queue-333/r1-repair/run-priority.mjs "$@"
@@ -0,0 +1,28 @@
packages/model-proxy/tests/usage-client.test.mjs
packages/model-proxy/tests/client.test.mjs
packages/model-proxy/tests/client-probe.test.mjs
packages/model-proxy/tests/page-client.test.mjs
packages/model-proxy/tests/management-key-encoding.test.mjs
packages/plugins/tests/kinds.test.mjs
packages/plugins/tests/loader.test.mjs
packages/plugins/tests/token-limit.test.mjs
packages/plugins/tests/daily-quota.test.mjs
packages/business/tests/plugin-settings.test.mjs
packages/business/tests/token-limit-settings.test.mjs
packages/bus/tests/usage.test.mjs
packages/bus/tests/proxy-usage.test.mjs
packages/bus/tests/p5-runtime.test.mjs
packages/bus/tests/p5-key-context.test.mjs
packages/bus/tests/limit-checks.test.mjs
packages/bus/tests/usage-runtime.test.mjs
packages/bus/tests/usage-broker.test.mjs
packages/bus/tests/daily-quota-runtime.test.mjs
packages/bus/tests/limits-runtime.test.mjs
packages/bus/tests/limit-stop.test.mjs
packages/bus/tests/plugins-verb.test.mjs
packages/webui/tests/usage.test.mjs
packages/webui/tests/usage-render.test.mjs
packages/bus/tests/p5-identity.test.mjs
packages/bus/tests/p5-key-compatibility.test.mjs
packages/bus/tests/p5-background.test.mjs
packages/bus/tests/model-keys.test.mjs
@@ -0,0 +1,25 @@
agents/codex/work/queue-333/receipts/01-token-red.txt: OK
agents/codex/work/queue-333/receipts/02-contract-red.txt: OK
agents/codex/work/queue-333/receipts/03-core-green.txt: OK
agents/codex/work/queue-333/receipts/04-integration-red.txt: OK
agents/codex/work/queue-333/receipts/05-collector-green.txt: OK
agents/codex/work/queue-333/receipts/06-collector-green.txt: OK
agents/codex/work/queue-333/receipts/07-wiring-green.txt: OK
agents/codex/work/queue-333/receipts/08-edges-red.txt: OK
agents/codex/work/queue-333/receipts/09-lookup-red.txt: OK
agents/codex/work/queue-333/receipts/10-lookup-behavior-red.txt: OK
agents/codex/work/queue-333/receipts/11-edges-green.txt: OK
agents/codex/work/queue-333/receipts/12-runtime.txt: OK
agents/codex/work/queue-333/receipts/13-runtime.txt: OK
agents/codex/work/queue-333/receipts/14-runtime.txt: OK
agents/codex/work/queue-333/receipts/15-safety-green.txt: OK
agents/codex/work/queue-333/receipts/16-upstream-value-mutant.txt: OK
agents/codex/work/queue-333/receipts/17-mutant-restored-green.txt: OK
agents/codex/work/queue-333/receipts/18-current-wholefiles.txt: OK
agents/codex/work/queue-333/receipts/19-current-wholefiles-green.txt: OK
agents/codex/work/queue-333/receipts/20-context-bypass-red.txt: OK
agents/codex/work/queue-333/receipts/21-context-green.txt: OK
agents/codex/work/queue-333/receipts/22-final-current-wholefiles-green.txt: OK
agents/codex/work/queue-333/receipts/23-missing-context-red.txt: OK
agents/codex/work/queue-333/receipts/24-final-current-wholefiles-green.txt: OK
agents/codex/work/queue-333/receipts/source-inputs.raw.jsonl: OK
@@ -0,0 +1,25 @@
83116bee02980cd12f66b9db2db0dfe4add8c1d2a19b7de3a3b05c18b0cec8cd agents/codex/work/queue-333/receipts/01-token-red.txt
0f21d268ed7777bcfc0290160f30016932f0f3580d9174daf84158833e693e0f agents/codex/work/queue-333/receipts/02-contract-red.txt
9aa1d4feb1924ac45c8fa9af14714aa8c89ef6ba7d711884f415c6473ffe20af agents/codex/work/queue-333/receipts/03-core-green.txt
11ed664ff680750630dd861bc60cc2cc47cba77575cb63e64001e3271162c33a agents/codex/work/queue-333/receipts/04-integration-red.txt
818e3654c49d95ac81200676c46ebecc8155b101352e4e34ed8907a6b4bd93db agents/codex/work/queue-333/receipts/05-collector-green.txt
304d137843363f96eb9b0bfef8a570b5d2c3ee53fc66da4ebb5e18a571f71fce agents/codex/work/queue-333/receipts/06-collector-green.txt
6bb1254ff078de90dac8503c326422180c5c40df7be6aea569ce6f41cf136a49 agents/codex/work/queue-333/receipts/07-wiring-green.txt
0fe51fde4f88bf85d049b26ebfd3048fbc15db3e6785d14f45b987256744def8 agents/codex/work/queue-333/receipts/08-edges-red.txt
e47bc241fe8bfcc8a84e64a274d51383f143b16b95fe5ffaf3fa5ec5030b5d2c agents/codex/work/queue-333/receipts/09-lookup-red.txt
688dff5c657bfb58c8a4125cbfb4decdb62633d0e1be9b2579dea2d2619db009 agents/codex/work/queue-333/receipts/10-lookup-behavior-red.txt
58ac0ed96465af6571b899402e47dc3cd76f420873975e0ca8df091184c9f322 agents/codex/work/queue-333/receipts/11-edges-green.txt
f3be41efca8f65dbf5a69b2ad5541d090db7f1f084b7d95eca5192cf07fcf0b2 agents/codex/work/queue-333/receipts/12-runtime.txt
9aefb96aa52e8baf033eebf14226c74db255b6047f9fd0a46d5bc20b2b75d04e agents/codex/work/queue-333/receipts/13-runtime.txt
9331e56310edd0a8d31807d9f0b7c1092188eb75be44e0c001f001a751b55654 agents/codex/work/queue-333/receipts/14-runtime.txt
d138c2fa4c79ed4bed64fec95c08ec706e092766d5d74c421a26206d7d844ded agents/codex/work/queue-333/receipts/15-safety-green.txt
10a1ad5d5eecfcdef684f35e861fa2903c2598008ce18b05fb56d2d5460f6fa0 agents/codex/work/queue-333/receipts/16-upstream-value-mutant.txt
25f57b7482a0110a8be18e233e2b216b2d99ea826359d60bf1c72c075da036de agents/codex/work/queue-333/receipts/17-mutant-restored-green.txt
aefa2196d51cf0e957bdf03b769757d27a174bd163627c72aa8c8eb2c47a21da agents/codex/work/queue-333/receipts/18-current-wholefiles.txt
31357c2a88cc3a70ed9fa4b79a43715b34493d9abbb816029f6a8ffac72f4db5 agents/codex/work/queue-333/receipts/19-current-wholefiles-green.txt
4fbae7204515aac046c7b782df18c5fba937fdfc536527740ffeffffe0f59226 agents/codex/work/queue-333/receipts/20-context-bypass-red.txt
764db5e9b464d6b070720977c0a62edbd4e9329ca918cedc1ee69419da96d47d agents/codex/work/queue-333/receipts/21-context-green.txt
5d45ed8ea8e79e91c4b41a59239824ef05cfa924a55b3cc6fb163120027ed441 agents/codex/work/queue-333/receipts/22-final-current-wholefiles-green.txt
f6928aae72409ec0e8b13da469c5a957ebc8f6ae1911dfeec8c681359fc4b429 agents/codex/work/queue-333/receipts/23-missing-context-red.txt
3358af061c35d42b00d5ee1e001939534c5e7563d4f5418ea85431605d0b9f6d agents/codex/work/queue-333/receipts/24-final-current-wholefiles-green.txt
9c16aa4b8e6d81aa5b9867fec5e0890b22e90db5c307da55badfcfa9f240aef1 agents/codex/work/queue-333/receipts/source-inputs.raw.jsonl
@@ -0,0 +1,43 @@
✔ REQ-LIMIT-3 token-limit exports interface version 2 with mayLaunch, mustStop and report (3.955474ms)
✔ REQ-LIMIT-3 each subject kind refuses at its limit and allows under it (1.336324ms)
✔ REQ-LIMIT-3 a limit covers only its own subject's records and launches (0.329981ms)
✔ REQ-LIMIT-4 only known records count; an unknown turn adds nothing and is counted apart (0.256881ms)
✔ REQ-LIMIT-3 a reset moves since: records before it no longer count (0.171382ms)
✔ REQ-LIMIT-3 limit 0 refuses with no records; the first limit hit in file order is named (0.142272ms)
✔ REQ-LIMIT-3 a key limit is not enforced while every record's account is null (decision 150 Q1) (0.184471ms)
✔ REQ-LIMIT-3 counts past the safe integer range come back as digit strings (0.143936ms)
✔ REQ-LIMIT-4 bad records or times throw a code, and the check reads nothing but its arguments (0.65868ms)
✔ REQ-LIMIT-3 no token limits: every launch is allowed and the report is empty (0.216805ms)
✔ REQ-LIMIT-3 token-limit ignores tokens.daily, which the daily-quota check enforces (row 126) (0.16854ms)
✖ P5 a model key ID limit counts stack records by key ID without an account (0.661965ms)
ℹ tests 12
ℹ suites 0
ℹ pass 11
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 51.890649
✖ failing tests:
test at packages/plugins/tests/token-limit.test.mjs:153:1
✖ P5 a model key ID limit counts stack records by key ID without an account (0.661965ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
true !== false
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/plugins/tests/token-limit.test.mjs:158:10)
at Test.runInAsyncScope (node:async_hooks:226:14)
at Test.run (node:internal/test_runner/test:1402:25)
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
at Test.postRun (node:internal/test_runner/test:1542:19)
at Test.run (node:internal/test_runner/test:1467:12)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: true,
expected: false,
operator: 'strictEqual',
diff: 'simple'
}
@@ -0,0 +1,131 @@
✔ REQ-LIMIT-3 schema: each subject kind, limit 0 and no ceiling are accepted; bad limits, times, keys and undeclared instances refuse (18.6933ms)
✔ REQ-LIMIT-3 the writer stamps since: a new limit gets now, a changed one keeps its time, a different time is refused (266.957706ms)
✔ REQ-LIMIT-3 only tokens.* at schema depth holds token limits: agent limits named `limit` save as sent, and a token limit named `limit` is stamped and reset (259.927876ms)
✔ REQ-LIMIT-3 a reset moves since to now, is logged with its actor, and refuses a path that is not a limit (136.121744ms)
✔ REQ-LIMIT-2 schema: launch.account names a credential set; a daily quota needs a reset and an IANA zone and names the account (27.149735ms)
✔ REQ-LIMIT-2 the writer stamps a daily quota's since, keeps its reset and zone, and a reset moves since (147.184856ms)
✖ P5 per-model-key quotas are unset by default, accept digit-leading IDs and only the human changes or resets them (2.663205ms)
✖ P5 queue read uses actual bounded fixed management GET and immediately drops client and upstream values (7.314165ms)
✖ P5 bad envelope refuses safely with no retry (1.407651ms)
✖ P5 over count refuses safely with no retry (0.970003ms)
✖ P5 missing key refuses safely with no retry (0.457173ms)
✖ P5 bad counts refuses safely with no retry (0.970914ms)
✖ P5 redirect refuses safely with no retry (0.566467ms)
✖ P5 refusal refuses safely with no retry (0.492518ms)
✔ REQ-LIMIT-2 daily-quota exports interface version 2 with mayLaunch, mustStop and report (4.119781ms)
✔ REQ-LIMIT-2 the count sums every kind of the account's known records since the later of the day start and since (11.801692ms)
✔ REQ-LIMIT-2 a launch with no account (pi) is covered by no daily quota (0.304042ms)
✔ REQ-LIMIT-4 an unknown turn adds nothing and is counted apart (0.440258ms)
✔ REQ-LIMIT-2 the day turns at the reset in its zone, not in UTC, and before it the day is yesterday's (0.636362ms)
✔ REQ-LIMIT-2 the spring DST change makes the day after a 00:00 reset 23 hours long (0.3629ms)
✔ REQ-LIMIT-2 the fall DST change makes the day after a 00:00 reset 25 hours long (0.307097ms)
✔ REQ-LIMIT-2 a reset the clocks skip starts the day at the first instant after the gap (1.317847ms)
✔ REQ-LIMIT-2 a reset the clocks repeat starts one day, at the first one (0.410965ms)
✔ REQ-LIMIT-2 a launch is refused at the quota, a turn that reaches it stops, and the next day allows again (1.040865ms)
✔ REQ-LIMIT-2 counts past the safe integer range come back as digit strings (0.338405ms)
✔ REQ-LIMIT-4 bad leaves, records or times throw a code, and the check reads nothing but its arguments (2.143241ms)
✔ REQ-LIMIT-2 no daily quotas: every launch is allowed and the report is empty (0.174843ms)
✖ P5 daily quota for a model key ID matches stack key records and resets the next day (0.717346ms)
ℹ tests 28
ℹ suites 0
ℹ pass 19
ℹ fail 9
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1055.443581
✖ failing tests:
test at packages/business/tests/token-limit-settings.test.mjs:154:1
✖ P5 per-model-key quotas are unset by default, accept digit-leading IDs and only the human changes or resets them (2.663205ms)
Error [BusinessError]: unsupported /tmp/mosaic-row333-4L4S3o/tmp/mosaic-business-CbuiLR/businesses/acme.json launch.limits.tokens.keys.012345abcdef key: "reset"
at refuse (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/src/errors.mjs:12:9)
at rejectUnknownKeys (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/src/util.mjs:17:33)
at tokenLimit (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/src/launch.mjs:31:3)
at file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/src/launch.mjs:57:80
at Array.map (<anonymous>)
at tokenMap (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/src/launch.mjs:57:51)
at checkTokenLimits (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/src/launch.mjs:71:48)
at checkLimits (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/src/launch.mjs:112:52)
at checkLaunch (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/src/business.mjs:196:16)
at validateBusinessDocument (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/src/business.mjs:310:57) {
exitCode: 2
}
test at packages/model-proxy/tests/usage-client.test.mjs:21:1
✖ P5 queue read uses actual bounded fixed management GET and immediately drops client and upstream values (7.314165ms)
TypeError: f.client.readUsageQueue is not a function
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/model-proxy/tests/usage-client.test.mjs:23:33)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async Test.run (node:internal/test_runner/test:1409:7)
at async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
test at packages/model-proxy/tests/usage-client.test.mjs:38:4
✖ P5 bad envelope refuses safely with no retry (1.407651ms)
TypeError: f.client.readUsageQueue is not a function
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/model-proxy/tests/usage-client.test.mjs:40:33)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
test at packages/model-proxy/tests/usage-client.test.mjs:38:4
✖ P5 over count refuses safely with no retry (0.970003ms)
TypeError: f.client.readUsageQueue is not a function
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/model-proxy/tests/usage-client.test.mjs:40:33)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
test at packages/model-proxy/tests/usage-client.test.mjs:38:4
✖ P5 missing key refuses safely with no retry (0.457173ms)
TypeError: f.client.readUsageQueue is not a function
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/model-proxy/tests/usage-client.test.mjs:40:33)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
test at packages/model-proxy/tests/usage-client.test.mjs:38:4
✖ P5 bad counts refuses safely with no retry (0.970914ms)
TypeError: f.client.readUsageQueue is not a function
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/model-proxy/tests/usage-client.test.mjs:40:33)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
test at packages/model-proxy/tests/usage-client.test.mjs:38:4
✖ P5 redirect refuses safely with no retry (0.566467ms)
TypeError: f.client.readUsageQueue is not a function
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/model-proxy/tests/usage-client.test.mjs:40:33)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
test at packages/model-proxy/tests/usage-client.test.mjs:38:4
✖ P5 refusal refuses safely with no retry (0.492518ms)
TypeError: f.client.readUsageQueue is not a function
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/model-proxy/tests/usage-client.test.mjs:40:33)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
test at packages/plugins/tests/daily-quota.test.mjs:173:1
✖ P5 daily quota for a model key ID matches stack key records and resets the next day (0.717346ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
true !== false
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/plugins/tests/daily-quota.test.mjs:178:10)
at Test.runInAsyncScope (node:async_hooks:226:14)
at Test.run (node:internal/test_runner/test:1402:25)
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
at Test.postRun (node:internal/test_runner/test:1542:19)
at Test.run (node:internal/test_runner/test:1467:12)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: true,
expected: false,
operator: 'strictEqual',
diff: 'simple'
}
@@ -0,0 +1,48 @@
✔ REQ-LIMIT-3 schema: each subject kind, limit 0 and no ceiling are accepted; bad limits, times, keys and undeclared instances refuse (12.739299ms)
✔ REQ-LIMIT-3 the writer stamps since: a new limit gets now, a changed one keeps its time, a different time is refused (233.858718ms)
✔ REQ-LIMIT-3 only tokens.* at schema depth holds token limits: agent limits named `limit` save as sent, and a token limit named `limit` is stamped and reset (274.692946ms)
✔ REQ-LIMIT-3 a reset moves since to now, is logged with its actor, and refuses a path that is not a limit (129.01269ms)
✔ REQ-LIMIT-2 schema: launch.account names a credential set; a daily quota needs a reset and an IANA zone and names the account (24.597721ms)
✔ REQ-LIMIT-2 the writer stamps a daily quota's since, keeps its reset and zone, and a reset moves since (146.514468ms)
✔ P5 per-model-key quotas are unset by default, accept digit-leading IDs and only the human changes or resets them (202.85529ms)
✔ P5 queue read uses actual bounded fixed management GET and immediately drops client and upstream values (14.363195ms)
✔ P5 bad envelope refuses safely with no retry (3.275949ms)
✔ P5 over count refuses safely with no retry (1.650709ms)
✔ P5 missing key refuses safely with no retry (1.355454ms)
✔ P5 bad counts refuses safely with no retry (2.028358ms)
✔ P5 redirect refuses safely with no retry (1.385706ms)
✔ P5 refusal refuses safely with no retry (1.027413ms)
✔ REQ-LIMIT-2 daily-quota exports interface version 2 with mayLaunch, mustStop and report (4.002643ms)
✔ REQ-LIMIT-2 the count sums every kind of the account's known records since the later of the day start and since (11.703557ms)
✔ REQ-LIMIT-2 a launch with no account (pi) is covered by no daily quota (0.285389ms)
✔ REQ-LIMIT-4 an unknown turn adds nothing and is counted apart (0.427944ms)
✔ REQ-LIMIT-2 the day turns at the reset in its zone, not in UTC, and before it the day is yesterday's (0.664291ms)
✔ REQ-LIMIT-2 the spring DST change makes the day after a 00:00 reset 23 hours long (0.359593ms)
✔ REQ-LIMIT-2 the fall DST change makes the day after a 00:00 reset 25 hours long (0.292084ms)
✔ REQ-LIMIT-2 a reset the clocks skip starts the day at the first instant after the gap (1.428363ms)
✔ REQ-LIMIT-2 a reset the clocks repeat starts one day, at the first one (0.427054ms)
✔ REQ-LIMIT-2 a launch is refused at the quota, a turn that reaches it stops, and the next day allows again (1.066274ms)
✔ REQ-LIMIT-2 counts past the safe integer range come back as digit strings (0.329306ms)
✔ REQ-LIMIT-4 bad leaves, records or times throw a code, and the check reads nothing but its arguments (2.160938ms)
✔ REQ-LIMIT-2 no daily quotas: every launch is allowed and the report is empty (0.172297ms)
✔ P5 daily quota for a model key ID matches stack key records and resets the next day (0.746089ms)
✔ REQ-LIMIT-3 token-limit exports interface version 2 with mayLaunch, mustStop and report (1.156529ms)
✔ REQ-LIMIT-3 each subject kind refuses at its limit and allows under it (1.303907ms)
✔ REQ-LIMIT-3 a limit covers only its own subject's records and launches (0.353216ms)
✔ REQ-LIMIT-4 only known records count; an unknown turn adds nothing and is counted apart (0.2777ms)
✔ REQ-LIMIT-3 a reset moves since: records before it no longer count (0.150391ms)
✔ REQ-LIMIT-3 limit 0 refuses with no records; the first limit hit in file order is named (0.1377ms)
✔ REQ-LIMIT-3 a key limit is not enforced while every record's account is null (decision 150 Q1) (0.170332ms)
✔ REQ-LIMIT-3 counts past the safe integer range come back as digit strings (0.135122ms)
✔ REQ-LIMIT-4 bad records or times throw a code, and the check reads nothing but its arguments (0.635473ms)
✔ REQ-LIMIT-3 no token limits: every launch is allowed and the report is empty (0.62587ms)
✔ REQ-LIMIT-3 token-limit ignores tokens.daily, which the daily-quota check enforces (row 126) (0.130727ms)
✔ P5 a model key ID limit counts stack records by key ID without an account (0.11813ms)
ℹ tests 40
ℹ suites 0
ℹ pass 40
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1270.553008
@@ -0,0 +1,80 @@
node:internal/modules/esm/resolve:272
throw new ERR_MODULE_NOT_FOUND(
^
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/src/proxy-usage.mjs' imported from /home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/proxy-usage.test.mjs
at finalizeResolution (node:internal/modules/esm/resolve:272:11)
at moduleResolve (node:internal/modules/esm/resolve:879:10)
at defaultResolve (node:internal/modules/esm/resolve:1006:11)
at #cachedDefaultResolve (node:internal/modules/esm/loader:708:20)
at #resolveAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:728:38)
at ModuleLoader.resolveSync (node:internal/modules/esm/loader:766:56)
at #resolve (node:internal/modules/esm/loader:690:17)
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:610:35)
at ModuleJob.syncLink (node:internal/modules/esm/module_job:277:33)
at ModuleJob.link (node:internal/modules/esm/module_job:389:17) {
code: 'ERR_MODULE_NOT_FOUND',
url: 'file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/src/proxy-usage.mjs'
}
Node.js v26.8.1
✖ packages/bus/tests/proxy-usage.test.mjs (51.269919ms)
✔ REQ-LIMIT-4 loader source records new turn kinds, excludes history and retries exactly once (51.514952ms)
✔ REQ-LIMIT-4 cut: unknown is durable and logged next to every total (50.36014ms)
✔ REQ-LIMIT-4 disabled: unknown is durable and logged next to every total (46.155638ms)
✔ REQ-LIMIT-4 missing-begin: unknown is durable and logged next to every total (40.267126ms)
✔ REQ-LIMIT-4 no-new-usage: unknown is durable and logged next to every total (45.725198ms)
✔ REQ-LIMIT-4 rewrite: unknown is durable and logged next to every total (45.864606ms)
✔ REQ-LIMIT-4 unfinished turn remains visibly unknown after accounting restarts (40.628929ms)
✔ usage records are append-only (40.809636ms)
✔ REQ-LIMIT-4 parse failure logs its safe code, never transcript content (46.321713ms)
✔ REQ-LIMIT-4 resumed run baselines history and exact totals do not overflow (56.488827ms)
✔ REQ-PLUG-1 core has no transcript import and disabled sources do not read any transcript (45.994492ms)
✔ REQ-LIMIT-4 a resumed thread bills only new assistant messages to its next run (46.867774ms)
✔ REQ-LIMIT-4 every enabled source is called; failure is unknown and a partial total stays labelled (55.909721ms)
✔ REQ-LIMIT-4 a turn whose reported sum exceeds safe precision is unknown, not rounded (72.188479ms)
✔ row 65 a run bound without a transcript directory records no-transcript (47.882475ms)
✖ P5 immutable stack key attribution survives rotation and restart without key values (46.501339ms)
✔ REQ-PLUG-1 schema: plugins is optional, names known kinds and checked module names (10.169709ms)
✔ REQ-PLUG-1 REQ-ROLE-3 the setter writes plugins through the organization writer and logs old and new names (136.187046ms)
✔ vikunja:19/309 a patch changes only the kinds it names; null removes one kind, explicitly and in the trail (158.840283ms)
✔ vikunja:19/309 an unknown kind (set or removed), a bad module, an empty patch and null on the wrong shape are refused, nothing written (1.730784ms)
✔ REQ-PLUG-1 REQ-ROLE-3 the writer checks the bytes it writes: a Date in plugins is refused there too (19.213042ms)
✔ REQ-PLUG-1 REQ-ROLE-3 a refused setter write throws a code, changes nothing and logs nothing (1.512701ms)
✔ vikunja:19/305 with an exists check, the setter refuses a module no tree file answers to, before anything is written (56.368217ms)
✖ P5 optional usage kind and pollSeconds configure through plugins.set; default stays absent and retention bound is strict (1.972898ms)
ℹ tests 25
ℹ suites 0
ℹ pass 22
ℹ fail 3
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1344.122542
✖ failing tests:
test at packages/bus/tests/proxy-usage.test.mjs:1:1
✖ packages/bus/tests/proxy-usage.test.mjs (51.269919ms)
'test failed'
test at packages/bus/tests/usage.test.mjs:157:1
✖ P5 immutable stack key attribution survives rotation and restart without key values (46.501339ms)
TypeError: Cannot read properties of undefined (reading '0')
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/usage.test.mjs:162:39)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
test at packages/business/tests/plugin-settings.test.mjs:148:1
✖ P5 optional usage kind and pollSeconds configure through plugins.set; default stays absent and retention bound is strict (1.972898ms)
Error: invalid-request
at Object.set (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/src/plugin-settings.mjs:22:13)
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/tests/plugin-settings.test.mjs:150:15)
at Test.runInAsyncScope (node:async_hooks:226:14)
at Test.run (node:internal/test_runner/test:1402:25)
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
at Test.postRun (node:internal/test_runner/test:1542:19)
at Test.run (node:internal/test_runner/test:1467:12)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
code: 'invalid-request'
}
@@ -0,0 +1,56 @@
file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/src/limits.mjs:126
const key = keyForSubject(business, subject);
^
SyntaxError: Identifier 'key' has already been declared
at compileSourceTextModule (node:internal/modules/esm/utils:355:16)
at ModuleLoader.moduleStrategy (node:internal/modules/esm/translators:93:18)
at #translate (node:internal/modules/esm/loader:441:20)
at afterLoad (node:internal/modules/esm/loader:509:29)
at ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:514:12)
at #getOrCreateModuleJobAfterResolve (node:internal/modules/esm/loader:567:36)
at afterResolve (node:internal/modules/esm/loader:614:52)
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:620:12)
at ModuleJob.syncLink (node:internal/modules/esm/module_job:277:33)
at ModuleJob.link (node:internal/modules/esm/module_job:389:17)
Node.js v26.8.1
✖ packages/bus/tests/proxy-usage.test.mjs (51.892872ms)
✔ REQ-LIMIT-4 loader source records new turn kinds, excludes history and retries exactly once (50.378772ms)
✔ REQ-LIMIT-4 cut: unknown is durable and logged next to every total (45.234905ms)
✔ REQ-LIMIT-4 disabled: unknown is durable and logged next to every total (44.712639ms)
✔ REQ-LIMIT-4 missing-begin: unknown is durable and logged next to every total (38.834227ms)
✔ REQ-LIMIT-4 no-new-usage: unknown is durable and logged next to every total (45.613047ms)
✔ REQ-LIMIT-4 rewrite: unknown is durable and logged next to every total (61.823662ms)
✔ REQ-LIMIT-4 unfinished turn remains visibly unknown after accounting restarts (39.178221ms)
✔ usage records are append-only (48.911454ms)
✔ REQ-LIMIT-4 parse failure logs its safe code, never transcript content (44.798699ms)
✔ REQ-LIMIT-4 resumed run baselines history and exact totals do not overflow (74.440531ms)
✔ REQ-PLUG-1 core has no transcript import and disabled sources do not read any transcript (44.272941ms)
✔ REQ-LIMIT-4 a resumed thread bills only new assistant messages to its next run (45.321015ms)
✔ REQ-LIMIT-4 every enabled source is called; failure is unknown and a partial total stays labelled (50.132554ms)
✔ REQ-LIMIT-4 a turn whose reported sum exceeds safe precision is unknown, not rounded (45.271975ms)
✔ row 65 a run bound without a transcript directory records no-transcript (45.784161ms)
✔ P5 immutable stack key attribution survives rotation and restart without key values (46.660026ms)
✔ REQ-PLUG-1 schema: plugins is optional, names known kinds and checked module names (9.948537ms)
✔ REQ-PLUG-1 REQ-ROLE-3 the setter writes plugins through the organization writer and logs old and new names (133.831911ms)
✔ vikunja:19/309 a patch changes only the kinds it names; null removes one kind, explicitly and in the trail (204.184755ms)
✔ vikunja:19/309 an unknown kind (set or removed), a bad module, an empty patch and null on the wrong shape are refused, nothing written (1.716312ms)
✔ REQ-PLUG-1 REQ-ROLE-3 the writer checks the bytes it writes: a Date in plugins is refused there too (21.420971ms)
✔ REQ-PLUG-1 REQ-ROLE-3 a refused setter write throws a code, changes nothing and logs nothing (1.601618ms)
✔ vikunja:19/305 with an exists check, the setter refuses a module no tree file answers to, before anything is written (51.983097ms)
✔ P5 optional usage kind and pollSeconds configure through plugins.set; default stays absent and retention bound is strict (99.930829ms)
ℹ tests 25
ℹ suites 0
ℹ pass 24
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1470.74285
✖ failing tests:
test at packages/bus/tests/proxy-usage.test.mjs:1:1
✖ packages/bus/tests/proxy-usage.test.mjs (51.892872ms)
'test failed'
@@ -0,0 +1,37 @@
✔ P5 usage plugin off by default, default poll is 15 seconds and configured polls skip early ticks (65.214926ms)
✔ P5 safe telemetry stores failures per key and proxy-labelled accounts; no client/upstream value enters store/log/view or quota records (52.537861ms)
✔ P5 unknown msk key goes only to value-free reconcile log and other businesses stay isolated (41.558814ms)
✔ P5 queue failure is safe, does not enforce and does not retry before poll deadline (41.087812ms)
✔ P5 retiring key keeps attribution and telemetry rows remain append-only across reader restart (47.727536ms)
✔ REQ-LIMIT-4 loader source records new turn kinds, excludes history and retries exactly once (50.881627ms)
✔ REQ-LIMIT-4 cut: unknown is durable and logged next to every total (45.298282ms)
✔ REQ-LIMIT-4 disabled: unknown is durable and logged next to every total (44.997351ms)
✔ REQ-LIMIT-4 missing-begin: unknown is durable and logged next to every total (39.610461ms)
✔ REQ-LIMIT-4 no-new-usage: unknown is durable and logged next to every total (45.405893ms)
✔ REQ-LIMIT-4 rewrite: unknown is durable and logged next to every total (45.836002ms)
✔ REQ-LIMIT-4 unfinished turn remains visibly unknown after accounting restarts (40.248661ms)
✔ usage records are append-only (40.155769ms)
✔ REQ-LIMIT-4 parse failure logs its safe code, never transcript content (45.604899ms)
✔ REQ-LIMIT-4 resumed run baselines history and exact totals do not overflow (55.889033ms)
✔ REQ-PLUG-1 core has no transcript import and disabled sources do not read any transcript (44.53629ms)
✔ REQ-LIMIT-4 a resumed thread bills only new assistant messages to its next run (45.80935ms)
✔ REQ-LIMIT-4 every enabled source is called; failure is unknown and a partial total stays labelled (54.81715ms)
✔ REQ-LIMIT-4 a turn whose reported sum exceeds safe precision is unknown, not rounded (46.31434ms)
✔ row 65 a run bound without a transcript directory records no-transcript (46.570895ms)
✔ P5 immutable stack key attribution survives rotation and restart without key values (47.523777ms)
✔ REQ-PLUG-1 schema: plugins is optional, names known kinds and checked module names (9.987571ms)
✔ REQ-PLUG-1 REQ-ROLE-3 the setter writes plugins through the organization writer and logs old and new names (141.127286ms)
✔ vikunja:19/309 a patch changes only the kinds it names; null removes one kind, explicitly and in the trail (184.625638ms)
✔ vikunja:19/309 an unknown kind (set or removed), a bad module, an empty patch and null on the wrong shape are refused, nothing written (1.650477ms)
✔ REQ-PLUG-1 REQ-ROLE-3 the writer checks the bytes it writes: a Date in plugins is refused there too (22.208259ms)
✔ REQ-PLUG-1 REQ-ROLE-3 a refused setter write throws a code, changes nothing and logs nothing (1.619398ms)
✔ vikunja:19/305 with an exists check, the setter refuses a module no tree file answers to, before anything is written (53.382155ms)
✔ P5 optional usage kind and pollSeconds configure through plugins.set; default stays absent and retention bound is strict (100.346538ms)
ℹ tests 29
ℹ suites 0
ℹ pass 29
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1701.08968
@@ -0,0 +1,61 @@
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mayLaunch","subject":{"instance":"coder","provider":"anthropic","model":"opus","account":"jason-max"},"path":["tokens","daily","jason-max"],"limit":0,"count":0,"unknownTurns":0}
usage: {"event":"usage-unknown","business":"demo","run":"run1","instance":"coder","turn":"0f9af1a6-ff5d-4a03-8deb-ee3d9ff7a587","source":"@none","code":"baseline-unknown"}
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mustStop","subject":{"instance":"coder","provider":"anthropic","model":"opus","account":"jason-max","run":"run1"},"path":["tokens","daily","jason-max"],"limit":0,"count":0,"unknownTurns":1}
usage: {"event":"usage-unknown","business":"demo","run":"run1","instance":"coder","turn":"139909cd-89c9-47ab-8924-fef1d9125ebc","source":"@none","code":"baseline-unknown"}
✔ REQ-LIMIT-2 runtime: limits counts the daily quota, and mayLaunch refuses only the account at it (160.313054ms)
✔ REQ-LIMIT-4 runtime: a run bound with the account writes it on its usage records and stops at the quota (141.082402ms)
✔ REQ-LIMIT-4 runtime: a run bound without an account records null and the daily quota never stops it (118.409041ms)
✔ REQ-LIMIT-4 bindLaunch keeps the account off session.launched, refuses one that is not an identifier, and takes null as none (60.812376ms)
✔ P5 usage plugin off by default, default poll is 15 seconds and configured polls skip early ticks (67.249055ms)
✔ P5 safe telemetry stores failures per key and proxy-labelled accounts; no client/upstream value enters store/log/view or quota records (48.031566ms)
✔ P5 unknown msk key goes only to value-free reconcile log and other businesses stay isolated (46.042815ms)
✔ P5 queue failure is safe, does not enforce and does not retry before poll deadline (41.173899ms)
✔ P5 retiring key keeps attribution and telemetry rows remain append-only across reader restart (52.566146ms)
✔ REQ-PLUG-1 runtime reaches transcript only through loader, over the real bus socket (131.491274ms)
✔ REQ-LIMIT-4 loader source records new turn kinds, excludes history and retries exactly once (52.546321ms)
✔ REQ-LIMIT-4 cut: unknown is durable and logged next to every total (47.077487ms)
✔ REQ-LIMIT-4 disabled: unknown is durable and logged next to every total (46.271817ms)
✔ REQ-LIMIT-4 missing-begin: unknown is durable and logged next to every total (40.225039ms)
✔ REQ-LIMIT-4 no-new-usage: unknown is durable and logged next to every total (45.02419ms)
✔ REQ-LIMIT-4 rewrite: unknown is durable and logged next to every total (47.584801ms)
✔ REQ-LIMIT-4 unfinished turn remains visibly unknown after accounting restarts (40.815955ms)
✔ usage records are append-only (41.122845ms)
✔ REQ-LIMIT-4 parse failure logs its safe code, never transcript content (45.862091ms)
✔ REQ-LIMIT-4 resumed run baselines history and exact totals do not overflow (57.327879ms)
✔ REQ-PLUG-1 core has no transcript import and disabled sources do not read any transcript (47.939521ms)
✔ REQ-LIMIT-4 a resumed thread bills only new assistant messages to its next run (46.384741ms)
✔ REQ-LIMIT-4 every enabled source is called; failure is unknown and a partial total stays labelled (98.373431ms)
✔ REQ-LIMIT-4 a turn whose reported sum exceeds safe precision is unknown, not rounded (46.863279ms)
✔ row 65 a run bound without a transcript directory records no-transcript (47.359644ms)
✔ P5 immutable stack key attribution survives rotation and restart without key values (51.503418ms)
✔ REQ-PLUG-1 REQ-LIMIT-4 the registry: usage-source at interface version 1, limit-check at 2 (row 125), each a list (1.131497ms)
✔ REQ-PLUG-1 checkPlugins accepts one key per kind, each a list of names, empty included (0.214135ms)
✔ REQ-PLUG-1 checkPlugins refuses bad shapes, unknown kinds, bad names and duplicates (0.919785ms)
✔ REQ-PLUG-1 a kind that switches on one module takes one name, not a list (0.136387ms)
✔ REQ-PLUG-1 checkPlugins reports through the caller's fail callback (0.149287ms)
✔ P5 usage telemetry is optional, single module, separate from enforcing sources (0.136962ms)
✔ REQ-PLUG-1 fixture modules of each kind switch on from a test organization file, no core file changed (8.544145ms)
✔ REQ-PLUG-1 a name not matching ^[a-z][a-z0-9-]*$ refuses and keeps the old setting (3.570635ms)
✔ REQ-PLUG-1 a missing module directory or index.mjs refuses and keeps the old setting (3.394552ms)
✔ REQ-PLUG-1 a symlinked module directory or index.mjs refuses and keeps the old setting (2.605144ms)
✔ REQ-PLUG-1 a symlinked kind directory refuses and keeps the old setting (2.314239ms)
✔ REQ-PLUG-1 a symlinked packages/plugins refuses (run with --preserve-symlinks so the path keeps it) (30.160706ms)
✔ REQ-PLUG-1 index.mjs swapped for a symlink after the lstat checks refuses at the realpath check (3.027836ms)
✔ REQ-PLUG-1 a path that can't be read refuses as unreadable, is logged and keeps the old setting (2.75119ms)
✔ REQ-PLUG-1 a path that becomes unreadable after the lstat checks refuses at either realpath (2.412894ms)
✔ REQ-PLUG-1 a module that fails to load refuses and keeps the old setting (2.793659ms)
✔ REQ-PLUG-1 a missing export refuses and keeps the old setting (3.303983ms)
✔ REQ-PLUG-1 a different interface version refuses and keeps the old setting (2.5092ms)
✔ REQ-PLUG-1 REQ-LIMIT-3 a version 1 limit check refuses after the bump to 2, and the old setting stays (2.97048ms)
✔ REQ-PLUG-1 a kind refused on its first load has nothing switched on, and the log names kind and name (1.870072ms)
✔ REQ-PLUG-1 the setting's shape: unknown kinds refuse alone, a bad whole setting keeps everything (2.648634ms)
✔ REQ-PLUG-1 loads run one at a time, so the last requested setting wins (102.357607ms)
✔ REQ-PLUG-1 the loader needs a log callback (1.14637ms)
ℹ tests 49
ℹ suites 0
ℹ pass 49
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 2281.541817
@@ -0,0 +1,120 @@
✔ REQ-LIMIT-3 limitLeaves finds every limit object and skips the agent numbers (1.223541ms)
✔ REQ-LIMIT-3 limitLeaves takes token limits at schema depth only, whatever their names (0.222664ms)
✔ REQ-LIMIT-3 with no check switched on a launch is allowed, a turn never stops, and every limit is not enforced (52.7698ms)
✔ REQ-LIMIT-3 a fixture check that refuses refuses the launch and stops the turn, logged with the limit and the count (43.539654ms)
✔ REQ-LIMIT-3 a report that omits a limit shows it not enforced; a counted entry and a reason come through (42.903925ms)
✔ REQ-LIMIT-4 each check gets the business, a copy of the limits, the subject, the records and the time (55.045959ms)
✔ REQ-LIMIT-4 fail closed: a throw refuses, stops and fails the report, naming the check and the code (44.040412ms)
✔ REQ-LIMIT-4 fail closed: a malformed answer, a promise, a rejected promise, a non-boolean or a bad hit is malformed-answer (47.200469ms)
✔ REQ-LIMIT-4 fail closed: a check switched on but not loaded refuses, stops and fails every limit as not-loaded (43.887012ms)
✔ REQ-LIMIT-4 state(), never-loaded case: before any load the report shows not enforced, or not-loaded for a switched-on check (42.425785ms)
✔ REQ-LIMIT-4 state(), first-load-refused case: a check refused on its first load is not-loaded in mayLaunch, mustStop and report (44.483506ms)
✔ REQ-LIMIT-4 fail closed: an unreadable organization file refuses and stops with check null; the report throws (43.702967ms)
✔ REQ-LIMIT-4 fail closed: unreadable records refuse and stop with check null and fail the report (0.492979ms)
✔ REQ-LIMIT-3 the shipped token-limit, through the real loader, counts known records only since the limit was set (85.991456ms)
✔ REQ-LIMIT-3 a token limit for a provider named limit is counted and refuses, beside an agent limit of the same name (51.829594ms)
✔ REQ-LIMIT-3 core reaches limit checks only through the plug-in loader (1.348009ms)
✖ P5 missing, ambiguous or invalid model key lookup fails closed without leaking a lookup error (41.10118ms)
✔ P5 trusted lookup uses the retiring run key rather than the agent current key (39.693163ms)
✔ REQ-PLUG-1 schema: plugins is optional, names known kinds and checked module names (9.742544ms)
✔ REQ-PLUG-1 REQ-ROLE-3 the setter writes plugins through the organization writer and logs old and new names (146.282626ms)
✔ vikunja:19/309 a patch changes only the kinds it names; null removes one kind, explicitly and in the trail (169.54836ms)
✔ vikunja:19/309 an unknown kind (set or removed), a bad module, an empty patch and null on the wrong shape are refused, nothing written (1.751884ms)
✔ REQ-PLUG-1 REQ-ROLE-3 the writer checks the bytes it writes: a Date in plugins is refused there too (21.391321ms)
✔ REQ-PLUG-1 REQ-ROLE-3 a refused setter write throws a code, changes nothing and logs nothing (1.677099ms)
✔ vikunja:19/305 with an exists check, the setter refuses a module no tree file answers to, before anything is written (52.536228ms)
✔ P5 optional usage kind and pollSeconds configure through plugins.set; default stays absent and retention bound is strict (94.782042ms)
✖ P5 only human can enable/disable telemetry or change polling, including direct organization writes (50.536153ms)
✖ P5 Console displays stack count per safe key separately from optional proxy account numbers (1.0934ms)
✖ P5 Console escapes hostile labels and labels unavailable telemetry without presenting a fresh zero (0.228091ms)
ℹ tests 29
ℹ suites 0
ℹ pass 25
ℹ fail 4
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1398.637079
✖ failing tests:
test at packages/bus/tests/limit-checks.test.mjs:328:1
✖ P5 missing, ambiguous or invalid model key lookup fails closed without leaking a lookup error (41.10118ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected
{
+ allow: true
- allow: false,
- check: null,
- code: 'proxy-key-refused'
}
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/limit-checks.test.mjs:333:10)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: { allow: true },
expected: { allow: false, check: null, code: 'proxy-key-refused' },
operator: 'deepStrictEqual',
diff: 'simple'
}
test at packages/business/tests/plugin-settings.test.mjs:161:1
✖ P5 only human can enable/disable telemetry or change polling, including direct organization writes (50.536153ms)
AssertionError [ERR_ASSERTION]: Missing expected exception.
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/business/tests/plugin-settings.test.mjs:163:56)
at Test.runInAsyncScope (node:async_hooks:226:14)
at Test.run (node:internal/test_runner/test:1402:25)
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
at Test.postRun (node:internal/test_runner/test:1542:19)
at Test.run (node:internal/test_runner/test:1467:12)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: false,
code: 'ERR_ASSERTION',
actual: undefined,
expected: { code: 'organization-usage-human-only' },
operator: 'throws',
diff: 'simple'
}
test at packages/webui/tests/usage-render.test.mjs:10:1
✖ P5 Console displays stack count per safe key separately from optional proxy account numbers (1.0934ms)
AssertionError [ERR_ASSERTION]: The input did not match the regular expression /Key: 012345abcdef/. Input:
'<section class="panel" aria-labelledby="token-usage-title"><h2 id="token-usage-title">Token usage</h2><p>Best reading of session-editable transcripts, not proof. Unknown turns may have used more tokens. Account is unassigned until account tracking is configured.</p><div class="table-wrap"><table id="token-usage-table"><thead><tr><th scope="col">Subject</th><th scope="col">Input</th><th scope="col">Output</th><th scope="col">Cache write</th><th scope="col">Cache read</th><th scope="col">Unknown turns</th></tr></thead><tbody><tr><th scope="row">Total</th><td>2</td><td>3</td><td>4</td><td>5</td><td>0</td></tr></tbody></table></div></section>'
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/webui/tests/usage-render.test.mjs:12:34)
at Test.runInAsyncScope (node:async_hooks:226:14)
at Test.run (node:internal/test_runner/test:1402:25)
at Test.start (node:internal/test_runner/test:1262:17)
at startSubtestAfterBootstrap (node:internal/test_runner/harness:387:17) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: '<section class="panel" aria-labelledby="token-usage-title"><h2 id="token-usage-title">Token usage</h2><p>Best reading of session-editable transcripts, not proof. Unknown turns may have used more tokens. Account is unassigned until account tracking is configured.</p><div class="table-wrap"><table id="token-usage-table"><thead><tr><th scope="col">Subject</th><th scope="col">Input</th><th scope="col">Output</th><th scope="col">Cache write</th><th scope="col">Cache read</th><th scope="col">Unknown turns</th></tr></thead><tbody><tr><th scope="row">Total</th><td>2</td><td>3</td><td>4</td><td>5</td><td>0</td></tr></tbody></table></div></section>',
expected: /Key: 012345abcdef/,
operator: 'match',
diff: 'simple'
}
test at packages/webui/tests/usage-render.test.mjs:17:1
✖ P5 Console escapes hostile labels and labels unavailable telemetry without presenting a fresh zero (0.228091ms)
AssertionError [ERR_ASSERTION]: The input did not match the regular expression /unavailable/. Input:
'<section class="panel" aria-labelledby="token-usage-title"><h2 id="token-usage-title">Token usage</h2><p>Best reading of session-editable transcripts, not proof. Unknown turns may have used more tokens. Account is unassigned until account tracking is configured.</p><div class="table-wrap"><table id="token-usage-table"><thead><tr><th scope="col">Subject</th><th scope="col">Input</th><th scope="col">Output</th><th scope="col">Cache write</th><th scope="col">Cache read</th><th scope="col">Unknown turns</th></tr></thead><tbody><tr><th scope="row">Total</th><td>2</td><td>3</td><td>4</td><td>5</td><td>0</td></tr></tbody></table></div></section>'
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/webui/tests/usage-render.test.mjs:19:42)
at Test.runInAsyncScope (node:async_hooks:226:14)
at Test.run (node:internal/test_runner/test:1402:25)
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
at Test.postRun (node:internal/test_runner/test:1542:19)
at Test.run (node:internal/test_runner/test:1467:12)
at async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: '<section class="panel" aria-labelledby="token-usage-title"><h2 id="token-usage-title">Token usage</h2><p>Best reading of session-editable transcripts, not proof. Unknown turns may have used more tokens. Account is unassigned until account tracking is configured.</p><div class="table-wrap"><table id="token-usage-table"><thead><tr><th scope="col">Subject</th><th scope="col">Input</th><th scope="col">Output</th><th scope="col">Cache write</th><th scope="col">Cache read</th><th scope="col">Unknown turns</th></tr></thead><tbody><tr><th scope="row">Total</th><td>2</td><td>3</td><td>4</td><td>5</td><td>0</td></tr></tbody></table></div></section>',
expected: /unavailable/,
operator: 'match',
diff: 'simple'
}
@@ -0,0 +1,59 @@
✔ REQ-LIMIT-3 limitLeaves finds every limit object and skips the agent numbers (1.351672ms)
✔ REQ-LIMIT-3 limitLeaves takes token limits at schema depth only, whatever their names (0.197022ms)
✔ REQ-LIMIT-3 with no check switched on a launch is allowed, a turn never stops, and every limit is not enforced (45.900174ms)
✔ REQ-LIMIT-3 a fixture check that refuses refuses the launch and stops the turn, logged with the limit and the count (48.270064ms)
✔ REQ-LIMIT-3 a report that omits a limit shows it not enforced; a counted entry and a reason come through (46.136204ms)
✔ REQ-LIMIT-4 each check gets the business, a copy of the limits, the subject, the records and the time (57.022124ms)
✔ REQ-LIMIT-4 fail closed: a throw refuses, stops and fails the report, naming the check and the code (45.147203ms)
✔ REQ-LIMIT-4 fail closed: a malformed answer, a promise, a rejected promise, a non-boolean or a bad hit is malformed-answer (47.845585ms)
✔ REQ-LIMIT-4 fail closed: a check switched on but not loaded refuses, stops and fails every limit as not-loaded (43.247414ms)
✔ REQ-LIMIT-4 state(), never-loaded case: before any load the report shows not enforced, or not-loaded for a switched-on check (45.643077ms)
✔ REQ-LIMIT-4 state(), first-load-refused case: a check refused on its first load is not-loaded in mayLaunch, mustStop and report (37.420192ms)
✔ REQ-LIMIT-4 fail closed: an unreadable organization file refuses and stops with check null; the report throws (41.526492ms)
✔ REQ-LIMIT-4 fail closed: unreadable records refuse and stop with check null and fail the report (0.579005ms)
✔ REQ-LIMIT-3 the shipped token-limit, through the real loader, counts known records only since the limit was set (89.130888ms)
✔ REQ-LIMIT-3 a token limit for a provider named limit is counted and refuses, beside an agent limit of the same name (53.18557ms)
✔ REQ-LIMIT-3 core reaches limit checks only through the plug-in loader (1.432955ms)
✖ P5 missing, ambiguous or invalid model key lookup fails closed without leaking a lookup error (45.896754ms)
✔ P5 trusted lookup uses the retiring run key rather than the agent current key (40.6658ms)
✖ P5 actual model metadata lookup rejects missing/ambiguous owners and never cross-attributes a retiring run (0.282933ms)
ℹ tests 19
ℹ suites 0
ℹ pass 17
ℹ fail 2
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 767.199722
✖ failing tests:
test at packages/bus/tests/limit-checks.test.mjs:328:1
✖ P5 missing, ambiguous or invalid model key lookup fails closed without leaking a lookup error (45.896754ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected
{
+ allow: true
- allow: false,
- check: null,
- code: 'proxy-key-refused'
}
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/limit-checks.test.mjs:333:10)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: { allow: true },
expected: { allow: false, check: null, code: 'proxy-key-refused' },
operator: 'deepStrictEqual',
diff: 'simple'
}
test at packages/bus/tests/limit-checks.test.mjs:346:1
✖ P5 actual model metadata lookup rejects missing/ambiguous owners and never cross-attributes a retiring run (0.282933ms)
TypeError: modelUsageKey is not a function
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/limit-checks.test.mjs:351:15)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
@@ -0,0 +1,66 @@
✔ REQ-LIMIT-3 limitLeaves finds every limit object and skips the agent numbers (1.471904ms)
✔ REQ-LIMIT-3 limitLeaves takes token limits at schema depth only, whatever their names (0.238869ms)
✔ REQ-LIMIT-3 with no check switched on a launch is allowed, a turn never stops, and every limit is not enforced (48.889383ms)
✔ REQ-LIMIT-3 a fixture check that refuses refuses the launch and stops the turn, logged with the limit and the count (48.804518ms)
✔ REQ-LIMIT-3 a report that omits a limit shows it not enforced; a counted entry and a reason come through (47.424391ms)
✔ REQ-LIMIT-4 each check gets the business, a copy of the limits, the subject, the records and the time (58.732905ms)
✔ REQ-LIMIT-4 fail closed: a throw refuses, stops and fails the report, naming the check and the code (46.311117ms)
✔ REQ-LIMIT-4 fail closed: a malformed answer, a promise, a rejected promise, a non-boolean or a bad hit is malformed-answer (52.110899ms)
✔ REQ-LIMIT-4 fail closed: a check switched on but not loaded refuses, stops and fails every limit as not-loaded (50.032452ms)
✔ REQ-LIMIT-4 state(), never-loaded case: before any load the report shows not enforced, or not-loaded for a switched-on check (45.35538ms)
✔ REQ-LIMIT-4 state(), first-load-refused case: a check refused on its first load is not-loaded in mayLaunch, mustStop and report (45.361587ms)
✔ REQ-LIMIT-4 fail closed: an unreadable organization file refuses and stops with check null; the report throws (47.343794ms)
✔ REQ-LIMIT-4 fail closed: unreadable records refuse and stop with check null and fail the report (0.52398ms)
✔ REQ-LIMIT-3 the shipped token-limit, through the real loader, counts known records only since the limit was set (91.231334ms)
✔ REQ-LIMIT-3 a token limit for a provider named limit is counted and refuses, beside an agent limit of the same name (56.207075ms)
✔ REQ-LIMIT-3 core reaches limit checks only through the plug-in loader (1.2189ms)
✖ P5 missing, ambiguous or invalid model key lookup fails closed without leaking a lookup error (44.848352ms)
✔ P5 trusted lookup uses the retiring run key rather than the agent current key (43.672096ms)
✖ P5 actual model metadata lookup rejects missing/ambiguous owners and never cross-attributes a retiring run (0.426717ms)
ℹ tests 19
ℹ suites 0
ℹ pass 17
ℹ fail 2
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 816.537108
✖ failing tests:
test at packages/bus/tests/limit-checks.test.mjs:328:1
✖ P5 missing, ambiguous or invalid model key lookup fails closed without leaking a lookup error (44.848352ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected
{
+ allow: true
- allow: false,
- check: null,
- code: 'proxy-key-refused'
}
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/limit-checks.test.mjs:333:10)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: { allow: true },
expected: { allow: false, check: null, code: 'proxy-key-refused' },
operator: 'deepStrictEqual',
diff: 'simple'
}
test at packages/bus/tests/limit-checks.test.mjs:346:1
✖ P5 actual model metadata lookup rejects missing/ambiguous owners and never cross-attributes a retiring run (0.426717ms)
AssertionError [ERR_ASSERTION]: Missing expected exception.
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/limit-checks.test.mjs:354:10)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: false,
code: 'ERR_ASSERTION',
actual: undefined,
expected: { code: 'proxy-key-refused' },
operator: 'throws',
diff: 'simple'
}
@@ -0,0 +1,38 @@
✔ REQ-LIMIT-3 limitLeaves finds every limit object and skips the agent numbers (1.497774ms)
✔ REQ-LIMIT-3 limitLeaves takes token limits at schema depth only, whatever their names (0.231342ms)
✔ REQ-LIMIT-3 with no check switched on a launch is allowed, a turn never stops, and every limit is not enforced (41.157068ms)
✔ REQ-LIMIT-3 a fixture check that refuses refuses the launch and stops the turn, logged with the limit and the count (47.622762ms)
✔ REQ-LIMIT-3 a report that omits a limit shows it not enforced; a counted entry and a reason come through (40.772915ms)
✔ REQ-LIMIT-4 each check gets the business, a copy of the limits, the subject, the records and the time (64.210535ms)
✔ REQ-LIMIT-4 fail closed: a throw refuses, stops and fails the report, naming the check and the code (41.33012ms)
✔ REQ-LIMIT-4 fail closed: a malformed answer, a promise, a rejected promise, a non-boolean or a bad hit is malformed-answer (46.47583ms)
✔ REQ-LIMIT-4 fail closed: a check switched on but not loaded refuses, stops and fails every limit as not-loaded (42.554949ms)
✔ REQ-LIMIT-4 state(), never-loaded case: before any load the report shows not enforced, or not-loaded for a switched-on check (42.55839ms)
✔ REQ-LIMIT-4 state(), first-load-refused case: a check refused on its first load is not-loaded in mayLaunch, mustStop and report (42.856274ms)
✔ REQ-LIMIT-4 fail closed: an unreadable organization file refuses and stops with check null; the report throws (42.087566ms)
✔ REQ-LIMIT-4 fail closed: unreadable records refuse and stop with check null and fail the report (0.540151ms)
✔ REQ-LIMIT-3 the shipped token-limit, through the real loader, counts known records only since the limit was set (83.555041ms)
✔ REQ-LIMIT-3 a token limit for a provider named limit is counted and refuses, beside an agent limit of the same name (50.237156ms)
✔ REQ-LIMIT-3 core reaches limit checks only through the plug-in loader (1.834976ms)
✔ P5 missing, ambiguous or invalid model key lookup fails closed without leaking a lookup error (41.561579ms)
✔ P5 trusted lookup uses the retiring run key rather than the agent current key (40.600997ms)
✔ P5 actual model metadata lookup rejects missing/ambiguous owners and never cross-attributes a retiring run (0.439799ms)
✔ REQ-PLUG-1 schema: plugins is optional, names known kinds and checked module names (10.470972ms)
✔ REQ-PLUG-1 REQ-ROLE-3 the setter writes plugins through the organization writer and logs old and new names (139.490847ms)
✔ vikunja:19/309 a patch changes only the kinds it names; null removes one kind, explicitly and in the trail (177.184056ms)
✔ vikunja:19/309 an unknown kind (set or removed), a bad module, an empty patch and null on the wrong shape are refused, nothing written (1.815855ms)
✔ REQ-PLUG-1 REQ-ROLE-3 the writer checks the bytes it writes: a Date in plugins is refused there too (21.853399ms)
✔ REQ-PLUG-1 REQ-ROLE-3 a refused setter write throws a code, changes nothing and logs nothing (1.605034ms)
✔ vikunja:19/305 with an exists check, the setter refuses a module no tree file answers to, before anything is written (52.267349ms)
✔ P5 optional usage kind and pollSeconds configure through plugins.set; default stays absent and retention bound is strict (94.963454ms)
✔ P5 only human can enable/disable telemetry or change polling, including direct organization writes (142.850292ms)
✔ P5 Console displays stack count per safe key separately from optional proxy account numbers (0.865798ms)
✔ P5 Console escapes hostile labels and labels unavailable telemetry without presenting a fresh zero (3.686422ms)
ℹ tests 30
ℹ suites 0
ℹ pass 30
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1490.937181
@@ -0,0 +1,30 @@
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["75a1bce4e569"]}
model-proxy: {"action":"proxy.reconcile","addedKeyIds":[],"removedKeyIds":[]}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["75a1bce4e569"]}
model-proxy: {"call":"PUT /v8/management/config/access/api-keys","status":200,"keyIds":["75a1bce4e569","9e2b7988546b"]}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["75a1bce4e569","9e2b7988546b"]}
model-proxy: {"action":"proxy.key.issued","keyIds":["9e2b7988546b"],"instance":"demo/coder"}
model-proxy: {"call":"GET /v1/models","status":200,"keyIds":["9e2b7988546b"]}
organization: {"event":"reload-needs-restart","business":"demo"}
✖ P5 real runtime binds stack usage to issued key, daily stops at stack count and human-only telemetry settings pass broker contract (212.342125ms)
ℹ tests 1
ℹ suites 0
ℹ pass 0
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 343.620467
✖ failing tests:
test at packages/bus/tests/p5-runtime.test.mjs:13:1
✖ P5 real runtime binds stack usage to issued key, daily stops at stack count and human-only telemetry settings pass broker contract (212.342125ms)
Error: invalid-launch-process
at Object.bindLaunch (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/src/runtime.mjs:641:15)
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-runtime.test.mjs:41:16)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async Test.run (node:internal/test_runner/test:1409:7)
at async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
code: 'invalid-launch-process'
}
@@ -0,0 +1,32 @@
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["44299c50ade8"]}
model-proxy: {"action":"proxy.reconcile","addedKeyIds":[],"removedKeyIds":[]}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["44299c50ade8"]}
model-proxy: {"call":"PUT /v8/management/config/access/api-keys","status":200,"keyIds":["44299c50ade8","9f64355841b6"]}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["44299c50ade8","9f64355841b6"]}
model-proxy: {"action":"proxy.key.issued","keyIds":["9f64355841b6"],"instance":"demo/coder"}
model-proxy: {"call":"GET /v1/models","status":200,"keyIds":["9f64355841b6"]}
organization: {"event":"reload-needs-restart","business":"demo"}
✖ P5 real runtime binds stack usage to issued key, daily stops at stack count and human-only telemetry settings pass broker contract (218.643013ms)
ℹ tests 1
ℹ suites 0
ℹ pass 0
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 343.099863
✖ failing tests:
test at packages/bus/tests/p5-runtime.test.mjs:14:1
✖ P5 real runtime binds stack usage to issued key, daily stops at stack count and human-only telemetry settings pass broker contract (218.643013ms)
Error: unauthenticated
at fail (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/src/broker.mjs:230:9)
at #session (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/src/broker.mjs:657:39)
at Broker.request (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/src/broker.mjs:4817:28)
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-runtime.test.mjs:43:13)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async Test.run (node:internal/test_runner/test:1409:7)
at async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
code: 'unauthenticated'
}
@@ -0,0 +1,20 @@
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["deae56d6265f"]}
model-proxy: {"action":"proxy.reconcile","addedKeyIds":[],"removedKeyIds":[]}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["deae56d6265f"]}
model-proxy: {"call":"PUT /v8/management/config/access/api-keys","status":200,"keyIds":["deae56d6265f","f39c9ad3cf05"]}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["deae56d6265f","f39c9ad3cf05"]}
model-proxy: {"action":"proxy.key.issued","keyIds":["f39c9ad3cf05"],"instance":"demo/coder"}
model-proxy: {"call":"GET /v1/models","status":200,"keyIds":["f39c9ad3cf05"]}
organization: {"event":"reload-needs-restart","business":"demo"}
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mustStop","subject":{"instance":"coder","provider":null,"model":null,"account":null,"run":"p5-run","modelKeyId":"f39c9ad3cf05"},"path":["tokens","keys","f39c9ad3cf05"],"limit":2,"count":2,"unknownTurns":0}
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mayLaunch","subject":{"instance":"coder","provider":"fixture","model":"fake","account":null,"modelKeyId":"f39c9ad3cf05"},"path":["tokens","keys","f39c9ad3cf05"],"limit":2,"count":2,"unknownTurns":0}
organization: {"event":"reload-needs-restart","business":"demo"}
✔ P5 real runtime binds stack usage to issued key, daily stops at stack count and human-only telemetry settings pass broker contract (304.08638ms)
ℹ tests 1
ℹ suites 0
ℹ pass 1
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 420.753441
@@ -0,0 +1,40 @@
✔ P5 usage plugin off by default, default poll is 15 seconds and configured polls skip early ticks (86.257274ms)
✔ P5 safe telemetry stores failures per key and proxy-labelled accounts; no client/upstream value enters store/log/view or quota records (54.618111ms)
✔ P5 unknown msk key goes only to value-free reconcile log and other businesses stay isolated (44.583676ms)
✔ P5 queue failure is safe, does not enforce and does not retry before poll deadline (46.4743ms)
✔ P5 retiring key keeps attribution and telemetry rows remain append-only across reader restart (56.121284ms)
✔ P5 malformed queue batch is atomic: no valid prefix, body or credential can reach store/log/view (47.108755ms)
✔ P5 concurrent ticks issue one bounded queue read and a closed collector never polls again (49.990509ms)
✔ REQ-LIMIT-4 loader source records new turn kinds, excludes history and retries exactly once (56.900609ms)
✔ REQ-LIMIT-4 cut: unknown is durable and logged next to every total (51.730832ms)
✔ REQ-LIMIT-4 disabled: unknown is durable and logged next to every total (50.614029ms)
✔ REQ-LIMIT-4 missing-begin: unknown is durable and logged next to every total (44.230231ms)
✔ REQ-LIMIT-4 no-new-usage: unknown is durable and logged next to every total (48.44147ms)
✔ REQ-LIMIT-4 rewrite: unknown is durable and logged next to every total (45.801767ms)
✔ REQ-LIMIT-4 unfinished turn remains visibly unknown after accounting restarts (39.52636ms)
✔ usage records are append-only (37.948303ms)
✔ REQ-LIMIT-4 parse failure logs its safe code, never transcript content (47.7119ms)
✔ REQ-LIMIT-4 resumed run baselines history and exact totals do not overflow (55.743022ms)
✔ REQ-PLUG-1 core has no transcript import and disabled sources do not read any transcript (57.173303ms)
✔ REQ-LIMIT-4 a resumed thread bills only new assistant messages to its next run (41.62154ms)
✔ REQ-LIMIT-4 every enabled source is called; failure is unknown and a partial total stays labelled (46.188396ms)
✔ REQ-LIMIT-4 a turn whose reported sum exceeds safe precision is unknown, not rounded (46.675381ms)
✔ row 65 a run bound without a transcript directory records no-transcript (43.283736ms)
✔ P5 immutable stack key attribution survives rotation and restart without key values (46.409665ms)
✔ P5 malformed key metadata is dropped rather than stored or exposed as a key value (45.477235ms)
✔ P5 queue read uses actual bounded fixed management GET and immediately drops client and upstream values (14.43995ms)
✔ P5 bad envelope refuses safely with no retry (2.606864ms)
✔ P5 over count refuses safely with no retry (1.613165ms)
✔ P5 missing key refuses safely with no retry (1.32277ms)
✔ P5 bad counts refuses safely with no retry (2.00608ms)
✔ P5 redirect refuses safely with no retry (1.518136ms)
✔ P5 refusal refuses safely with no retry (1.062337ms)
✔ P5 malformed event after a valid event rejects the entire queue before any credential can escape (1.122725ms)
ℹ tests 32
ℹ suites 0
ℹ pass 32
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1490.423611
@@ -0,0 +1,99 @@
✔ P5 usage plugin off by default, default poll is 15 seconds and configured polls skip early ticks (60.34137ms)
✖ P5 safe telemetry stores failures per key and proxy-labelled accounts; no client/upstream value enters store/log/view or quota records (43.55479ms)
✖ P5 unknown msk key goes only to value-free reconcile log and other businesses stay isolated (42.788302ms)
✔ P5 queue failure is safe, does not enforce and does not retry before poll deadline (43.315969ms)
✖ P5 retiring key keeps attribution and telemetry rows remain append-only across reader restart (40.209703ms)
✔ P5 malformed queue batch is atomic: no valid prefix, body or credential can reach store/log/view (38.596309ms)
✔ P5 concurrent ticks issue one bounded queue read and a closed collector never polls again (45.908134ms)
✖ P5 queue read uses actual bounded fixed management GET and immediately drops client and upstream values (16.729146ms)
✔ P5 bad envelope refuses safely with no retry (3.674119ms)
✔ P5 over count refuses safely with no retry (1.818219ms)
✔ P5 missing key refuses safely with no retry (1.550156ms)
✔ P5 bad counts refuses safely with no retry (2.537033ms)
✔ P5 redirect refuses safely with no retry (1.858685ms)
✔ P5 refusal refuses safely with no retry (1.153412ms)
✔ P5 malformed event after a valid event rejects the entire queue before any credential can escape (1.135306ms)
ℹ tests 15
ℹ suites 0
ℹ pass 11
ℹ fail 4
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 487.776777
✖ failing tests:
test at packages/bus/tests/proxy-usage.test.mjs:36:1
✖ P5 safe telemetry stores failures per key and proxy-labelled accounts; no client/upstream value enters store/log/view or quota records (43.55479ms)
TypeError: Cannot read properties of undefined (reading 'keyId')
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/proxy-usage.test.mjs:38:87)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
test at packages/bus/tests/proxy-usage.test.mjs:47:1
✖ P5 unknown msk key goes only to value-free reconcile log and other businesses stay isolated (42.788302ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected
+ undefined
- {
- action: 'proxy.usage.reconcile',
- code: 'proxy-usage-unknown-key',
- keyId: 'f76403e5ce2e'
- }
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/proxy-usage.test.mjs:49:9)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: undefined,
expected: { action: 'proxy.usage.reconcile', keyId: 'f76403e5ce2e', code: 'proxy-usage-unknown-key' },
operator: 'deepStrictEqual',
diff: 'simple'
}
test at packages/bus/tests/proxy-usage.test.mjs:58:1
✖ P5 retiring key keeps attribution and telemetry rows remain append-only across reader restart (40.209703ms)
AssertionError [ERR_ASSERTION]: Missing expected exception.
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/proxy-usage.test.mjs:63:9)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: false,
code: 'ERR_ASSERTION',
actual: undefined,
expected: /append-only/,
operator: 'throws',
diff: 'simple'
}
test at packages/model-proxy/tests/usage-client.test.mjs:21:1
✖ P5 queue read uses actual bounded fixed management GET and immediately drops client and upstream values (16.729146ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected
[
{
+ accountId: 'made-up-upstream-canary',
- accountId: '51dfa8a6722b',
cacheRead: 4,
cacheWrite: 3,
failed: true,
input: 7,
keyId: 'd1e3e19ac482',
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/model-proxy/tests/usage-client.test.mjs:24:10)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async Test.run (node:internal/test_runner/test:1409:7)
at async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: [ { keyId: 'd1e3e19ac482', accountId: 'made-up-upstream-canary', managed: true, failed: true, statusCode: 503, input: 7, output: 2, cacheWrite: 3, cacheRead: 4 } ],
expected: [ { keyId: 'd1e3e19ac482', accountId: '51dfa8a6722b', managed: true, failed: true, statusCode: 503, input: 7, output: 2, cacheWrite: 3, cacheRead: 4 } ],
operator: 'deepStrictEqual',
diff: 'simple'
}
@@ -0,0 +1,23 @@
✔ P5 usage plugin off by default, default poll is 15 seconds and configured polls skip early ticks (63.115978ms)
✔ P5 safe telemetry stores failures per key and proxy-labelled accounts; no client/upstream value enters store/log/view or quota records (53.184947ms)
✔ P5 unknown msk key goes only to value-free reconcile log and other businesses stay isolated (43.353706ms)
✔ P5 queue failure is safe, does not enforce and does not retry before poll deadline (42.937785ms)
✔ P5 retiring key keeps attribution and telemetry rows remain append-only across reader restart (48.231864ms)
✔ P5 malformed queue batch is atomic: no valid prefix, body or credential can reach store/log/view (42.352423ms)
✔ P5 concurrent ticks issue one bounded queue read and a closed collector never polls again (43.470712ms)
✔ P5 queue read uses actual bounded fixed management GET and immediately drops client and upstream values (15.069336ms)
✔ P5 bad envelope refuses safely with no retry (2.896886ms)
✔ P5 over count refuses safely with no retry (1.591065ms)
✔ P5 missing key refuses safely with no retry (1.351768ms)
✔ P5 bad counts refuses safely with no retry (2.127704ms)
✔ P5 redirect refuses safely with no retry (1.349646ms)
✔ P5 refusal refuses safely with no retry (1.162024ms)
✔ P5 malformed event after a valid event rejects the entire queue before any credential can escape (1.135262ms)
ℹ tests 15
ℹ suites 0
ℹ pass 15
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 508.770711
@@ -0,0 +1,243 @@
serial nice19; private HOME/XDG_CONFIG_HOME/TMPDIR/MOSAIC_CONFIG; unchanged whole-file budgets
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mayLaunch","subject":{"instance":"coder","provider":"anthropic","model":"opus","account":"jason-max"},"path":["tokens","daily","jason-max"],"limit":0,"count":0,"unknownTurns":0}
usage: {"event":"usage-unknown","business":"demo","run":"run1","instance":"coder","turn":"bc8872d6-c10d-4cbc-963c-dd87cf9163e5","source":"@none","code":"baseline-unknown"}
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mustStop","subject":{"instance":"coder","provider":"anthropic","model":"opus","account":"jason-max","run":"run1"},"path":["tokens","daily","jason-max"],"limit":0,"count":0,"unknownTurns":1}
usage: {"event":"usage-unknown","business":"demo","run":"run1","instance":"coder","turn":"3e17a52f-1444-4d91-a204-87e39766f9c6","source":"@none","code":"baseline-unknown"}
✔ REQ-LIMIT-2 runtime: limits counts the daily quota, and mayLaunch refuses only the account at it (170.726529ms)
✔ REQ-LIMIT-4 runtime: a run bound with the account writes it on its usage records and stops at the quota (145.594621ms)
✔ REQ-LIMIT-4 runtime: a run bound without an account records null and the daily quota never stops it (126.673361ms)
✔ REQ-LIMIT-4 bindLaunch keeps the account off session.launched, refuses one that is not an identifier, and takes null as none (67.580463ms)
✔ REQ-LIMIT-3 limitLeaves finds every limit object and skips the agent numbers (1.298781ms)
✔ REQ-LIMIT-3 limitLeaves takes token limits at schema depth only, whatever their names (0.222463ms)
✔ REQ-LIMIT-3 with no check switched on a launch is allowed, a turn never stops, and every limit is not enforced (47.459097ms)
✔ REQ-LIMIT-3 a fixture check that refuses refuses the launch and stops the turn, logged with the limit and the count (46.035967ms)
✔ REQ-LIMIT-3 a report that omits a limit shows it not enforced; a counted entry and a reason come through (45.718506ms)
✔ REQ-LIMIT-4 each check gets the business, a copy of the limits, the subject, the records and the time (57.755296ms)
✔ REQ-LIMIT-4 fail closed: a throw refuses, stops and fails the report, naming the check and the code (45.052811ms)
✔ REQ-LIMIT-4 fail closed: a malformed answer, a promise, a rejected promise, a non-boolean or a bad hit is malformed-answer (51.313528ms)
✔ REQ-LIMIT-4 fail closed: a check switched on but not loaded refuses, stops and fails every limit as not-loaded (46.094531ms)
✔ REQ-LIMIT-4 state(), never-loaded case: before any load the report shows not enforced, or not-loaded for a switched-on check (48.189649ms)
✔ REQ-LIMIT-4 state(), first-load-refused case: a check refused on its first load is not-loaded in mayLaunch, mustStop and report (44.413841ms)
✔ REQ-LIMIT-4 fail closed: an unreadable organization file refuses and stops with check null; the report throws (46.465199ms)
✔ REQ-LIMIT-4 fail closed: unreadable records refuse and stop with check null and fail the report (0.636118ms)
✔ REQ-LIMIT-3 the shipped token-limit, through the real loader, counts known records only since the limit was set (87.250164ms)
✔ REQ-LIMIT-3 a token limit for a provider named limit is counted and refuses, beside an agent limit of the same name (52.454059ms)
✔ REQ-LIMIT-3 core reaches limit checks only through the plug-in loader (2.054757ms)
✔ P5 missing, ambiguous or invalid model key lookup fails closed without leaking a lookup error (42.170203ms)
✔ P5 trusted lookup uses the retiring run key rather than the agent current key (41.545306ms)
✔ P5 actual model metadata lookup rejects missing/ambiguous owners and never cross-attributes a retiring run (0.418717ms)
✖ REQ-LIMIT-4 a role run at its limit stops at the end of its turn: RESULT and read land first, the claim is revoked by limit-check (106.432474ms)
✔ REQ-LIMIT-4 the stop also lands on state; a run with no stop ends without a limit (170.782587ms)
✔ REQ-LIMIT-4 fail closed: a mustStop throw or a malformed answer stops the run, naming the bus and the code (437.666292ms)
✔ REQ-LIMIT-4 a thread run at its limit is released with the reason, and its end record names the limit (120.745836ms)
✔ REQ-LIMIT-4 a broker with no limit checks configured never stops a run (80.230732ms)
limits: {"event":"limit-reached","business":"demo","check":"token-limit","export":"mayLaunch","subject":{"instance":"coder","provider":"zai","model":"glm-5.3-flash","account":null},"path":["tokens","instances","coder"],"limit":0,"count":0,"unknownTurns":0}
organization: {"event":"reload-needs-restart","business":"demo"}
usage: {"event":"usage-unknown","business":"demo","run":"run1","instance":"coder","turn":"3646df55-73df-46ac-a828-41d4c0adef5c","source":"@none","code":"baseline-unknown"}
limits: {"event":"limit-reached","business":"demo","check":"token-limit","export":"mustStop","subject":{"instance":"coder","provider":"zai","model":"glm-5.3-flash","account":null,"run":"run1"},"path":["tokens","instances","coder"],"limit":0,"count":0,"unknownTurns":1}
usage: {"event":"usage-unknown","business":"demo","run":"run1","instance":"coder","turn":"ae4d4f3a-9306-4a9d-88c5-234c2f2bfcaf","source":"@none","code":"baseline-unknown"}
✔ REQ-LIMIT-3 REQ-LIMIT-4 runtime: limits carries the token count, mayLaunch refuses at the limit, a reset moves since (243.095091ms)
organization: {"event":"reload-needs-restart","business":"demo"}
✔ REQ-LIMIT-3 runtime: with no limit check switched on, the limit shows not enforced and every launch is allowed (90.928952ms)
✔ REQ-LIMIT-4 runtime: the broker asks the shipped token-limit after a turn, and the run at its limit stops on its next receive (143.039435ms)
✔ REQ-LIMIT-4 runtime: with no usage source a turn is unknown, counts zero and stops nothing under a limit of 1 (136.591564ms)
✔ REQ-LIMIT-3 runtime: switching a limit check on with plugins.set loads it without a launch or a turn (171.913947ms)
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["ddaa88bc74e9"]}
model-proxy: {"action":"proxy.reconcile","addedKeyIds":[],"removedKeyIds":[]}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["ddaa88bc74e9"]}
model-proxy: {"call":"PUT /v8/management/config/access/api-keys","status":200,"keyIds":["ddaa88bc74e9","fd2b06e41cec"]}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["ddaa88bc74e9","fd2b06e41cec"]}
model-proxy: {"action":"proxy.key.issued","keyIds":["fd2b06e41cec"],"instance":"demo/coder"}
model-proxy: {"call":"GET /v1/models","status":200,"keyIds":["fd2b06e41cec"]}
organization: {"event":"reload-needs-restart","business":"demo"}
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mustStop","subject":{"instance":"coder","provider":null,"model":null,"account":null,"run":"p5-run","modelKeyId":"fd2b06e41cec"},"path":["tokens","keys","fd2b06e41cec"],"limit":2,"count":2,"unknownTurns":0}
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mayLaunch","subject":{"instance":"coder","provider":"fixture","model":"fake","account":null,"modelKeyId":"fd2b06e41cec"},"path":["tokens","keys","fd2b06e41cec"],"limit":2,"count":2,"unknownTurns":0}
organization: {"event":"reload-needs-restart","business":"demo"}
✔ P5 real runtime binds stack usage to issued key, daily stops at stack count and human-only telemetry settings pass broker contract (313.95876ms)
organization: {"event":"reload-needs-restart","business":"demo"}
organization: {"event":"reload-needs-restart","business":"demo"}
organization: {"event":"reload-needs-restart","business":"demo"}
organization: {"event":"reload-needs-restart","business":"demo"}
✔ plugins and plugins.set refuse every non-human session and a forged actor, and pass only the patch with the verified actor (100.42834ms)
✔ runtime: the switch changes the organization file, the receipt carries the actor, and a bad shape, an unknown module and a stale revision are refused with nothing written (261.328835ms)
✔ vikunja:19/309 through the broker, a patch switches the kinds it names and keeps the rest; null removes one kind and is trailed (199.005826ms)
✔ P5 usage plugin off by default, default poll is 15 seconds and configured polls skip early ticks (59.508865ms)
✔ P5 safe telemetry stores failures per key and proxy-labelled accounts; no client/upstream value enters store/log/view or quota records (54.132395ms)
✔ P5 unknown msk key goes only to value-free reconcile log and other businesses stay isolated (42.918239ms)
✔ P5 queue failure is safe, does not enforce and does not retry before poll deadline (47.414676ms)
✔ P5 retiring key keeps attribution and telemetry rows remain append-only across reader restart (49.580277ms)
✔ P5 malformed queue batch is atomic: no valid prefix, body or credential can reach store/log/view (42.767702ms)
✔ P5 concurrent ticks issue one bounded queue read and a closed collector never polls again (44.597112ms)
✔ REQ-LIMIT-4 usage protocol binds run identity, requires a delivered turn and isolates businesses (115.479121ms)
✔ REQ-PLUG-1 runtime reaches transcript only through loader, over the real bus socket (137.456433ms)
✔ REQ-LIMIT-4 loader source records new turn kinds, excludes history and retries exactly once (52.575663ms)
✔ REQ-LIMIT-4 cut: unknown is durable and logged next to every total (47.838399ms)
✔ REQ-LIMIT-4 disabled: unknown is durable and logged next to every total (46.771667ms)
✔ REQ-LIMIT-4 missing-begin: unknown is durable and logged next to every total (40.568247ms)
✔ REQ-LIMIT-4 no-new-usage: unknown is durable and logged next to every total (45.022848ms)
✔ REQ-LIMIT-4 rewrite: unknown is durable and logged next to every total (44.520995ms)
✔ REQ-LIMIT-4 unfinished turn remains visibly unknown after accounting restarts (38.477112ms)
✔ usage records are append-only (38.207707ms)
✔ REQ-LIMIT-4 parse failure logs its safe code, never transcript content (49.361853ms)
✔ REQ-LIMIT-4 resumed run baselines history and exact totals do not overflow (59.674051ms)
✔ REQ-PLUG-1 core has no transcript import and disabled sources do not read any transcript (52.284427ms)
✔ REQ-LIMIT-4 a resumed thread bills only new assistant messages to its next run (54.284346ms)
✔ REQ-LIMIT-4 every enabled source is called; failure is unknown and a partial total stays labelled (54.236183ms)
✔ REQ-LIMIT-4 a turn whose reported sum exceeds safe precision is unknown, not rounded (50.417947ms)
✔ row 65 a run bound without a transcript directory records no-transcript (49.190606ms)
✔ P5 immutable stack key attribution survives rotation and restart without key values (45.910581ms)
✔ P5 malformed key metadata is dropped rather than stored or exposed as a key value (45.051417ms)
✔ REQ-PLUG-1 schema: plugins is optional, names known kinds and checked module names (9.756957ms)
✔ REQ-PLUG-1 REQ-ROLE-3 the setter writes plugins through the organization writer and logs old and new names (139.461766ms)
✔ vikunja:19/309 a patch changes only the kinds it names; null removes one kind, explicitly and in the trail (198.116707ms)
✔ vikunja:19/309 an unknown kind (set or removed), a bad module, an empty patch and null on the wrong shape are refused, nothing written (1.940571ms)
✔ REQ-PLUG-1 REQ-ROLE-3 the writer checks the bytes it writes: a Date in plugins is refused there too (23.77339ms)
✔ REQ-PLUG-1 REQ-ROLE-3 a refused setter write throws a code, changes nothing and logs nothing (1.651382ms)
✔ vikunja:19/305 with an exists check, the setter refuses a module no tree file answers to, before anything is written (56.64271ms)
✔ P5 optional usage kind and pollSeconds configure through plugins.set; default stays absent and retention bound is strict (100.452598ms)
✔ P5 only human can enable/disable telemetry or change polling, including direct organization writes (148.009247ms)
✔ REQ-LIMIT-3 schema: each subject kind, limit 0 and no ceiling are accepted; bad limits, times, keys and undeclared instances refuse (12.986058ms)
✔ REQ-LIMIT-3 the writer stamps since: a new limit gets now, a changed one keeps its time, a different time is refused (248.032277ms)
✔ REQ-LIMIT-3 only tokens.* at schema depth holds token limits: agent limits named `limit` save as sent, and a token limit named `limit` is stamped and reset (276.275719ms)
✔ REQ-LIMIT-3 a reset moves since to now, is logged with its actor, and refuses a path that is not a limit (149.313217ms)
✔ REQ-LIMIT-2 schema: launch.account names a credential set; a daily quota needs a reset and an IANA zone and names the account (22.104886ms)
✔ REQ-LIMIT-2 the writer stamps a daily quota's since, keeps its reset and zone, and a reset moves since (155.859496ms)
✔ P5 per-model-key quotas are unset by default, accept digit-leading IDs and only the human changes or resets them (232.766603ms)
✔ probeKey observes 200 with one agent-authenticated GET /v1/models (13.606016ms)
✔ probeKey observes 401 with one agent-authenticated GET /v1/models (2.349516ms)
✔ probeKey observes 503 with one agent-authenticated GET /v1/models (1.394451ms)
✔ proxy-down: agent-key probe connection failure is sanitized (1.448631ms)
✔ proxy-down: silent listener cannot extend probe request deadline (50.92774ms)
✔ agent-key probe returns redirect status without following Location or exposing key (2.519341ms)
✔ proxy-client-invalid: https://127.0.0.1:18318 (0.954469ms)
✔ proxy-client-invalid: http://example.com:18318 (0.688091ms)
✔ proxy-client-invalid: http://localhost:18318 (0.089486ms)
✔ proxy-client-invalid: http://127.0.0.1:8317 (0.072442ms)
✔ proxy-client-invalid: http://user:[email protected]:18318 (0.075664ms)
✔ proxy-client-invalid: http://127.0.0.1:18318/path (0.064187ms)
✔ client GET/PUT v8 only, Authorization header, receipt IDs without values or bodies (15.756687ms)
✔ proxy-client-refused (3.167201ms)
✔ proxy-client-response (1.333201ms)
✔ proxy-client-redirect (1.083098ms)
✔ proxy-client-down: transport errors redact details (0.993207ms)
✔ proxy-client-invalid: PUT rejects object key records and empty strings locally (0.155978ms)
✔ proxy-management-key-invalid: missing, symlink and public key file refuse without values (1.086163ms)
✔ bus management-key loader supplies a private fixture key without exposing it on the client (0.529214ms)
✔ proxy-client-response: truncated response remains a redacted named refusal (12.081487ms)
✔ management client ignores ambient fetch dispatchers (1.152012ms)
✔ proxy-key-invalid: Latin-1 leaves complete config/data inventories unchanged (3.391538ms)
✔ proxy-key-invalid: leading space leaves complete config/data inventories unchanged (1.062708ms)
✔ proxy-key-invalid: trailing space leaves complete config/data inventories unchanged (1.046332ms)
✔ proxy-key-invalid: internal space leaves complete config/data inventories unchanged (1.087954ms)
✔ printable non-space ASCII control initializes and authenticates with unchanged existing files (16.664061ms)
✔ OAuth management calls keep URL and state out of receipts (16.723462ms)
✔ upstream key goes only in request body and upstream refusal body is discarded (3.387523ms)
✔ redirected management calls are not followed or retried (1.835042ms)
✔ P5 queue read uses actual bounded fixed management GET and immediately drops client and upstream values (14.543908ms)
✔ P5 bad envelope refuses safely with no retry (2.805976ms)
✔ P5 over count refuses safely with no retry (1.641432ms)
✔ P5 missing key refuses safely with no retry (1.977544ms)
✔ P5 bad counts refuses safely with no retry (1.458ms)
✔ P5 redirect refuses safely with no retry (1.387336ms)
✔ P5 refusal refuses safely with no retry (1.028864ms)
✔ P5 malformed event after a valid event rejects the entire queue before any credential can escape (1.11627ms)
✔ REQ-LIMIT-2 daily-quota exports interface version 2 with mayLaunch, mustStop and report (1.248222ms)
✔ REQ-LIMIT-2 the count sums every kind of the account's known records since the later of the day start and since (11.695173ms)
✔ REQ-LIMIT-2 a launch with no account (pi) is covered by no daily quota (0.286778ms)
✔ REQ-LIMIT-4 an unknown turn adds nothing and is counted apart (0.491571ms)
✔ REQ-LIMIT-2 the day turns at the reset in its zone, not in UTC, and before it the day is yesterday's (0.574704ms)
✔ REQ-LIMIT-2 the spring DST change makes the day after a 00:00 reset 23 hours long (0.368738ms)
✔ REQ-LIMIT-2 the fall DST change makes the day after a 00:00 reset 25 hours long (0.297179ms)
✔ REQ-LIMIT-2 a reset the clocks skip starts the day at the first instant after the gap (0.789063ms)
✔ REQ-LIMIT-2 a reset the clocks repeat starts one day, at the first one (0.436754ms)
✔ REQ-LIMIT-2 a launch is refused at the quota, a turn that reaches it stops, and the next day allows again (1.07467ms)
✔ REQ-LIMIT-2 counts past the safe integer range come back as digit strings (0.372713ms)
✔ REQ-LIMIT-4 bad leaves, records or times throw a code, and the check reads nothing but its arguments (2.387209ms)
✔ REQ-LIMIT-2 no daily quotas: every launch is allowed and the report is empty (0.190068ms)
✔ P5 daily quota for a model key ID matches stack key records and resets the next day (0.797912ms)
✔ REQ-PLUG-1 REQ-LIMIT-4 the registry: usage-source at interface version 1, limit-check at 2 (row 125), each a list (1.067108ms)
✔ REQ-PLUG-1 checkPlugins accepts one key per kind, each a list of names, empty included (0.242701ms)
✔ REQ-PLUG-1 checkPlugins refuses bad shapes, unknown kinds, bad names and duplicates (0.499586ms)
✔ REQ-PLUG-1 a kind that switches on one module takes one name, not a list (0.148124ms)
✔ REQ-PLUG-1 checkPlugins reports through the caller's fail callback (0.132027ms)
✔ P5 usage telemetry is optional, single module, separate from enforcing sources (0.141236ms)
✔ REQ-PLUG-1 fixture modules of each kind switch on from a test organization file, no core file changed (9.357471ms)
✔ REQ-PLUG-1 a name not matching ^[a-z][a-z0-9-]*$ refuses and keeps the old setting (3.869634ms)
✔ REQ-PLUG-1 a missing module directory or index.mjs refuses and keeps the old setting (2.937122ms)
✔ REQ-PLUG-1 a symlinked module directory or index.mjs refuses and keeps the old setting (2.673271ms)
✔ REQ-PLUG-1 a symlinked kind directory refuses and keeps the old setting (2.374164ms)
✔ REQ-PLUG-1 a symlinked packages/plugins refuses (run with --preserve-symlinks so the path keeps it) (27.658454ms)
✔ REQ-PLUG-1 index.mjs swapped for a symlink after the lstat checks refuses at the realpath check (2.627026ms)
✔ REQ-PLUG-1 a path that can't be read refuses as unreadable, is logged and keeps the old setting (2.181959ms)
✔ REQ-PLUG-1 a path that becomes unreadable after the lstat checks refuses at either realpath (2.491019ms)
✔ REQ-PLUG-1 a module that fails to load refuses and keeps the old setting (2.663113ms)
✔ REQ-PLUG-1 a missing export refuses and keeps the old setting (3.78261ms)
✔ REQ-PLUG-1 a different interface version refuses and keeps the old setting (2.634605ms)
✔ REQ-PLUG-1 REQ-LIMIT-3 a version 1 limit check refuses after the bump to 2, and the old setting stays (2.598243ms)
✔ REQ-PLUG-1 a kind refused on its first load has nothing switched on, and the log names kind and name (1.844243ms)
✔ REQ-PLUG-1 the setting's shape: unknown kinds refuse alone, a bad whole setting keeps everything (2.647337ms)
✔ REQ-PLUG-1 loads run one at a time, so the last requested setting wins (102.801872ms)
✔ REQ-PLUG-1 the loader needs a log callback (1.263318ms)
✔ REQ-LIMIT-3 token-limit exports interface version 2 with mayLaunch, mustStop and report (1.188308ms)
✔ REQ-LIMIT-3 each subject kind refuses at its limit and allows under it (1.33092ms)
✔ REQ-LIMIT-3 a limit covers only its own subject's records and launches (0.355614ms)
✔ REQ-LIMIT-4 only known records count; an unknown turn adds nothing and is counted apart (0.231653ms)
✔ REQ-LIMIT-3 a reset moves since: records before it no longer count (0.148217ms)
✔ REQ-LIMIT-3 limit 0 refuses with no records; the first limit hit in file order is named (0.136573ms)
✔ REQ-LIMIT-3 a key limit is not enforced while every record's account is null (decision 150 Q1) (0.176874ms)
✔ REQ-LIMIT-3 counts past the safe integer range come back as digit strings (0.124961ms)
✔ REQ-LIMIT-4 bad records or times throw a code, and the check reads nothing but its arguments (0.607578ms)
✔ REQ-LIMIT-3 no token limits: every launch is allowed and the report is empty (0.23856ms)
✔ REQ-LIMIT-3 token-limit ignores tokens.daily, which the daily-quota check enforces (row 126) (0.114066ms)
✔ P5 a model key ID limit counts stack records by key ID without an account (0.118256ms)
✔ P5 Console displays stack count per safe key separately from optional proxy account numbers (0.841797ms)
✔ P5 Console escapes hostile labels and labels unavailable telemetry without presenting a fresh zero (0.176474ms)
✔ REQ-WEB-1 usage read keeps unknown counts and each token kind; no query or write is accepted (25.573147ms)
✔ REQ-WEB-1 malformed usage is refused instead of shown as zero (4.896859ms)
ℹ tests 170
ℹ suites 0
ℹ pass 169
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 9018.08934
✖ failing tests:
test at packages/bus/tests/limit-stop.test.mjs:51:1
✖ REQ-LIMIT-4 a role run at its limit stops at the end of its turn: RESULT and read land first, the claim is revoked by limit-check (106.432474ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected
... Skipped lines
[
{
business: 'demo',
subject: {
account: null,
...
provider: 'anthropic',
+ run: 'run1'
}
},
{
business: 'demo',
subject: {
...
provider: 'anthropic',
+ run: 'run1'
}
}
]
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/limit-stop.test.mjs:61:10)
at async Test.run (node:internal/test_runner/test:1409:7)
at async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: [ { business: 'demo', subject: [Object] }, { business: 'demo', subject: [Object] } ],
expected: [ { business: 'demo', subject: [Object] }, { business: 'demo', subject: [Object] } ],
operator: 'deepStrictEqual',
diff: 'simple'
}
@@ -0,0 +1,204 @@
serial nice19; private HOME/XDG_CONFIG_HOME/TMPDIR/MOSAIC_CONFIG; unchanged whole-file budgets
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mayLaunch","subject":{"instance":"coder","provider":"anthropic","model":"opus","account":"jason-max"},"path":["tokens","daily","jason-max"],"limit":0,"count":0,"unknownTurns":0}
usage: {"event":"usage-unknown","business":"demo","run":"run1","instance":"coder","turn":"5bb2f720-5e85-4a68-a925-a3353c40a2f8","source":"@none","code":"baseline-unknown"}
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mustStop","subject":{"instance":"coder","provider":"anthropic","model":"opus","account":"jason-max"},"path":["tokens","daily","jason-max"],"limit":0,"count":0,"unknownTurns":1}
usage: {"event":"usage-unknown","business":"demo","run":"run1","instance":"coder","turn":"705b4abe-0076-4b91-a1cc-5086242adeed","source":"@none","code":"baseline-unknown"}
✔ REQ-LIMIT-2 runtime: limits counts the daily quota, and mayLaunch refuses only the account at it (161.759642ms)
✔ REQ-LIMIT-4 runtime: a run bound with the account writes it on its usage records and stops at the quota (143.832834ms)
✔ REQ-LIMIT-4 runtime: a run bound without an account records null and the daily quota never stops it (121.34683ms)
✔ REQ-LIMIT-4 bindLaunch keeps the account off session.launched, refuses one that is not an identifier, and takes null as none (69.700044ms)
✔ REQ-LIMIT-3 limitLeaves finds every limit object and skips the agent numbers (1.251176ms)
✔ REQ-LIMIT-3 limitLeaves takes token limits at schema depth only, whatever their names (0.204566ms)
✔ REQ-LIMIT-3 with no check switched on a launch is allowed, a turn never stops, and every limit is not enforced (51.271224ms)
✔ REQ-LIMIT-3 a fixture check that refuses refuses the launch and stops the turn, logged with the limit and the count (52.372536ms)
✔ REQ-LIMIT-3 a report that omits a limit shows it not enforced; a counted entry and a reason come through (45.813258ms)
✔ REQ-LIMIT-4 each check gets the business, a copy of the limits, the subject, the records and the time (54.966516ms)
✔ REQ-LIMIT-4 fail closed: a throw refuses, stops and fails the report, naming the check and the code (45.689186ms)
✔ REQ-LIMIT-4 fail closed: a malformed answer, a promise, a rejected promise, a non-boolean or a bad hit is malformed-answer (47.849713ms)
✔ REQ-LIMIT-4 fail closed: a check switched on but not loaded refuses, stops and fails every limit as not-loaded (48.476916ms)
✔ REQ-LIMIT-4 state(), never-loaded case: before any load the report shows not enforced, or not-loaded for a switched-on check (50.630185ms)
✔ REQ-LIMIT-4 state(), first-load-refused case: a check refused on its first load is not-loaded in mayLaunch, mustStop and report (43.636714ms)
✔ REQ-LIMIT-4 fail closed: an unreadable organization file refuses and stops with check null; the report throws (43.52912ms)
✔ REQ-LIMIT-4 fail closed: unreadable records refuse and stop with check null and fail the report (0.50935ms)
✔ REQ-LIMIT-3 the shipped token-limit, through the real loader, counts known records only since the limit was set (85.225278ms)
✔ REQ-LIMIT-3 a token limit for a provider named limit is counted and refuses, beside an agent limit of the same name (51.638301ms)
✔ REQ-LIMIT-3 core reaches limit checks only through the plug-in loader (1.900971ms)
✔ P5 missing, ambiguous or invalid model key lookup fails closed without leaking a lookup error (52.673427ms)
✔ P5 trusted lookup uses the retiring run key rather than the agent current key (41.052561ms)
✔ P5 actual model metadata lookup rejects missing/ambiguous owners and never cross-attributes a retiring run (0.486898ms)
✔ REQ-LIMIT-4 a role run at its limit stops at the end of its turn: RESULT and read land first, the claim is revoked by limit-check (142.265785ms)
✔ REQ-LIMIT-4 the stop also lands on state; a run with no stop ends without a limit (186.467373ms)
✔ REQ-LIMIT-4 fail closed: a mustStop throw or a malformed answer stops the run, naming the bus and the code (423.452103ms)
✔ REQ-LIMIT-4 a thread run at its limit is released with the reason, and its end record names the limit (110.322117ms)
✔ REQ-LIMIT-4 a broker with no limit checks configured never stops a run (77.036392ms)
limits: {"event":"limit-reached","business":"demo","check":"token-limit","export":"mayLaunch","subject":{"instance":"coder","provider":"zai","model":"glm-5.3-flash","account":null},"path":["tokens","instances","coder"],"limit":0,"count":0,"unknownTurns":0}
organization: {"event":"reload-needs-restart","business":"demo"}
usage: {"event":"usage-unknown","business":"demo","run":"run1","instance":"coder","turn":"071301b4-8009-4918-9b07-39907d1d5082","source":"@none","code":"baseline-unknown"}
limits: {"event":"limit-reached","business":"demo","check":"token-limit","export":"mustStop","subject":{"instance":"coder","provider":"zai","model":"glm-5.3-flash","account":null},"path":["tokens","instances","coder"],"limit":0,"count":0,"unknownTurns":1}
usage: {"event":"usage-unknown","business":"demo","run":"run1","instance":"coder","turn":"231aab8c-068f-4e5a-81e9-19b1cf7d34cc","source":"@none","code":"baseline-unknown"}
✔ REQ-LIMIT-3 REQ-LIMIT-4 runtime: limits carries the token count, mayLaunch refuses at the limit, a reset moves since (248.63219ms)
organization: {"event":"reload-needs-restart","business":"demo"}
✔ REQ-LIMIT-3 runtime: with no limit check switched on, the limit shows not enforced and every launch is allowed (87.393715ms)
✔ REQ-LIMIT-4 runtime: the broker asks the shipped token-limit after a turn, and the run at its limit stops on its next receive (140.096907ms)
✔ REQ-LIMIT-4 runtime: with no usage source a turn is unknown, counts zero and stops nothing under a limit of 1 (122.214342ms)
✔ REQ-LIMIT-3 runtime: switching a limit check on with plugins.set loads it without a launch or a turn (161.718448ms)
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["2817f62132a8"]}
model-proxy: {"action":"proxy.reconcile","addedKeyIds":[],"removedKeyIds":[]}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["2817f62132a8"]}
model-proxy: {"call":"PUT /v8/management/config/access/api-keys","status":200,"keyIds":["2817f62132a8","e87aa1b93018"]}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["2817f62132a8","e87aa1b93018"]}
model-proxy: {"action":"proxy.key.issued","keyIds":["e87aa1b93018"],"instance":"demo/coder"}
model-proxy: {"call":"GET /v1/models","status":200,"keyIds":["e87aa1b93018"]}
organization: {"event":"reload-needs-restart","business":"demo"}
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mustStop","subject":{"instance":"coder","provider":null,"model":null,"account":null,"modelKeyId":"e87aa1b93018"},"path":["tokens","keys","e87aa1b93018"],"limit":2,"count":2,"unknownTurns":0}
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mayLaunch","subject":{"instance":"coder","provider":"fixture","model":"fake","account":null,"modelKeyId":"e87aa1b93018"},"path":["tokens","keys","e87aa1b93018"],"limit":2,"count":2,"unknownTurns":0}
organization: {"event":"reload-needs-restart","business":"demo"}
✔ P5 real runtime binds stack usage to issued key, daily stops at stack count and human-only telemetry settings pass broker contract (311.047592ms)
organization: {"event":"reload-needs-restart","business":"demo"}
organization: {"event":"reload-needs-restart","business":"demo"}
organization: {"event":"reload-needs-restart","business":"demo"}
organization: {"event":"reload-needs-restart","business":"demo"}
✔ plugins and plugins.set refuse every non-human session and a forged actor, and pass only the patch with the verified actor (99.333676ms)
✔ runtime: the switch changes the organization file, the receipt carries the actor, and a bad shape, an unknown module and a stale revision are refused with nothing written (257.002212ms)
✔ vikunja:19/309 through the broker, a patch switches the kinds it names and keeps the rest; null removes one kind and is trailed (196.173099ms)
✔ P5 usage plugin off by default, default poll is 15 seconds and configured polls skip early ticks (58.628561ms)
✔ P5 safe telemetry stores failures per key and proxy-labelled accounts; no client/upstream value enters store/log/view or quota records (52.79243ms)
✔ P5 unknown msk key goes only to value-free reconcile log and other businesses stay isolated (42.569864ms)
✔ P5 queue failure is safe, does not enforce and does not retry before poll deadline (41.831504ms)
✔ P5 retiring key keeps attribution and telemetry rows remain append-only across reader restart (47.808191ms)
✔ P5 malformed queue batch is atomic: no valid prefix, body or credential can reach store/log/view (43.023649ms)
✔ P5 concurrent ticks issue one bounded queue read and a closed collector never polls again (42.774113ms)
✔ REQ-LIMIT-4 usage protocol binds run identity, requires a delivered turn and isolates businesses (111.658595ms)
✔ REQ-PLUG-1 runtime reaches transcript only through loader, over the real bus socket (136.372459ms)
✔ REQ-LIMIT-4 loader source records new turn kinds, excludes history and retries exactly once (52.523881ms)
✔ REQ-LIMIT-4 cut: unknown is durable and logged next to every total (60.980995ms)
✔ REQ-LIMIT-4 disabled: unknown is durable and logged next to every total (47.608728ms)
✔ REQ-LIMIT-4 missing-begin: unknown is durable and logged next to every total (40.927657ms)
✔ REQ-LIMIT-4 no-new-usage: unknown is durable and logged next to every total (55.771008ms)
✔ REQ-LIMIT-4 rewrite: unknown is durable and logged next to every total (57.407378ms)
✔ REQ-LIMIT-4 unfinished turn remains visibly unknown after accounting restarts (42.03284ms)
✔ usage records are append-only (41.064096ms)
✔ REQ-LIMIT-4 parse failure logs its safe code, never transcript content (46.863323ms)
✔ REQ-LIMIT-4 resumed run baselines history and exact totals do not overflow (51.492502ms)
✔ REQ-PLUG-1 core has no transcript import and disabled sources do not read any transcript (40.548781ms)
✔ REQ-LIMIT-4 a resumed thread bills only new assistant messages to its next run (41.97363ms)
✔ REQ-LIMIT-4 every enabled source is called; failure is unknown and a partial total stays labelled (50.186944ms)
✔ REQ-LIMIT-4 a turn whose reported sum exceeds safe precision is unknown, not rounded (44.545546ms)
✔ row 65 a run bound without a transcript directory records no-transcript (44.101897ms)
✔ P5 immutable stack key attribution survives rotation and restart without key values (44.09141ms)
✔ P5 malformed key metadata is dropped rather than stored or exposed as a key value (44.151576ms)
✔ REQ-PLUG-1 schema: plugins is optional, names known kinds and checked module names (9.654239ms)
✔ REQ-PLUG-1 REQ-ROLE-3 the setter writes plugins through the organization writer and logs old and new names (136.405265ms)
✔ vikunja:19/309 a patch changes only the kinds it names; null removes one kind, explicitly and in the trail (164.709168ms)
✔ vikunja:19/309 an unknown kind (set or removed), a bad module, an empty patch and null on the wrong shape are refused, nothing written (1.961195ms)
✔ REQ-PLUG-1 REQ-ROLE-3 the writer checks the bytes it writes: a Date in plugins is refused there too (20.250129ms)
✔ REQ-PLUG-1 REQ-ROLE-3 a refused setter write throws a code, changes nothing and logs nothing (1.590323ms)
✔ vikunja:19/305 with an exists check, the setter refuses a module no tree file answers to, before anything is written (50.378509ms)
✔ P5 optional usage kind and pollSeconds configure through plugins.set; default stays absent and retention bound is strict (93.589584ms)
✔ P5 only human can enable/disable telemetry or change polling, including direct organization writes (146.907219ms)
✔ REQ-LIMIT-3 schema: each subject kind, limit 0 and no ceiling are accepted; bad limits, times, keys and undeclared instances refuse (14.755461ms)
✔ REQ-LIMIT-3 the writer stamps since: a new limit gets now, a changed one keeps its time, a different time is refused (223.35974ms)
✔ REQ-LIMIT-3 only tokens.* at schema depth holds token limits: agent limits named `limit` save as sent, and a token limit named `limit` is stamped and reset (262.018477ms)
✔ REQ-LIMIT-3 a reset moves since to now, is logged with its actor, and refuses a path that is not a limit (136.45906ms)
✔ REQ-LIMIT-2 schema: launch.account names a credential set; a daily quota needs a reset and an IANA zone and names the account (22.468222ms)
✔ REQ-LIMIT-2 the writer stamps a daily quota's since, keeps its reset and zone, and a reset moves since (146.912888ms)
✔ P5 per-model-key quotas are unset by default, accept digit-leading IDs and only the human changes or resets them (199.214764ms)
✔ probeKey observes 200 with one agent-authenticated GET /v1/models (13.500079ms)
✔ probeKey observes 401 with one agent-authenticated GET /v1/models (2.29275ms)
✔ probeKey observes 503 with one agent-authenticated GET /v1/models (1.453939ms)
✔ proxy-down: agent-key probe connection failure is sanitized (1.448596ms)
✔ proxy-down: silent listener cannot extend probe request deadline (51.226767ms)
✔ agent-key probe returns redirect status without following Location or exposing key (2.599627ms)
✔ proxy-client-invalid: https://127.0.0.1:18318 (0.940367ms)
✔ proxy-client-invalid: http://example.com:18318 (0.110721ms)
✔ proxy-client-invalid: http://localhost:18318 (0.551474ms)
✔ proxy-client-invalid: http://127.0.0.1:8317 (0.085358ms)
✔ proxy-client-invalid: http://user:[email protected]:18318 (0.082245ms)
✔ proxy-client-invalid: http://127.0.0.1:18318/path (0.071237ms)
✔ client GET/PUT v8 only, Authorization header, receipt IDs without values or bodies (16.679264ms)
✔ proxy-client-refused (2.60845ms)
✔ proxy-client-response (1.279043ms)
✔ proxy-client-redirect (1.146966ms)
✔ proxy-client-down: transport errors redact details (0.949938ms)
✔ proxy-client-invalid: PUT rejects object key records and empty strings locally (0.180359ms)
✔ proxy-management-key-invalid: missing, symlink and public key file refuse without values (0.938153ms)
✔ bus management-key loader supplies a private fixture key without exposing it on the client (0.489424ms)
✔ proxy-client-response: truncated response remains a redacted named refusal (12.060482ms)
✔ management client ignores ambient fetch dispatchers (1.377676ms)
✔ proxy-key-invalid: Latin-1 leaves complete config/data inventories unchanged (3.526441ms)
✔ proxy-key-invalid: leading space leaves complete config/data inventories unchanged (1.110569ms)
✔ proxy-key-invalid: trailing space leaves complete config/data inventories unchanged (1.01067ms)
✔ proxy-key-invalid: internal space leaves complete config/data inventories unchanged (1.13613ms)
✔ printable non-space ASCII control initializes and authenticates with unchanged existing files (17.073708ms)
✔ OAuth management calls keep URL and state out of receipts (16.393438ms)
✔ upstream key goes only in request body and upstream refusal body is discarded (3.072175ms)
✔ redirected management calls are not followed or retried (1.57426ms)
✔ P5 queue read uses actual bounded fixed management GET and immediately drops client and upstream values (15.82294ms)
✔ P5 bad envelope refuses safely with no retry (2.96929ms)
✔ P5 over count refuses safely with no retry (1.741334ms)
✔ P5 missing key refuses safely with no retry (1.466913ms)
✔ P5 bad counts refuses safely with no retry (2.929775ms)
✔ P5 redirect refuses safely with no retry (1.463954ms)
✔ P5 refusal refuses safely with no retry (1.03957ms)
✔ P5 malformed event after a valid event rejects the entire queue before any credential can escape (1.194237ms)
✔ REQ-LIMIT-2 daily-quota exports interface version 2 with mayLaunch, mustStop and report (1.253421ms)
✔ REQ-LIMIT-2 the count sums every kind of the account's known records since the later of the day start and since (12.848519ms)
✔ REQ-LIMIT-2 a launch with no account (pi) is covered by no daily quota (0.34571ms)
✔ REQ-LIMIT-4 an unknown turn adds nothing and is counted apart (0.530747ms)
✔ REQ-LIMIT-2 the day turns at the reset in its zone, not in UTC, and before it the day is yesterday's (0.735447ms)
✔ REQ-LIMIT-2 the spring DST change makes the day after a 00:00 reset 23 hours long (0.388703ms)
✔ REQ-LIMIT-2 the fall DST change makes the day after a 00:00 reset 25 hours long (0.354873ms)
✔ REQ-LIMIT-2 a reset the clocks skip starts the day at the first instant after the gap (0.967098ms)
✔ REQ-LIMIT-2 a reset the clocks repeat starts one day, at the first one (0.478992ms)
✔ REQ-LIMIT-2 a launch is refused at the quota, a turn that reaches it stops, and the next day allows again (1.167482ms)
✔ REQ-LIMIT-2 counts past the safe integer range come back as digit strings (0.375179ms)
✔ REQ-LIMIT-4 bad leaves, records or times throw a code, and the check reads nothing but its arguments (2.739059ms)
✔ REQ-LIMIT-2 no daily quotas: every launch is allowed and the report is empty (0.22961ms)
✔ P5 daily quota for a model key ID matches stack key records and resets the next day (0.935079ms)
✔ REQ-PLUG-1 REQ-LIMIT-4 the registry: usage-source at interface version 1, limit-check at 2 (row 125), each a list (1.194208ms)
✔ REQ-PLUG-1 checkPlugins accepts one key per kind, each a list of names, empty included (0.254856ms)
✔ REQ-PLUG-1 checkPlugins refuses bad shapes, unknown kinds, bad names and duplicates (1.125412ms)
✔ REQ-PLUG-1 a kind that switches on one module takes one name, not a list (0.161968ms)
✔ REQ-PLUG-1 checkPlugins reports through the caller's fail callback (0.141125ms)
✔ P5 usage telemetry is optional, single module, separate from enforcing sources (0.146226ms)
✔ REQ-PLUG-1 fixture modules of each kind switch on from a test organization file, no core file changed (9.365221ms)
✔ REQ-PLUG-1 a name not matching ^[a-z][a-z0-9-]*$ refuses and keeps the old setting (4.138219ms)
✔ REQ-PLUG-1 a missing module directory or index.mjs refuses and keeps the old setting (3.181488ms)
✔ REQ-PLUG-1 a symlinked module directory or index.mjs refuses and keeps the old setting (3.076206ms)
✔ REQ-PLUG-1 a symlinked kind directory refuses and keeps the old setting (2.618445ms)
✔ REQ-PLUG-1 a symlinked packages/plugins refuses (run with --preserve-symlinks so the path keeps it) (30.33829ms)
✔ REQ-PLUG-1 index.mjs swapped for a symlink after the lstat checks refuses at the realpath check (2.849943ms)
✔ REQ-PLUG-1 a path that can't be read refuses as unreadable, is logged and keeps the old setting (2.25734ms)
✔ REQ-PLUG-1 a path that becomes unreadable after the lstat checks refuses at either realpath (2.597703ms)
✔ REQ-PLUG-1 a module that fails to load refuses and keeps the old setting (2.743636ms)
✔ REQ-PLUG-1 a missing export refuses and keeps the old setting (3.876351ms)
✔ REQ-PLUG-1 a different interface version refuses and keeps the old setting (2.717178ms)
✔ REQ-PLUG-1 REQ-LIMIT-3 a version 1 limit check refuses after the bump to 2, and the old setting stays (2.639476ms)
✔ REQ-PLUG-1 a kind refused on its first load has nothing switched on, and the log names kind and name (1.884786ms)
✔ REQ-PLUG-1 the setting's shape: unknown kinds refuse alone, a bad whole setting keeps everything (3.078835ms)
✔ REQ-PLUG-1 loads run one at a time, so the last requested setting wins (102.865433ms)
✔ REQ-PLUG-1 the loader needs a log callback (1.252523ms)
✔ REQ-LIMIT-3 token-limit exports interface version 2 with mayLaunch, mustStop and report (1.15958ms)
✔ REQ-LIMIT-3 each subject kind refuses at its limit and allows under it (1.269598ms)
✔ REQ-LIMIT-3 a limit covers only its own subject's records and launches (0.319894ms)
✔ REQ-LIMIT-4 only known records count; an unknown turn adds nothing and is counted apart (0.245595ms)
✔ REQ-LIMIT-3 a reset moves since: records before it no longer count (0.147653ms)
✔ REQ-LIMIT-3 limit 0 refuses with no records; the first limit hit in file order is named (0.136545ms)
✔ REQ-LIMIT-3 a key limit is not enforced while every record's account is null (decision 150 Q1) (0.161235ms)
✔ REQ-LIMIT-3 counts past the safe integer range come back as digit strings (0.131986ms)
✔ REQ-LIMIT-4 bad records or times throw a code, and the check reads nothing but its arguments (0.612439ms)
✔ REQ-LIMIT-3 no token limits: every launch is allowed and the report is empty (0.225872ms)
✔ REQ-LIMIT-3 token-limit ignores tokens.daily, which the daily-quota check enforces (row 126) (0.115054ms)
✔ P5 a model key ID limit counts stack records by key ID without an account (0.118321ms)
✔ P5 Console displays stack count per safe key separately from optional proxy account numbers (0.840194ms)
✔ P5 Console escapes hostile labels and labels unavailable telemetry without presenting a fresh zero (0.169412ms)
✔ REQ-WEB-1 usage read keeps unknown counts and each token kind; no query or write is accepted (25.71419ms)
✔ REQ-WEB-1 malformed usage is refused instead of shown as zero (4.903993ms)
ℹ tests 170
ℹ suites 0
ℹ pass 170
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 8854.156666
@@ -0,0 +1,36 @@
✔ P5 broker preserves original plugin subject and derives internal run context from authenticated native caller (99.462478ms)
✖ P5 configured key quotas never use a supplied safe-looking ID when trusted metadata lookup is missing (43.555167ms)
✔ P5 internal context resolves exactly current or retained generation; wrong business, instance, run and owner refuse (0.357162ms)
ℹ tests 3
ℹ suites 0
ℹ pass 2
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 237.626033
✖ failing tests:
test at packages/bus/tests/p5-key-context.test.mjs:23:1
✖ P5 configured key quotas never use a supplied safe-looking ID when trusted metadata lookup is missing (43.555167ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected
{
+ stop: false
- check: null,
- code: 'proxy-key-refused',
- stop: true
}
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-key-context.test.mjs:27:9)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: { stop: false },
expected: { stop: true, check: null, code: 'proxy-key-refused' },
operator: 'deepStrictEqual',
diff: 'simple'
}
@@ -0,0 +1,23 @@
✔ REQ-LIMIT-4 a role run at its limit stops at the end of its turn: RESULT and read land first, the claim is revoked by limit-check (135.950817ms)
✔ REQ-LIMIT-4 the stop also lands on state; a run with no stop ends without a limit (183.02595ms)
✔ REQ-LIMIT-4 fail closed: a mustStop throw or a malformed answer stops the run, naming the bus and the code (446.621104ms)
✔ REQ-LIMIT-4 a thread run at its limit is released with the reason, and its end record names the limit (114.707723ms)
✔ REQ-LIMIT-4 a broker with no limit checks configured never stops a run (71.318028ms)
✔ P5 broker preserves original plugin subject and derives internal run context from authenticated native caller (89.174131ms)
✔ P5 configured key quotas never use a supplied safe-looking ID when trusted metadata lookup is missing (41.80406ms)
✔ P5 internal context resolves exactly current or retained generation; wrong business, instance, run and owner refuse (0.436962ms)
✔ P5 usage plugin off by default, default poll is 15 seconds and configured polls skip early ticks (57.810472ms)
✔ P5 safe telemetry stores failures per key and proxy-labelled accounts; no client/upstream value enters store/log/view or quota records (54.180897ms)
✔ P5 unknown msk key goes only to value-free reconcile log and other businesses stay isolated (41.762914ms)
✔ P5 queue failure is safe, does not enforce and does not retry before poll deadline (43.65014ms)
✔ P5 retiring key keeps attribution and telemetry rows remain append-only across reader restart (50.005361ms)
✔ P5 malformed queue batch is atomic: no valid prefix, body or credential can reach store/log/view (42.308399ms)
✔ P5 concurrent ticks issue one bounded queue read and a closed collector never polls again (46.350571ms)
ℹ tests 15
ℹ suites 0
ℹ pass 15
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1674.306377
@@ -0,0 +1,207 @@
serial nice19; private HOME/XDG_CONFIG_HOME/TMPDIR/MOSAIC_CONFIG; unchanged whole-file budgets
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mayLaunch","subject":{"instance":"coder","provider":"anthropic","model":"opus","account":"jason-max"},"path":["tokens","daily","jason-max"],"limit":0,"count":0,"unknownTurns":0}
usage: {"event":"usage-unknown","business":"demo","run":"run1","instance":"coder","turn":"4fe53301-641b-494d-a461-847c03170e3f","source":"@none","code":"baseline-unknown"}
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mustStop","subject":{"instance":"coder","provider":"anthropic","model":"opus","account":"jason-max"},"path":["tokens","daily","jason-max"],"limit":0,"count":0,"unknownTurns":1}
usage: {"event":"usage-unknown","business":"demo","run":"run1","instance":"coder","turn":"797da8e3-f04c-4e40-b8e1-bfb60b07c554","source":"@none","code":"baseline-unknown"}
✔ REQ-LIMIT-2 runtime: limits counts the daily quota, and mayLaunch refuses only the account at it (158.160821ms)
✔ REQ-LIMIT-4 runtime: a run bound with the account writes it on its usage records and stops at the quota (143.809206ms)
✔ REQ-LIMIT-4 runtime: a run bound without an account records null and the daily quota never stops it (121.006833ms)
✔ REQ-LIMIT-4 bindLaunch keeps the account off session.launched, refuses one that is not an identifier, and takes null as none (64.961645ms)
✔ REQ-LIMIT-3 limitLeaves finds every limit object and skips the agent numbers (1.220027ms)
✔ REQ-LIMIT-3 limitLeaves takes token limits at schema depth only, whatever their names (0.214936ms)
✔ REQ-LIMIT-3 with no check switched on a launch is allowed, a turn never stops, and every limit is not enforced (44.021673ms)
✔ REQ-LIMIT-3 a fixture check that refuses refuses the launch and stops the turn, logged with the limit and the count (43.052934ms)
✔ REQ-LIMIT-3 a report that omits a limit shows it not enforced; a counted entry and a reason come through (40.139268ms)
✔ REQ-LIMIT-4 each check gets the business, a copy of the limits, the subject, the records and the time (52.680831ms)
✔ REQ-LIMIT-4 fail closed: a throw refuses, stops and fails the report, naming the check and the code (47.313105ms)
✔ REQ-LIMIT-4 fail closed: a malformed answer, a promise, a rejected promise, a non-boolean or a bad hit is malformed-answer (46.754294ms)
✔ REQ-LIMIT-4 fail closed: a check switched on but not loaded refuses, stops and fails every limit as not-loaded (42.493056ms)
✔ REQ-LIMIT-4 state(), never-loaded case: before any load the report shows not enforced, or not-loaded for a switched-on check (41.402846ms)
✔ REQ-LIMIT-4 state(), first-load-refused case: a check refused on its first load is not-loaded in mayLaunch, mustStop and report (41.969573ms)
✔ REQ-LIMIT-4 fail closed: an unreadable organization file refuses and stops with check null; the report throws (41.694193ms)
✔ REQ-LIMIT-4 fail closed: unreadable records refuse and stop with check null and fail the report (0.52246ms)
✔ REQ-LIMIT-3 the shipped token-limit, through the real loader, counts known records only since the limit was set (83.096899ms)
✔ REQ-LIMIT-3 a token limit for a provider named limit is counted and refuses, beside an agent limit of the same name (50.535823ms)
✔ REQ-LIMIT-3 core reaches limit checks only through the plug-in loader (1.710249ms)
✔ P5 missing, ambiguous or invalid model key lookup fails closed without leaking a lookup error (41.544044ms)
✔ P5 trusted lookup uses the retiring run key rather than the agent current key (39.590387ms)
✔ P5 actual model metadata lookup rejects missing/ambiguous owners and never cross-attributes a retiring run (0.460753ms)
✔ REQ-LIMIT-4 a role run at its limit stops at the end of its turn: RESULT and read land first, the claim is revoked by limit-check (132.493862ms)
✔ REQ-LIMIT-4 the stop also lands on state; a run with no stop ends without a limit (177.559162ms)
✔ REQ-LIMIT-4 fail closed: a mustStop throw or a malformed answer stops the run, naming the bus and the code (440.047034ms)
✔ REQ-LIMIT-4 a thread run at its limit is released with the reason, and its end record names the limit (109.873105ms)
✔ REQ-LIMIT-4 a broker with no limit checks configured never stops a run (77.150566ms)
limits: {"event":"limit-reached","business":"demo","check":"token-limit","export":"mayLaunch","subject":{"instance":"coder","provider":"zai","model":"glm-5.3-flash","account":null},"path":["tokens","instances","coder"],"limit":0,"count":0,"unknownTurns":0}
organization: {"event":"reload-needs-restart","business":"demo"}
usage: {"event":"usage-unknown","business":"demo","run":"run1","instance":"coder","turn":"b338e07c-04c8-4942-902f-484f07e73153","source":"@none","code":"baseline-unknown"}
limits: {"event":"limit-reached","business":"demo","check":"token-limit","export":"mustStop","subject":{"instance":"coder","provider":"zai","model":"glm-5.3-flash","account":null},"path":["tokens","instances","coder"],"limit":0,"count":0,"unknownTurns":1}
usage: {"event":"usage-unknown","business":"demo","run":"run1","instance":"coder","turn":"fd7f45ea-e03c-49dd-a53c-e385fdd5acbf","source":"@none","code":"baseline-unknown"}
✔ REQ-LIMIT-3 REQ-LIMIT-4 runtime: limits carries the token count, mayLaunch refuses at the limit, a reset moves since (245.80231ms)
organization: {"event":"reload-needs-restart","business":"demo"}
✔ REQ-LIMIT-3 runtime: with no limit check switched on, the limit shows not enforced and every launch is allowed (84.052026ms)
✔ REQ-LIMIT-4 runtime: the broker asks the shipped token-limit after a turn, and the run at its limit stops on its next receive (136.937413ms)
✔ REQ-LIMIT-4 runtime: with no usage source a turn is unknown, counts zero and stops nothing under a limit of 1 (118.705264ms)
✔ REQ-LIMIT-3 runtime: switching a limit check on with plugins.set loads it without a launch or a turn (165.970294ms)
✔ P5 broker preserves original plugin subject and derives internal run context from authenticated native caller (90.023506ms)
✔ P5 configured key quotas never use a supplied safe-looking ID when trusted metadata lookup is missing (42.127316ms)
✔ P5 internal context resolves exactly current or retained generation; wrong business, instance, run and owner refuse (0.383979ms)
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["59bfaebcb056"]}
model-proxy: {"action":"proxy.reconcile","addedKeyIds":[],"removedKeyIds":[]}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["59bfaebcb056"]}
model-proxy: {"call":"PUT /v8/management/config/access/api-keys","status":200,"keyIds":["59bfaebcb056","fa6669b39602"]}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["59bfaebcb056","fa6669b39602"]}
model-proxy: {"action":"proxy.key.issued","keyIds":["fa6669b39602"],"instance":"demo/coder"}
model-proxy: {"call":"GET /v1/models","status":200,"keyIds":["fa6669b39602"]}
organization: {"event":"reload-needs-restart","business":"demo"}
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mustStop","subject":{"instance":"coder","provider":null,"model":null,"account":null,"modelKeyId":"fa6669b39602"},"path":["tokens","keys","fa6669b39602"],"limit":2,"count":2,"unknownTurns":0}
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mayLaunch","subject":{"instance":"coder","provider":"fixture","model":"fake","account":null,"modelKeyId":"fa6669b39602"},"path":["tokens","keys","fa6669b39602"],"limit":2,"count":2,"unknownTurns":0}
organization: {"event":"reload-needs-restart","business":"demo"}
✔ P5 real runtime binds stack usage to issued key, daily stops at stack count and human-only telemetry settings pass broker contract (325.548897ms)
organization: {"event":"reload-needs-restart","business":"demo"}
organization: {"event":"reload-needs-restart","business":"demo"}
organization: {"event":"reload-needs-restart","business":"demo"}
organization: {"event":"reload-needs-restart","business":"demo"}
✔ plugins and plugins.set refuse every non-human session and a forged actor, and pass only the patch with the verified actor (104.870501ms)
✔ runtime: the switch changes the organization file, the receipt carries the actor, and a bad shape, an unknown module and a stale revision are refused with nothing written (268.507544ms)
✔ vikunja:19/309 through the broker, a patch switches the kinds it names and keeps the rest; null removes one kind and is trailed (215.488037ms)
✔ P5 usage plugin off by default, default poll is 15 seconds and configured polls skip early ticks (60.18695ms)
✔ P5 safe telemetry stores failures per key and proxy-labelled accounts; no client/upstream value enters store/log/view or quota records (56.879533ms)
✔ P5 unknown msk key goes only to value-free reconcile log and other businesses stay isolated (46.789381ms)
✔ P5 queue failure is safe, does not enforce and does not retry before poll deadline (43.152978ms)
✔ P5 retiring key keeps attribution and telemetry rows remain append-only across reader restart (49.497425ms)
✔ P5 malformed queue batch is atomic: no valid prefix, body or credential can reach store/log/view (46.179514ms)
✔ P5 concurrent ticks issue one bounded queue read and a closed collector never polls again (46.481349ms)
✔ REQ-LIMIT-4 usage protocol binds run identity, requires a delivered turn and isolates businesses (113.617169ms)
✔ REQ-PLUG-1 runtime reaches transcript only through loader, over the real bus socket (154.197141ms)
✔ REQ-LIMIT-4 loader source records new turn kinds, excludes history and retries exactly once (55.1487ms)
✔ REQ-LIMIT-4 cut: unknown is durable and logged next to every total (48.001192ms)
✔ REQ-LIMIT-4 disabled: unknown is durable and logged next to every total (52.699151ms)
✔ REQ-LIMIT-4 missing-begin: unknown is durable and logged next to every total (43.859028ms)
✔ REQ-LIMIT-4 no-new-usage: unknown is durable and logged next to every total (49.684957ms)
✔ REQ-LIMIT-4 rewrite: unknown is durable and logged next to every total (48.842941ms)
✔ REQ-LIMIT-4 unfinished turn remains visibly unknown after accounting restarts (46.725304ms)
✔ usage records are append-only (43.666526ms)
✔ REQ-LIMIT-4 parse failure logs its safe code, never transcript content (50.791657ms)
✔ REQ-LIMIT-4 resumed run baselines history and exact totals do not overflow (67.235771ms)
✔ REQ-PLUG-1 core has no transcript import and disabled sources do not read any transcript (50.444244ms)
✔ REQ-LIMIT-4 a resumed thread bills only new assistant messages to its next run (48.518074ms)
✔ REQ-LIMIT-4 every enabled source is called; failure is unknown and a partial total stays labelled (52.596237ms)
✔ REQ-LIMIT-4 a turn whose reported sum exceeds safe precision is unknown, not rounded (48.989984ms)
✔ row 65 a run bound without a transcript directory records no-transcript (47.601985ms)
✔ P5 immutable stack key attribution survives rotation and restart without key values (58.908338ms)
✔ P5 malformed key metadata is dropped rather than stored or exposed as a key value (48.622269ms)
✔ REQ-PLUG-1 schema: plugins is optional, names known kinds and checked module names (11.123203ms)
✔ REQ-PLUG-1 REQ-ROLE-3 the setter writes plugins through the organization writer and logs old and new names (144.541984ms)
✔ vikunja:19/309 a patch changes only the kinds it names; null removes one kind, explicitly and in the trail (186.444017ms)
✔ vikunja:19/309 an unknown kind (set or removed), a bad module, an empty patch and null on the wrong shape are refused, nothing written (2.070716ms)
✔ REQ-PLUG-1 REQ-ROLE-3 the writer checks the bytes it writes: a Date in plugins is refused there too (24.002633ms)
✔ REQ-PLUG-1 REQ-ROLE-3 a refused setter write throws a code, changes nothing and logs nothing (1.819444ms)
✔ vikunja:19/305 with an exists check, the setter refuses a module no tree file answers to, before anything is written (53.502998ms)
✔ P5 optional usage kind and pollSeconds configure through plugins.set; default stays absent and retention bound is strict (102.914554ms)
✔ P5 only human can enable/disable telemetry or change polling, including direct organization writes (153.795381ms)
✔ REQ-LIMIT-3 schema: each subject kind, limit 0 and no ceiling are accepted; bad limits, times, keys and undeclared instances refuse (12.633498ms)
✔ REQ-LIMIT-3 the writer stamps since: a new limit gets now, a changed one keeps its time, a different time is refused (250.719331ms)
✔ REQ-LIMIT-3 only tokens.* at schema depth holds token limits: agent limits named `limit` save as sent, and a token limit named `limit` is stamped and reset (279.391871ms)
✔ REQ-LIMIT-3 a reset moves since to now, is logged with its actor, and refuses a path that is not a limit (143.161688ms)
✔ REQ-LIMIT-2 schema: launch.account names a credential set; a daily quota needs a reset and an IANA zone and names the account (22.600091ms)
✔ REQ-LIMIT-2 the writer stamps a daily quota's since, keeps its reset and zone, and a reset moves since (147.449414ms)
✔ P5 per-model-key quotas are unset by default, accept digit-leading IDs and only the human changes or resets them (211.379051ms)
✔ probeKey observes 200 with one agent-authenticated GET /v1/models (13.650453ms)
✔ probeKey observes 401 with one agent-authenticated GET /v1/models (2.452411ms)
✔ probeKey observes 503 with one agent-authenticated GET /v1/models (1.454096ms)
✔ proxy-down: agent-key probe connection failure is sanitized (1.507584ms)
✔ proxy-down: silent listener cannot extend probe request deadline (51.18593ms)
✔ agent-key probe returns redirect status without following Location or exposing key (2.629896ms)
✔ proxy-client-invalid: https://127.0.0.1:18318 (0.940604ms)
✔ proxy-client-invalid: http://example.com:18318 (0.620294ms)
✔ proxy-client-invalid: http://localhost:18318 (0.082993ms)
✔ proxy-client-invalid: http://127.0.0.1:8317 (0.075406ms)
✔ proxy-client-invalid: http://user:[email protected]:18318 (0.082019ms)
✔ proxy-client-invalid: http://127.0.0.1:18318/path (0.077949ms)
✔ client GET/PUT v8 only, Authorization header, receipt IDs without values or bodies (16.759591ms)
✔ proxy-client-refused (2.644555ms)
✔ proxy-client-response (1.257544ms)
✔ proxy-client-redirect (1.116738ms)
✔ proxy-client-down: transport errors redact details (0.932782ms)
✔ proxy-client-invalid: PUT rejects object key records and empty strings locally (0.174045ms)
✔ proxy-management-key-invalid: missing, symlink and public key file refuse without values (0.93563ms)
✔ bus management-key loader supplies a private fixture key without exposing it on the client (0.481342ms)
✔ proxy-client-response: truncated response remains a redacted named refusal (11.038179ms)
✔ management client ignores ambient fetch dispatchers (1.371561ms)
✔ proxy-key-invalid: Latin-1 leaves complete config/data inventories unchanged (3.426795ms)
✔ proxy-key-invalid: leading space leaves complete config/data inventories unchanged (1.114261ms)
✔ proxy-key-invalid: trailing space leaves complete config/data inventories unchanged (1.011023ms)
✔ proxy-key-invalid: internal space leaves complete config/data inventories unchanged (1.128478ms)
✔ printable non-space ASCII control initializes and authenticates with unchanged existing files (16.93766ms)
✔ OAuth management calls keep URL and state out of receipts (16.303618ms)
✔ upstream key goes only in request body and upstream refusal body is discarded (3.098596ms)
✔ redirected management calls are not followed or retried (1.618972ms)
✔ P5 queue read uses actual bounded fixed management GET and immediately drops client and upstream values (14.682335ms)
✔ P5 bad envelope refuses safely with no retry (2.770996ms)
✔ P5 over count refuses safely with no retry (1.619582ms)
✔ P5 missing key refuses safely with no retry (2.024573ms)
✔ P5 bad counts refuses safely with no retry (1.40751ms)
✔ P5 redirect refuses safely with no retry (1.380605ms)
✔ P5 refusal refuses safely with no retry (0.992984ms)
✔ P5 malformed event after a valid event rejects the entire queue before any credential can escape (1.079984ms)
✔ REQ-LIMIT-2 daily-quota exports interface version 2 with mayLaunch, mustStop and report (1.195525ms)
✔ REQ-LIMIT-2 the count sums every kind of the account's known records since the later of the day start and since (12.385039ms)
✔ REQ-LIMIT-2 a launch with no account (pi) is covered by no daily quota (0.294446ms)
✔ REQ-LIMIT-4 an unknown turn adds nothing and is counted apart (0.448244ms)
✔ REQ-LIMIT-2 the day turns at the reset in its zone, not in UTC, and before it the day is yesterday's (0.585636ms)
✔ REQ-LIMIT-2 the spring DST change makes the day after a 00:00 reset 23 hours long (0.344176ms)
✔ REQ-LIMIT-2 the fall DST change makes the day after a 00:00 reset 25 hours long (0.309404ms)
✔ REQ-LIMIT-2 a reset the clocks skip starts the day at the first instant after the gap (0.823288ms)
✔ REQ-LIMIT-2 a reset the clocks repeat starts one day, at the first one (0.462864ms)
✔ REQ-LIMIT-2 a launch is refused at the quota, a turn that reaches it stops, and the next day allows again (1.053193ms)
✔ REQ-LIMIT-2 counts past the safe integer range come back as digit strings (0.384911ms)
✔ REQ-LIMIT-4 bad leaves, records or times throw a code, and the check reads nothing but its arguments (2.335648ms)
✔ REQ-LIMIT-2 no daily quotas: every launch is allowed and the report is empty (0.194429ms)
✔ P5 daily quota for a model key ID matches stack key records and resets the next day (0.764141ms)
✔ REQ-PLUG-1 REQ-LIMIT-4 the registry: usage-source at interface version 1, limit-check at 2 (row 125), each a list (1.078533ms)
✔ REQ-PLUG-1 checkPlugins accepts one key per kind, each a list of names, empty included (0.243968ms)
✔ REQ-PLUG-1 checkPlugins refuses bad shapes, unknown kinds, bad names and duplicates (0.928754ms)
✔ REQ-PLUG-1 a kind that switches on one module takes one name, not a list (0.133743ms)
✔ REQ-PLUG-1 checkPlugins reports through the caller's fail callback (0.128969ms)
✔ P5 usage telemetry is optional, single module, separate from enforcing sources (0.180465ms)
✔ REQ-PLUG-1 fixture modules of each kind switch on from a test organization file, no core file changed (9.158842ms)
✔ REQ-PLUG-1 a name not matching ^[a-z][a-z0-9-]*$ refuses and keeps the old setting (4.034236ms)
✔ REQ-PLUG-1 a missing module directory or index.mjs refuses and keeps the old setting (3.123767ms)
✔ REQ-PLUG-1 a symlinked module directory or index.mjs refuses and keeps the old setting (2.857748ms)
✔ REQ-PLUG-1 a symlinked kind directory refuses and keeps the old setting (2.422702ms)
✔ REQ-PLUG-1 a symlinked packages/plugins refuses (run with --preserve-symlinks so the path keeps it) (27.290401ms)
✔ REQ-PLUG-1 index.mjs swapped for a symlink after the lstat checks refuses at the realpath check (2.752498ms)
✔ REQ-PLUG-1 a path that can't be read refuses as unreadable, is logged and keeps the old setting (2.289418ms)
✔ REQ-PLUG-1 a path that becomes unreadable after the lstat checks refuses at either realpath (2.561921ms)
✔ REQ-PLUG-1 a module that fails to load refuses and keeps the old setting (2.761977ms)
✔ REQ-PLUG-1 a missing export refuses and keeps the old setting (3.894842ms)
✔ REQ-PLUG-1 a different interface version refuses and keeps the old setting (2.759495ms)
✔ REQ-PLUG-1 REQ-LIMIT-3 a version 1 limit check refuses after the bump to 2, and the old setting stays (2.719036ms)
✔ REQ-PLUG-1 a kind refused on its first load has nothing switched on, and the log names kind and name (2.205867ms)
✔ REQ-PLUG-1 the setting's shape: unknown kinds refuse alone, a bad whole setting keeps everything (3.120271ms)
✔ REQ-PLUG-1 loads run one at a time, so the last requested setting wins (103.864421ms)
✔ REQ-PLUG-1 the loader needs a log callback (1.369307ms)
✔ REQ-LIMIT-3 token-limit exports interface version 2 with mayLaunch, mustStop and report (1.204087ms)
✔ REQ-LIMIT-3 each subject kind refuses at its limit and allows under it (1.293377ms)
✔ REQ-LIMIT-3 a limit covers only its own subject's records and launches (0.332255ms)
✔ REQ-LIMIT-4 only known records count; an unknown turn adds nothing and is counted apart (0.241481ms)
✔ REQ-LIMIT-3 a reset moves since: records before it no longer count (0.148082ms)
✔ REQ-LIMIT-3 limit 0 refuses with no records; the first limit hit in file order is named (0.130431ms)
✔ REQ-LIMIT-3 a key limit is not enforced while every record's account is null (decision 150 Q1) (0.168183ms)
✔ REQ-LIMIT-3 counts past the safe integer range come back as digit strings (0.134841ms)
✔ REQ-LIMIT-4 bad records or times throw a code, and the check reads nothing but its arguments (0.611062ms)
✔ REQ-LIMIT-3 no token limits: every launch is allowed and the report is empty (0.218561ms)
✔ REQ-LIMIT-3 token-limit ignores tokens.daily, which the daily-quota check enforces (row 126) (0.116475ms)
✔ P5 a model key ID limit counts stack records by key ID without an account (0.113961ms)
✔ P5 Console displays stack count per safe key separately from optional proxy account numbers (0.908576ms)
✔ P5 Console escapes hostile labels and labels unavailable telemetry without presenting a fresh zero (0.662967ms)
✔ REQ-WEB-1 usage read keeps unknown counts and each token kind; no query or write is accepted (26.726073ms)
✔ REQ-WEB-1 malformed usage is refused instead of shown as zero (5.304556ms)
ℹ tests 173
ℹ suites 0
ℹ pass 173
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 9284.877315
@@ -0,0 +1,37 @@
✔ P5 broker preserves original plugin subject and derives internal run context from authenticated native caller (100.714572ms)
✔ P5 configured key quotas never use a supplied safe-looking ID when trusted metadata lookup is missing (42.059265ms)
✔ P5 internal context resolves exactly current or retained generation; wrong business, instance, run and owner refuse (0.383747ms)
✖ P5 model-key mustStop without native run context fails closed even when the current key resolves (42.738629ms)
ℹ tests 4
ℹ suites 0
ℹ pass 3
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 276.940054
✖ failing tests:
test at packages/bus/tests/p5-key-context.test.mjs:39:1
✖ P5 model-key mustStop without native run context fails closed even when the current key resolves (42.738629ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected
{
+ stop: false
- check: null,
- code: 'proxy-key-refused',
- stop: true
}
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/t3-79263d4f/packages/bus/tests/p5-key-context.test.mjs:43:9)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: { stop: false },
expected: { stop: true, check: null, code: 'proxy-key-refused' },
operator: 'deepStrictEqual',
diff: 'simple'
}
@@ -0,0 +1,208 @@
serial nice19; private HOME/XDG_CONFIG_HOME/TMPDIR/MOSAIC_CONFIG; unchanged whole-file budgets
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mayLaunch","subject":{"instance":"coder","provider":"anthropic","model":"opus","account":"jason-max"},"path":["tokens","daily","jason-max"],"limit":0,"count":0,"unknownTurns":0}
usage: {"event":"usage-unknown","business":"demo","run":"run1","instance":"coder","turn":"713a4859-153d-4efb-9e60-6abbd4549b0e","source":"@none","code":"baseline-unknown"}
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mustStop","subject":{"instance":"coder","provider":"anthropic","model":"opus","account":"jason-max"},"path":["tokens","daily","jason-max"],"limit":0,"count":0,"unknownTurns":1}
usage: {"event":"usage-unknown","business":"demo","run":"run1","instance":"coder","turn":"6615caa1-e75d-463c-b6b8-789d6dc77e40","source":"@none","code":"baseline-unknown"}
✔ REQ-LIMIT-2 runtime: limits counts the daily quota, and mayLaunch refuses only the account at it (160.549327ms)
✔ REQ-LIMIT-4 runtime: a run bound with the account writes it on its usage records and stops at the quota (143.628999ms)
✔ REQ-LIMIT-4 runtime: a run bound without an account records null and the daily quota never stops it (123.342684ms)
✔ REQ-LIMIT-4 bindLaunch keeps the account off session.launched, refuses one that is not an identifier, and takes null as none (67.349794ms)
✔ REQ-LIMIT-3 limitLeaves finds every limit object and skips the agent numbers (1.271433ms)
✔ REQ-LIMIT-3 limitLeaves takes token limits at schema depth only, whatever their names (0.194636ms)
✔ REQ-LIMIT-3 with no check switched on a launch is allowed, a turn never stops, and every limit is not enforced (45.635942ms)
✔ REQ-LIMIT-3 a fixture check that refuses refuses the launch and stops the turn, logged with the limit and the count (46.176242ms)
✔ REQ-LIMIT-3 a report that omits a limit shows it not enforced; a counted entry and a reason come through (44.938267ms)
✔ REQ-LIMIT-4 each check gets the business, a copy of the limits, the subject, the records and the time (54.558566ms)
✔ REQ-LIMIT-4 fail closed: a throw refuses, stops and fails the report, naming the check and the code (46.342833ms)
✔ REQ-LIMIT-4 fail closed: a malformed answer, a promise, a rejected promise, a non-boolean or a bad hit is malformed-answer (47.766687ms)
✔ REQ-LIMIT-4 fail closed: a check switched on but not loaded refuses, stops and fails every limit as not-loaded (43.59231ms)
✔ REQ-LIMIT-4 state(), never-loaded case: before any load the report shows not enforced, or not-loaded for a switched-on check (48.104463ms)
✔ REQ-LIMIT-4 state(), first-load-refused case: a check refused on its first load is not-loaded in mayLaunch, mustStop and report (42.805959ms)
✔ REQ-LIMIT-4 fail closed: an unreadable organization file refuses and stops with check null; the report throws (43.597155ms)
✔ REQ-LIMIT-4 fail closed: unreadable records refuse and stop with check null and fail the report (0.492317ms)
✔ REQ-LIMIT-3 the shipped token-limit, through the real loader, counts known records only since the limit was set (91.037972ms)
✔ REQ-LIMIT-3 a token limit for a provider named limit is counted and refuses, beside an agent limit of the same name (50.368678ms)
✔ REQ-LIMIT-3 core reaches limit checks only through the plug-in loader (1.715607ms)
✔ P5 missing, ambiguous or invalid model key lookup fails closed without leaking a lookup error (40.810413ms)
✔ P5 trusted lookup uses the retiring run key rather than the agent current key (35.820247ms)
✔ P5 actual model metadata lookup rejects missing/ambiguous owners and never cross-attributes a retiring run (0.45891ms)
✔ REQ-LIMIT-4 a role run at its limit stops at the end of its turn: RESULT and read land first, the claim is revoked by limit-check (121.318326ms)
✔ REQ-LIMIT-4 the stop also lands on state; a run with no stop ends without a limit (168.385765ms)
✔ REQ-LIMIT-4 fail closed: a mustStop throw or a malformed answer stops the run, naming the bus and the code (417.685568ms)
✔ REQ-LIMIT-4 a thread run at its limit is released with the reason, and its end record names the limit (114.909337ms)
✔ REQ-LIMIT-4 a broker with no limit checks configured never stops a run (77.129589ms)
limits: {"event":"limit-reached","business":"demo","check":"token-limit","export":"mayLaunch","subject":{"instance":"coder","provider":"zai","model":"glm-5.3-flash","account":null},"path":["tokens","instances","coder"],"limit":0,"count":0,"unknownTurns":0}
organization: {"event":"reload-needs-restart","business":"demo"}
usage: {"event":"usage-unknown","business":"demo","run":"run1","instance":"coder","turn":"5c3d20b7-bbe0-44e1-876f-393c04bf33e3","source":"@none","code":"baseline-unknown"}
limits: {"event":"limit-reached","business":"demo","check":"token-limit","export":"mustStop","subject":{"instance":"coder","provider":"zai","model":"glm-5.3-flash","account":null},"path":["tokens","instances","coder"],"limit":0,"count":0,"unknownTurns":1}
usage: {"event":"usage-unknown","business":"demo","run":"run1","instance":"coder","turn":"1ed92631-bf69-4279-8f2e-da5c8c2d9061","source":"@none","code":"baseline-unknown"}
✔ REQ-LIMIT-3 REQ-LIMIT-4 runtime: limits carries the token count, mayLaunch refuses at the limit, a reset moves since (242.78734ms)
organization: {"event":"reload-needs-restart","business":"demo"}
✔ REQ-LIMIT-3 runtime: with no limit check switched on, the limit shows not enforced and every launch is allowed (83.772136ms)
✔ REQ-LIMIT-4 runtime: the broker asks the shipped token-limit after a turn, and the run at its limit stops on its next receive (135.822066ms)
✔ REQ-LIMIT-4 runtime: with no usage source a turn is unknown, counts zero and stops nothing under a limit of 1 (121.123659ms)
✔ REQ-LIMIT-3 runtime: switching a limit check on with plugins.set loads it without a launch or a turn (159.884938ms)
✔ P5 broker preserves original plugin subject and derives internal run context from authenticated native caller (89.685601ms)
✔ P5 configured key quotas never use a supplied safe-looking ID when trusted metadata lookup is missing (41.975207ms)
✔ P5 internal context resolves exactly current or retained generation; wrong business, instance, run and owner refuse (0.374876ms)
✔ P5 model-key mustStop without native run context fails closed even when the current key resolves (39.706143ms)
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["2ab905e62cf4"]}
model-proxy: {"action":"proxy.reconcile","addedKeyIds":[],"removedKeyIds":[]}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["2ab905e62cf4"]}
model-proxy: {"call":"PUT /v8/management/config/access/api-keys","status":200,"keyIds":["2ab905e62cf4","f81b23885f0a"]}
model-proxy: {"call":"GET /v8/management/config/access/api-keys","status":200,"keyIds":["2ab905e62cf4","f81b23885f0a"]}
model-proxy: {"action":"proxy.key.issued","keyIds":["f81b23885f0a"],"instance":"demo/coder"}
model-proxy: {"call":"GET /v1/models","status":200,"keyIds":["f81b23885f0a"]}
organization: {"event":"reload-needs-restart","business":"demo"}
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mustStop","subject":{"instance":"coder","provider":null,"model":null,"account":null,"modelKeyId":"f81b23885f0a"},"path":["tokens","keys","f81b23885f0a"],"limit":2,"count":2,"unknownTurns":0}
limits: {"event":"limit-reached","business":"demo","check":"daily-quota","export":"mayLaunch","subject":{"instance":"coder","provider":"fixture","model":"fake","account":null,"modelKeyId":"f81b23885f0a"},"path":["tokens","keys","f81b23885f0a"],"limit":2,"count":2,"unknownTurns":0}
organization: {"event":"reload-needs-restart","business":"demo"}
✔ P5 real runtime binds stack usage to issued key, daily stops at stack count and human-only telemetry settings pass broker contract (319.346483ms)
organization: {"event":"reload-needs-restart","business":"demo"}
organization: {"event":"reload-needs-restart","business":"demo"}
organization: {"event":"reload-needs-restart","business":"demo"}
organization: {"event":"reload-needs-restart","business":"demo"}
✔ plugins and plugins.set refuse every non-human session and a forged actor, and pass only the patch with the verified actor (102.705755ms)
✔ runtime: the switch changes the organization file, the receipt carries the actor, and a bad shape, an unknown module and a stale revision are refused with nothing written (258.622237ms)
✔ vikunja:19/309 through the broker, a patch switches the kinds it names and keeps the rest; null removes one kind and is trailed (194.943673ms)
✔ P5 usage plugin off by default, default poll is 15 seconds and configured polls skip early ticks (58.879723ms)
✔ P5 safe telemetry stores failures per key and proxy-labelled accounts; no client/upstream value enters store/log/view or quota records (51.610465ms)
✔ P5 unknown msk key goes only to value-free reconcile log and other businesses stay isolated (41.842706ms)
✔ P5 queue failure is safe, does not enforce and does not retry before poll deadline (43.265972ms)
✔ P5 retiring key keeps attribution and telemetry rows remain append-only across reader restart (45.846149ms)
✔ P5 malformed queue batch is atomic: no valid prefix, body or credential can reach store/log/view (42.767318ms)
✔ P5 concurrent ticks issue one bounded queue read and a closed collector never polls again (42.425739ms)
✔ REQ-LIMIT-4 usage protocol binds run identity, requires a delivered turn and isolates businesses (107.035274ms)
✔ REQ-PLUG-1 runtime reaches transcript only through loader, over the real bus socket (138.029928ms)
✔ REQ-LIMIT-4 loader source records new turn kinds, excludes history and retries exactly once (102.708913ms)
✔ REQ-LIMIT-4 cut: unknown is durable and logged next to every total (51.29996ms)
✔ REQ-LIMIT-4 disabled: unknown is durable and logged next to every total (44.547138ms)
✔ REQ-LIMIT-4 missing-begin: unknown is durable and logged next to every total (40.305662ms)
✔ REQ-LIMIT-4 no-new-usage: unknown is durable and logged next to every total (46.243747ms)
✔ REQ-LIMIT-4 rewrite: unknown is durable and logged next to every total (49.699154ms)
✔ REQ-LIMIT-4 unfinished turn remains visibly unknown after accounting restarts (41.750326ms)
✔ usage records are append-only (44.741061ms)
✔ REQ-LIMIT-4 parse failure logs its safe code, never transcript content (46.066508ms)
✔ REQ-LIMIT-4 resumed run baselines history and exact totals do not overflow (58.388899ms)
✔ REQ-PLUG-1 core has no transcript import and disabled sources do not read any transcript (45.643672ms)
✔ REQ-LIMIT-4 a resumed thread bills only new assistant messages to its next run (46.749719ms)
✔ REQ-LIMIT-4 every enabled source is called; failure is unknown and a partial total stays labelled (51.822533ms)
✔ REQ-LIMIT-4 a turn whose reported sum exceeds safe precision is unknown, not rounded (53.80965ms)
✔ row 65 a run bound without a transcript directory records no-transcript (57.433717ms)
✔ P5 immutable stack key attribution survives rotation and restart without key values (47.921754ms)
✔ P5 malformed key metadata is dropped rather than stored or exposed as a key value (48.881094ms)
✔ REQ-PLUG-1 schema: plugins is optional, names known kinds and checked module names (9.919614ms)
✔ REQ-PLUG-1 REQ-ROLE-3 the setter writes plugins through the organization writer and logs old and new names (141.282316ms)
✔ vikunja:19/309 a patch changes only the kinds it names; null removes one kind, explicitly and in the trail (199.085632ms)
✔ vikunja:19/309 an unknown kind (set or removed), a bad module, an empty patch and null on the wrong shape are refused, nothing written (5.994558ms)
✔ REQ-PLUG-1 REQ-ROLE-3 the writer checks the bytes it writes: a Date in plugins is refused there too (29.095644ms)
✔ REQ-PLUG-1 REQ-ROLE-3 a refused setter write throws a code, changes nothing and logs nothing (2.986444ms)
✔ vikunja:19/305 with an exists check, the setter refuses a module no tree file answers to, before anything is written (64.912764ms)
✔ P5 optional usage kind and pollSeconds configure through plugins.set; default stays absent and retention bound is strict (124.041908ms)
✔ P5 only human can enable/disable telemetry or change polling, including direct organization writes (163.47796ms)
✔ REQ-LIMIT-3 schema: each subject kind, limit 0 and no ceiling are accepted; bad limits, times, keys and undeclared instances refuse (25.815386ms)
✔ REQ-LIMIT-3 the writer stamps since: a new limit gets now, a changed one keeps its time, a different time is refused (253.253525ms)
✔ REQ-LIMIT-3 only tokens.* at schema depth holds token limits: agent limits named `limit` save as sent, and a token limit named `limit` is stamped and reset (294.58611ms)
✔ REQ-LIMIT-3 a reset moves since to now, is logged with its actor, and refuses a path that is not a limit (144.894737ms)
✔ REQ-LIMIT-2 schema: launch.account names a credential set; a daily quota needs a reset and an IANA zone and names the account (26.673634ms)
✔ REQ-LIMIT-2 the writer stamps a daily quota's since, keeps its reset and zone, and a reset moves since (173.373389ms)
✔ P5 per-model-key quotas are unset by default, accept digit-leading IDs and only the human changes or resets them (221.557913ms)
✔ probeKey observes 200 with one agent-authenticated GET /v1/models (13.906006ms)
✔ probeKey observes 401 with one agent-authenticated GET /v1/models (2.654873ms)
✔ probeKey observes 503 with one agent-authenticated GET /v1/models (1.465852ms)
✔ proxy-down: agent-key probe connection failure is sanitized (1.484469ms)
✔ proxy-down: silent listener cannot extend probe request deadline (52.146773ms)
✔ agent-key probe returns redirect status without following Location or exposing key (2.580254ms)
✔ proxy-client-invalid: https://127.0.0.1:18318 (0.937801ms)
✔ proxy-client-invalid: http://example.com:18318 (0.535029ms)
✔ proxy-client-invalid: http://localhost:18318 (0.087694ms)
✔ proxy-client-invalid: http://127.0.0.1:8317 (0.069318ms)
✔ proxy-client-invalid: http://user:[email protected]:18318 (0.073249ms)
✔ proxy-client-invalid: http://127.0.0.1:18318/path (0.061539ms)
✔ client GET/PUT v8 only, Authorization header, receipt IDs without values or bodies (16.662783ms)
✔ proxy-client-refused (2.363491ms)
✔ proxy-client-response (1.26715ms)
✔ proxy-client-redirect (1.119781ms)
✔ proxy-client-down: transport errors redact details (0.943923ms)
✔ proxy-client-invalid: PUT rejects object key records and empty strings locally (0.172918ms)
✔ proxy-management-key-invalid: missing, symlink and public key file refuse without values (0.890633ms)
✔ bus management-key loader supplies a private fixture key without exposing it on the client (0.473687ms)
✔ proxy-client-response: truncated response remains a redacted named refusal (10.816438ms)
✔ management client ignores ambient fetch dispatchers (1.14023ms)
✔ proxy-key-invalid: Latin-1 leaves complete config/data inventories unchanged (3.507611ms)
✔ proxy-key-invalid: leading space leaves complete config/data inventories unchanged (1.092119ms)
✔ proxy-key-invalid: trailing space leaves complete config/data inventories unchanged (1.004054ms)
✔ proxy-key-invalid: internal space leaves complete config/data inventories unchanged (1.102862ms)
✔ printable non-space ASCII control initializes and authenticates with unchanged existing files (16.268442ms)
✔ OAuth management calls keep URL and state out of receipts (16.20323ms)
✔ upstream key goes only in request body and upstream refusal body is discarded (3.013252ms)
✔ redirected management calls are not followed or retried (1.543184ms)
✔ P5 queue read uses actual bounded fixed management GET and immediately drops client and upstream values (14.200284ms)
✔ P5 bad envelope refuses safely with no retry (2.700404ms)
✔ P5 over count refuses safely with no retry (1.604716ms)
✔ P5 missing key refuses safely with no retry (1.370666ms)
✔ P5 bad counts refuses safely with no retry (2.020663ms)
✔ P5 redirect refuses safely with no retry (1.338733ms)
✔ P5 refusal refuses safely with no retry (0.975888ms)
✔ P5 malformed event after a valid event rejects the entire queue before any credential can escape (1.062269ms)
✔ REQ-LIMIT-2 daily-quota exports interface version 2 with mayLaunch, mustStop and report (1.111774ms)
✔ REQ-LIMIT-2 the count sums every kind of the account's known records since the later of the day start and since (11.668338ms)
✔ REQ-LIMIT-2 a launch with no account (pi) is covered by no daily quota (0.297908ms)
✔ REQ-LIMIT-4 an unknown turn adds nothing and is counted apart (0.432147ms)
✔ REQ-LIMIT-2 the day turns at the reset in its zone, not in UTC, and before it the day is yesterday's (0.598992ms)
✔ REQ-LIMIT-2 the spring DST change makes the day after a 00:00 reset 23 hours long (0.356206ms)
✔ REQ-LIMIT-2 the fall DST change makes the day after a 00:00 reset 25 hours long (0.313154ms)
✔ REQ-LIMIT-2 a reset the clocks skip starts the day at the first instant after the gap (0.81377ms)
✔ REQ-LIMIT-2 a reset the clocks repeat starts one day, at the first one (0.455025ms)
✔ REQ-LIMIT-2 a launch is refused at the quota, a turn that reaches it stops, and the next day allows again (1.086843ms)
✔ REQ-LIMIT-2 counts past the safe integer range come back as digit strings (0.349512ms)
✔ REQ-LIMIT-4 bad leaves, records or times throw a code, and the check reads nothing but its arguments (2.388492ms)
✔ REQ-LIMIT-2 no daily quotas: every launch is allowed and the report is empty (0.195575ms)
✔ P5 daily quota for a model key ID matches stack key records and resets the next day (0.769635ms)
✔ REQ-PLUG-1 REQ-LIMIT-4 the registry: usage-source at interface version 1, limit-check at 2 (row 125), each a list (1.012155ms)
✔ REQ-PLUG-1 checkPlugins accepts one key per kind, each a list of names, empty included (0.250245ms)
✔ REQ-PLUG-1 checkPlugins refuses bad shapes, unknown kinds, bad names and duplicates (0.922679ms)
✔ REQ-PLUG-1 a kind that switches on one module takes one name, not a list (0.147977ms)
✔ REQ-PLUG-1 checkPlugins reports through the caller's fail callback (0.122575ms)
✔ P5 usage telemetry is optional, single module, separate from enforcing sources (0.132403ms)
✔ REQ-PLUG-1 fixture modules of each kind switch on from a test organization file, no core file changed (9.032509ms)
✔ REQ-PLUG-1 a name not matching ^[a-z][a-z0-9-]*$ refuses and keeps the old setting (3.876412ms)
✔ REQ-PLUG-1 a missing module directory or index.mjs refuses and keeps the old setting (2.975479ms)
✔ REQ-PLUG-1 a symlinked module directory or index.mjs refuses and keeps the old setting (2.818854ms)
✔ REQ-PLUG-1 a symlinked kind directory refuses and keeps the old setting (2.461598ms)
✔ REQ-PLUG-1 a symlinked packages/plugins refuses (run with --preserve-symlinks so the path keeps it) (30.463335ms)
✔ REQ-PLUG-1 index.mjs swapped for a symlink after the lstat checks refuses at the realpath check (2.687366ms)
✔ REQ-PLUG-1 a path that can't be read refuses as unreadable, is logged and keeps the old setting (2.214904ms)
✔ REQ-PLUG-1 a path that becomes unreadable after the lstat checks refuses at either realpath (2.519903ms)
✔ REQ-PLUG-1 a module that fails to load refuses and keeps the old setting (2.657821ms)
✔ REQ-PLUG-1 a missing export refuses and keeps the old setting (3.655045ms)
✔ REQ-PLUG-1 a different interface version refuses and keeps the old setting (2.640761ms)
✔ REQ-PLUG-1 REQ-LIMIT-3 a version 1 limit check refuses after the bump to 2, and the old setting stays (2.650255ms)
✔ REQ-PLUG-1 a kind refused on its first load has nothing switched on, and the log names kind and name (2.148582ms)
✔ REQ-PLUG-1 the setting's shape: unknown kinds refuse alone, a bad whole setting keeps everything (2.724542ms)
✔ REQ-PLUG-1 loads run one at a time, so the last requested setting wins (103.671706ms)
✔ REQ-PLUG-1 the loader needs a log callback (1.199165ms)
✔ REQ-LIMIT-3 token-limit exports interface version 2 with mayLaunch, mustStop and report (0.667098ms)
✔ REQ-LIMIT-3 each subject kind refuses at its limit and allows under it (1.777171ms)
✔ REQ-LIMIT-3 a limit covers only its own subject's records and launches (0.345096ms)
✔ REQ-LIMIT-4 only known records count; an unknown turn adds nothing and is counted apart (0.242181ms)
✔ REQ-LIMIT-3 a reset moves since: records before it no longer count (0.147915ms)
✔ REQ-LIMIT-3 limit 0 refuses with no records; the first limit hit in file order is named (0.129665ms)
✔ REQ-LIMIT-3 a key limit is not enforced while every record's account is null (decision 150 Q1) (0.156705ms)
✔ REQ-LIMIT-3 counts past the safe integer range come back as digit strings (0.145396ms)
✔ REQ-LIMIT-4 bad records or times throw a code, and the check reads nothing but its arguments (0.617108ms)
✔ REQ-LIMIT-3 no token limits: every launch is allowed and the report is empty (0.218957ms)
✔ REQ-LIMIT-3 token-limit ignores tokens.daily, which the daily-quota check enforces (row 126) (0.119273ms)
✔ P5 a model key ID limit counts stack records by key ID without an account (0.120965ms)
✔ P5 Console displays stack count per safe key separately from optional proxy account numbers (0.925558ms)
✔ P5 Console escapes hostile labels and labels unavailable telemetry without presenting a fresh zero (0.191209ms)
✔ REQ-WEB-1 usage read keeps unknown counts and each token kind; no query or write is accepted (27.325912ms)
✔ REQ-WEB-1 malformed usage is refused instead of shown as zero (5.087908ms)
ℹ tests 174
ℹ suites 0
ℹ pass 174
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 9323.231998
@@ -0,0 +1,944 @@
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/bus/tests/daily-quota-runtime.test.mjs","sha256":"dbbfa80b4082fd44e2f08539b5455653fac062321b8f2106f638e2d8161fa3eb"}
{"path":"packages/bus/src/store.mjs","sha256":"dd7fce9706402efd1c5a5b81f7d0fa3793de203e7a6aef4e118e934aebdc7c84"}
{"path":"packages/bus/src/broker.mjs","sha256":"c0144adade79c2cfc6b8247721393f0250b1d64f6c6c04d85738cb80939c42e5"}
{"path":"packages/bus/src/proxy-page-vocabulary.mjs","sha256":"cec059ea4bef5ef62f6181123bfe64bca21d8985d5357471da8c0a3199a877f9"}
{"path":"packages/model-proxy/src/validation.mjs","sha256":"e66453cf6662677cf28cbad1ae8f7509917d333e5b80404ab02c53f5cf75e9e1"}
{"path":"packages/bus/src/address.mjs","sha256":"232a1c77c2f17011c53b55fc6052f70985598210769d41d7c2c0b535328aad23"}
{"path":"packages/processing-control/src/state.mjs","sha256":"ed834770fed863cb0c15b75062de1fd63dea940f3b42020b769a7e62b319c8ed"}
{"path":"packages/plugins/src/kinds.mjs","sha256":"eaa258a1aadadb5a75450fa73fdbcea0b53636adb50ed9a508193d29d564ca78"}
{"path":"packages/tasks/src/requirements.mjs","sha256":"38e7b85650247759f06c09fce205b2970b8368bc81491f51dc6b3c90ba2a846d"}
{"path":"packages/bus/src/landing.mjs","sha256":"9919febc7679168e0a72c0ef51983120283e595fea290a5e8e948409bf5c911b"}
{"path":"packages/business/src/vocabulary.mjs","sha256":"de1f04628e400084a46e77fd7e03c7a039f0f80c9e07bb486c9c012f187aa3eb"}
{"path":"packages/bus/schema.sql","sha256":"a2ba3a46f12e56139ecae9e55227d00847842aedec50c1d92aaae28844ca48e7"}
{"path":"packages/bus/src/migrations/3b.sql","sha256":"179ffe356d4ff19a49b5ebad39b6c6bfd7771deb8e1b7c55b5e746f039d69e65"}
{"path":"packages/bus/src/migrations/3b-3c.sql","sha256":"b753f630301bf125e9e286b4156d0736930dd8fb9cd8eb2ebf316688f9191a07"}
{"path":"packages/bus/src/migrations/3c-3d.sql","sha256":"0423832d05aa68f9191d7362827bd19310001165b895fb2de40b962fe68f9d56"}
{"path":"packages/bus/src/migrations/3d-3e.sql","sha256":"d9aacc974d5047790e65c30a90068259bb9396dc92d4904eae3b9c5dbbb2f077"}
{"path":"packages/bus/src/migrations/3e-3f.sql","sha256":"bf0b72c606b1a56a1610f09619b0c1118f1f300c636824ea13fd51a4ca6ac4b3"}
{"path":"packages/bus/src/migrations/3f-3g.sql","sha256":"82f54b264919e34282bc214e34e9849f701cd3723b9b2f0a0d107c16f939dc05"}
{"path":"packages/bus/src/migrations/3g-3h.sql","sha256":"76168e4f9f6b427286ddb8402fd833acadb01d6325a85f60e9ccf8d42fe2d1d0"}
{"path":"packages/bus/src/migrations/3h-3i.sql","sha256":"e058e6cea8da7b6e649f3e03f2b81dc5444ee940a64274d0e367124c93545035"}
{"path":"packages/bus/src/migrations/3i-3j.sql","sha256":"5ad122ca950e43e066f3d9ed215e73353e6b26de6687b961a8818d69c9465031"}
{"path":"packages/bus/src/migrations/3j-3k.sql","sha256":"2e2bb1fe70076f5e24406a18a923b9e55c4192178a0a704a1b9716032676f9d4"}
{"path":"packages/bus/src/migrations/3k-3l.sql","sha256":"eb2822c73e527697399691ae520092277ddbd4d2a9a42a0731b3c81cc3569e58"}
{"path":"packages/bus/src/migrations/3l-3m.sql","sha256":"791879f06a3e97d3cfbe6112e2fb6502457af30b3e0198e3da1192038906d156"}
{"path":"packages/bus/src/migrations/3m-3n.sql","sha256":"b40bc6a7bedc459d6827cbf0414619e48fc5dce2febdeff70a647345f2281c3a"}
{"path":"packages/bus/src/runtime.mjs","sha256":"969d04eb06b97093c7f9f0dfa6b51084c781e967e2668814083bbba84a2af7b6"}
{"path":"packages/project/src/index.mjs","sha256":"3ab38cc40ce9ed1a714a59a1f2c336c3792a59431a6a9cc655ba6a2f47513899"}
{"path":"packages/project/src/paths.mjs","sha256":"bd9debcf3f9bb92560e74f220a0b108dfe24154bc6d1fb03c5ec414356d451f9"}
{"path":"packages/project/src/git.mjs","sha256":"af6865a4cace92ef27910098507ffedfc8dfe768cea088b1fee21d0876cc556e"}
{"path":"packages/seat/src/checkout.mjs","sha256":"5aca02491fe8df51487968ce62c776d493d0fe693cc41478b84bef7b49c8948d"}
{"path":"packages/processing-control/src/effects.mjs","sha256":"3bc600649267f011e21ed8266fb16927b0ad3a0e2c49e4b54062d34c544d0c17"}
{"path":"packages/processing-control/src/runtimes.mjs","sha256":"7145420aa354180689a5c84423928fc60c8123476dcfed3364c9cf4542f8c7ea"}
{"path":"packages/project/src/validate.mjs","sha256":"e49ab5e825f0706da2f3c8dfcf33c1331a38d77ca2d35b03359ee68ea74652c5"}
{"path":"packages/project/src/read.mjs","sha256":"42113cd20eb8f04dd252f9963a6f1a84806af9cae7beb6808c4d584a2548220c"}
{"path":"packages/library/src/index.mjs","sha256":"98c2c2877549c3e2c5963ec4e49d99ab3b6d6ad54fb3bfae86cf98542207157e"}
{"path":"packages/library/src/problems.mjs","sha256":"0c8764b03dae0150c56af74bcb113cf583dcbe1fa0c6f7386ef2d48d59a6bd31"}
{"path":"packages/library/src/mapping.mjs","sha256":"c83c626c7cdc2a00ba4217c34b889ca0517cd2022d1f8fc9e7d3a14a0293a802"}
{"path":"packages/library/src/scope.mjs","sha256":"97e12255f52ad638eeacd152eb26822f9a2aa72cd30e2fed1193f51cd6e56192"}
{"path":"packages/library/src/supporting.mjs","sha256":"6a3b4de2070e62b1cca1c0ab20f2883d3153fc61608d1bf7670cecea08765b4c"}
{"path":"packages/library/src/links.mjs","sha256":"def32a176cb70c86248e45908edde22f9c4c5f88575a4af0a396a05f617358bc"}
{"path":"packages/library/src/reader.mjs","sha256":"ea126533afb7e74b71419eb943febb6b242eb96fc6917d9df1019db3e7e6ce8d"}
{"path":"packages/library/src/render.mjs","sha256":"bfc3de029d3c8f0dcc96c90fde30d6da58bbb5b72d8f13e3f536c0d735c73ca5"}
{"path":"packages/library/src/survey.mjs","sha256":"016bfa5c80572c0baf90ced39cb3d3ec66d395f0be15c2727b9552a9dd849093"}
{"path":"packages/library/src/mirror.mjs","sha256":"26b824d6885e5c6d1b8bd71e754a9fa333c26307693f7e6a0c6a8e6300ecb4ae"}
{"path":"packages/library/src/sync.mjs","sha256":"a58f3aec5ed9b3530b363e2fdbd38bc9ded7635d261ab2fca3cb31c45dcd3dfa"}
{"path":"packages/library/src/index-build.mjs","sha256":"70c1fe75cb2149c9a074d55a6301d5b66157c2dc2e777b92bac338cce09d89c7"}
{"path":"packages/library/src/query.mjs","sha256":"bafe113bee70f17bd249876d6bdd1c08fa051223c2111955e5d5f275bd76bba0"}
{"path":"packages/library/src/limits.mjs","sha256":"98ef45ed61144aaea44d8aea1ac43082b6d340297e46846d01772da38728e530"}
{"path":"packages/library/src/guard.mjs","sha256":"f710d9600a17f6e2989a289cfe84e58f161d86c7306605946ce05fa71b364eb2"}
{"path":"packages/library/src/reply-protocol.mjs","sha256":"7b46f47b5e9d6b554b5d39bce2cd95c4610f5f35b8ab8fdc5a2864b3214be809"}
{"path":"packages/library/src/write.mjs","sha256":"a301b7c7e3f42f66cb69d88991220f4e236f25a6e5951c61e79ec4ef2b714198"}
{"path":"packages/bus/src/credentials.mjs","sha256":"10485afcf94c29ac9f3d5ba30b12248a2379efd69185ff9fb90e9fed25fe0678"}
{"path":"packages/bus/src/server.mjs","sha256":"8318bed9168ac3f58c09de40a139b68aacefd684e6c117406e181e2ca5ab4ec7"}
{"path":"packages/bus/src/interpreter.mjs","sha256":"56bfc8dcba476886d7de61a1e798aae8e3041c2434c62d44fc40a168d22bb3bd"}
{"path":"packages/bus/src/peercred.mjs","sha256":"29c88655e8b9aed8db604573c9213fd9f3c40ef35ff04f4eda8fbe8f1b8a32d7"}
{"path":"packages/business/src/launch-settings.mjs","sha256":"e14d73f719664499d809909962a6ecc16d4ffb9d824fcdee699e0778809d9e96"}
{"path":"packages/business/src/organization.mjs","sha256":"fa4ba1ae878cd27287865fa12115f8a6c1175a2dfd1011d5f8aca11e46e669c7"}
{"path":"packages/business/src/business.mjs","sha256":"aaa4578fd4133f64119de6c8786a14759240a8910677529fdeae57173058b7d9"}
{"path":"packages/business/src/errors.mjs","sha256":"cd4eb5960c17ce32f26d1a49196866ce04efc42c1d90b18b046af5fda8b9ff0a"}
{"path":"packages/business/src/launch.mjs","sha256":"0aa94dbd14acd379a4837cc3e70b9618b3fa797d74124314e7245a8a3070e98c"}
{"path":"packages/business/src/util.mjs","sha256":"e1f0e70a4bbba8ae2ad6185ab61770b15acda403e90fc708e13027a1e9ec663c"}
{"path":"packages/business/src/vars.mjs","sha256":"f6b15ee8dad2d985c0ae66b1f106ca46cb56ec86ac8cd5dec8a05c887596a421"}
{"path":"packages/business/src/credentials.mjs","sha256":"c3422b1e144177f9dd3015ac036ee1d2cde02bd2b3be406364f3b3f45d8c9b73"}
{"path":"packages/business/src/role.mjs","sha256":"b10af84d7422da4d0e8c0a4fea1064eebbc2fac6a838a1b3939b554e22dedfc9"}
{"path":"packages/business/src/resolve.mjs","sha256":"712183465fee099606223d84423afc54e3386a0c8e468c68d5ac39c1e676d109"}
{"path":"packages/business/src/project.mjs","sha256":"9472996134c520c31971e66006d1c1683709f6df4f76fe3445bdc97a18637eff"}
{"path":"packages/seat/src/session.mjs","sha256":"c37a6ef6f6d2b4e61443e77d800656bf31e38913bf7dbdc4ca955f4a83b13a41"}
{"path":"packages/seat/src/proc.mjs","sha256":"382cbf7e0ff336911e288ce858bdbfbec693bc2b69879720d1f0b4c7d8455198"}
{"path":"packages/seat/src/sandbox.mjs","sha256":"0868f393f6fb117d430428ec390e435359737eae0792b4a4d1f54797c7a6c1bf"}
{"path":"packages/seat/src/seat.mjs","sha256":"eec970961a667c9e614d1474d33c31a019b2cf1b0bf931a51458d874bca13a15"}
{"path":"packages/seat/src/compactions.mjs","sha256":"c5de99284b8fa61763b8dd30a58809bbc086529eeb10587586d52b0df2754774"}
{"path":"packages/seat/src/working.mjs","sha256":"621f5c223811444336f0f5d6ad10bc7afce075491653c0527d6c26ca568b79c3"}
{"path":"packages/plugins/src/loader.mjs","sha256":"2e99f9222424cf9503253701568f0bb5ef579a22930f9f224e5b63ad6b4f745f"}
{"path":"packages/business/src/plugin-settings.mjs","sha256":"9d2c68dd21c6c9553af75f4b137c4f169e95761f32528767e0518d0313311f50"}
{"path":"packages/model-proxy/src/client.mjs","sha256":"f5f86cad661034f223a76352d877fa8d7883bfa921a7a01282347a9a03272441"}
{"path":"packages/model-proxy/src/common.mjs","sha256":"a6fb88352018b8f21593a0bb9311f87162c80d8b1e05e62b4d43b1e69af21b23"}
{"path":"packages/bus/src/proxy-page.mjs","sha256":"af36aae674f46a4e5eacfe176fde8b58cd0b171a6d70e07ee6d479e0f558cce7"}
{"path":"packages/model-proxy/src/settings.mjs","sha256":"1eac4b5741b360a077bb1c871c008b64f7c7119afc64be4d6e4a0dcdb3a313bb"}
{"path":"packages/bus/src/model-keys.mjs","sha256":"b4e11975bd56db4c816ada297902f033b3db7754d4a05319f03d640e17374550"}
{"path":"packages/business/src/instance-settings.mjs","sha256":"09f2bde85a6d7a8f0b1d1c60ac589b845b0c95e991b2f807758878416b13c6bd"}
{"path":"packages/bus/src/credential-verbs.mjs","sha256":"86b4321dd436b97e389101873197dbab95b3d2202e5ef7da712c4978f4f9159f"}
{"path":"packages/bus/src/business.mjs","sha256":"ff927da3cf22fbacc9ace77b2e8b803bffc2953fb58cf7ab4e5f6f6493732996"}
{"path":"packages/bus/src/web.mjs","sha256":"68efa3c9d0a72095f503208ed5c2e660ef9bca68d3ea15f0fc2f1826a68e09cc"}
{"path":"packages/discord/src/web.mjs","sha256":"e5a7b64720872b12b34223549537ace05ebf0ca8a29b2f844d2b7c5cc9ea41f7"}
{"path":"packages/bus/src/host-run.mjs","sha256":"324c05b16253e0fcfc1a0299d1d8ab45850ea723fad1f67bcc07fc031f50d593"}
{"path":"packages/bus/src/host-grant.mjs","sha256":"48337cdbc41d503f17962d3e3ad014183b1286165f97da6fd88b4faa50be3949"}
{"path":"packages/business/src/hosts.mjs","sha256":"e08b11b70b54f13e3b18996dd903f841e04fd6c64791e96063df8b164c663882"}
{"path":"packages/bus/src/gitea-grant.mjs","sha256":"27d7d5322c2f12641e350867d3ac6f838b33832951e69f057e3a7a28b8ac4d5b"}
{"path":"packages/bus/src/principal.mjs","sha256":"2b1e18be825e8264b16506d6294863acbba812956cfdf8e056f21faaa94f7137"}
{"path":"packages/bus/src/human.mjs","sha256":"bb13c146717cdc46d75d157177e400edac4d3e10f14fe511027a25fd44cec885"}
{"path":"packages/bus/src/tester.mjs","sha256":"5e9e08ca8069e1de35232f26d48a77792388128dda659893909f2d34b5af2346"}
{"path":"packages/business/src/access.mjs","sha256":"af028c999a6ab4d42b321c3f047e683b226c7ad232a2ae9cfc623b7dd5a4dd5f"}
{"path":"packages/bus/src/usage.mjs","sha256":"4ae57d053c4b217e1c1a22ada3ed1c5d4a3f0e61b8d2798e9db37997cd071a29"}
{"path":"packages/bus/src/proxy-usage.mjs","sha256":"5a6c3707e6a64304cfd37f1875eb378c6eb58bf438cc40365fe913eaec7cee59"}
{"path":"packages/bus/src/limits.mjs","sha256":"18c1aacd280ebf0f200d5e6fc1dd1a7e098a3046c1cb8427140bb2198ac81cd3"}
{"path":"packages/processing-control/src/coordinator.mjs","sha256":"ddc7318297abc4ec4dd03d425820b7323db609e554cfc5341cfdfa6934271e73"}
{"path":"packages/discord/src/processing.mjs","sha256":"8fa9968862dff77fa6d8be5210c22d13712fd622a8cbc722d167be5be80d0783"}
{"path":"packages/discord/src/binding.mjs","sha256":"5ab69c4111dd9589a197172ffe6968bf414f41c552b7910e5478a27c446cfaec"}
{"path":"packages/discord/src/setspark.mjs","sha256":"ba09d286e707860afa53300f8802ac8e6193ab2d2e7abe9d2b07cbdef3822387"}
{"path":"packages/discord/src/errors.mjs","sha256":"917b0e6c4f100e93f056b925e38d97eacdd8b2596e39fbd3f88c0b62b973d8ed"}
{"path":"packages/discord/src/tools.mjs","sha256":"975503616245bb6051f06ecbf47436ce7d030f21af23042df7f3341062df967f"}
{"path":"packages/discord/src/git.mjs","sha256":"c28e04a0055997ea0b34bea1ad2912adb248d5fd43713df1e6f5a661d87949b7"}
{"path":"packages/discord/src/journal.mjs","sha256":"12684e926574c3fe7f693a03b60d1393df483f5feb4b47c9dd7c5a7ac050aec5"}
{"path":"packages/processing-control/src/containers.mjs","sha256":"781973277c09133de15fc39be35b372a79066479097d46923c8ab7782f011dcd"}
{"path":"packages/project/schemas/project.schema.json","sha256":"f069c012e9660d5d0491a21f98e936b725f6818e1c3136dfec61b3c800bd58de"}
{"path":"packages/project/schemas/requirement.schema.json","sha256":"79a1e7b567af7162bb88ca69861075fc579a858e8aec4e49824ccdc370b690c3"}
{"path":"packages/project/schemas/decision.schema.json","sha256":"925bb03ac99e5845e4bfa20b4561a331f034f88e187db82213df6602a7ceee4b"}
{"path":"packages/model-proxy/PIN","sha256":"889ac9589fadf7654d4dbb914f968cbafe4255ed215bd6a9ff3f331757c9017b"}
{"path":"packages/business/tests/helpers.mjs","sha256":"a6a9971b42ddf176d9415caee3efc2eb16791dead5f0f0557d28449a550aefa1"}
{"path":"packages/plugins/harness/claude-code/index.mjs","sha256":"a317ac544359d321bb91b67cd87fc6ef431b72df9ac9f7f2a9ff291ed1a9109a"}
{"path":"packages/harness/src/gate.mjs","sha256":"a74ef2db4093c0c797ba9e7e28e4e4df0ceac9040385f00e60a273f39af9610b"}
{"path":"packages/plugins/harness/pi/index.mjs","sha256":"39c225f157b8f66b416625bda689153505743ffcfdc32964bb1f3d2c6fcb73af"}
{"path":"packages/plugins/harness/pi/compactions.mjs","sha256":"aabaf5c4602e28f025c18b2e2ddd6fa0d1648870101a5de0c4424d97b24472dd"}
{"path":"packages/plugins/limit-check/daily-quota/index.mjs","sha256":"3749b9f6dd681ef424ee7d7e4d80ccee87b3655df8cd8fe9ccd0d505dcaaee9b"}
{"path":"packages/tasks/requirements.json","sha256":"80b58323994d70e8bb496d81225aeb3d2cdfda464654b68b3b082e9af1fac5c1"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/bus/tests/limit-checks.test.mjs","sha256":"45870a4903d1996915c0086a6beb4d0a4c75b38386b7c5e6d98b5bc811c3b541"}
{"path":"packages/bus/src/store.mjs","sha256":"dd7fce9706402efd1c5a5b81f7d0fa3793de203e7a6aef4e118e934aebdc7c84"}
{"path":"packages/bus/src/limits.mjs","sha256":"18c1aacd280ebf0f200d5e6fc1dd1a7e098a3046c1cb8427140bb2198ac81cd3"}
{"path":"packages/plugins/src/loader.mjs","sha256":"2e99f9222424cf9503253701568f0bb5ef579a22930f9f224e5b63ad6b4f745f"}
{"path":"packages/plugins/src/kinds.mjs","sha256":"eaa258a1aadadb5a75450fa73fdbcea0b53636adb50ed9a508193d29d564ca78"}
{"path":"packages/bus/src/usage.mjs","sha256":"4ae57d053c4b217e1c1a22ada3ed1c5d4a3f0e61b8d2798e9db37997cd071a29"}
{"path":"packages/plugins/tests/helpers.mjs","sha256":"5d5e5dccdae3f94b8540d187a8899ec36f9c9933cae3933249c2d8c400c75aa2"}
{"path":"packages/bus/schema.sql","sha256":"a2ba3a46f12e56139ecae9e55227d00847842aedec50c1d92aaae28844ca48e7"}
{"path":"packages/bus/src/migrations/3b.sql","sha256":"179ffe356d4ff19a49b5ebad39b6c6bfd7771deb8e1b7c55b5e746f039d69e65"}
{"path":"packages/bus/src/migrations/3b-3c.sql","sha256":"b753f630301bf125e9e286b4156d0736930dd8fb9cd8eb2ebf316688f9191a07"}
{"path":"packages/bus/src/migrations/3c-3d.sql","sha256":"0423832d05aa68f9191d7362827bd19310001165b895fb2de40b962fe68f9d56"}
{"path":"packages/bus/src/migrations/3d-3e.sql","sha256":"d9aacc974d5047790e65c30a90068259bb9396dc92d4904eae3b9c5dbbb2f077"}
{"path":"packages/bus/src/migrations/3e-3f.sql","sha256":"bf0b72c606b1a56a1610f09619b0c1118f1f300c636824ea13fd51a4ca6ac4b3"}
{"path":"packages/bus/src/migrations/3f-3g.sql","sha256":"82f54b264919e34282bc214e34e9849f701cd3723b9b2f0a0d107c16f939dc05"}
{"path":"packages/bus/src/migrations/3g-3h.sql","sha256":"76168e4f9f6b427286ddb8402fd833acadb01d6325a85f60e9ccf8d42fe2d1d0"}
{"path":"packages/bus/src/migrations/3h-3i.sql","sha256":"e058e6cea8da7b6e649f3e03f2b81dc5444ee940a64274d0e367124c93545035"}
{"path":"packages/bus/src/migrations/3i-3j.sql","sha256":"5ad122ca950e43e066f3d9ed215e73353e6b26de6687b961a8818d69c9465031"}
{"path":"packages/bus/src/migrations/3j-3k.sql","sha256":"2e2bb1fe70076f5e24406a18a923b9e55c4192178a0a704a1b9716032676f9d4"}
{"path":"packages/bus/src/migrations/3k-3l.sql","sha256":"eb2822c73e527697399691ae520092277ddbd4d2a9a42a0731b3c81cc3569e58"}
{"path":"packages/bus/src/migrations/3l-3m.sql","sha256":"791879f06a3e97d3cfbe6112e2fb6502457af30b3e0198e3da1192038906d156"}
{"path":"packages/bus/src/migrations/3m-3n.sql","sha256":"b40bc6a7bedc459d6827cbf0414619e48fc5dce2febdeff70a647345f2281c3a"}
{"path":"packages/plugins/limit-check/token-limit/index.mjs","sha256":"4d0c6f5f87101f94608c02001a49d62cef113da48c539b2d2488dfbed1a4c524"}
{"path":"packages/bus/src/runtime.mjs","sha256":"969d04eb06b97093c7f9f0dfa6b51084c781e967e2668814083bbba84a2af7b6"}
{"path":"packages/bus/src/broker.mjs","sha256":"c0144adade79c2cfc6b8247721393f0250b1d64f6c6c04d85738cb80939c42e5"}
{"path":"packages/bus/src/process.mjs","sha256":"ed13afdce6359df31d35a79496ebb4afdefef82030a8326a76b2a25b37e98d9d"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/bus/tests/limit-stop.test.mjs","sha256":"561d0950b788d08ad9a79ccd6572ad6976ba4b2e2b1c79d1e4d06827a84c131b"}
{"path":"packages/bus/src/store.mjs","sha256":"dd7fce9706402efd1c5a5b81f7d0fa3793de203e7a6aef4e118e934aebdc7c84"}
{"path":"packages/bus/src/broker.mjs","sha256":"c0144adade79c2cfc6b8247721393f0250b1d64f6c6c04d85738cb80939c42e5"}
{"path":"packages/bus/src/proxy-page-vocabulary.mjs","sha256":"cec059ea4bef5ef62f6181123bfe64bca21d8985d5357471da8c0a3199a877f9"}
{"path":"packages/model-proxy/src/validation.mjs","sha256":"e66453cf6662677cf28cbad1ae8f7509917d333e5b80404ab02c53f5cf75e9e1"}
{"path":"packages/bus/src/address.mjs","sha256":"232a1c77c2f17011c53b55fc6052f70985598210769d41d7c2c0b535328aad23"}
{"path":"packages/processing-control/src/state.mjs","sha256":"ed834770fed863cb0c15b75062de1fd63dea940f3b42020b769a7e62b319c8ed"}
{"path":"packages/plugins/src/kinds.mjs","sha256":"eaa258a1aadadb5a75450fa73fdbcea0b53636adb50ed9a508193d29d564ca78"}
{"path":"packages/tasks/src/requirements.mjs","sha256":"38e7b85650247759f06c09fce205b2970b8368bc81491f51dc6b3c90ba2a846d"}
{"path":"packages/bus/src/landing.mjs","sha256":"9919febc7679168e0a72c0ef51983120283e595fea290a5e8e948409bf5c911b"}
{"path":"packages/business/src/vocabulary.mjs","sha256":"de1f04628e400084a46e77fd7e03c7a039f0f80c9e07bb486c9c012f187aa3eb"}
{"path":"packages/bus/schema.sql","sha256":"a2ba3a46f12e56139ecae9e55227d00847842aedec50c1d92aaae28844ca48e7"}
{"path":"packages/bus/src/migrations/3b.sql","sha256":"179ffe356d4ff19a49b5ebad39b6c6bfd7771deb8e1b7c55b5e746f039d69e65"}
{"path":"packages/bus/src/migrations/3b-3c.sql","sha256":"b753f630301bf125e9e286b4156d0736930dd8fb9cd8eb2ebf316688f9191a07"}
{"path":"packages/bus/src/migrations/3c-3d.sql","sha256":"0423832d05aa68f9191d7362827bd19310001165b895fb2de40b962fe68f9d56"}
{"path":"packages/bus/src/migrations/3d-3e.sql","sha256":"d9aacc974d5047790e65c30a90068259bb9396dc92d4904eae3b9c5dbbb2f077"}
{"path":"packages/bus/src/migrations/3e-3f.sql","sha256":"bf0b72c606b1a56a1610f09619b0c1118f1f300c636824ea13fd51a4ca6ac4b3"}
{"path":"packages/bus/src/migrations/3f-3g.sql","sha256":"82f54b264919e34282bc214e34e9849f701cd3723b9b2f0a0d107c16f939dc05"}
{"path":"packages/bus/src/migrations/3g-3h.sql","sha256":"76168e4f9f6b427286ddb8402fd833acadb01d6325a85f60e9ccf8d42fe2d1d0"}
{"path":"packages/bus/src/migrations/3h-3i.sql","sha256":"e058e6cea8da7b6e649f3e03f2b81dc5444ee940a64274d0e367124c93545035"}
{"path":"packages/bus/src/migrations/3i-3j.sql","sha256":"5ad122ca950e43e066f3d9ed215e73353e6b26de6687b961a8818d69c9465031"}
{"path":"packages/bus/src/migrations/3j-3k.sql","sha256":"2e2bb1fe70076f5e24406a18a923b9e55c4192178a0a704a1b9716032676f9d4"}
{"path":"packages/bus/src/migrations/3k-3l.sql","sha256":"eb2822c73e527697399691ae520092277ddbd4d2a9a42a0731b3c81cc3569e58"}
{"path":"packages/bus/src/migrations/3l-3m.sql","sha256":"791879f06a3e97d3cfbe6112e2fb6502457af30b3e0198e3da1192038906d156"}
{"path":"packages/bus/src/migrations/3m-3n.sql","sha256":"b40bc6a7bedc459d6827cbf0414619e48fc5dce2febdeff70a647345f2281c3a"}
{"path":"roles/assistant.json","sha256":"5f63ff52aaccf06a0f2415ffdd9d1903c202679cf953bef5266a6841b5e39ab7"}
{"path":"packages/tasks/requirements.json","sha256":"80b58323994d70e8bb496d81225aeb3d2cdfda464654b68b3b082e9af1fac5c1"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/bus/tests/limits-runtime.test.mjs","sha256":"a2e553025edbe6e930c9d03b48289c53b51b153ac9ae49bb21bf721b725f1913"}
{"path":"packages/bus/src/runtime.mjs","sha256":"969d04eb06b97093c7f9f0dfa6b51084c781e967e2668814083bbba84a2af7b6"}
{"path":"packages/bus/src/store.mjs","sha256":"dd7fce9706402efd1c5a5b81f7d0fa3793de203e7a6aef4e118e934aebdc7c84"}
{"path":"packages/project/src/index.mjs","sha256":"3ab38cc40ce9ed1a714a59a1f2c336c3792a59431a6a9cc655ba6a2f47513899"}
{"path":"packages/project/src/paths.mjs","sha256":"bd9debcf3f9bb92560e74f220a0b108dfe24154bc6d1fb03c5ec414356d451f9"}
{"path":"packages/project/src/git.mjs","sha256":"af6865a4cace92ef27910098507ffedfc8dfe768cea088b1fee21d0876cc556e"}
{"path":"packages/seat/src/checkout.mjs","sha256":"5aca02491fe8df51487968ce62c776d493d0fe693cc41478b84bef7b49c8948d"}
{"path":"packages/processing-control/src/effects.mjs","sha256":"3bc600649267f011e21ed8266fb16927b0ad3a0e2c49e4b54062d34c544d0c17"}
{"path":"packages/processing-control/src/state.mjs","sha256":"ed834770fed863cb0c15b75062de1fd63dea940f3b42020b769a7e62b319c8ed"}
{"path":"packages/processing-control/src/runtimes.mjs","sha256":"7145420aa354180689a5c84423928fc60c8123476dcfed3364c9cf4542f8c7ea"}
{"path":"packages/project/src/validate.mjs","sha256":"e49ab5e825f0706da2f3c8dfcf33c1331a38d77ca2d35b03359ee68ea74652c5"}
{"path":"packages/project/src/read.mjs","sha256":"42113cd20eb8f04dd252f9963a6f1a84806af9cae7beb6808c4d584a2548220c"}
{"path":"packages/library/src/index.mjs","sha256":"98c2c2877549c3e2c5963ec4e49d99ab3b6d6ad54fb3bfae86cf98542207157e"}
{"path":"packages/library/src/problems.mjs","sha256":"0c8764b03dae0150c56af74bcb113cf583dcbe1fa0c6f7386ef2d48d59a6bd31"}
{"path":"packages/library/src/mapping.mjs","sha256":"c83c626c7cdc2a00ba4217c34b889ca0517cd2022d1f8fc9e7d3a14a0293a802"}
{"path":"packages/library/src/scope.mjs","sha256":"97e12255f52ad638eeacd152eb26822f9a2aa72cd30e2fed1193f51cd6e56192"}
{"path":"packages/library/src/supporting.mjs","sha256":"6a3b4de2070e62b1cca1c0ab20f2883d3153fc61608d1bf7670cecea08765b4c"}
{"path":"packages/library/src/links.mjs","sha256":"def32a176cb70c86248e45908edde22f9c4c5f88575a4af0a396a05f617358bc"}
{"path":"packages/library/src/reader.mjs","sha256":"ea126533afb7e74b71419eb943febb6b242eb96fc6917d9df1019db3e7e6ce8d"}
{"path":"packages/library/src/render.mjs","sha256":"bfc3de029d3c8f0dcc96c90fde30d6da58bbb5b72d8f13e3f536c0d735c73ca5"}
{"path":"packages/library/src/survey.mjs","sha256":"016bfa5c80572c0baf90ced39cb3d3ec66d395f0be15c2727b9552a9dd849093"}
{"path":"packages/library/src/mirror.mjs","sha256":"26b824d6885e5c6d1b8bd71e754a9fa333c26307693f7e6a0c6a8e6300ecb4ae"}
{"path":"packages/library/src/sync.mjs","sha256":"a58f3aec5ed9b3530b363e2fdbd38bc9ded7635d261ab2fca3cb31c45dcd3dfa"}
{"path":"packages/library/src/index-build.mjs","sha256":"70c1fe75cb2149c9a074d55a6301d5b66157c2dc2e777b92bac338cce09d89c7"}
{"path":"packages/library/src/query.mjs","sha256":"bafe113bee70f17bd249876d6bdd1c08fa051223c2111955e5d5f275bd76bba0"}
{"path":"packages/library/src/limits.mjs","sha256":"98ef45ed61144aaea44d8aea1ac43082b6d340297e46846d01772da38728e530"}
{"path":"packages/library/src/guard.mjs","sha256":"f710d9600a17f6e2989a289cfe84e58f161d86c7306605946ce05fa71b364eb2"}
{"path":"packages/library/src/reply-protocol.mjs","sha256":"7b46f47b5e9d6b554b5d39bce2cd95c4610f5f35b8ab8fdc5a2864b3214be809"}
{"path":"packages/library/src/write.mjs","sha256":"a301b7c7e3f42f66cb69d88991220f4e236f25a6e5951c61e79ec4ef2b714198"}
{"path":"packages/business/src/vocabulary.mjs","sha256":"de1f04628e400084a46e77fd7e03c7a039f0f80c9e07bb486c9c012f187aa3eb"}
{"path":"packages/bus/src/broker.mjs","sha256":"c0144adade79c2cfc6b8247721393f0250b1d64f6c6c04d85738cb80939c42e5"}
{"path":"packages/bus/src/proxy-page-vocabulary.mjs","sha256":"cec059ea4bef5ef62f6181123bfe64bca21d8985d5357471da8c0a3199a877f9"}
{"path":"packages/model-proxy/src/validation.mjs","sha256":"e66453cf6662677cf28cbad1ae8f7509917d333e5b80404ab02c53f5cf75e9e1"}
{"path":"packages/bus/src/address.mjs","sha256":"232a1c77c2f17011c53b55fc6052f70985598210769d41d7c2c0b535328aad23"}
{"path":"packages/plugins/src/kinds.mjs","sha256":"eaa258a1aadadb5a75450fa73fdbcea0b53636adb50ed9a508193d29d564ca78"}
{"path":"packages/tasks/src/requirements.mjs","sha256":"38e7b85650247759f06c09fce205b2970b8368bc81491f51dc6b3c90ba2a846d"}
{"path":"packages/bus/src/landing.mjs","sha256":"9919febc7679168e0a72c0ef51983120283e595fea290a5e8e948409bf5c911b"}
{"path":"packages/bus/src/credentials.mjs","sha256":"10485afcf94c29ac9f3d5ba30b12248a2379efd69185ff9fb90e9fed25fe0678"}
{"path":"packages/bus/src/server.mjs","sha256":"8318bed9168ac3f58c09de40a139b68aacefd684e6c117406e181e2ca5ab4ec7"}
{"path":"packages/bus/src/interpreter.mjs","sha256":"56bfc8dcba476886d7de61a1e798aae8e3041c2434c62d44fc40a168d22bb3bd"}
{"path":"packages/bus/src/peercred.mjs","sha256":"29c88655e8b9aed8db604573c9213fd9f3c40ef35ff04f4eda8fbe8f1b8a32d7"}
{"path":"packages/business/src/launch-settings.mjs","sha256":"e14d73f719664499d809909962a6ecc16d4ffb9d824fcdee699e0778809d9e96"}
{"path":"packages/business/src/organization.mjs","sha256":"fa4ba1ae878cd27287865fa12115f8a6c1175a2dfd1011d5f8aca11e46e669c7"}
{"path":"packages/business/src/business.mjs","sha256":"aaa4578fd4133f64119de6c8786a14759240a8910677529fdeae57173058b7d9"}
{"path":"packages/business/src/errors.mjs","sha256":"cd4eb5960c17ce32f26d1a49196866ce04efc42c1d90b18b046af5fda8b9ff0a"}
{"path":"packages/business/src/launch.mjs","sha256":"0aa94dbd14acd379a4837cc3e70b9618b3fa797d74124314e7245a8a3070e98c"}
{"path":"packages/business/src/util.mjs","sha256":"e1f0e70a4bbba8ae2ad6185ab61770b15acda403e90fc708e13027a1e9ec663c"}
{"path":"packages/business/src/vars.mjs","sha256":"f6b15ee8dad2d985c0ae66b1f106ca46cb56ec86ac8cd5dec8a05c887596a421"}
{"path":"packages/business/src/credentials.mjs","sha256":"c3422b1e144177f9dd3015ac036ee1d2cde02bd2b3be406364f3b3f45d8c9b73"}
{"path":"packages/business/src/role.mjs","sha256":"b10af84d7422da4d0e8c0a4fea1064eebbc2fac6a838a1b3939b554e22dedfc9"}
{"path":"packages/business/src/resolve.mjs","sha256":"712183465fee099606223d84423afc54e3386a0c8e468c68d5ac39c1e676d109"}
{"path":"packages/business/src/project.mjs","sha256":"9472996134c520c31971e66006d1c1683709f6df4f76fe3445bdc97a18637eff"}
{"path":"packages/seat/src/session.mjs","sha256":"c37a6ef6f6d2b4e61443e77d800656bf31e38913bf7dbdc4ca955f4a83b13a41"}
{"path":"packages/seat/src/proc.mjs","sha256":"382cbf7e0ff336911e288ce858bdbfbec693bc2b69879720d1f0b4c7d8455198"}
{"path":"packages/seat/src/sandbox.mjs","sha256":"0868f393f6fb117d430428ec390e435359737eae0792b4a4d1f54797c7a6c1bf"}
{"path":"packages/seat/src/seat.mjs","sha256":"eec970961a667c9e614d1474d33c31a019b2cf1b0bf931a51458d874bca13a15"}
{"path":"packages/seat/src/compactions.mjs","sha256":"c5de99284b8fa61763b8dd30a58809bbc086529eeb10587586d52b0df2754774"}
{"path":"packages/seat/src/working.mjs","sha256":"621f5c223811444336f0f5d6ad10bc7afce075491653c0527d6c26ca568b79c3"}
{"path":"packages/plugins/src/loader.mjs","sha256":"2e99f9222424cf9503253701568f0bb5ef579a22930f9f224e5b63ad6b4f745f"}
{"path":"packages/business/src/plugin-settings.mjs","sha256":"9d2c68dd21c6c9553af75f4b137c4f169e95761f32528767e0518d0313311f50"}
{"path":"packages/model-proxy/src/client.mjs","sha256":"f5f86cad661034f223a76352d877fa8d7883bfa921a7a01282347a9a03272441"}
{"path":"packages/model-proxy/src/common.mjs","sha256":"a6fb88352018b8f21593a0bb9311f87162c80d8b1e05e62b4d43b1e69af21b23"}
{"path":"packages/bus/src/proxy-page.mjs","sha256":"af36aae674f46a4e5eacfe176fde8b58cd0b171a6d70e07ee6d479e0f558cce7"}
{"path":"packages/model-proxy/src/settings.mjs","sha256":"1eac4b5741b360a077bb1c871c008b64f7c7119afc64be4d6e4a0dcdb3a313bb"}
{"path":"packages/bus/src/model-keys.mjs","sha256":"b4e11975bd56db4c816ada297902f033b3db7754d4a05319f03d640e17374550"}
{"path":"packages/business/src/instance-settings.mjs","sha256":"09f2bde85a6d7a8f0b1d1c60ac589b845b0c95e991b2f807758878416b13c6bd"}
{"path":"packages/bus/src/credential-verbs.mjs","sha256":"86b4321dd436b97e389101873197dbab95b3d2202e5ef7da712c4978f4f9159f"}
{"path":"packages/bus/src/business.mjs","sha256":"ff927da3cf22fbacc9ace77b2e8b803bffc2953fb58cf7ab4e5f6f6493732996"}
{"path":"packages/bus/src/web.mjs","sha256":"68efa3c9d0a72095f503208ed5c2e660ef9bca68d3ea15f0fc2f1826a68e09cc"}
{"path":"packages/discord/src/web.mjs","sha256":"e5a7b64720872b12b34223549537ace05ebf0ca8a29b2f844d2b7c5cc9ea41f7"}
{"path":"packages/bus/src/host-run.mjs","sha256":"324c05b16253e0fcfc1a0299d1d8ab45850ea723fad1f67bcc07fc031f50d593"}
{"path":"packages/bus/src/host-grant.mjs","sha256":"48337cdbc41d503f17962d3e3ad014183b1286165f97da6fd88b4faa50be3949"}
{"path":"packages/business/src/hosts.mjs","sha256":"e08b11b70b54f13e3b18996dd903f841e04fd6c64791e96063df8b164c663882"}
{"path":"packages/bus/src/gitea-grant.mjs","sha256":"27d7d5322c2f12641e350867d3ac6f838b33832951e69f057e3a7a28b8ac4d5b"}
{"path":"packages/bus/src/principal.mjs","sha256":"2b1e18be825e8264b16506d6294863acbba812956cfdf8e056f21faaa94f7137"}
{"path":"packages/bus/src/human.mjs","sha256":"bb13c146717cdc46d75d157177e400edac4d3e10f14fe511027a25fd44cec885"}
{"path":"packages/bus/src/tester.mjs","sha256":"5e9e08ca8069e1de35232f26d48a77792388128dda659893909f2d34b5af2346"}
{"path":"packages/business/src/access.mjs","sha256":"af028c999a6ab4d42b321c3f047e683b226c7ad232a2ae9cfc623b7dd5a4dd5f"}
{"path":"packages/bus/src/usage.mjs","sha256":"4ae57d053c4b217e1c1a22ada3ed1c5d4a3f0e61b8d2798e9db37997cd071a29"}
{"path":"packages/bus/src/proxy-usage.mjs","sha256":"5a6c3707e6a64304cfd37f1875eb378c6eb58bf438cc40365fe913eaec7cee59"}
{"path":"packages/bus/src/limits.mjs","sha256":"18c1aacd280ebf0f200d5e6fc1dd1a7e098a3046c1cb8427140bb2198ac81cd3"}
{"path":"packages/processing-control/src/coordinator.mjs","sha256":"ddc7318297abc4ec4dd03d425820b7323db609e554cfc5341cfdfa6934271e73"}
{"path":"packages/discord/src/processing.mjs","sha256":"8fa9968862dff77fa6d8be5210c22d13712fd622a8cbc722d167be5be80d0783"}
{"path":"packages/discord/src/binding.mjs","sha256":"5ab69c4111dd9589a197172ffe6968bf414f41c552b7910e5478a27c446cfaec"}
{"path":"packages/discord/src/setspark.mjs","sha256":"ba09d286e707860afa53300f8802ac8e6193ab2d2e7abe9d2b07cbdef3822387"}
{"path":"packages/discord/src/errors.mjs","sha256":"917b0e6c4f100e93f056b925e38d97eacdd8b2596e39fbd3f88c0b62b973d8ed"}
{"path":"packages/discord/src/tools.mjs","sha256":"975503616245bb6051f06ecbf47436ce7d030f21af23042df7f3341062df967f"}
{"path":"packages/discord/src/git.mjs","sha256":"c28e04a0055997ea0b34bea1ad2912adb248d5fd43713df1e6f5a661d87949b7"}
{"path":"packages/discord/src/journal.mjs","sha256":"12684e926574c3fe7f693a03b60d1393df483f5feb4b47c9dd7c5a7ac050aec5"}
{"path":"packages/processing-control/src/containers.mjs","sha256":"781973277c09133de15fc39be35b372a79066479097d46923c8ab7782f011dcd"}
{"path":"packages/bus/schema.sql","sha256":"a2ba3a46f12e56139ecae9e55227d00847842aedec50c1d92aaae28844ca48e7"}
{"path":"packages/bus/src/migrations/3b.sql","sha256":"179ffe356d4ff19a49b5ebad39b6c6bfd7771deb8e1b7c55b5e746f039d69e65"}
{"path":"packages/bus/src/migrations/3b-3c.sql","sha256":"b753f630301bf125e9e286b4156d0736930dd8fb9cd8eb2ebf316688f9191a07"}
{"path":"packages/bus/src/migrations/3c-3d.sql","sha256":"0423832d05aa68f9191d7362827bd19310001165b895fb2de40b962fe68f9d56"}
{"path":"packages/bus/src/migrations/3d-3e.sql","sha256":"d9aacc974d5047790e65c30a90068259bb9396dc92d4904eae3b9c5dbbb2f077"}
{"path":"packages/bus/src/migrations/3e-3f.sql","sha256":"bf0b72c606b1a56a1610f09619b0c1118f1f300c636824ea13fd51a4ca6ac4b3"}
{"path":"packages/bus/src/migrations/3f-3g.sql","sha256":"82f54b264919e34282bc214e34e9849f701cd3723b9b2f0a0d107c16f939dc05"}
{"path":"packages/bus/src/migrations/3g-3h.sql","sha256":"76168e4f9f6b427286ddb8402fd833acadb01d6325a85f60e9ccf8d42fe2d1d0"}
{"path":"packages/bus/src/migrations/3h-3i.sql","sha256":"e058e6cea8da7b6e649f3e03f2b81dc5444ee940a64274d0e367124c93545035"}
{"path":"packages/bus/src/migrations/3i-3j.sql","sha256":"5ad122ca950e43e066f3d9ed215e73353e6b26de6687b961a8818d69c9465031"}
{"path":"packages/bus/src/migrations/3j-3k.sql","sha256":"2e2bb1fe70076f5e24406a18a923b9e55c4192178a0a704a1b9716032676f9d4"}
{"path":"packages/bus/src/migrations/3k-3l.sql","sha256":"eb2822c73e527697399691ae520092277ddbd4d2a9a42a0731b3c81cc3569e58"}
{"path":"packages/bus/src/migrations/3l-3m.sql","sha256":"791879f06a3e97d3cfbe6112e2fb6502457af30b3e0198e3da1192038906d156"}
{"path":"packages/bus/src/migrations/3m-3n.sql","sha256":"b40bc6a7bedc459d6827cbf0414619e48fc5dce2febdeff70a647345f2281c3a"}
{"path":"packages/project/schemas/project.schema.json","sha256":"f069c012e9660d5d0491a21f98e936b725f6818e1c3136dfec61b3c800bd58de"}
{"path":"packages/project/schemas/requirement.schema.json","sha256":"79a1e7b567af7162bb88ca69861075fc579a858e8aec4e49824ccdc370b690c3"}
{"path":"packages/project/schemas/decision.schema.json","sha256":"925bb03ac99e5845e4bfa20b4561a331f034f88e187db82213df6602a7ceee4b"}
{"path":"packages/model-proxy/PIN","sha256":"889ac9589fadf7654d4dbb914f968cbafe4255ed215bd6a9ff3f331757c9017b"}
{"path":"packages/business/tests/helpers.mjs","sha256":"a6a9971b42ddf176d9415caee3efc2eb16791dead5f0f0557d28449a550aefa1"}
{"path":"packages/plugins/harness/claude-code/index.mjs","sha256":"a317ac544359d321bb91b67cd87fc6ef431b72df9ac9f7f2a9ff291ed1a9109a"}
{"path":"packages/harness/src/gate.mjs","sha256":"a74ef2db4093c0c797ba9e7e28e4e4df0ceac9040385f00e60a273f39af9610b"}
{"path":"packages/plugins/harness/pi/index.mjs","sha256":"39c225f157b8f66b416625bda689153505743ffcfdc32964bb1f3d2c6fcb73af"}
{"path":"packages/plugins/harness/pi/compactions.mjs","sha256":"aabaf5c4602e28f025c18b2e2ddd6fa0d1648870101a5de0c4424d97b24472dd"}
{"path":"packages/plugins/limit-check/token-limit/index.mjs","sha256":"4d0c6f5f87101f94608c02001a49d62cef113da48c539b2d2488dfbed1a4c524"}
{"path":"packages/tasks/requirements.json","sha256":"80b58323994d70e8bb496d81225aeb3d2cdfda464654b68b3b082e9af1fac5c1"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/bus/tests/p5-key-context.test.mjs","sha256":"e37114eab9c5f21015ea8e429f0574d3ea34b06263f1e42b83b31b8d2df222a7"}
{"path":"packages/bus/src/store.mjs","sha256":"dd7fce9706402efd1c5a5b81f7d0fa3793de203e7a6aef4e118e934aebdc7c84"}
{"path":"packages/bus/src/broker.mjs","sha256":"c0144adade79c2cfc6b8247721393f0250b1d64f6c6c04d85738cb80939c42e5"}
{"path":"packages/bus/src/proxy-page-vocabulary.mjs","sha256":"cec059ea4bef5ef62f6181123bfe64bca21d8985d5357471da8c0a3199a877f9"}
{"path":"packages/model-proxy/src/validation.mjs","sha256":"e66453cf6662677cf28cbad1ae8f7509917d333e5b80404ab02c53f5cf75e9e1"}
{"path":"packages/bus/src/address.mjs","sha256":"232a1c77c2f17011c53b55fc6052f70985598210769d41d7c2c0b535328aad23"}
{"path":"packages/processing-control/src/state.mjs","sha256":"ed834770fed863cb0c15b75062de1fd63dea940f3b42020b769a7e62b319c8ed"}
{"path":"packages/plugins/src/kinds.mjs","sha256":"eaa258a1aadadb5a75450fa73fdbcea0b53636adb50ed9a508193d29d564ca78"}
{"path":"packages/tasks/src/requirements.mjs","sha256":"38e7b85650247759f06c09fce205b2970b8368bc81491f51dc6b3c90ba2a846d"}
{"path":"packages/bus/src/landing.mjs","sha256":"9919febc7679168e0a72c0ef51983120283e595fea290a5e8e948409bf5c911b"}
{"path":"packages/business/src/vocabulary.mjs","sha256":"de1f04628e400084a46e77fd7e03c7a039f0f80c9e07bb486c9c012f187aa3eb"}
{"path":"packages/bus/src/limits.mjs","sha256":"18c1aacd280ebf0f200d5e6fc1dd1a7e098a3046c1cb8427140bb2198ac81cd3"}
{"path":"packages/plugins/src/loader.mjs","sha256":"2e99f9222424cf9503253701568f0bb5ef579a22930f9f224e5b63ad6b4f745f"}
{"path":"packages/bus/src/usage.mjs","sha256":"4ae57d053c4b217e1c1a22ada3ed1c5d4a3f0e61b8d2798e9db37997cd071a29"}
{"path":"packages/bus/schema.sql","sha256":"a2ba3a46f12e56139ecae9e55227d00847842aedec50c1d92aaae28844ca48e7"}
{"path":"packages/bus/src/migrations/3b.sql","sha256":"179ffe356d4ff19a49b5ebad39b6c6bfd7771deb8e1b7c55b5e746f039d69e65"}
{"path":"packages/bus/src/migrations/3b-3c.sql","sha256":"b753f630301bf125e9e286b4156d0736930dd8fb9cd8eb2ebf316688f9191a07"}
{"path":"packages/bus/src/migrations/3c-3d.sql","sha256":"0423832d05aa68f9191d7362827bd19310001165b895fb2de40b962fe68f9d56"}
{"path":"packages/bus/src/migrations/3d-3e.sql","sha256":"d9aacc974d5047790e65c30a90068259bb9396dc92d4904eae3b9c5dbbb2f077"}
{"path":"packages/bus/src/migrations/3e-3f.sql","sha256":"bf0b72c606b1a56a1610f09619b0c1118f1f300c636824ea13fd51a4ca6ac4b3"}
{"path":"packages/bus/src/migrations/3f-3g.sql","sha256":"82f54b264919e34282bc214e34e9849f701cd3723b9b2f0a0d107c16f939dc05"}
{"path":"packages/bus/src/migrations/3g-3h.sql","sha256":"76168e4f9f6b427286ddb8402fd833acadb01d6325a85f60e9ccf8d42fe2d1d0"}
{"path":"packages/bus/src/migrations/3h-3i.sql","sha256":"e058e6cea8da7b6e649f3e03f2b81dc5444ee940a64274d0e367124c93545035"}
{"path":"packages/bus/src/migrations/3i-3j.sql","sha256":"5ad122ca950e43e066f3d9ed215e73353e6b26de6687b961a8818d69c9465031"}
{"path":"packages/bus/src/migrations/3j-3k.sql","sha256":"2e2bb1fe70076f5e24406a18a923b9e55c4192178a0a704a1b9716032676f9d4"}
{"path":"packages/bus/src/migrations/3k-3l.sql","sha256":"eb2822c73e527697399691ae520092277ddbd4d2a9a42a0731b3c81cc3569e58"}
{"path":"packages/bus/src/migrations/3l-3m.sql","sha256":"791879f06a3e97d3cfbe6112e2fb6502457af30b3e0198e3da1192038906d156"}
{"path":"packages/bus/src/migrations/3m-3n.sql","sha256":"b40bc6a7bedc459d6827cbf0414619e48fc5dce2febdeff70a647345f2281c3a"}
{"path":"packages/tasks/requirements.json","sha256":"80b58323994d70e8bb496d81225aeb3d2cdfda464654b68b3b082e9af1fac5c1"}
{"path":"packages/plugins/limit-check/token-limit/index.mjs","sha256":"4d0c6f5f87101f94608c02001a49d62cef113da48c539b2d2488dfbed1a4c524"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/bus/tests/p5-runtime.test.mjs","sha256":"241e779016ffd0b54c5646cb4fac7e21ea1167e77afbd652ff4e01f8d238f99c"}
{"path":"packages/bus/src/runtime.mjs","sha256":"969d04eb06b97093c7f9f0dfa6b51084c781e967e2668814083bbba84a2af7b6"}
{"path":"packages/bus/src/store.mjs","sha256":"dd7fce9706402efd1c5a5b81f7d0fa3793de203e7a6aef4e118e934aebdc7c84"}
{"path":"packages/project/src/index.mjs","sha256":"3ab38cc40ce9ed1a714a59a1f2c336c3792a59431a6a9cc655ba6a2f47513899"}
{"path":"packages/project/src/paths.mjs","sha256":"bd9debcf3f9bb92560e74f220a0b108dfe24154bc6d1fb03c5ec414356d451f9"}
{"path":"packages/project/src/git.mjs","sha256":"af6865a4cace92ef27910098507ffedfc8dfe768cea088b1fee21d0876cc556e"}
{"path":"packages/seat/src/checkout.mjs","sha256":"5aca02491fe8df51487968ce62c776d493d0fe693cc41478b84bef7b49c8948d"}
{"path":"packages/processing-control/src/effects.mjs","sha256":"3bc600649267f011e21ed8266fb16927b0ad3a0e2c49e4b54062d34c544d0c17"}
{"path":"packages/processing-control/src/state.mjs","sha256":"ed834770fed863cb0c15b75062de1fd63dea940f3b42020b769a7e62b319c8ed"}
{"path":"packages/processing-control/src/runtimes.mjs","sha256":"7145420aa354180689a5c84423928fc60c8123476dcfed3364c9cf4542f8c7ea"}
{"path":"packages/project/src/validate.mjs","sha256":"e49ab5e825f0706da2f3c8dfcf33c1331a38d77ca2d35b03359ee68ea74652c5"}
{"path":"packages/project/src/read.mjs","sha256":"42113cd20eb8f04dd252f9963a6f1a84806af9cae7beb6808c4d584a2548220c"}
{"path":"packages/library/src/index.mjs","sha256":"98c2c2877549c3e2c5963ec4e49d99ab3b6d6ad54fb3bfae86cf98542207157e"}
{"path":"packages/library/src/problems.mjs","sha256":"0c8764b03dae0150c56af74bcb113cf583dcbe1fa0c6f7386ef2d48d59a6bd31"}
{"path":"packages/library/src/mapping.mjs","sha256":"c83c626c7cdc2a00ba4217c34b889ca0517cd2022d1f8fc9e7d3a14a0293a802"}
{"path":"packages/library/src/scope.mjs","sha256":"97e12255f52ad638eeacd152eb26822f9a2aa72cd30e2fed1193f51cd6e56192"}
{"path":"packages/library/src/supporting.mjs","sha256":"6a3b4de2070e62b1cca1c0ab20f2883d3153fc61608d1bf7670cecea08765b4c"}
{"path":"packages/library/src/links.mjs","sha256":"def32a176cb70c86248e45908edde22f9c4c5f88575a4af0a396a05f617358bc"}
{"path":"packages/library/src/reader.mjs","sha256":"ea126533afb7e74b71419eb943febb6b242eb96fc6917d9df1019db3e7e6ce8d"}
{"path":"packages/library/src/render.mjs","sha256":"bfc3de029d3c8f0dcc96c90fde30d6da58bbb5b72d8f13e3f536c0d735c73ca5"}
{"path":"packages/library/src/survey.mjs","sha256":"016bfa5c80572c0baf90ced39cb3d3ec66d395f0be15c2727b9552a9dd849093"}
{"path":"packages/library/src/mirror.mjs","sha256":"26b824d6885e5c6d1b8bd71e754a9fa333c26307693f7e6a0c6a8e6300ecb4ae"}
{"path":"packages/library/src/sync.mjs","sha256":"a58f3aec5ed9b3530b363e2fdbd38bc9ded7635d261ab2fca3cb31c45dcd3dfa"}
{"path":"packages/library/src/index-build.mjs","sha256":"70c1fe75cb2149c9a074d55a6301d5b66157c2dc2e777b92bac338cce09d89c7"}
{"path":"packages/library/src/query.mjs","sha256":"bafe113bee70f17bd249876d6bdd1c08fa051223c2111955e5d5f275bd76bba0"}
{"path":"packages/library/src/limits.mjs","sha256":"98ef45ed61144aaea44d8aea1ac43082b6d340297e46846d01772da38728e530"}
{"path":"packages/library/src/guard.mjs","sha256":"f710d9600a17f6e2989a289cfe84e58f161d86c7306605946ce05fa71b364eb2"}
{"path":"packages/library/src/reply-protocol.mjs","sha256":"7b46f47b5e9d6b554b5d39bce2cd95c4610f5f35b8ab8fdc5a2864b3214be809"}
{"path":"packages/library/src/write.mjs","sha256":"a301b7c7e3f42f66cb69d88991220f4e236f25a6e5951c61e79ec4ef2b714198"}
{"path":"packages/business/src/vocabulary.mjs","sha256":"de1f04628e400084a46e77fd7e03c7a039f0f80c9e07bb486c9c012f187aa3eb"}
{"path":"packages/bus/src/broker.mjs","sha256":"c0144adade79c2cfc6b8247721393f0250b1d64f6c6c04d85738cb80939c42e5"}
{"path":"packages/bus/src/proxy-page-vocabulary.mjs","sha256":"cec059ea4bef5ef62f6181123bfe64bca21d8985d5357471da8c0a3199a877f9"}
{"path":"packages/model-proxy/src/validation.mjs","sha256":"e66453cf6662677cf28cbad1ae8f7509917d333e5b80404ab02c53f5cf75e9e1"}
{"path":"packages/bus/src/address.mjs","sha256":"232a1c77c2f17011c53b55fc6052f70985598210769d41d7c2c0b535328aad23"}
{"path":"packages/plugins/src/kinds.mjs","sha256":"eaa258a1aadadb5a75450fa73fdbcea0b53636adb50ed9a508193d29d564ca78"}
{"path":"packages/tasks/src/requirements.mjs","sha256":"38e7b85650247759f06c09fce205b2970b8368bc81491f51dc6b3c90ba2a846d"}
{"path":"packages/bus/src/landing.mjs","sha256":"9919febc7679168e0a72c0ef51983120283e595fea290a5e8e948409bf5c911b"}
{"path":"packages/bus/src/credentials.mjs","sha256":"10485afcf94c29ac9f3d5ba30b12248a2379efd69185ff9fb90e9fed25fe0678"}
{"path":"packages/bus/src/server.mjs","sha256":"8318bed9168ac3f58c09de40a139b68aacefd684e6c117406e181e2ca5ab4ec7"}
{"path":"packages/bus/src/interpreter.mjs","sha256":"56bfc8dcba476886d7de61a1e798aae8e3041c2434c62d44fc40a168d22bb3bd"}
{"path":"packages/bus/src/peercred.mjs","sha256":"29c88655e8b9aed8db604573c9213fd9f3c40ef35ff04f4eda8fbe8f1b8a32d7"}
{"path":"packages/business/src/launch-settings.mjs","sha256":"e14d73f719664499d809909962a6ecc16d4ffb9d824fcdee699e0778809d9e96"}
{"path":"packages/business/src/organization.mjs","sha256":"fa4ba1ae878cd27287865fa12115f8a6c1175a2dfd1011d5f8aca11e46e669c7"}
{"path":"packages/business/src/business.mjs","sha256":"aaa4578fd4133f64119de6c8786a14759240a8910677529fdeae57173058b7d9"}
{"path":"packages/business/src/errors.mjs","sha256":"cd4eb5960c17ce32f26d1a49196866ce04efc42c1d90b18b046af5fda8b9ff0a"}
{"path":"packages/business/src/launch.mjs","sha256":"0aa94dbd14acd379a4837cc3e70b9618b3fa797d74124314e7245a8a3070e98c"}
{"path":"packages/business/src/util.mjs","sha256":"e1f0e70a4bbba8ae2ad6185ab61770b15acda403e90fc708e13027a1e9ec663c"}
{"path":"packages/business/src/vars.mjs","sha256":"f6b15ee8dad2d985c0ae66b1f106ca46cb56ec86ac8cd5dec8a05c887596a421"}
{"path":"packages/business/src/credentials.mjs","sha256":"c3422b1e144177f9dd3015ac036ee1d2cde02bd2b3be406364f3b3f45d8c9b73"}
{"path":"packages/business/src/role.mjs","sha256":"b10af84d7422da4d0e8c0a4fea1064eebbc2fac6a838a1b3939b554e22dedfc9"}
{"path":"packages/business/src/resolve.mjs","sha256":"712183465fee099606223d84423afc54e3386a0c8e468c68d5ac39c1e676d109"}
{"path":"packages/business/src/project.mjs","sha256":"9472996134c520c31971e66006d1c1683709f6df4f76fe3445bdc97a18637eff"}
{"path":"packages/seat/src/session.mjs","sha256":"c37a6ef6f6d2b4e61443e77d800656bf31e38913bf7dbdc4ca955f4a83b13a41"}
{"path":"packages/seat/src/proc.mjs","sha256":"382cbf7e0ff336911e288ce858bdbfbec693bc2b69879720d1f0b4c7d8455198"}
{"path":"packages/seat/src/sandbox.mjs","sha256":"0868f393f6fb117d430428ec390e435359737eae0792b4a4d1f54797c7a6c1bf"}
{"path":"packages/seat/src/seat.mjs","sha256":"eec970961a667c9e614d1474d33c31a019b2cf1b0bf931a51458d874bca13a15"}
{"path":"packages/seat/src/compactions.mjs","sha256":"c5de99284b8fa61763b8dd30a58809bbc086529eeb10587586d52b0df2754774"}
{"path":"packages/seat/src/working.mjs","sha256":"621f5c223811444336f0f5d6ad10bc7afce075491653c0527d6c26ca568b79c3"}
{"path":"packages/plugins/src/loader.mjs","sha256":"2e99f9222424cf9503253701568f0bb5ef579a22930f9f224e5b63ad6b4f745f"}
{"path":"packages/business/src/plugin-settings.mjs","sha256":"9d2c68dd21c6c9553af75f4b137c4f169e95761f32528767e0518d0313311f50"}
{"path":"packages/model-proxy/src/client.mjs","sha256":"f5f86cad661034f223a76352d877fa8d7883bfa921a7a01282347a9a03272441"}
{"path":"packages/model-proxy/src/common.mjs","sha256":"a6fb88352018b8f21593a0bb9311f87162c80d8b1e05e62b4d43b1e69af21b23"}
{"path":"packages/bus/src/proxy-page.mjs","sha256":"af36aae674f46a4e5eacfe176fde8b58cd0b171a6d70e07ee6d479e0f558cce7"}
{"path":"packages/model-proxy/src/settings.mjs","sha256":"1eac4b5741b360a077bb1c871c008b64f7c7119afc64be4d6e4a0dcdb3a313bb"}
{"path":"packages/bus/src/model-keys.mjs","sha256":"b4e11975bd56db4c816ada297902f033b3db7754d4a05319f03d640e17374550"}
{"path":"packages/business/src/instance-settings.mjs","sha256":"09f2bde85a6d7a8f0b1d1c60ac589b845b0c95e991b2f807758878416b13c6bd"}
{"path":"packages/bus/src/credential-verbs.mjs","sha256":"86b4321dd436b97e389101873197dbab95b3d2202e5ef7da712c4978f4f9159f"}
{"path":"packages/bus/src/business.mjs","sha256":"ff927da3cf22fbacc9ace77b2e8b803bffc2953fb58cf7ab4e5f6f6493732996"}
{"path":"packages/bus/src/web.mjs","sha256":"68efa3c9d0a72095f503208ed5c2e660ef9bca68d3ea15f0fc2f1826a68e09cc"}
{"path":"packages/discord/src/web.mjs","sha256":"e5a7b64720872b12b34223549537ace05ebf0ca8a29b2f844d2b7c5cc9ea41f7"}
{"path":"packages/bus/src/host-run.mjs","sha256":"324c05b16253e0fcfc1a0299d1d8ab45850ea723fad1f67bcc07fc031f50d593"}
{"path":"packages/bus/src/host-grant.mjs","sha256":"48337cdbc41d503f17962d3e3ad014183b1286165f97da6fd88b4faa50be3949"}
{"path":"packages/business/src/hosts.mjs","sha256":"e08b11b70b54f13e3b18996dd903f841e04fd6c64791e96063df8b164c663882"}
{"path":"packages/bus/src/gitea-grant.mjs","sha256":"27d7d5322c2f12641e350867d3ac6f838b33832951e69f057e3a7a28b8ac4d5b"}
{"path":"packages/bus/src/principal.mjs","sha256":"2b1e18be825e8264b16506d6294863acbba812956cfdf8e056f21faaa94f7137"}
{"path":"packages/bus/src/human.mjs","sha256":"bb13c146717cdc46d75d157177e400edac4d3e10f14fe511027a25fd44cec885"}
{"path":"packages/bus/src/tester.mjs","sha256":"5e9e08ca8069e1de35232f26d48a77792388128dda659893909f2d34b5af2346"}
{"path":"packages/business/src/access.mjs","sha256":"af028c999a6ab4d42b321c3f047e683b226c7ad232a2ae9cfc623b7dd5a4dd5f"}
{"path":"packages/bus/src/usage.mjs","sha256":"4ae57d053c4b217e1c1a22ada3ed1c5d4a3f0e61b8d2798e9db37997cd071a29"}
{"path":"packages/bus/src/proxy-usage.mjs","sha256":"5a6c3707e6a64304cfd37f1875eb378c6eb58bf438cc40365fe913eaec7cee59"}
{"path":"packages/bus/src/limits.mjs","sha256":"18c1aacd280ebf0f200d5e6fc1dd1a7e098a3046c1cb8427140bb2198ac81cd3"}
{"path":"packages/processing-control/src/coordinator.mjs","sha256":"ddc7318297abc4ec4dd03d425820b7323db609e554cfc5341cfdfa6934271e73"}
{"path":"packages/discord/src/processing.mjs","sha256":"8fa9968862dff77fa6d8be5210c22d13712fd622a8cbc722d167be5be80d0783"}
{"path":"packages/discord/src/binding.mjs","sha256":"5ab69c4111dd9589a197172ffe6968bf414f41c552b7910e5478a27c446cfaec"}
{"path":"packages/discord/src/setspark.mjs","sha256":"ba09d286e707860afa53300f8802ac8e6193ab2d2e7abe9d2b07cbdef3822387"}
{"path":"packages/discord/src/errors.mjs","sha256":"917b0e6c4f100e93f056b925e38d97eacdd8b2596e39fbd3f88c0b62b973d8ed"}
{"path":"packages/discord/src/tools.mjs","sha256":"975503616245bb6051f06ecbf47436ce7d030f21af23042df7f3341062df967f"}
{"path":"packages/discord/src/git.mjs","sha256":"c28e04a0055997ea0b34bea1ad2912adb248d5fd43713df1e6f5a661d87949b7"}
{"path":"packages/discord/src/journal.mjs","sha256":"12684e926574c3fe7f693a03b60d1393df483f5feb4b47c9dd7c5a7ac050aec5"}
{"path":"packages/processing-control/src/containers.mjs","sha256":"781973277c09133de15fc39be35b372a79066479097d46923c8ab7782f011dcd"}
{"path":"packages/business/tests/helpers.mjs","sha256":"a6a9971b42ddf176d9415caee3efc2eb16791dead5f0f0557d28449a550aefa1"}
{"path":"packages/bus/schema.sql","sha256":"a2ba3a46f12e56139ecae9e55227d00847842aedec50c1d92aaae28844ca48e7"}
{"path":"packages/bus/src/migrations/3b.sql","sha256":"179ffe356d4ff19a49b5ebad39b6c6bfd7771deb8e1b7c55b5e746f039d69e65"}
{"path":"packages/bus/src/migrations/3b-3c.sql","sha256":"b753f630301bf125e9e286b4156d0736930dd8fb9cd8eb2ebf316688f9191a07"}
{"path":"packages/bus/src/migrations/3c-3d.sql","sha256":"0423832d05aa68f9191d7362827bd19310001165b895fb2de40b962fe68f9d56"}
{"path":"packages/bus/src/migrations/3d-3e.sql","sha256":"d9aacc974d5047790e65c30a90068259bb9396dc92d4904eae3b9c5dbbb2f077"}
{"path":"packages/bus/src/migrations/3e-3f.sql","sha256":"bf0b72c606b1a56a1610f09619b0c1118f1f300c636824ea13fd51a4ca6ac4b3"}
{"path":"packages/bus/src/migrations/3f-3g.sql","sha256":"82f54b264919e34282bc214e34e9849f701cd3723b9b2f0a0d107c16f939dc05"}
{"path":"packages/bus/src/migrations/3g-3h.sql","sha256":"76168e4f9f6b427286ddb8402fd833acadb01d6325a85f60e9ccf8d42fe2d1d0"}
{"path":"packages/bus/src/migrations/3h-3i.sql","sha256":"e058e6cea8da7b6e649f3e03f2b81dc5444ee940a64274d0e367124c93545035"}
{"path":"packages/bus/src/migrations/3i-3j.sql","sha256":"5ad122ca950e43e066f3d9ed215e73353e6b26de6687b961a8818d69c9465031"}
{"path":"packages/bus/src/migrations/3j-3k.sql","sha256":"2e2bb1fe70076f5e24406a18a923b9e55c4192178a0a704a1b9716032676f9d4"}
{"path":"packages/bus/src/migrations/3k-3l.sql","sha256":"eb2822c73e527697399691ae520092277ddbd4d2a9a42a0731b3c81cc3569e58"}
{"path":"packages/bus/src/migrations/3l-3m.sql","sha256":"791879f06a3e97d3cfbe6112e2fb6502457af30b3e0198e3da1192038906d156"}
{"path":"packages/bus/src/migrations/3m-3n.sql","sha256":"b40bc6a7bedc459d6827cbf0414619e48fc5dce2febdeff70a647345f2281c3a"}
{"path":"packages/project/schemas/project.schema.json","sha256":"f069c012e9660d5d0491a21f98e936b725f6818e1c3136dfec61b3c800bd58de"}
{"path":"packages/project/schemas/requirement.schema.json","sha256":"79a1e7b567af7162bb88ca69861075fc579a858e8aec4e49824ccdc370b690c3"}
{"path":"packages/project/schemas/decision.schema.json","sha256":"925bb03ac99e5845e4bfa20b4561a331f034f88e187db82213df6602a7ceee4b"}
{"path":"packages/model-proxy/PIN","sha256":"889ac9589fadf7654d4dbb914f968cbafe4255ed215bd6a9ff3f331757c9017b"}
{"path":"packages/plugins/harness/claude-code/index.mjs","sha256":"a317ac544359d321bb91b67cd87fc6ef431b72df9ac9f7f2a9ff291ed1a9109a"}
{"path":"packages/harness/src/gate.mjs","sha256":"a74ef2db4093c0c797ba9e7e28e4e4df0ceac9040385f00e60a273f39af9610b"}
{"path":"packages/plugins/harness/pi/index.mjs","sha256":"39c225f157b8f66b416625bda689153505743ffcfdc32964bb1f3d2c6fcb73af"}
{"path":"packages/plugins/harness/pi/compactions.mjs","sha256":"aabaf5c4602e28f025c18b2e2ddd6fa0d1648870101a5de0c4424d97b24472dd"}
{"path":"packages/plugins/usage-source/transcript/index.mjs","sha256":"d09ae19db3eb69477783163559bd6a8e5b59a6f5af0eafd62d0e2e3bd325065e"}
{"path":"packages/plugins/limit-check/daily-quota/index.mjs","sha256":"3749b9f6dd681ef424ee7d7e4d80ccee87b3655df8cd8fe9ccd0d505dcaaee9b"}
{"path":"packages/tasks/requirements.json","sha256":"80b58323994d70e8bb496d81225aeb3d2cdfda464654b68b3b082e9af1fac5c1"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/bus/tests/plugins-verb.test.mjs","sha256":"895ffddbcca1b38fdaa17eefdeca9092a9b9a934d3a54a3bf7857f42fe99fba7"}
{"path":"packages/bus/src/store.mjs","sha256":"dd7fce9706402efd1c5a5b81f7d0fa3793de203e7a6aef4e118e934aebdc7c84"}
{"path":"packages/bus/src/broker.mjs","sha256":"c0144adade79c2cfc6b8247721393f0250b1d64f6c6c04d85738cb80939c42e5"}
{"path":"packages/bus/src/proxy-page-vocabulary.mjs","sha256":"cec059ea4bef5ef62f6181123bfe64bca21d8985d5357471da8c0a3199a877f9"}
{"path":"packages/model-proxy/src/validation.mjs","sha256":"e66453cf6662677cf28cbad1ae8f7509917d333e5b80404ab02c53f5cf75e9e1"}
{"path":"packages/bus/src/address.mjs","sha256":"232a1c77c2f17011c53b55fc6052f70985598210769d41d7c2c0b535328aad23"}
{"path":"packages/processing-control/src/state.mjs","sha256":"ed834770fed863cb0c15b75062de1fd63dea940f3b42020b769a7e62b319c8ed"}
{"path":"packages/plugins/src/kinds.mjs","sha256":"eaa258a1aadadb5a75450fa73fdbcea0b53636adb50ed9a508193d29d564ca78"}
{"path":"packages/tasks/src/requirements.mjs","sha256":"38e7b85650247759f06c09fce205b2970b8368bc81491f51dc6b3c90ba2a846d"}
{"path":"packages/bus/src/landing.mjs","sha256":"9919febc7679168e0a72c0ef51983120283e595fea290a5e8e948409bf5c911b"}
{"path":"packages/business/src/vocabulary.mjs","sha256":"de1f04628e400084a46e77fd7e03c7a039f0f80c9e07bb486c9c012f187aa3eb"}
{"path":"packages/bus/schema.sql","sha256":"a2ba3a46f12e56139ecae9e55227d00847842aedec50c1d92aaae28844ca48e7"}
{"path":"packages/bus/src/migrations/3b.sql","sha256":"179ffe356d4ff19a49b5ebad39b6c6bfd7771deb8e1b7c55b5e746f039d69e65"}
{"path":"packages/bus/src/migrations/3b-3c.sql","sha256":"b753f630301bf125e9e286b4156d0736930dd8fb9cd8eb2ebf316688f9191a07"}
{"path":"packages/bus/src/migrations/3c-3d.sql","sha256":"0423832d05aa68f9191d7362827bd19310001165b895fb2de40b962fe68f9d56"}
{"path":"packages/bus/src/migrations/3d-3e.sql","sha256":"d9aacc974d5047790e65c30a90068259bb9396dc92d4904eae3b9c5dbbb2f077"}
{"path":"packages/bus/src/migrations/3e-3f.sql","sha256":"bf0b72c606b1a56a1610f09619b0c1118f1f300c636824ea13fd51a4ca6ac4b3"}
{"path":"packages/bus/src/migrations/3f-3g.sql","sha256":"82f54b264919e34282bc214e34e9849f701cd3723b9b2f0a0d107c16f939dc05"}
{"path":"packages/bus/src/migrations/3g-3h.sql","sha256":"76168e4f9f6b427286ddb8402fd833acadb01d6325a85f60e9ccf8d42fe2d1d0"}
{"path":"packages/bus/src/migrations/3h-3i.sql","sha256":"e058e6cea8da7b6e649f3e03f2b81dc5444ee940a64274d0e367124c93545035"}
{"path":"packages/bus/src/migrations/3i-3j.sql","sha256":"5ad122ca950e43e066f3d9ed215e73353e6b26de6687b961a8818d69c9465031"}
{"path":"packages/bus/src/migrations/3j-3k.sql","sha256":"2e2bb1fe70076f5e24406a18a923b9e55c4192178a0a704a1b9716032676f9d4"}
{"path":"packages/bus/src/migrations/3k-3l.sql","sha256":"eb2822c73e527697399691ae520092277ddbd4d2a9a42a0731b3c81cc3569e58"}
{"path":"packages/bus/src/migrations/3l-3m.sql","sha256":"791879f06a3e97d3cfbe6112e2fb6502457af30b3e0198e3da1192038906d156"}
{"path":"packages/bus/src/migrations/3m-3n.sql","sha256":"b40bc6a7bedc459d6827cbf0414619e48fc5dce2febdeff70a647345f2281c3a"}
{"path":"packages/tasks/requirements.json","sha256":"80b58323994d70e8bb496d81225aeb3d2cdfda464654b68b3b082e9af1fac5c1"}
{"path":"packages/bus/src/runtime.mjs","sha256":"969d04eb06b97093c7f9f0dfa6b51084c781e967e2668814083bbba84a2af7b6"}
{"path":"packages/project/src/index.mjs","sha256":"3ab38cc40ce9ed1a714a59a1f2c336c3792a59431a6a9cc655ba6a2f47513899"}
{"path":"packages/project/src/paths.mjs","sha256":"bd9debcf3f9bb92560e74f220a0b108dfe24154bc6d1fb03c5ec414356d451f9"}
{"path":"packages/project/src/git.mjs","sha256":"af6865a4cace92ef27910098507ffedfc8dfe768cea088b1fee21d0876cc556e"}
{"path":"packages/seat/src/checkout.mjs","sha256":"5aca02491fe8df51487968ce62c776d493d0fe693cc41478b84bef7b49c8948d"}
{"path":"packages/processing-control/src/effects.mjs","sha256":"3bc600649267f011e21ed8266fb16927b0ad3a0e2c49e4b54062d34c544d0c17"}
{"path":"packages/processing-control/src/runtimes.mjs","sha256":"7145420aa354180689a5c84423928fc60c8123476dcfed3364c9cf4542f8c7ea"}
{"path":"packages/project/src/validate.mjs","sha256":"e49ab5e825f0706da2f3c8dfcf33c1331a38d77ca2d35b03359ee68ea74652c5"}
{"path":"packages/project/src/read.mjs","sha256":"42113cd20eb8f04dd252f9963a6f1a84806af9cae7beb6808c4d584a2548220c"}
{"path":"packages/library/src/index.mjs","sha256":"98c2c2877549c3e2c5963ec4e49d99ab3b6d6ad54fb3bfae86cf98542207157e"}
{"path":"packages/library/src/problems.mjs","sha256":"0c8764b03dae0150c56af74bcb113cf583dcbe1fa0c6f7386ef2d48d59a6bd31"}
{"path":"packages/library/src/mapping.mjs","sha256":"c83c626c7cdc2a00ba4217c34b889ca0517cd2022d1f8fc9e7d3a14a0293a802"}
{"path":"packages/library/src/scope.mjs","sha256":"97e12255f52ad638eeacd152eb26822f9a2aa72cd30e2fed1193f51cd6e56192"}
{"path":"packages/library/src/supporting.mjs","sha256":"6a3b4de2070e62b1cca1c0ab20f2883d3153fc61608d1bf7670cecea08765b4c"}
{"path":"packages/library/src/links.mjs","sha256":"def32a176cb70c86248e45908edde22f9c4c5f88575a4af0a396a05f617358bc"}
{"path":"packages/library/src/reader.mjs","sha256":"ea126533afb7e74b71419eb943febb6b242eb96fc6917d9df1019db3e7e6ce8d"}
{"path":"packages/library/src/render.mjs","sha256":"bfc3de029d3c8f0dcc96c90fde30d6da58bbb5b72d8f13e3f536c0d735c73ca5"}
{"path":"packages/library/src/survey.mjs","sha256":"016bfa5c80572c0baf90ced39cb3d3ec66d395f0be15c2727b9552a9dd849093"}
{"path":"packages/library/src/mirror.mjs","sha256":"26b824d6885e5c6d1b8bd71e754a9fa333c26307693f7e6a0c6a8e6300ecb4ae"}
{"path":"packages/library/src/sync.mjs","sha256":"a58f3aec5ed9b3530b363e2fdbd38bc9ded7635d261ab2fca3cb31c45dcd3dfa"}
{"path":"packages/library/src/index-build.mjs","sha256":"70c1fe75cb2149c9a074d55a6301d5b66157c2dc2e777b92bac338cce09d89c7"}
{"path":"packages/library/src/query.mjs","sha256":"bafe113bee70f17bd249876d6bdd1c08fa051223c2111955e5d5f275bd76bba0"}
{"path":"packages/library/src/limits.mjs","sha256":"98ef45ed61144aaea44d8aea1ac43082b6d340297e46846d01772da38728e530"}
{"path":"packages/library/src/guard.mjs","sha256":"f710d9600a17f6e2989a289cfe84e58f161d86c7306605946ce05fa71b364eb2"}
{"path":"packages/library/src/reply-protocol.mjs","sha256":"7b46f47b5e9d6b554b5d39bce2cd95c4610f5f35b8ab8fdc5a2864b3214be809"}
{"path":"packages/library/src/write.mjs","sha256":"a301b7c7e3f42f66cb69d88991220f4e236f25a6e5951c61e79ec4ef2b714198"}
{"path":"packages/bus/src/credentials.mjs","sha256":"10485afcf94c29ac9f3d5ba30b12248a2379efd69185ff9fb90e9fed25fe0678"}
{"path":"packages/bus/src/server.mjs","sha256":"8318bed9168ac3f58c09de40a139b68aacefd684e6c117406e181e2ca5ab4ec7"}
{"path":"packages/bus/src/interpreter.mjs","sha256":"56bfc8dcba476886d7de61a1e798aae8e3041c2434c62d44fc40a168d22bb3bd"}
{"path":"packages/bus/src/peercred.mjs","sha256":"29c88655e8b9aed8db604573c9213fd9f3c40ef35ff04f4eda8fbe8f1b8a32d7"}
{"path":"packages/business/src/launch-settings.mjs","sha256":"e14d73f719664499d809909962a6ecc16d4ffb9d824fcdee699e0778809d9e96"}
{"path":"packages/business/src/organization.mjs","sha256":"fa4ba1ae878cd27287865fa12115f8a6c1175a2dfd1011d5f8aca11e46e669c7"}
{"path":"packages/business/src/business.mjs","sha256":"aaa4578fd4133f64119de6c8786a14759240a8910677529fdeae57173058b7d9"}
{"path":"packages/business/src/errors.mjs","sha256":"cd4eb5960c17ce32f26d1a49196866ce04efc42c1d90b18b046af5fda8b9ff0a"}
{"path":"packages/business/src/launch.mjs","sha256":"0aa94dbd14acd379a4837cc3e70b9618b3fa797d74124314e7245a8a3070e98c"}
{"path":"packages/business/src/util.mjs","sha256":"e1f0e70a4bbba8ae2ad6185ab61770b15acda403e90fc708e13027a1e9ec663c"}
{"path":"packages/business/src/vars.mjs","sha256":"f6b15ee8dad2d985c0ae66b1f106ca46cb56ec86ac8cd5dec8a05c887596a421"}
{"path":"packages/business/src/credentials.mjs","sha256":"c3422b1e144177f9dd3015ac036ee1d2cde02bd2b3be406364f3b3f45d8c9b73"}
{"path":"packages/business/src/role.mjs","sha256":"b10af84d7422da4d0e8c0a4fea1064eebbc2fac6a838a1b3939b554e22dedfc9"}
{"path":"packages/business/src/resolve.mjs","sha256":"712183465fee099606223d84423afc54e3386a0c8e468c68d5ac39c1e676d109"}
{"path":"packages/business/src/project.mjs","sha256":"9472996134c520c31971e66006d1c1683709f6df4f76fe3445bdc97a18637eff"}
{"path":"packages/seat/src/session.mjs","sha256":"c37a6ef6f6d2b4e61443e77d800656bf31e38913bf7dbdc4ca955f4a83b13a41"}
{"path":"packages/seat/src/proc.mjs","sha256":"382cbf7e0ff336911e288ce858bdbfbec693bc2b69879720d1f0b4c7d8455198"}
{"path":"packages/seat/src/sandbox.mjs","sha256":"0868f393f6fb117d430428ec390e435359737eae0792b4a4d1f54797c7a6c1bf"}
{"path":"packages/seat/src/seat.mjs","sha256":"eec970961a667c9e614d1474d33c31a019b2cf1b0bf931a51458d874bca13a15"}
{"path":"packages/seat/src/compactions.mjs","sha256":"c5de99284b8fa61763b8dd30a58809bbc086529eeb10587586d52b0df2754774"}
{"path":"packages/seat/src/working.mjs","sha256":"621f5c223811444336f0f5d6ad10bc7afce075491653c0527d6c26ca568b79c3"}
{"path":"packages/plugins/src/loader.mjs","sha256":"2e99f9222424cf9503253701568f0bb5ef579a22930f9f224e5b63ad6b4f745f"}
{"path":"packages/business/src/plugin-settings.mjs","sha256":"9d2c68dd21c6c9553af75f4b137c4f169e95761f32528767e0518d0313311f50"}
{"path":"packages/model-proxy/src/client.mjs","sha256":"f5f86cad661034f223a76352d877fa8d7883bfa921a7a01282347a9a03272441"}
{"path":"packages/model-proxy/src/common.mjs","sha256":"a6fb88352018b8f21593a0bb9311f87162c80d8b1e05e62b4d43b1e69af21b23"}
{"path":"packages/bus/src/proxy-page.mjs","sha256":"af36aae674f46a4e5eacfe176fde8b58cd0b171a6d70e07ee6d479e0f558cce7"}
{"path":"packages/model-proxy/src/settings.mjs","sha256":"1eac4b5741b360a077bb1c871c008b64f7c7119afc64be4d6e4a0dcdb3a313bb"}
{"path":"packages/bus/src/model-keys.mjs","sha256":"b4e11975bd56db4c816ada297902f033b3db7754d4a05319f03d640e17374550"}
{"path":"packages/business/src/instance-settings.mjs","sha256":"09f2bde85a6d7a8f0b1d1c60ac589b845b0c95e991b2f807758878416b13c6bd"}
{"path":"packages/bus/src/credential-verbs.mjs","sha256":"86b4321dd436b97e389101873197dbab95b3d2202e5ef7da712c4978f4f9159f"}
{"path":"packages/bus/src/business.mjs","sha256":"ff927da3cf22fbacc9ace77b2e8b803bffc2953fb58cf7ab4e5f6f6493732996"}
{"path":"packages/bus/src/web.mjs","sha256":"68efa3c9d0a72095f503208ed5c2e660ef9bca68d3ea15f0fc2f1826a68e09cc"}
{"path":"packages/discord/src/web.mjs","sha256":"e5a7b64720872b12b34223549537ace05ebf0ca8a29b2f844d2b7c5cc9ea41f7"}
{"path":"packages/bus/src/host-run.mjs","sha256":"324c05b16253e0fcfc1a0299d1d8ab45850ea723fad1f67bcc07fc031f50d593"}
{"path":"packages/bus/src/host-grant.mjs","sha256":"48337cdbc41d503f17962d3e3ad014183b1286165f97da6fd88b4faa50be3949"}
{"path":"packages/business/src/hosts.mjs","sha256":"e08b11b70b54f13e3b18996dd903f841e04fd6c64791e96063df8b164c663882"}
{"path":"packages/bus/src/gitea-grant.mjs","sha256":"27d7d5322c2f12641e350867d3ac6f838b33832951e69f057e3a7a28b8ac4d5b"}
{"path":"packages/bus/src/principal.mjs","sha256":"2b1e18be825e8264b16506d6294863acbba812956cfdf8e056f21faaa94f7137"}
{"path":"packages/bus/src/human.mjs","sha256":"bb13c146717cdc46d75d157177e400edac4d3e10f14fe511027a25fd44cec885"}
{"path":"packages/bus/src/tester.mjs","sha256":"5e9e08ca8069e1de35232f26d48a77792388128dda659893909f2d34b5af2346"}
{"path":"packages/business/src/access.mjs","sha256":"af028c999a6ab4d42b321c3f047e683b226c7ad232a2ae9cfc623b7dd5a4dd5f"}
{"path":"packages/bus/src/usage.mjs","sha256":"4ae57d053c4b217e1c1a22ada3ed1c5d4a3f0e61b8d2798e9db37997cd071a29"}
{"path":"packages/bus/src/proxy-usage.mjs","sha256":"5a6c3707e6a64304cfd37f1875eb378c6eb58bf438cc40365fe913eaec7cee59"}
{"path":"packages/bus/src/limits.mjs","sha256":"18c1aacd280ebf0f200d5e6fc1dd1a7e098a3046c1cb8427140bb2198ac81cd3"}
{"path":"packages/processing-control/src/coordinator.mjs","sha256":"ddc7318297abc4ec4dd03d425820b7323db609e554cfc5341cfdfa6934271e73"}
{"path":"packages/discord/src/processing.mjs","sha256":"8fa9968862dff77fa6d8be5210c22d13712fd622a8cbc722d167be5be80d0783"}
{"path":"packages/discord/src/binding.mjs","sha256":"5ab69c4111dd9589a197172ffe6968bf414f41c552b7910e5478a27c446cfaec"}
{"path":"packages/discord/src/setspark.mjs","sha256":"ba09d286e707860afa53300f8802ac8e6193ab2d2e7abe9d2b07cbdef3822387"}
{"path":"packages/discord/src/errors.mjs","sha256":"917b0e6c4f100e93f056b925e38d97eacdd8b2596e39fbd3f88c0b62b973d8ed"}
{"path":"packages/discord/src/tools.mjs","sha256":"975503616245bb6051f06ecbf47436ce7d030f21af23042df7f3341062df967f"}
{"path":"packages/discord/src/git.mjs","sha256":"c28e04a0055997ea0b34bea1ad2912adb248d5fd43713df1e6f5a661d87949b7"}
{"path":"packages/discord/src/journal.mjs","sha256":"12684e926574c3fe7f693a03b60d1393df483f5feb4b47c9dd7c5a7ac050aec5"}
{"path":"packages/processing-control/src/containers.mjs","sha256":"781973277c09133de15fc39be35b372a79066479097d46923c8ab7782f011dcd"}
{"path":"packages/project/schemas/project.schema.json","sha256":"f069c012e9660d5d0491a21f98e936b725f6818e1c3136dfec61b3c800bd58de"}
{"path":"packages/project/schemas/requirement.schema.json","sha256":"79a1e7b567af7162bb88ca69861075fc579a858e8aec4e49824ccdc370b690c3"}
{"path":"packages/project/schemas/decision.schema.json","sha256":"925bb03ac99e5845e4bfa20b4561a331f034f88e187db82213df6602a7ceee4b"}
{"path":"packages/model-proxy/PIN","sha256":"889ac9589fadf7654d4dbb914f968cbafe4255ed215bd6a9ff3f331757c9017b"}
{"path":"packages/business/tests/helpers.mjs","sha256":"a6a9971b42ddf176d9415caee3efc2eb16791dead5f0f0557d28449a550aefa1"}
{"path":"packages/plugins/harness/claude-code/index.mjs","sha256":"a317ac544359d321bb91b67cd87fc6ef431b72df9ac9f7f2a9ff291ed1a9109a"}
{"path":"packages/harness/src/gate.mjs","sha256":"a74ef2db4093c0c797ba9e7e28e4e4df0ceac9040385f00e60a273f39af9610b"}
{"path":"packages/plugins/harness/pi/index.mjs","sha256":"39c225f157b8f66b416625bda689153505743ffcfdc32964bb1f3d2c6fcb73af"}
{"path":"packages/plugins/harness/pi/compactions.mjs","sha256":"aabaf5c4602e28f025c18b2e2ddd6fa0d1648870101a5de0c4424d97b24472dd"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/bus/tests/proxy-usage.test.mjs","sha256":"84c8351029272b6ee05e7fd81b4cc4453553ceeb7a5127a1333dae63d1336ad5"}
{"path":"packages/bus/src/store.mjs","sha256":"dd7fce9706402efd1c5a5b81f7d0fa3793de203e7a6aef4e118e934aebdc7c84"}
{"path":"packages/bus/src/usage.mjs","sha256":"4ae57d053c4b217e1c1a22ada3ed1c5d4a3f0e61b8d2798e9db37997cd071a29"}
{"path":"packages/plugins/src/loader.mjs","sha256":"2e99f9222424cf9503253701568f0bb5ef579a22930f9f224e5b63ad6b4f745f"}
{"path":"packages/plugins/src/kinds.mjs","sha256":"eaa258a1aadadb5a75450fa73fdbcea0b53636adb50ed9a508193d29d564ca78"}
{"path":"packages/bus/src/limits.mjs","sha256":"18c1aacd280ebf0f200d5e6fc1dd1a7e098a3046c1cb8427140bb2198ac81cd3"}
{"path":"packages/bus/src/proxy-usage.mjs","sha256":"5a6c3707e6a64304cfd37f1875eb378c6eb58bf438cc40365fe913eaec7cee59"}
{"path":"packages/model-proxy/src/client.mjs","sha256":"f5f86cad661034f223a76352d877fa8d7883bfa921a7a01282347a9a03272441"}
{"path":"packages/model-proxy/src/common.mjs","sha256":"a6fb88352018b8f21593a0bb9311f87162c80d8b1e05e62b4d43b1e69af21b23"}
{"path":"packages/model-proxy/src/validation.mjs","sha256":"e66453cf6662677cf28cbad1ae8f7509917d333e5b80404ab02c53f5cf75e9e1"}
{"path":"packages/bus/schema.sql","sha256":"a2ba3a46f12e56139ecae9e55227d00847842aedec50c1d92aaae28844ca48e7"}
{"path":"packages/bus/src/migrations/3b.sql","sha256":"179ffe356d4ff19a49b5ebad39b6c6bfd7771deb8e1b7c55b5e746f039d69e65"}
{"path":"packages/bus/src/migrations/3b-3c.sql","sha256":"b753f630301bf125e9e286b4156d0736930dd8fb9cd8eb2ebf316688f9191a07"}
{"path":"packages/bus/src/migrations/3c-3d.sql","sha256":"0423832d05aa68f9191d7362827bd19310001165b895fb2de40b962fe68f9d56"}
{"path":"packages/bus/src/migrations/3d-3e.sql","sha256":"d9aacc974d5047790e65c30a90068259bb9396dc92d4904eae3b9c5dbbb2f077"}
{"path":"packages/bus/src/migrations/3e-3f.sql","sha256":"bf0b72c606b1a56a1610f09619b0c1118f1f300c636824ea13fd51a4ca6ac4b3"}
{"path":"packages/bus/src/migrations/3f-3g.sql","sha256":"82f54b264919e34282bc214e34e9849f701cd3723b9b2f0a0d107c16f939dc05"}
{"path":"packages/bus/src/migrations/3g-3h.sql","sha256":"76168e4f9f6b427286ddb8402fd833acadb01d6325a85f60e9ccf8d42fe2d1d0"}
{"path":"packages/bus/src/migrations/3h-3i.sql","sha256":"e058e6cea8da7b6e649f3e03f2b81dc5444ee940a64274d0e367124c93545035"}
{"path":"packages/bus/src/migrations/3i-3j.sql","sha256":"5ad122ca950e43e066f3d9ed215e73353e6b26de6687b961a8818d69c9465031"}
{"path":"packages/bus/src/migrations/3j-3k.sql","sha256":"2e2bb1fe70076f5e24406a18a923b9e55c4192178a0a704a1b9716032676f9d4"}
{"path":"packages/bus/src/migrations/3k-3l.sql","sha256":"eb2822c73e527697399691ae520092277ddbd4d2a9a42a0731b3c81cc3569e58"}
{"path":"packages/bus/src/migrations/3l-3m.sql","sha256":"791879f06a3e97d3cfbe6112e2fb6502457af30b3e0198e3da1192038906d156"}
{"path":"packages/bus/src/migrations/3m-3n.sql","sha256":"b40bc6a7bedc459d6827cbf0414619e48fc5dce2febdeff70a647345f2281c3a"}
{"path":"packages/model-proxy/PIN","sha256":"889ac9589fadf7654d4dbb914f968cbafe4255ed215bd6a9ff3f331757c9017b"}
{"path":"packages/plugins/usage/cliproxy-queue/index.mjs","sha256":"6096a577cd5d7e8bf84fd6b98ab284e2f47d5facebd027548e07e6aeec442f96"}
{"path":"packages/plugins/limit-check/token-limit/index.mjs","sha256":"4d0c6f5f87101f94608c02001a49d62cef113da48c539b2d2488dfbed1a4c524"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/bus/tests/usage-broker.test.mjs","sha256":"4b2149ea4219f49db19669ada9f88931f7691cdd73dd27dceec6e8fe1f76dd0c"}
{"path":"packages/bus/src/store.mjs","sha256":"dd7fce9706402efd1c5a5b81f7d0fa3793de203e7a6aef4e118e934aebdc7c84"}
{"path":"packages/bus/src/broker.mjs","sha256":"c0144adade79c2cfc6b8247721393f0250b1d64f6c6c04d85738cb80939c42e5"}
{"path":"packages/bus/src/proxy-page-vocabulary.mjs","sha256":"cec059ea4bef5ef62f6181123bfe64bca21d8985d5357471da8c0a3199a877f9"}
{"path":"packages/model-proxy/src/validation.mjs","sha256":"e66453cf6662677cf28cbad1ae8f7509917d333e5b80404ab02c53f5cf75e9e1"}
{"path":"packages/bus/src/address.mjs","sha256":"232a1c77c2f17011c53b55fc6052f70985598210769d41d7c2c0b535328aad23"}
{"path":"packages/processing-control/src/state.mjs","sha256":"ed834770fed863cb0c15b75062de1fd63dea940f3b42020b769a7e62b319c8ed"}
{"path":"packages/plugins/src/kinds.mjs","sha256":"eaa258a1aadadb5a75450fa73fdbcea0b53636adb50ed9a508193d29d564ca78"}
{"path":"packages/tasks/src/requirements.mjs","sha256":"38e7b85650247759f06c09fce205b2970b8368bc81491f51dc6b3c90ba2a846d"}
{"path":"packages/bus/src/landing.mjs","sha256":"9919febc7679168e0a72c0ef51983120283e595fea290a5e8e948409bf5c911b"}
{"path":"packages/business/src/vocabulary.mjs","sha256":"de1f04628e400084a46e77fd7e03c7a039f0f80c9e07bb486c9c012f187aa3eb"}
{"path":"packages/bus/schema.sql","sha256":"a2ba3a46f12e56139ecae9e55227d00847842aedec50c1d92aaae28844ca48e7"}
{"path":"packages/bus/src/migrations/3b.sql","sha256":"179ffe356d4ff19a49b5ebad39b6c6bfd7771deb8e1b7c55b5e746f039d69e65"}
{"path":"packages/bus/src/migrations/3b-3c.sql","sha256":"b753f630301bf125e9e286b4156d0736930dd8fb9cd8eb2ebf316688f9191a07"}
{"path":"packages/bus/src/migrations/3c-3d.sql","sha256":"0423832d05aa68f9191d7362827bd19310001165b895fb2de40b962fe68f9d56"}
{"path":"packages/bus/src/migrations/3d-3e.sql","sha256":"d9aacc974d5047790e65c30a90068259bb9396dc92d4904eae3b9c5dbbb2f077"}
{"path":"packages/bus/src/migrations/3e-3f.sql","sha256":"bf0b72c606b1a56a1610f09619b0c1118f1f300c636824ea13fd51a4ca6ac4b3"}
{"path":"packages/bus/src/migrations/3f-3g.sql","sha256":"82f54b264919e34282bc214e34e9849f701cd3723b9b2f0a0d107c16f939dc05"}
{"path":"packages/bus/src/migrations/3g-3h.sql","sha256":"76168e4f9f6b427286ddb8402fd833acadb01d6325a85f60e9ccf8d42fe2d1d0"}
{"path":"packages/bus/src/migrations/3h-3i.sql","sha256":"e058e6cea8da7b6e649f3e03f2b81dc5444ee940a64274d0e367124c93545035"}
{"path":"packages/bus/src/migrations/3i-3j.sql","sha256":"5ad122ca950e43e066f3d9ed215e73353e6b26de6687b961a8818d69c9465031"}
{"path":"packages/bus/src/migrations/3j-3k.sql","sha256":"2e2bb1fe70076f5e24406a18a923b9e55c4192178a0a704a1b9716032676f9d4"}
{"path":"packages/bus/src/migrations/3k-3l.sql","sha256":"eb2822c73e527697399691ae520092277ddbd4d2a9a42a0731b3c81cc3569e58"}
{"path":"packages/bus/src/migrations/3l-3m.sql","sha256":"791879f06a3e97d3cfbe6112e2fb6502457af30b3e0198e3da1192038906d156"}
{"path":"packages/bus/src/migrations/3m-3n.sql","sha256":"b40bc6a7bedc459d6827cbf0414619e48fc5dce2febdeff70a647345f2281c3a"}
{"path":"packages/tasks/requirements.json","sha256":"80b58323994d70e8bb496d81225aeb3d2cdfda464654b68b3b082e9af1fac5c1"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/bus/tests/usage-runtime.test.mjs","sha256":"5abe93fca8442f06ff68760623e91262d863e1191fa35a3d0c87d7b0e6c0a4c6"}
{"path":"packages/bus/src/runtime.mjs","sha256":"969d04eb06b97093c7f9f0dfa6b51084c781e967e2668814083bbba84a2af7b6"}
{"path":"packages/bus/src/store.mjs","sha256":"dd7fce9706402efd1c5a5b81f7d0fa3793de203e7a6aef4e118e934aebdc7c84"}
{"path":"packages/project/src/index.mjs","sha256":"3ab38cc40ce9ed1a714a59a1f2c336c3792a59431a6a9cc655ba6a2f47513899"}
{"path":"packages/project/src/paths.mjs","sha256":"bd9debcf3f9bb92560e74f220a0b108dfe24154bc6d1fb03c5ec414356d451f9"}
{"path":"packages/project/src/git.mjs","sha256":"af6865a4cace92ef27910098507ffedfc8dfe768cea088b1fee21d0876cc556e"}
{"path":"packages/seat/src/checkout.mjs","sha256":"5aca02491fe8df51487968ce62c776d493d0fe693cc41478b84bef7b49c8948d"}
{"path":"packages/processing-control/src/effects.mjs","sha256":"3bc600649267f011e21ed8266fb16927b0ad3a0e2c49e4b54062d34c544d0c17"}
{"path":"packages/processing-control/src/state.mjs","sha256":"ed834770fed863cb0c15b75062de1fd63dea940f3b42020b769a7e62b319c8ed"}
{"path":"packages/processing-control/src/runtimes.mjs","sha256":"7145420aa354180689a5c84423928fc60c8123476dcfed3364c9cf4542f8c7ea"}
{"path":"packages/project/src/validate.mjs","sha256":"e49ab5e825f0706da2f3c8dfcf33c1331a38d77ca2d35b03359ee68ea74652c5"}
{"path":"packages/project/src/read.mjs","sha256":"42113cd20eb8f04dd252f9963a6f1a84806af9cae7beb6808c4d584a2548220c"}
{"path":"packages/library/src/index.mjs","sha256":"98c2c2877549c3e2c5963ec4e49d99ab3b6d6ad54fb3bfae86cf98542207157e"}
{"path":"packages/library/src/problems.mjs","sha256":"0c8764b03dae0150c56af74bcb113cf583dcbe1fa0c6f7386ef2d48d59a6bd31"}
{"path":"packages/library/src/mapping.mjs","sha256":"c83c626c7cdc2a00ba4217c34b889ca0517cd2022d1f8fc9e7d3a14a0293a802"}
{"path":"packages/library/src/scope.mjs","sha256":"97e12255f52ad638eeacd152eb26822f9a2aa72cd30e2fed1193f51cd6e56192"}
{"path":"packages/library/src/supporting.mjs","sha256":"6a3b4de2070e62b1cca1c0ab20f2883d3153fc61608d1bf7670cecea08765b4c"}
{"path":"packages/library/src/links.mjs","sha256":"def32a176cb70c86248e45908edde22f9c4c5f88575a4af0a396a05f617358bc"}
{"path":"packages/library/src/reader.mjs","sha256":"ea126533afb7e74b71419eb943febb6b242eb96fc6917d9df1019db3e7e6ce8d"}
{"path":"packages/library/src/render.mjs","sha256":"bfc3de029d3c8f0dcc96c90fde30d6da58bbb5b72d8f13e3f536c0d735c73ca5"}
{"path":"packages/library/src/survey.mjs","sha256":"016bfa5c80572c0baf90ced39cb3d3ec66d395f0be15c2727b9552a9dd849093"}
{"path":"packages/library/src/mirror.mjs","sha256":"26b824d6885e5c6d1b8bd71e754a9fa333c26307693f7e6a0c6a8e6300ecb4ae"}
{"path":"packages/library/src/sync.mjs","sha256":"a58f3aec5ed9b3530b363e2fdbd38bc9ded7635d261ab2fca3cb31c45dcd3dfa"}
{"path":"packages/library/src/index-build.mjs","sha256":"70c1fe75cb2149c9a074d55a6301d5b66157c2dc2e777b92bac338cce09d89c7"}
{"path":"packages/library/src/query.mjs","sha256":"bafe113bee70f17bd249876d6bdd1c08fa051223c2111955e5d5f275bd76bba0"}
{"path":"packages/library/src/limits.mjs","sha256":"98ef45ed61144aaea44d8aea1ac43082b6d340297e46846d01772da38728e530"}
{"path":"packages/library/src/guard.mjs","sha256":"f710d9600a17f6e2989a289cfe84e58f161d86c7306605946ce05fa71b364eb2"}
{"path":"packages/library/src/reply-protocol.mjs","sha256":"7b46f47b5e9d6b554b5d39bce2cd95c4610f5f35b8ab8fdc5a2864b3214be809"}
{"path":"packages/library/src/write.mjs","sha256":"a301b7c7e3f42f66cb69d88991220f4e236f25a6e5951c61e79ec4ef2b714198"}
{"path":"packages/business/src/vocabulary.mjs","sha256":"de1f04628e400084a46e77fd7e03c7a039f0f80c9e07bb486c9c012f187aa3eb"}
{"path":"packages/bus/src/broker.mjs","sha256":"c0144adade79c2cfc6b8247721393f0250b1d64f6c6c04d85738cb80939c42e5"}
{"path":"packages/bus/src/proxy-page-vocabulary.mjs","sha256":"cec059ea4bef5ef62f6181123bfe64bca21d8985d5357471da8c0a3199a877f9"}
{"path":"packages/model-proxy/src/validation.mjs","sha256":"e66453cf6662677cf28cbad1ae8f7509917d333e5b80404ab02c53f5cf75e9e1"}
{"path":"packages/bus/src/address.mjs","sha256":"232a1c77c2f17011c53b55fc6052f70985598210769d41d7c2c0b535328aad23"}
{"path":"packages/plugins/src/kinds.mjs","sha256":"eaa258a1aadadb5a75450fa73fdbcea0b53636adb50ed9a508193d29d564ca78"}
{"path":"packages/tasks/src/requirements.mjs","sha256":"38e7b85650247759f06c09fce205b2970b8368bc81491f51dc6b3c90ba2a846d"}
{"path":"packages/bus/src/landing.mjs","sha256":"9919febc7679168e0a72c0ef51983120283e595fea290a5e8e948409bf5c911b"}
{"path":"packages/bus/src/credentials.mjs","sha256":"10485afcf94c29ac9f3d5ba30b12248a2379efd69185ff9fb90e9fed25fe0678"}
{"path":"packages/bus/src/server.mjs","sha256":"8318bed9168ac3f58c09de40a139b68aacefd684e6c117406e181e2ca5ab4ec7"}
{"path":"packages/bus/src/interpreter.mjs","sha256":"56bfc8dcba476886d7de61a1e798aae8e3041c2434c62d44fc40a168d22bb3bd"}
{"path":"packages/bus/src/peercred.mjs","sha256":"29c88655e8b9aed8db604573c9213fd9f3c40ef35ff04f4eda8fbe8f1b8a32d7"}
{"path":"packages/business/src/launch-settings.mjs","sha256":"e14d73f719664499d809909962a6ecc16d4ffb9d824fcdee699e0778809d9e96"}
{"path":"packages/business/src/organization.mjs","sha256":"fa4ba1ae878cd27287865fa12115f8a6c1175a2dfd1011d5f8aca11e46e669c7"}
{"path":"packages/business/src/business.mjs","sha256":"aaa4578fd4133f64119de6c8786a14759240a8910677529fdeae57173058b7d9"}
{"path":"packages/business/src/errors.mjs","sha256":"cd4eb5960c17ce32f26d1a49196866ce04efc42c1d90b18b046af5fda8b9ff0a"}
{"path":"packages/business/src/launch.mjs","sha256":"0aa94dbd14acd379a4837cc3e70b9618b3fa797d74124314e7245a8a3070e98c"}
{"path":"packages/business/src/util.mjs","sha256":"e1f0e70a4bbba8ae2ad6185ab61770b15acda403e90fc708e13027a1e9ec663c"}
{"path":"packages/business/src/vars.mjs","sha256":"f6b15ee8dad2d985c0ae66b1f106ca46cb56ec86ac8cd5dec8a05c887596a421"}
{"path":"packages/business/src/credentials.mjs","sha256":"c3422b1e144177f9dd3015ac036ee1d2cde02bd2b3be406364f3b3f45d8c9b73"}
{"path":"packages/business/src/role.mjs","sha256":"b10af84d7422da4d0e8c0a4fea1064eebbc2fac6a838a1b3939b554e22dedfc9"}
{"path":"packages/business/src/resolve.mjs","sha256":"712183465fee099606223d84423afc54e3386a0c8e468c68d5ac39c1e676d109"}
{"path":"packages/business/src/project.mjs","sha256":"9472996134c520c31971e66006d1c1683709f6df4f76fe3445bdc97a18637eff"}
{"path":"packages/seat/src/session.mjs","sha256":"c37a6ef6f6d2b4e61443e77d800656bf31e38913bf7dbdc4ca955f4a83b13a41"}
{"path":"packages/seat/src/proc.mjs","sha256":"382cbf7e0ff336911e288ce858bdbfbec693bc2b69879720d1f0b4c7d8455198"}
{"path":"packages/seat/src/sandbox.mjs","sha256":"0868f393f6fb117d430428ec390e435359737eae0792b4a4d1f54797c7a6c1bf"}
{"path":"packages/seat/src/seat.mjs","sha256":"eec970961a667c9e614d1474d33c31a019b2cf1b0bf931a51458d874bca13a15"}
{"path":"packages/seat/src/compactions.mjs","sha256":"c5de99284b8fa61763b8dd30a58809bbc086529eeb10587586d52b0df2754774"}
{"path":"packages/seat/src/working.mjs","sha256":"621f5c223811444336f0f5d6ad10bc7afce075491653c0527d6c26ca568b79c3"}
{"path":"packages/plugins/src/loader.mjs","sha256":"2e99f9222424cf9503253701568f0bb5ef579a22930f9f224e5b63ad6b4f745f"}
{"path":"packages/business/src/plugin-settings.mjs","sha256":"9d2c68dd21c6c9553af75f4b137c4f169e95761f32528767e0518d0313311f50"}
{"path":"packages/model-proxy/src/client.mjs","sha256":"f5f86cad661034f223a76352d877fa8d7883bfa921a7a01282347a9a03272441"}
{"path":"packages/model-proxy/src/common.mjs","sha256":"a6fb88352018b8f21593a0bb9311f87162c80d8b1e05e62b4d43b1e69af21b23"}
{"path":"packages/bus/src/proxy-page.mjs","sha256":"af36aae674f46a4e5eacfe176fde8b58cd0b171a6d70e07ee6d479e0f558cce7"}
{"path":"packages/model-proxy/src/settings.mjs","sha256":"1eac4b5741b360a077bb1c871c008b64f7c7119afc64be4d6e4a0dcdb3a313bb"}
{"path":"packages/bus/src/model-keys.mjs","sha256":"b4e11975bd56db4c816ada297902f033b3db7754d4a05319f03d640e17374550"}
{"path":"packages/business/src/instance-settings.mjs","sha256":"09f2bde85a6d7a8f0b1d1c60ac589b845b0c95e991b2f807758878416b13c6bd"}
{"path":"packages/bus/src/credential-verbs.mjs","sha256":"86b4321dd436b97e389101873197dbab95b3d2202e5ef7da712c4978f4f9159f"}
{"path":"packages/bus/src/business.mjs","sha256":"ff927da3cf22fbacc9ace77b2e8b803bffc2953fb58cf7ab4e5f6f6493732996"}
{"path":"packages/bus/src/web.mjs","sha256":"68efa3c9d0a72095f503208ed5c2e660ef9bca68d3ea15f0fc2f1826a68e09cc"}
{"path":"packages/discord/src/web.mjs","sha256":"e5a7b64720872b12b34223549537ace05ebf0ca8a29b2f844d2b7c5cc9ea41f7"}
{"path":"packages/bus/src/host-run.mjs","sha256":"324c05b16253e0fcfc1a0299d1d8ab45850ea723fad1f67bcc07fc031f50d593"}
{"path":"packages/bus/src/host-grant.mjs","sha256":"48337cdbc41d503f17962d3e3ad014183b1286165f97da6fd88b4faa50be3949"}
{"path":"packages/business/src/hosts.mjs","sha256":"e08b11b70b54f13e3b18996dd903f841e04fd6c64791e96063df8b164c663882"}
{"path":"packages/bus/src/gitea-grant.mjs","sha256":"27d7d5322c2f12641e350867d3ac6f838b33832951e69f057e3a7a28b8ac4d5b"}
{"path":"packages/bus/src/principal.mjs","sha256":"2b1e18be825e8264b16506d6294863acbba812956cfdf8e056f21faaa94f7137"}
{"path":"packages/bus/src/human.mjs","sha256":"bb13c146717cdc46d75d157177e400edac4d3e10f14fe511027a25fd44cec885"}
{"path":"packages/bus/src/tester.mjs","sha256":"5e9e08ca8069e1de35232f26d48a77792388128dda659893909f2d34b5af2346"}
{"path":"packages/business/src/access.mjs","sha256":"af028c999a6ab4d42b321c3f047e683b226c7ad232a2ae9cfc623b7dd5a4dd5f"}
{"path":"packages/bus/src/usage.mjs","sha256":"4ae57d053c4b217e1c1a22ada3ed1c5d4a3f0e61b8d2798e9db37997cd071a29"}
{"path":"packages/bus/src/proxy-usage.mjs","sha256":"5a6c3707e6a64304cfd37f1875eb378c6eb58bf438cc40365fe913eaec7cee59"}
{"path":"packages/bus/src/limits.mjs","sha256":"18c1aacd280ebf0f200d5e6fc1dd1a7e098a3046c1cb8427140bb2198ac81cd3"}
{"path":"packages/processing-control/src/coordinator.mjs","sha256":"ddc7318297abc4ec4dd03d425820b7323db609e554cfc5341cfdfa6934271e73"}
{"path":"packages/discord/src/processing.mjs","sha256":"8fa9968862dff77fa6d8be5210c22d13712fd622a8cbc722d167be5be80d0783"}
{"path":"packages/discord/src/binding.mjs","sha256":"5ab69c4111dd9589a197172ffe6968bf414f41c552b7910e5478a27c446cfaec"}
{"path":"packages/discord/src/setspark.mjs","sha256":"ba09d286e707860afa53300f8802ac8e6193ab2d2e7abe9d2b07cbdef3822387"}
{"path":"packages/discord/src/errors.mjs","sha256":"917b0e6c4f100e93f056b925e38d97eacdd8b2596e39fbd3f88c0b62b973d8ed"}
{"path":"packages/discord/src/tools.mjs","sha256":"975503616245bb6051f06ecbf47436ce7d030f21af23042df7f3341062df967f"}
{"path":"packages/discord/src/git.mjs","sha256":"c28e04a0055997ea0b34bea1ad2912adb248d5fd43713df1e6f5a661d87949b7"}
{"path":"packages/discord/src/journal.mjs","sha256":"12684e926574c3fe7f693a03b60d1393df483f5feb4b47c9dd7c5a7ac050aec5"}
{"path":"packages/processing-control/src/containers.mjs","sha256":"781973277c09133de15fc39be35b372a79066479097d46923c8ab7782f011dcd"}
{"path":"packages/bus/src/client.mjs","sha256":"f3d483f61a24cbc9cce235e1e92889f09b8cecf513fcaf90c741f316f62262e2"}
{"path":"packages/bus/schema.sql","sha256":"a2ba3a46f12e56139ecae9e55227d00847842aedec50c1d92aaae28844ca48e7"}
{"path":"packages/bus/src/migrations/3b.sql","sha256":"179ffe356d4ff19a49b5ebad39b6c6bfd7771deb8e1b7c55b5e746f039d69e65"}
{"path":"packages/bus/src/migrations/3b-3c.sql","sha256":"b753f630301bf125e9e286b4156d0736930dd8fb9cd8eb2ebf316688f9191a07"}
{"path":"packages/bus/src/migrations/3c-3d.sql","sha256":"0423832d05aa68f9191d7362827bd19310001165b895fb2de40b962fe68f9d56"}
{"path":"packages/bus/src/migrations/3d-3e.sql","sha256":"d9aacc974d5047790e65c30a90068259bb9396dc92d4904eae3b9c5dbbb2f077"}
{"path":"packages/bus/src/migrations/3e-3f.sql","sha256":"bf0b72c606b1a56a1610f09619b0c1118f1f300c636824ea13fd51a4ca6ac4b3"}
{"path":"packages/bus/src/migrations/3f-3g.sql","sha256":"82f54b264919e34282bc214e34e9849f701cd3723b9b2f0a0d107c16f939dc05"}
{"path":"packages/bus/src/migrations/3g-3h.sql","sha256":"76168e4f9f6b427286ddb8402fd833acadb01d6325a85f60e9ccf8d42fe2d1d0"}
{"path":"packages/bus/src/migrations/3h-3i.sql","sha256":"e058e6cea8da7b6e649f3e03f2b81dc5444ee940a64274d0e367124c93545035"}
{"path":"packages/bus/src/migrations/3i-3j.sql","sha256":"5ad122ca950e43e066f3d9ed215e73353e6b26de6687b961a8818d69c9465031"}
{"path":"packages/bus/src/migrations/3j-3k.sql","sha256":"2e2bb1fe70076f5e24406a18a923b9e55c4192178a0a704a1b9716032676f9d4"}
{"path":"packages/bus/src/migrations/3k-3l.sql","sha256":"eb2822c73e527697399691ae520092277ddbd4d2a9a42a0731b3c81cc3569e58"}
{"path":"packages/bus/src/migrations/3l-3m.sql","sha256":"791879f06a3e97d3cfbe6112e2fb6502457af30b3e0198e3da1192038906d156"}
{"path":"packages/bus/src/migrations/3m-3n.sql","sha256":"b40bc6a7bedc459d6827cbf0414619e48fc5dce2febdeff70a647345f2281c3a"}
{"path":"packages/project/schemas/project.schema.json","sha256":"f069c012e9660d5d0491a21f98e936b725f6818e1c3136dfec61b3c800bd58de"}
{"path":"packages/project/schemas/requirement.schema.json","sha256":"79a1e7b567af7162bb88ca69861075fc579a858e8aec4e49824ccdc370b690c3"}
{"path":"packages/project/schemas/decision.schema.json","sha256":"925bb03ac99e5845e4bfa20b4561a331f034f88e187db82213df6602a7ceee4b"}
{"path":"packages/model-proxy/PIN","sha256":"889ac9589fadf7654d4dbb914f968cbafe4255ed215bd6a9ff3f331757c9017b"}
{"path":"packages/plugins/usage-source/transcript/index.mjs","sha256":"d09ae19db3eb69477783163559bd6a8e5b59a6f5af0eafd62d0e2e3bd325065e"}
{"path":"packages/plugins/harness/pi/index.mjs","sha256":"39c225f157b8f66b416625bda689153505743ffcfdc32964bb1f3d2c6fcb73af"}
{"path":"packages/plugins/harness/pi/compactions.mjs","sha256":"aabaf5c4602e28f025c18b2e2ddd6fa0d1648870101a5de0c4424d97b24472dd"}
{"path":"packages/tasks/requirements.json","sha256":"80b58323994d70e8bb496d81225aeb3d2cdfda464654b68b3b082e9af1fac5c1"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/bus/tests/usage.test.mjs","sha256":"2613ba0561572a7d4f753066922fddc90cca812cb0ce2b3e0a9a4d249a15e340"}
{"path":"packages/bus/src/store.mjs","sha256":"dd7fce9706402efd1c5a5b81f7d0fa3793de203e7a6aef4e118e934aebdc7c84"}
{"path":"packages/bus/src/usage.mjs","sha256":"4ae57d053c4b217e1c1a22ada3ed1c5d4a3f0e61b8d2798e9db37997cd071a29"}
{"path":"packages/plugins/src/loader.mjs","sha256":"2e99f9222424cf9503253701568f0bb5ef579a22930f9f224e5b63ad6b4f745f"}
{"path":"packages/plugins/src/kinds.mjs","sha256":"eaa258a1aadadb5a75450fa73fdbcea0b53636adb50ed9a508193d29d564ca78"}
{"path":"packages/bus/schema.sql","sha256":"a2ba3a46f12e56139ecae9e55227d00847842aedec50c1d92aaae28844ca48e7"}
{"path":"packages/bus/src/migrations/3b.sql","sha256":"179ffe356d4ff19a49b5ebad39b6c6bfd7771deb8e1b7c55b5e746f039d69e65"}
{"path":"packages/bus/src/migrations/3b-3c.sql","sha256":"b753f630301bf125e9e286b4156d0736930dd8fb9cd8eb2ebf316688f9191a07"}
{"path":"packages/bus/src/migrations/3c-3d.sql","sha256":"0423832d05aa68f9191d7362827bd19310001165b895fb2de40b962fe68f9d56"}
{"path":"packages/bus/src/migrations/3d-3e.sql","sha256":"d9aacc974d5047790e65c30a90068259bb9396dc92d4904eae3b9c5dbbb2f077"}
{"path":"packages/bus/src/migrations/3e-3f.sql","sha256":"bf0b72c606b1a56a1610f09619b0c1118f1f300c636824ea13fd51a4ca6ac4b3"}
{"path":"packages/bus/src/migrations/3f-3g.sql","sha256":"82f54b264919e34282bc214e34e9849f701cd3723b9b2f0a0d107c16f939dc05"}
{"path":"packages/bus/src/migrations/3g-3h.sql","sha256":"76168e4f9f6b427286ddb8402fd833acadb01d6325a85f60e9ccf8d42fe2d1d0"}
{"path":"packages/bus/src/migrations/3h-3i.sql","sha256":"e058e6cea8da7b6e649f3e03f2b81dc5444ee940a64274d0e367124c93545035"}
{"path":"packages/bus/src/migrations/3i-3j.sql","sha256":"5ad122ca950e43e066f3d9ed215e73353e6b26de6687b961a8818d69c9465031"}
{"path":"packages/bus/src/migrations/3j-3k.sql","sha256":"2e2bb1fe70076f5e24406a18a923b9e55c4192178a0a704a1b9716032676f9d4"}
{"path":"packages/bus/src/migrations/3k-3l.sql","sha256":"eb2822c73e527697399691ae520092277ddbd4d2a9a42a0731b3c81cc3569e58"}
{"path":"packages/bus/src/migrations/3l-3m.sql","sha256":"791879f06a3e97d3cfbe6112e2fb6502457af30b3e0198e3da1192038906d156"}
{"path":"packages/bus/src/migrations/3m-3n.sql","sha256":"b40bc6a7bedc459d6827cbf0414619e48fc5dce2febdeff70a647345f2281c3a"}
{"path":"packages/plugins/usage-source/transcript/index.mjs","sha256":"d09ae19db3eb69477783163559bd6a8e5b59a6f5af0eafd62d0e2e3bd325065e"}
{"path":"packages/plugins/tests/helpers.mjs","sha256":"5d5e5dccdae3f94b8540d187a8899ec36f9c9933cae3933249c2d8c400c75aa2"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/business/tests/plugin-settings.test.mjs","sha256":"f0dfe004905dce31317d85d89a05802db878c3472e765e85dc9f1e04166e1df6"}
{"path":"packages/business/tests/helpers.mjs","sha256":"a6a9971b42ddf176d9415caee3efc2eb16791dead5f0f0557d28449a550aefa1"}
{"path":"packages/business/src/business.mjs","sha256":"aaa4578fd4133f64119de6c8786a14759240a8910677529fdeae57173058b7d9"}
{"path":"packages/business/src/errors.mjs","sha256":"cd4eb5960c17ce32f26d1a49196866ce04efc42c1d90b18b046af5fda8b9ff0a"}
{"path":"packages/business/src/launch.mjs","sha256":"0aa94dbd14acd379a4837cc3e70b9618b3fa797d74124314e7245a8a3070e98c"}
{"path":"packages/business/src/util.mjs","sha256":"e1f0e70a4bbba8ae2ad6185ab61770b15acda403e90fc708e13027a1e9ec663c"}
{"path":"packages/business/src/vocabulary.mjs","sha256":"de1f04628e400084a46e77fd7e03c7a039f0f80c9e07bb486c9c012f187aa3eb"}
{"path":"packages/business/src/vars.mjs","sha256":"f6b15ee8dad2d985c0ae66b1f106ca46cb56ec86ac8cd5dec8a05c887596a421"}
{"path":"packages/plugins/src/kinds.mjs","sha256":"eaa258a1aadadb5a75450fa73fdbcea0b53636adb50ed9a508193d29d564ca78"}
{"path":"packages/business/src/credentials.mjs","sha256":"c3422b1e144177f9dd3015ac036ee1d2cde02bd2b3be406364f3b3f45d8c9b73"}
{"path":"packages/business/src/role.mjs","sha256":"b10af84d7422da4d0e8c0a4fea1064eebbc2fac6a838a1b3939b554e22dedfc9"}
{"path":"packages/library/src/mapping.mjs","sha256":"c83c626c7cdc2a00ba4217c34b889ca0517cd2022d1f8fc9e7d3a14a0293a802"}
{"path":"packages/library/src/problems.mjs","sha256":"0c8764b03dae0150c56af74bcb113cf583dcbe1fa0c6f7386ef2d48d59a6bd31"}
{"path":"packages/business/src/plugin-settings.mjs","sha256":"9d2c68dd21c6c9553af75f4b137c4f169e95761f32528767e0518d0313311f50"}
{"path":"packages/business/src/organization.mjs","sha256":"fa4ba1ae878cd27287865fa12115f8a6c1175a2dfd1011d5f8aca11e46e669c7"}
{"path":"packages/library/src/limits.mjs","sha256":"98ef45ed61144aaea44d8aea1ac43082b6d340297e46846d01772da38728e530"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/business/tests/token-limit-settings.test.mjs","sha256":"bc6b3a31e8918d70aced7151b91ac4b39afec4081054024b162acb0e8f8fae07"}
{"path":"packages/business/tests/helpers.mjs","sha256":"a6a9971b42ddf176d9415caee3efc2eb16791dead5f0f0557d28449a550aefa1"}
{"path":"packages/business/src/business.mjs","sha256":"aaa4578fd4133f64119de6c8786a14759240a8910677529fdeae57173058b7d9"}
{"path":"packages/business/src/errors.mjs","sha256":"cd4eb5960c17ce32f26d1a49196866ce04efc42c1d90b18b046af5fda8b9ff0a"}
{"path":"packages/business/src/launch.mjs","sha256":"0aa94dbd14acd379a4837cc3e70b9618b3fa797d74124314e7245a8a3070e98c"}
{"path":"packages/business/src/util.mjs","sha256":"e1f0e70a4bbba8ae2ad6185ab61770b15acda403e90fc708e13027a1e9ec663c"}
{"path":"packages/business/src/vocabulary.mjs","sha256":"de1f04628e400084a46e77fd7e03c7a039f0f80c9e07bb486c9c012f187aa3eb"}
{"path":"packages/business/src/vars.mjs","sha256":"f6b15ee8dad2d985c0ae66b1f106ca46cb56ec86ac8cd5dec8a05c887596a421"}
{"path":"packages/plugins/src/kinds.mjs","sha256":"eaa258a1aadadb5a75450fa73fdbcea0b53636adb50ed9a508193d29d564ca78"}
{"path":"packages/business/src/credentials.mjs","sha256":"c3422b1e144177f9dd3015ac036ee1d2cde02bd2b3be406364f3b3f45d8c9b73"}
{"path":"packages/business/src/role.mjs","sha256":"b10af84d7422da4d0e8c0a4fea1064eebbc2fac6a838a1b3939b554e22dedfc9"}
{"path":"packages/library/src/mapping.mjs","sha256":"c83c626c7cdc2a00ba4217c34b889ca0517cd2022d1f8fc9e7d3a14a0293a802"}
{"path":"packages/library/src/problems.mjs","sha256":"0c8764b03dae0150c56af74bcb113cf583dcbe1fa0c6f7386ef2d48d59a6bd31"}
{"path":"packages/business/src/launch-settings.mjs","sha256":"e14d73f719664499d809909962a6ecc16d4ffb9d824fcdee699e0778809d9e96"}
{"path":"packages/business/src/organization.mjs","sha256":"fa4ba1ae878cd27287865fa12115f8a6c1175a2dfd1011d5f8aca11e46e669c7"}
{"path":"packages/library/src/limits.mjs","sha256":"98ef45ed61144aaea44d8aea1ac43082b6d340297e46846d01772da38728e530"}
{"path":"packages/business/src/resolve.mjs","sha256":"712183465fee099606223d84423afc54e3386a0c8e468c68d5ac39c1e676d109"}
{"path":"packages/business/src/project.mjs","sha256":"9472996134c520c31971e66006d1c1683709f6df4f76fe3445bdc97a18637eff"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/model-proxy/tests/client-probe.test.mjs","sha256":"77327681d6eb51f25d7aeffcc532b7e8269c1dc59139cb03adb4a3a1409f63e9"}
{"path":"packages/model-proxy/src/client.mjs","sha256":"f5f86cad661034f223a76352d877fa8d7883bfa921a7a01282347a9a03272441"}
{"path":"packages/model-proxy/src/common.mjs","sha256":"a6fb88352018b8f21593a0bb9311f87162c80d8b1e05e62b4d43b1e69af21b23"}
{"path":"packages/model-proxy/src/validation.mjs","sha256":"e66453cf6662677cf28cbad1ae8f7509917d333e5b80404ab02c53f5cf75e9e1"}
{"path":"packages/model-proxy/PIN","sha256":"889ac9589fadf7654d4dbb914f968cbafe4255ed215bd6a9ff3f331757c9017b"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/model-proxy/tests/client.test.mjs","sha256":"790c6a50ec030a8b27a28fac7fd129bd9eabe79774adf11d6620c00df9b6ae86"}
{"path":"packages/model-proxy/src/client.mjs","sha256":"f5f86cad661034f223a76352d877fa8d7883bfa921a7a01282347a9a03272441"}
{"path":"packages/model-proxy/src/common.mjs","sha256":"a6fb88352018b8f21593a0bb9311f87162c80d8b1e05e62b4d43b1e69af21b23"}
{"path":"packages/model-proxy/src/validation.mjs","sha256":"e66453cf6662677cf28cbad1ae8f7509917d333e5b80404ab02c53f5cf75e9e1"}
{"path":"packages/model-proxy/PIN","sha256":"889ac9589fadf7654d4dbb914f968cbafe4255ed215bd6a9ff3f331757c9017b"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/model-proxy/tests/management-key-encoding.test.mjs","sha256":"95e39a519f7ac8b9592876e6157191169f9b14d002163867a6ff6ab808e42c14"}
{"path":"packages/model-proxy/src/common.mjs","sha256":"a6fb88352018b8f21593a0bb9311f87162c80d8b1e05e62b4d43b1e69af21b23"}
{"path":"packages/model-proxy/src/validation.mjs","sha256":"e66453cf6662677cf28cbad1ae8f7509917d333e5b80404ab02c53f5cf75e9e1"}
{"path":"packages/model-proxy/src/settings.mjs","sha256":"1eac4b5741b360a077bb1c871c008b64f7c7119afc64be4d6e4a0dcdb3a313bb"}
{"path":"packages/model-proxy/src/client.mjs","sha256":"f5f86cad661034f223a76352d877fa8d7883bfa921a7a01282347a9a03272441"}
{"path":"packages/model-proxy/PIN","sha256":"889ac9589fadf7654d4dbb914f968cbafe4255ed215bd6a9ff3f331757c9017b"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/model-proxy/tests/page-client.test.mjs","sha256":"f24e1d121a340cbcaa3f6cd6390eeb7d4b05f778dd498d76ba099cba5a719dea"}
{"path":"packages/model-proxy/src/client.mjs","sha256":"f5f86cad661034f223a76352d877fa8d7883bfa921a7a01282347a9a03272441"}
{"path":"packages/model-proxy/src/common.mjs","sha256":"a6fb88352018b8f21593a0bb9311f87162c80d8b1e05e62b4d43b1e69af21b23"}
{"path":"packages/model-proxy/src/validation.mjs","sha256":"e66453cf6662677cf28cbad1ae8f7509917d333e5b80404ab02c53f5cf75e9e1"}
{"path":"packages/model-proxy/PIN","sha256":"889ac9589fadf7654d4dbb914f968cbafe4255ed215bd6a9ff3f331757c9017b"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/model-proxy/tests/usage-client.test.mjs","sha256":"1ad66d56800a31cfbd387939e640653bc72150f4e73822d9e3c777b3bffbf1e1"}
{"path":"packages/model-proxy/src/client.mjs","sha256":"f5f86cad661034f223a76352d877fa8d7883bfa921a7a01282347a9a03272441"}
{"path":"packages/model-proxy/src/common.mjs","sha256":"a6fb88352018b8f21593a0bb9311f87162c80d8b1e05e62b4d43b1e69af21b23"}
{"path":"packages/model-proxy/src/validation.mjs","sha256":"e66453cf6662677cf28cbad1ae8f7509917d333e5b80404ab02c53f5cf75e9e1"}
{"path":"packages/model-proxy/PIN","sha256":"889ac9589fadf7654d4dbb914f968cbafe4255ed215bd6a9ff3f331757c9017b"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/plugins/tests/daily-quota.test.mjs","sha256":"3d4fab56fea4c45c6a317ef41121aa5b6da0502a6ef614b7931f91cafdfc1f71"}
{"path":"packages/plugins/limit-check/daily-quota/index.mjs","sha256":"3749b9f6dd681ef424ee7d7e4d80ccee87b3655df8cd8fe9ccd0d505dcaaee9b"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/plugins/tests/kinds.test.mjs","sha256":"f3081e1dbdac20ade2246c743bcbb3934be686f79f378af21c365cd1451893ba"}
{"path":"packages/plugins/src/kinds.mjs","sha256":"eaa258a1aadadb5a75450fa73fdbcea0b53636adb50ed9a508193d29d564ca78"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/plugins/tests/loader.test.mjs","sha256":"8588ad7eee0c9ce5de3b53e3b88562812a155a3d791a2bd3413bb1754655d78b"}
{"path":"packages/plugins/tests/helpers.mjs","sha256":"5d5e5dccdae3f94b8540d187a8899ec36f9c9933cae3933249c2d8c400c75aa2"}
{"path":"packages/business/tests/helpers.mjs","sha256":"a6a9971b42ddf176d9415caee3efc2eb16791dead5f0f0557d28449a550aefa1"}
{"path":"packages/business/src/business.mjs","sha256":"aaa4578fd4133f64119de6c8786a14759240a8910677529fdeae57173058b7d9"}
{"path":"packages/business/src/errors.mjs","sha256":"cd4eb5960c17ce32f26d1a49196866ce04efc42c1d90b18b046af5fda8b9ff0a"}
{"path":"packages/business/src/launch.mjs","sha256":"0aa94dbd14acd379a4837cc3e70b9618b3fa797d74124314e7245a8a3070e98c"}
{"path":"packages/business/src/util.mjs","sha256":"e1f0e70a4bbba8ae2ad6185ab61770b15acda403e90fc708e13027a1e9ec663c"}
{"path":"packages/business/src/vocabulary.mjs","sha256":"de1f04628e400084a46e77fd7e03c7a039f0f80c9e07bb486c9c012f187aa3eb"}
{"path":"packages/business/src/vars.mjs","sha256":"f6b15ee8dad2d985c0ae66b1f106ca46cb56ec86ac8cd5dec8a05c887596a421"}
{"path":"packages/plugins/src/kinds.mjs","sha256":"eaa258a1aadadb5a75450fa73fdbcea0b53636adb50ed9a508193d29d564ca78"}
{"path":"packages/business/src/credentials.mjs","sha256":"c3422b1e144177f9dd3015ac036ee1d2cde02bd2b3be406364f3b3f45d8c9b73"}
{"path":"packages/business/src/role.mjs","sha256":"b10af84d7422da4d0e8c0a4fea1064eebbc2fac6a838a1b3939b554e22dedfc9"}
{"path":"packages/library/src/mapping.mjs","sha256":"c83c626c7cdc2a00ba4217c34b889ca0517cd2022d1f8fc9e7d3a14a0293a802"}
{"path":"packages/library/src/problems.mjs","sha256":"0c8764b03dae0150c56af74bcb113cf583dcbe1fa0c6f7386ef2d48d59a6bd31"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/plugins/tests/token-limit.test.mjs","sha256":"6e96bb96278ec754ca1816a24f49ef677771615ab5cf186ae41969fc2f93d8cc"}
{"path":"packages/plugins/limit-check/token-limit/index.mjs","sha256":"4d0c6f5f87101f94608c02001a49d62cef113da48c539b2d2488dfbed1a4c524"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/webui/tests/usage-render.test.mjs","sha256":"39f50991578b98594183390a00efbca84fda90ef61617eea4215e2c75f90b82c"}
{"path":"packages/webui/src/public/bus.js","sha256":"3c7a35e25b4c1cfda19ac9466d4b2fbc86c880761a1d04ad3ece8bc485f60f93"}
{"path":"agents/codex/work/queue-333/trace-inputs.mjs","sha256":"06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1"}
{"path":"packages/webui/tests/usage.test.mjs","sha256":"f96d06974bc83051c0d5c9000e38161ea0cc231997410bcc6c42ed7f55718dfd"}
{"path":"packages/webui/src/serve.mjs","sha256":"7b7bee91604b7bd973027b177de83205db9aed366e694072fc6343b46465b5ba"}
{"path":"packages/webui/src/proxy-http.mjs","sha256":"a09028cd5ca57367f597d0681e84926ca871fd4626769e9947927d949c2b6ab7"}
{"path":"packages/webui/src/tester-socket.mjs","sha256":"1c1fe0c795adac97f28502564a75f26d5666d9be5ae51169f7dd5bb7741fad16"}
{"path":"packages/webui/src/bus.mjs","sha256":"4ebf6c2b5d71c23d85cbde83f69aa671058dc2195c9ae4bdda624f6940729d1b"}
{"path":"packages/cli/src/transport.mjs","sha256":"662642a8ce739fcb6c188ad07125a94e008c8a305eced127c8041d472c56e55b"}
{"path":"packages/cli/src/errors.mjs","sha256":"c7bdd98a3ddeeb9bc4415d907b92555d723c566eba314075d91486da9b5e85dc"}
{"path":"packages/cli/src/host.mjs","sha256":"a0936aee783ff47dd58fc907fefd86f63e571809a3ce5b0d6d931f71e756b15e"}
{"path":"packages/seat/src/proc.mjs","sha256":"382cbf7e0ff336911e288ce858bdbfbec693bc2b69879720d1f0b4c7d8455198"}
{"path":"packages/bus/src/views.mjs","sha256":"1f31aefa71984fba90c5390df5cc595d929681965f57485ad4972143d5c4b15f"}
{"path":"packages/bus/src/broker.mjs","sha256":"c0144adade79c2cfc6b8247721393f0250b1d64f6c6c04d85738cb80939c42e5"}
{"path":"packages/bus/src/proxy-page-vocabulary.mjs","sha256":"cec059ea4bef5ef62f6181123bfe64bca21d8985d5357471da8c0a3199a877f9"}
{"path":"packages/model-proxy/src/validation.mjs","sha256":"e66453cf6662677cf28cbad1ae8f7509917d333e5b80404ab02c53f5cf75e9e1"}
{"path":"packages/bus/src/address.mjs","sha256":"232a1c77c2f17011c53b55fc6052f70985598210769d41d7c2c0b535328aad23"}
{"path":"packages/processing-control/src/state.mjs","sha256":"ed834770fed863cb0c15b75062de1fd63dea940f3b42020b769a7e62b319c8ed"}
{"path":"packages/plugins/src/kinds.mjs","sha256":"eaa258a1aadadb5a75450fa73fdbcea0b53636adb50ed9a508193d29d564ca78"}
{"path":"packages/tasks/src/requirements.mjs","sha256":"38e7b85650247759f06c09fce205b2970b8368bc81491f51dc6b3c90ba2a846d"}
{"path":"packages/bus/src/landing.mjs","sha256":"9919febc7679168e0a72c0ef51983120283e595fea290a5e8e948409bf5c911b"}
{"path":"packages/business/src/vocabulary.mjs","sha256":"de1f04628e400084a46e77fd7e03c7a039f0f80c9e07bb486c9c012f187aa3eb"}
{"path":"packages/webui/src/reads.mjs","sha256":"46defeb3b4be0e1a22e4b89445872ad6b15cdee182076e9e6222219ae29997f4"}
{"path":"packages/business/src/index.mjs","sha256":"a386ce5bd1d41d86f7b90641a423a2b651b491c8989d5085412c7d202ac1cb30"}
{"path":"packages/business/src/errors.mjs","sha256":"cd4eb5960c17ce32f26d1a49196866ce04efc42c1d90b18b046af5fda8b9ff0a"}
{"path":"packages/business/src/role.mjs","sha256":"b10af84d7422da4d0e8c0a4fea1064eebbc2fac6a838a1b3939b554e22dedfc9"}
{"path":"packages/business/src/util.mjs","sha256":"e1f0e70a4bbba8ae2ad6185ab61770b15acda403e90fc708e13027a1e9ec663c"}
{"path":"packages/business/src/vars.mjs","sha256":"f6b15ee8dad2d985c0ae66b1f106ca46cb56ec86ac8cd5dec8a05c887596a421"}
{"path":"packages/business/src/credentials.mjs","sha256":"c3422b1e144177f9dd3015ac036ee1d2cde02bd2b3be406364f3b3f45d8c9b73"}
{"path":"packages/business/src/business.mjs","sha256":"aaa4578fd4133f64119de6c8786a14759240a8910677529fdeae57173058b7d9"}
{"path":"packages/business/src/launch.mjs","sha256":"0aa94dbd14acd379a4837cc3e70b9618b3fa797d74124314e7245a8a3070e98c"}
{"path":"packages/library/src/mapping.mjs","sha256":"c83c626c7cdc2a00ba4217c34b889ca0517cd2022d1f8fc9e7d3a14a0293a802"}
{"path":"packages/library/src/problems.mjs","sha256":"0c8764b03dae0150c56af74bcb113cf583dcbe1fa0c6f7386ef2d48d59a6bd31"}
{"path":"packages/business/src/access.mjs","sha256":"af028c999a6ab4d42b321c3f047e683b226c7ad232a2ae9cfc623b7dd5a4dd5f"}
{"path":"packages/business/src/project.mjs","sha256":"9472996134c520c31971e66006d1c1683709f6df4f76fe3445bdc97a18637eff"}
{"path":"packages/business/src/resolve.mjs","sha256":"712183465fee099606223d84423afc54e3386a0c8e468c68d5ac39c1e676d109"}
{"path":"packages/business/src/library-seats.mjs","sha256":"93a7fddac9a08b5f740a0a277b29b8a3459e6f5a4fd33a37212437cb456b9b62"}
{"path":"packages/business/src/launch-settings.mjs","sha256":"e14d73f719664499d809909962a6ecc16d4ffb9d824fcdee699e0778809d9e96"}
{"path":"packages/business/src/organization.mjs","sha256":"fa4ba1ae878cd27287865fa12115f8a6c1175a2dfd1011d5f8aca11e46e669c7"}
{"path":"packages/library/src/limits.mjs","sha256":"98ef45ed61144aaea44d8aea1ac43082b6d340297e46846d01772da38728e530"}
{"path":"packages/seat/src/session.mjs","sha256":"c37a6ef6f6d2b4e61443e77d800656bf31e38913bf7dbdc4ca955f4a83b13a41"}
{"path":"packages/seat/src/sandbox.mjs","sha256":"0868f393f6fb117d430428ec390e435359737eae0792b4a4d1f54797c7a6c1bf"}
{"path":"packages/seat/src/seat.mjs","sha256":"eec970961a667c9e614d1474d33c31a019b2cf1b0bf931a51458d874bca13a15"}
{"path":"packages/cli/src/boot-status.mjs","sha256":"147a17bbdcbc34efe20a88a4cabe796c101cb63dce621d28103f4de29def4cc2"}
{"path":"packages/cli/src/cli.mjs","sha256":"1e663b175e18e39ff68c9ac3a65ff71fc777a6c37ebca035fce6a2783d0aaac3"}
{"path":"packages/discord/src/binding.mjs","sha256":"5ab69c4111dd9589a197172ffe6968bf414f41c552b7910e5478a27c446cfaec"}
{"path":"packages/discord/src/web.mjs","sha256":"e5a7b64720872b12b34223549537ace05ebf0ca8a29b2f844d2b7c5cc9ea41f7"}
{"path":"packages/discord/src/setspark.mjs","sha256":"ba09d286e707860afa53300f8802ac8e6193ab2d2e7abe9d2b07cbdef3822387"}
{"path":"packages/discord/src/errors.mjs","sha256":"917b0e6c4f100e93f056b925e38d97eacdd8b2596e39fbd3f88c0b62b973d8ed"}
{"path":"packages/discord/src/tools.mjs","sha256":"975503616245bb6051f06ecbf47436ce7d030f21af23042df7f3341062df967f"}
{"path":"packages/discord/src/git.mjs","sha256":"c28e04a0055997ea0b34bea1ad2912adb248d5fd43713df1e6f5a661d87949b7"}
{"path":"packages/cli/src/project.mjs","sha256":"6cfe7fd5086ddb59c5666060c6f8044c2852e0f3d5755b1fa206f7521173f300"}
{"path":"packages/project/src/index.mjs","sha256":"3ab38cc40ce9ed1a714a59a1f2c336c3792a59431a6a9cc655ba6a2f47513899"}
{"path":"packages/project/src/paths.mjs","sha256":"bd9debcf3f9bb92560e74f220a0b108dfe24154bc6d1fb03c5ec414356d451f9"}
{"path":"packages/project/src/git.mjs","sha256":"af6865a4cace92ef27910098507ffedfc8dfe768cea088b1fee21d0876cc556e"}
{"path":"packages/seat/src/checkout.mjs","sha256":"5aca02491fe8df51487968ce62c776d493d0fe693cc41478b84bef7b49c8948d"}
{"path":"packages/processing-control/src/effects.mjs","sha256":"3bc600649267f011e21ed8266fb16927b0ad3a0e2c49e4b54062d34c544d0c17"}
{"path":"packages/processing-control/src/runtimes.mjs","sha256":"7145420aa354180689a5c84423928fc60c8123476dcfed3364c9cf4542f8c7ea"}
{"path":"packages/project/src/validate.mjs","sha256":"e49ab5e825f0706da2f3c8dfcf33c1331a38d77ca2d35b03359ee68ea74652c5"}
{"path":"packages/project/src/read.mjs","sha256":"42113cd20eb8f04dd252f9963a6f1a84806af9cae7beb6808c4d584a2548220c"}
{"path":"packages/cli/src/config.mjs","sha256":"d960c2a9df3f7c84deff22dad1f0ab120f95ee365984e390de98eba7292b65a1"}
{"path":"packages/bus/src/business.mjs","sha256":"ff927da3cf22fbacc9ace77b2e8b803bffc2953fb58cf7ab4e5f6f6493732996"}
{"path":"packages/cli/src/access.mjs","sha256":"c4949a16173d11f9d32d10d3ddd58a181631848b259bef1998820a78f5694808"}
{"path":"packages/cli/src/format.mjs","sha256":"481d9956698df7765ca8556d57164fb78f131708a09900d5a55b9048b5638f5f"}
{"path":"packages/cli/src/thread.mjs","sha256":"58888b7731f8009d4c3f8be2caf4445f13dd8f534e1633f6e2720b259fcc3f92"}
{"path":"packages/cli/src/session.mjs","sha256":"1a30048032f5bb64419ae9716a1692978bc1a137220a094d1900298aca6ba1d7"}
{"path":"packages/cli/src/limits.mjs","sha256":"2f291a71f490f2741edada7a3e3788500f8976a08eb8ab1411f6c5982f778260"}
{"path":"packages/business/src/migrate-launch.mjs","sha256":"44fa089c9024934a2f9fb5ef99552eb18d616842210cbc0fc860ea32ce0b1524"}
{"path":"packages/cli/src/plugins.mjs","sha256":"f8d9fc24ccd71494fb2914914949cb08948ae93fb3180b9531eb807c921a6f53"}
{"path":"packages/cli/src/model-proxy.mjs","sha256":"9a043f122e1d49103bab64716d0eb80cfc09da3c91f7e2eb014b0d8ff0b02f3d"}
{"path":"packages/model-proxy/src/fetch.mjs","sha256":"00378d2ea95ac4945899696462f8ff4c70dc020cc58d93663d731d2f2f333783"}
{"path":"packages/model-proxy/src/common.mjs","sha256":"a6fb88352018b8f21593a0bb9311f87162c80d8b1e05e62b4d43b1e69af21b23"}
{"path":"packages/model-proxy/src/settings.mjs","sha256":"1eac4b5741b360a077bb1c871c008b64f7c7119afc64be4d6e4a0dcdb3a313bb"}
{"path":"packages/cli/src/credentials.mjs","sha256":"19755f7bb002d8455990c5dc7c458e64aeb95252ec7231a2ed2fd9c638fcb511"}
{"path":"packages/cli/src/hosts.mjs","sha256":"60419503898f5e7f3046df5e749098728fbdfea76eb5c53b5dc9b909329abe2e"}
{"path":"packages/cli/src/grants.mjs","sha256":"b586907ca8f351f60dc19ec2683df75d2d70ddb12955d09fb14560c9d3bed3dc"}
{"path":"packages/cli/src/instances.mjs","sha256":"8d6dab8da62b4458477572ca1956adad57bc0b0d308df6eae57477175c345d7a"}
{"path":"packages/plugins/src/channel.mjs","sha256":"5fcecf8336ee247e8ac2f626b21e4c79b1edc49082eadfd536cd23016c6bb756"}
{"path":"packages/plugins/src/loader.mjs","sha256":"2e99f9222424cf9503253701568f0bb5ef579a22930f9f224e5b63ad6b4f745f"}
{"path":"packages/cli/src/launcher.mjs","sha256":"373d4c028dfa6d85c748d56f56359789fe2b81987f522ac23747fd37bb5478ed"}
{"path":"packages/cli/src/model-stall.mjs","sha256":"0bdc91dcaa096bd3dc9d08a1dea59893a21f6505c843e698ad9c8daa4b74364b"}
{"path":"packages/harness/src/bundle.mjs","sha256":"e944a4c7a26d1fe55e13ac1eca31dd86c302dc7c868224b8b000b27255976153"}
{"path":"packages/harness/src/tools.mjs","sha256":"38fe84040a78c3f8a8dcde4339d88db3b5df9ef669d605ad1d92ff3e8b646b40"}
{"path":"packages/seat/src/compactions.mjs","sha256":"c5de99284b8fa61763b8dd30a58809bbc086529eeb10587586d52b0df2754774"}
{"path":"packages/cli/src/git-socket.mjs","sha256":"3076a53b9891d4d0e084306567b88ded12c4de53a943c029646a424bf59d8e49"}
{"path":"packages/seat/src/landing.mjs","sha256":"6f7c938a32b349ee49ce95b89ad499e599f6016e5e9d7efd79a9ea4177b4d175"}
{"path":"packages/seat/src/working.mjs","sha256":"621f5c223811444336f0f5d6ad10bc7afce075491653c0527d6c26ca568b79c3"}
{"path":"packages/cli/src/app.mjs","sha256":"15a8ee212fc37cea28e389f60ddb8916f9e1509cdcfb2e522acfe548702a16dc"}
{"path":"packages/cli/src/screens.mjs","sha256":"9d03335628ae62e85c5fbc08c2e739ed0bd43b10d486faf397129a56a1b343e0"}
{"path":"packages/conversation/src/terminal.mjs","sha256":"c24d28a073659640b8b027eb12ad150ba895c3001091b892ecef2ec1da40d5cd"}
{"path":"packages/conversation/src/client.mjs","sha256":"a45beb82438bb42d97d1e322010e175e785767664e548b90c4125e98b7660003"}
{"path":"packages/conversation/src/framing.mjs","sha256":"eaf0772b60bb17fbf9548267c9cfeb0104f92f5cbafdfcb60c1633883eec6432"}
{"path":"packages/conversation/src/records.mjs","sha256":"96f7b64c2e2c3493e270224542818fd14f042e3cf0ac14788b3f881010bc25b1"}
{"path":"packages/conversation/src/parts.mjs","sha256":"da336ed2a2a149ff56ac12af2440a8353d4573c33e9069381be60f1a0ca70151"}
{"path":"packages/conversation/src/transcript.mjs","sha256":"f834ee740e7149e7d2ed976112d0719ce0660270e3b61cf93e1774d112c992a2"}
{"path":"packages/cli/src/usage.mjs","sha256":"f9e0c69849633ae36a7a6aa22729a690dc40292178ac3db43accbb131fd7b4ca"}
{"path":"packages/tasks/src/fields.mjs","sha256":"c9a883e9a1649277edce97adca40bca2874df7b5312c70e4ac6f6d4a1c860841"}
{"path":"packages/webui/src/chat-http.mjs","sha256":"3a5321a5f492a98d342e4ddcc1e9da3522cfff89a4f9bc3f51d2ab1426d3de1b"}
{"path":"packages/webui/src/processing-http.mjs","sha256":"c3825a02c3b4f4e5537db4a945439d707e177e74c3e8b1fc2cb777515e610b64"}
{"path":"packages/webui/src/decision-http.mjs","sha256":"93d4d0c36d0b74eaace24bce4c3e7179b7418377eb4df6d0f6a9ca89d5eb8e39"}
{"path":"packages/webui/tests/fixture.mjs","sha256":"b35d3f3471d6d83ef2d19d6102eaecce2ddec9330f337d7194f1d7be03cbd216"}
{"path":"packages/control-board/src/serve.mjs","sha256":"2eb25c46e85ddadd3bdbdbe605db54a6e09845155384a209622554d78307e583"}
{"path":"packages/control-board/src/scan.mjs","sha256":"6d74b131af360268be748a1f8f7f2b3f5a9180365e7279426640883fc295a676"}
{"path":"packages/control-board/src/discord.mjs","sha256":"8966f1f98ea81b4525345fc4889db5e0e5263ca41b5132ac8dd9bd99a2c88522"}
{"path":"packages/discord/src/journal.mjs","sha256":"12684e926574c3fe7f693a03b60d1393df483f5feb4b47c9dd7c5a7ac050aec5"}
{"path":"packages/conversation/src/reader.mjs","sha256":"75d0cc982c36b0a81ff23f0da9da1b56906c496250a043f91d3a3b18ffa8e51b"}
{"path":"packages/conversation/src/safe-fs.mjs","sha256":"62b0f7e9f798f584fcc0e4ead0522e44fd113bd0803f2bad92ffa480cadb7527"}
{"path":"packages/conversation/src/pi.mjs","sha256":"20e781240846298fa65f9a8226b5e1ee1e81338b81229334666d845c17c99ac1"}
{"path":"packages/project/schemas/project.schema.json","sha256":"f069c012e9660d5d0491a21f98e936b725f6818e1c3136dfec61b3c800bd58de"}
{"path":"packages/project/schemas/requirement.schema.json","sha256":"79a1e7b567af7162bb88ca69861075fc579a858e8aec4e49824ccdc370b690c3"}
{"path":"packages/project/schemas/decision.schema.json","sha256":"925bb03ac99e5845e4bfa20b4561a331f034f88e187db82213df6602a7ceee4b"}
{"path":"packages/model-proxy/PIN","sha256":"889ac9589fadf7654d4dbb914f968cbafe4255ed215bd6a9ff3f331757c9017b"}
@@ -0,0 +1,202 @@
06794536ac746e9cf02ca698838cd5355987b29fd6a18a8fb3b51464c41f10c1 agents/codex/work/queue-333/trace-inputs.mjs
a2ba3a46f12e56139ecae9e55227d00847842aedec50c1d92aaae28844ca48e7 packages/bus/schema.sql
232a1c77c2f17011c53b55fc6052f70985598210769d41d7c2c0b535328aad23 packages/bus/src/address.mjs
c0144adade79c2cfc6b8247721393f0250b1d64f6c6c04d85738cb80939c42e5 packages/bus/src/broker.mjs
ff927da3cf22fbacc9ace77b2e8b803bffc2953fb58cf7ab4e5f6f6493732996 packages/bus/src/business.mjs
f3d483f61a24cbc9cce235e1e92889f09b8cecf513fcaf90c741f316f62262e2 packages/bus/src/client.mjs
86b4321dd436b97e389101873197dbab95b3d2202e5ef7da712c4978f4f9159f packages/bus/src/credential-verbs.mjs
10485afcf94c29ac9f3d5ba30b12248a2379efd69185ff9fb90e9fed25fe0678 packages/bus/src/credentials.mjs
27d7d5322c2f12641e350867d3ac6f838b33832951e69f057e3a7a28b8ac4d5b packages/bus/src/gitea-grant.mjs
48337cdbc41d503f17962d3e3ad014183b1286165f97da6fd88b4faa50be3949 packages/bus/src/host-grant.mjs
324c05b16253e0fcfc1a0299d1d8ab45850ea723fad1f67bcc07fc031f50d593 packages/bus/src/host-run.mjs
bb13c146717cdc46d75d157177e400edac4d3e10f14fe511027a25fd44cec885 packages/bus/src/human.mjs
56bfc8dcba476886d7de61a1e798aae8e3041c2434c62d44fc40a168d22bb3bd packages/bus/src/interpreter.mjs
9919febc7679168e0a72c0ef51983120283e595fea290a5e8e948409bf5c911b packages/bus/src/landing.mjs
18c1aacd280ebf0f200d5e6fc1dd1a7e098a3046c1cb8427140bb2198ac81cd3 packages/bus/src/limits.mjs
b753f630301bf125e9e286b4156d0736930dd8fb9cd8eb2ebf316688f9191a07 packages/bus/src/migrations/3b-3c.sql
179ffe356d4ff19a49b5ebad39b6c6bfd7771deb8e1b7c55b5e746f039d69e65 packages/bus/src/migrations/3b.sql
0423832d05aa68f9191d7362827bd19310001165b895fb2de40b962fe68f9d56 packages/bus/src/migrations/3c-3d.sql
d9aacc974d5047790e65c30a90068259bb9396dc92d4904eae3b9c5dbbb2f077 packages/bus/src/migrations/3d-3e.sql
bf0b72c606b1a56a1610f09619b0c1118f1f300c636824ea13fd51a4ca6ac4b3 packages/bus/src/migrations/3e-3f.sql
82f54b264919e34282bc214e34e9849f701cd3723b9b2f0a0d107c16f939dc05 packages/bus/src/migrations/3f-3g.sql
76168e4f9f6b427286ddb8402fd833acadb01d6325a85f60e9ccf8d42fe2d1d0 packages/bus/src/migrations/3g-3h.sql
e058e6cea8da7b6e649f3e03f2b81dc5444ee940a64274d0e367124c93545035 packages/bus/src/migrations/3h-3i.sql
5ad122ca950e43e066f3d9ed215e73353e6b26de6687b961a8818d69c9465031 packages/bus/src/migrations/3i-3j.sql
2e2bb1fe70076f5e24406a18a923b9e55c4192178a0a704a1b9716032676f9d4 packages/bus/src/migrations/3j-3k.sql
eb2822c73e527697399691ae520092277ddbd4d2a9a42a0731b3c81cc3569e58 packages/bus/src/migrations/3k-3l.sql
791879f06a3e97d3cfbe6112e2fb6502457af30b3e0198e3da1192038906d156 packages/bus/src/migrations/3l-3m.sql
b40bc6a7bedc459d6827cbf0414619e48fc5dce2febdeff70a647345f2281c3a packages/bus/src/migrations/3m-3n.sql
b4e11975bd56db4c816ada297902f033b3db7754d4a05319f03d640e17374550 packages/bus/src/model-keys.mjs
29c88655e8b9aed8db604573c9213fd9f3c40ef35ff04f4eda8fbe8f1b8a32d7 packages/bus/src/peercred.mjs
2b1e18be825e8264b16506d6294863acbba812956cfdf8e056f21faaa94f7137 packages/bus/src/principal.mjs
ed13afdce6359df31d35a79496ebb4afdefef82030a8326a76b2a25b37e98d9d packages/bus/src/process.mjs
cec059ea4bef5ef62f6181123bfe64bca21d8985d5357471da8c0a3199a877f9 packages/bus/src/proxy-page-vocabulary.mjs
af36aae674f46a4e5eacfe176fde8b58cd0b171a6d70e07ee6d479e0f558cce7 packages/bus/src/proxy-page.mjs
5a6c3707e6a64304cfd37f1875eb378c6eb58bf438cc40365fe913eaec7cee59 packages/bus/src/proxy-usage.mjs
969d04eb06b97093c7f9f0dfa6b51084c781e967e2668814083bbba84a2af7b6 packages/bus/src/runtime.mjs
8318bed9168ac3f58c09de40a139b68aacefd684e6c117406e181e2ca5ab4ec7 packages/bus/src/server.mjs
dd7fce9706402efd1c5a5b81f7d0fa3793de203e7a6aef4e118e934aebdc7c84 packages/bus/src/store.mjs
5e9e08ca8069e1de35232f26d48a77792388128dda659893909f2d34b5af2346 packages/bus/src/tester.mjs
4ae57d053c4b217e1c1a22ada3ed1c5d4a3f0e61b8d2798e9db37997cd071a29 packages/bus/src/usage.mjs
1f31aefa71984fba90c5390df5cc595d929681965f57485ad4972143d5c4b15f packages/bus/src/views.mjs
68efa3c9d0a72095f503208ed5c2e660ef9bca68d3ea15f0fc2f1826a68e09cc packages/bus/src/web.mjs
dbbfa80b4082fd44e2f08539b5455653fac062321b8f2106f638e2d8161fa3eb packages/bus/tests/daily-quota-runtime.test.mjs
45870a4903d1996915c0086a6beb4d0a4c75b38386b7c5e6d98b5bc811c3b541 packages/bus/tests/limit-checks.test.mjs
561d0950b788d08ad9a79ccd6572ad6976ba4b2e2b1c79d1e4d06827a84c131b packages/bus/tests/limit-stop.test.mjs
a2e553025edbe6e930c9d03b48289c53b51b153ac9ae49bb21bf721b725f1913 packages/bus/tests/limits-runtime.test.mjs
e37114eab9c5f21015ea8e429f0574d3ea34b06263f1e42b83b31b8d2df222a7 packages/bus/tests/p5-key-context.test.mjs
241e779016ffd0b54c5646cb4fac7e21ea1167e77afbd652ff4e01f8d238f99c packages/bus/tests/p5-runtime.test.mjs
895ffddbcca1b38fdaa17eefdeca9092a9b9a934d3a54a3bf7857f42fe99fba7 packages/bus/tests/plugins-verb.test.mjs
84c8351029272b6ee05e7fd81b4cc4453553ceeb7a5127a1333dae63d1336ad5 packages/bus/tests/proxy-usage.test.mjs
4b2149ea4219f49db19669ada9f88931f7691cdd73dd27dceec6e8fe1f76dd0c packages/bus/tests/usage-broker.test.mjs
5abe93fca8442f06ff68760623e91262d863e1191fa35a3d0c87d7b0e6c0a4c6 packages/bus/tests/usage-runtime.test.mjs
2613ba0561572a7d4f753066922fddc90cca812cb0ce2b3e0a9a4d249a15e340 packages/bus/tests/usage.test.mjs
af028c999a6ab4d42b321c3f047e683b226c7ad232a2ae9cfc623b7dd5a4dd5f packages/business/src/access.mjs
aaa4578fd4133f64119de6c8786a14759240a8910677529fdeae57173058b7d9 packages/business/src/business.mjs
c3422b1e144177f9dd3015ac036ee1d2cde02bd2b3be406364f3b3f45d8c9b73 packages/business/src/credentials.mjs
cd4eb5960c17ce32f26d1a49196866ce04efc42c1d90b18b046af5fda8b9ff0a packages/business/src/errors.mjs
e08b11b70b54f13e3b18996dd903f841e04fd6c64791e96063df8b164c663882 packages/business/src/hosts.mjs
a386ce5bd1d41d86f7b90641a423a2b651b491c8989d5085412c7d202ac1cb30 packages/business/src/index.mjs
09f2bde85a6d7a8f0b1d1c60ac589b845b0c95e991b2f807758878416b13c6bd packages/business/src/instance-settings.mjs
e14d73f719664499d809909962a6ecc16d4ffb9d824fcdee699e0778809d9e96 packages/business/src/launch-settings.mjs
0aa94dbd14acd379a4837cc3e70b9618b3fa797d74124314e7245a8a3070e98c packages/business/src/launch.mjs
93a7fddac9a08b5f740a0a277b29b8a3459e6f5a4fd33a37212437cb456b9b62 packages/business/src/library-seats.mjs
44fa089c9024934a2f9fb5ef99552eb18d616842210cbc0fc860ea32ce0b1524 packages/business/src/migrate-launch.mjs
fa4ba1ae878cd27287865fa12115f8a6c1175a2dfd1011d5f8aca11e46e669c7 packages/business/src/organization.mjs
9d2c68dd21c6c9553af75f4b137c4f169e95761f32528767e0518d0313311f50 packages/business/src/plugin-settings.mjs
9472996134c520c31971e66006d1c1683709f6df4f76fe3445bdc97a18637eff packages/business/src/project.mjs
712183465fee099606223d84423afc54e3386a0c8e468c68d5ac39c1e676d109 packages/business/src/resolve.mjs
b10af84d7422da4d0e8c0a4fea1064eebbc2fac6a838a1b3939b554e22dedfc9 packages/business/src/role.mjs
e1f0e70a4bbba8ae2ad6185ab61770b15acda403e90fc708e13027a1e9ec663c packages/business/src/util.mjs
f6b15ee8dad2d985c0ae66b1f106ca46cb56ec86ac8cd5dec8a05c887596a421 packages/business/src/vars.mjs
de1f04628e400084a46e77fd7e03c7a039f0f80c9e07bb486c9c012f187aa3eb packages/business/src/vocabulary.mjs
a6a9971b42ddf176d9415caee3efc2eb16791dead5f0f0557d28449a550aefa1 packages/business/tests/helpers.mjs
f0dfe004905dce31317d85d89a05802db878c3472e765e85dc9f1e04166e1df6 packages/business/tests/plugin-settings.test.mjs
bc6b3a31e8918d70aced7151b91ac4b39afec4081054024b162acb0e8f8fae07 packages/business/tests/token-limit-settings.test.mjs
c4949a16173d11f9d32d10d3ddd58a181631848b259bef1998820a78f5694808 packages/cli/src/access.mjs
15a8ee212fc37cea28e389f60ddb8916f9e1509cdcfb2e522acfe548702a16dc packages/cli/src/app.mjs
147a17bbdcbc34efe20a88a4cabe796c101cb63dce621d28103f4de29def4cc2 packages/cli/src/boot-status.mjs
1e663b175e18e39ff68c9ac3a65ff71fc777a6c37ebca035fce6a2783d0aaac3 packages/cli/src/cli.mjs
d960c2a9df3f7c84deff22dad1f0ab120f95ee365984e390de98eba7292b65a1 packages/cli/src/config.mjs
19755f7bb002d8455990c5dc7c458e64aeb95252ec7231a2ed2fd9c638fcb511 packages/cli/src/credentials.mjs
c7bdd98a3ddeeb9bc4415d907b92555d723c566eba314075d91486da9b5e85dc packages/cli/src/errors.mjs
481d9956698df7765ca8556d57164fb78f131708a09900d5a55b9048b5638f5f packages/cli/src/format.mjs
3076a53b9891d4d0e084306567b88ded12c4de53a943c029646a424bf59d8e49 packages/cli/src/git-socket.mjs
b586907ca8f351f60dc19ec2683df75d2d70ddb12955d09fb14560c9d3bed3dc packages/cli/src/grants.mjs
a0936aee783ff47dd58fc907fefd86f63e571809a3ce5b0d6d931f71e756b15e packages/cli/src/host.mjs
60419503898f5e7f3046df5e749098728fbdfea76eb5c53b5dc9b909329abe2e packages/cli/src/hosts.mjs
8d6dab8da62b4458477572ca1956adad57bc0b0d308df6eae57477175c345d7a packages/cli/src/instances.mjs
373d4c028dfa6d85c748d56f56359789fe2b81987f522ac23747fd37bb5478ed packages/cli/src/launcher.mjs
2f291a71f490f2741edada7a3e3788500f8976a08eb8ab1411f6c5982f778260 packages/cli/src/limits.mjs
9a043f122e1d49103bab64716d0eb80cfc09da3c91f7e2eb014b0d8ff0b02f3d packages/cli/src/model-proxy.mjs
0bdc91dcaa096bd3dc9d08a1dea59893a21f6505c843e698ad9c8daa4b74364b packages/cli/src/model-stall.mjs
f8d9fc24ccd71494fb2914914949cb08948ae93fb3180b9531eb807c921a6f53 packages/cli/src/plugins.mjs
6cfe7fd5086ddb59c5666060c6f8044c2852e0f3d5755b1fa206f7521173f300 packages/cli/src/project.mjs
9d03335628ae62e85c5fbc08c2e739ed0bd43b10d486faf397129a56a1b343e0 packages/cli/src/screens.mjs
1a30048032f5bb64419ae9716a1692978bc1a137220a094d1900298aca6ba1d7 packages/cli/src/session.mjs
58888b7731f8009d4c3f8be2caf4445f13dd8f534e1633f6e2720b259fcc3f92 packages/cli/src/thread.mjs
662642a8ce739fcb6c188ad07125a94e008c8a305eced127c8041d472c56e55b packages/cli/src/transport.mjs
f9e0c69849633ae36a7a6aa22729a690dc40292178ac3db43accbb131fd7b4ca packages/cli/src/usage.mjs
8966f1f98ea81b4525345fc4889db5e0e5263ca41b5132ac8dd9bd99a2c88522 packages/control-board/src/discord.mjs
6d74b131af360268be748a1f8f7f2b3f5a9180365e7279426640883fc295a676 packages/control-board/src/scan.mjs
2eb25c46e85ddadd3bdbdbe605db54a6e09845155384a209622554d78307e583 packages/control-board/src/serve.mjs
a45beb82438bb42d97d1e322010e175e785767664e548b90c4125e98b7660003 packages/conversation/src/client.mjs
eaf0772b60bb17fbf9548267c9cfeb0104f92f5cbafdfcb60c1633883eec6432 packages/conversation/src/framing.mjs
da336ed2a2a149ff56ac12af2440a8353d4573c33e9069381be60f1a0ca70151 packages/conversation/src/parts.mjs
20e781240846298fa65f9a8226b5e1ee1e81338b81229334666d845c17c99ac1 packages/conversation/src/pi.mjs
75d0cc982c36b0a81ff23f0da9da1b56906c496250a043f91d3a3b18ffa8e51b packages/conversation/src/reader.mjs
96f7b64c2e2c3493e270224542818fd14f042e3cf0ac14788b3f881010bc25b1 packages/conversation/src/records.mjs
62b0f7e9f798f584fcc0e4ead0522e44fd113bd0803f2bad92ffa480cadb7527 packages/conversation/src/safe-fs.mjs
c24d28a073659640b8b027eb12ad150ba895c3001091b892ecef2ec1da40d5cd packages/conversation/src/terminal.mjs
f834ee740e7149e7d2ed976112d0719ce0660270e3b61cf93e1774d112c992a2 packages/conversation/src/transcript.mjs
5ab69c4111dd9589a197172ffe6968bf414f41c552b7910e5478a27c446cfaec packages/discord/src/binding.mjs
917b0e6c4f100e93f056b925e38d97eacdd8b2596e39fbd3f88c0b62b973d8ed packages/discord/src/errors.mjs
c28e04a0055997ea0b34bea1ad2912adb248d5fd43713df1e6f5a661d87949b7 packages/discord/src/git.mjs
12684e926574c3fe7f693a03b60d1393df483f5feb4b47c9dd7c5a7ac050aec5 packages/discord/src/journal.mjs
8fa9968862dff77fa6d8be5210c22d13712fd622a8cbc722d167be5be80d0783 packages/discord/src/processing.mjs
ba09d286e707860afa53300f8802ac8e6193ab2d2e7abe9d2b07cbdef3822387 packages/discord/src/setspark.mjs
975503616245bb6051f06ecbf47436ce7d030f21af23042df7f3341062df967f packages/discord/src/tools.mjs
e5a7b64720872b12b34223549537ace05ebf0ca8a29b2f844d2b7c5cc9ea41f7 packages/discord/src/web.mjs
e944a4c7a26d1fe55e13ac1eca31dd86c302dc7c868224b8b000b27255976153 packages/harness/src/bundle.mjs
a74ef2db4093c0c797ba9e7e28e4e4df0ceac9040385f00e60a273f39af9610b packages/harness/src/gate.mjs
38fe84040a78c3f8a8dcde4339d88db3b5df9ef669d605ad1d92ff3e8b646b40 packages/harness/src/tools.mjs
f710d9600a17f6e2989a289cfe84e58f161d86c7306605946ce05fa71b364eb2 packages/library/src/guard.mjs
70c1fe75cb2149c9a074d55a6301d5b66157c2dc2e777b92bac338cce09d89c7 packages/library/src/index-build.mjs
98c2c2877549c3e2c5963ec4e49d99ab3b6d6ad54fb3bfae86cf98542207157e packages/library/src/index.mjs
98ef45ed61144aaea44d8aea1ac43082b6d340297e46846d01772da38728e530 packages/library/src/limits.mjs
def32a176cb70c86248e45908edde22f9c4c5f88575a4af0a396a05f617358bc packages/library/src/links.mjs
c83c626c7cdc2a00ba4217c34b889ca0517cd2022d1f8fc9e7d3a14a0293a802 packages/library/src/mapping.mjs
26b824d6885e5c6d1b8bd71e754a9fa333c26307693f7e6a0c6a8e6300ecb4ae packages/library/src/mirror.mjs
0c8764b03dae0150c56af74bcb113cf583dcbe1fa0c6f7386ef2d48d59a6bd31 packages/library/src/problems.mjs
bafe113bee70f17bd249876d6bdd1c08fa051223c2111955e5d5f275bd76bba0 packages/library/src/query.mjs
ea126533afb7e74b71419eb943febb6b242eb96fc6917d9df1019db3e7e6ce8d packages/library/src/reader.mjs
bfc3de029d3c8f0dcc96c90fde30d6da58bbb5b72d8f13e3f536c0d735c73ca5 packages/library/src/render.mjs
7b46f47b5e9d6b554b5d39bce2cd95c4610f5f35b8ab8fdc5a2864b3214be809 packages/library/src/reply-protocol.mjs
97e12255f52ad638eeacd152eb26822f9a2aa72cd30e2fed1193f51cd6e56192 packages/library/src/scope.mjs
6a3b4de2070e62b1cca1c0ab20f2883d3153fc61608d1bf7670cecea08765b4c packages/library/src/supporting.mjs
016bfa5c80572c0baf90ced39cb3d3ec66d395f0be15c2727b9552a9dd849093 packages/library/src/survey.mjs
a58f3aec5ed9b3530b363e2fdbd38bc9ded7635d261ab2fca3cb31c45dcd3dfa packages/library/src/sync.mjs
a301b7c7e3f42f66cb69d88991220f4e236f25a6e5951c61e79ec4ef2b714198 packages/library/src/write.mjs
889ac9589fadf7654d4dbb914f968cbafe4255ed215bd6a9ff3f331757c9017b packages/model-proxy/PIN
f5f86cad661034f223a76352d877fa8d7883bfa921a7a01282347a9a03272441 packages/model-proxy/src/client.mjs
a6fb88352018b8f21593a0bb9311f87162c80d8b1e05e62b4d43b1e69af21b23 packages/model-proxy/src/common.mjs
00378d2ea95ac4945899696462f8ff4c70dc020cc58d93663d731d2f2f333783 packages/model-proxy/src/fetch.mjs
1eac4b5741b360a077bb1c871c008b64f7c7119afc64be4d6e4a0dcdb3a313bb packages/model-proxy/src/settings.mjs
e66453cf6662677cf28cbad1ae8f7509917d333e5b80404ab02c53f5cf75e9e1 packages/model-proxy/src/validation.mjs
77327681d6eb51f25d7aeffcc532b7e8269c1dc59139cb03adb4a3a1409f63e9 packages/model-proxy/tests/client-probe.test.mjs
790c6a50ec030a8b27a28fac7fd129bd9eabe79774adf11d6620c00df9b6ae86 packages/model-proxy/tests/client.test.mjs
95e39a519f7ac8b9592876e6157191169f9b14d002163867a6ff6ab808e42c14 packages/model-proxy/tests/management-key-encoding.test.mjs
f24e1d121a340cbcaa3f6cd6390eeb7d4b05f778dd498d76ba099cba5a719dea packages/model-proxy/tests/page-client.test.mjs
1ad66d56800a31cfbd387939e640653bc72150f4e73822d9e3c777b3bffbf1e1 packages/model-proxy/tests/usage-client.test.mjs
a317ac544359d321bb91b67cd87fc6ef431b72df9ac9f7f2a9ff291ed1a9109a packages/plugins/harness/claude-code/index.mjs
aabaf5c4602e28f025c18b2e2ddd6fa0d1648870101a5de0c4424d97b24472dd packages/plugins/harness/pi/compactions.mjs
39c225f157b8f66b416625bda689153505743ffcfdc32964bb1f3d2c6fcb73af packages/plugins/harness/pi/index.mjs
3749b9f6dd681ef424ee7d7e4d80ccee87b3655df8cd8fe9ccd0d505dcaaee9b packages/plugins/limit-check/daily-quota/index.mjs
4d0c6f5f87101f94608c02001a49d62cef113da48c539b2d2488dfbed1a4c524 packages/plugins/limit-check/token-limit/index.mjs
5fcecf8336ee247e8ac2f626b21e4c79b1edc49082eadfd536cd23016c6bb756 packages/plugins/src/channel.mjs
eaa258a1aadadb5a75450fa73fdbcea0b53636adb50ed9a508193d29d564ca78 packages/plugins/src/kinds.mjs
2e99f9222424cf9503253701568f0bb5ef579a22930f9f224e5b63ad6b4f745f packages/plugins/src/loader.mjs
3d4fab56fea4c45c6a317ef41121aa5b6da0502a6ef614b7931f91cafdfc1f71 packages/plugins/tests/daily-quota.test.mjs
5d5e5dccdae3f94b8540d187a8899ec36f9c9933cae3933249c2d8c400c75aa2 packages/plugins/tests/helpers.mjs
f3081e1dbdac20ade2246c743bcbb3934be686f79f378af21c365cd1451893ba packages/plugins/tests/kinds.test.mjs
8588ad7eee0c9ce5de3b53e3b88562812a155a3d791a2bd3413bb1754655d78b packages/plugins/tests/loader.test.mjs
6e96bb96278ec754ca1816a24f49ef677771615ab5cf186ae41969fc2f93d8cc packages/plugins/tests/token-limit.test.mjs
d09ae19db3eb69477783163559bd6a8e5b59a6f5af0eafd62d0e2e3bd325065e packages/plugins/usage-source/transcript/index.mjs
6096a577cd5d7e8bf84fd6b98ab284e2f47d5facebd027548e07e6aeec442f96 packages/plugins/usage/cliproxy-queue/index.mjs
781973277c09133de15fc39be35b372a79066479097d46923c8ab7782f011dcd packages/processing-control/src/containers.mjs
ddc7318297abc4ec4dd03d425820b7323db609e554cfc5341cfdfa6934271e73 packages/processing-control/src/coordinator.mjs
3bc600649267f011e21ed8266fb16927b0ad3a0e2c49e4b54062d34c544d0c17 packages/processing-control/src/effects.mjs
7145420aa354180689a5c84423928fc60c8123476dcfed3364c9cf4542f8c7ea packages/processing-control/src/runtimes.mjs
ed834770fed863cb0c15b75062de1fd63dea940f3b42020b769a7e62b319c8ed packages/processing-control/src/state.mjs
925bb03ac99e5845e4bfa20b4561a331f034f88e187db82213df6602a7ceee4b packages/project/schemas/decision.schema.json
f069c012e9660d5d0491a21f98e936b725f6818e1c3136dfec61b3c800bd58de packages/project/schemas/project.schema.json
79a1e7b567af7162bb88ca69861075fc579a858e8aec4e49824ccdc370b690c3 packages/project/schemas/requirement.schema.json
af6865a4cace92ef27910098507ffedfc8dfe768cea088b1fee21d0876cc556e packages/project/src/git.mjs
3ab38cc40ce9ed1a714a59a1f2c336c3792a59431a6a9cc655ba6a2f47513899 packages/project/src/index.mjs
bd9debcf3f9bb92560e74f220a0b108dfe24154bc6d1fb03c5ec414356d451f9 packages/project/src/paths.mjs
42113cd20eb8f04dd252f9963a6f1a84806af9cae7beb6808c4d584a2548220c packages/project/src/read.mjs
e49ab5e825f0706da2f3c8dfcf33c1331a38d77ca2d35b03359ee68ea74652c5 packages/project/src/validate.mjs
5aca02491fe8df51487968ce62c776d493d0fe693cc41478b84bef7b49c8948d packages/seat/src/checkout.mjs
c5de99284b8fa61763b8dd30a58809bbc086529eeb10587586d52b0df2754774 packages/seat/src/compactions.mjs
6f7c938a32b349ee49ce95b89ad499e599f6016e5e9d7efd79a9ea4177b4d175 packages/seat/src/landing.mjs
382cbf7e0ff336911e288ce858bdbfbec693bc2b69879720d1f0b4c7d8455198 packages/seat/src/proc.mjs
0868f393f6fb117d430428ec390e435359737eae0792b4a4d1f54797c7a6c1bf packages/seat/src/sandbox.mjs
eec970961a667c9e614d1474d33c31a019b2cf1b0bf931a51458d874bca13a15 packages/seat/src/seat.mjs
c37a6ef6f6d2b4e61443e77d800656bf31e38913bf7dbdc4ca955f4a83b13a41 packages/seat/src/session.mjs
621f5c223811444336f0f5d6ad10bc7afce075491653c0527d6c26ca568b79c3 packages/seat/src/working.mjs
80b58323994d70e8bb496d81225aeb3d2cdfda464654b68b3b082e9af1fac5c1 packages/tasks/requirements.json
c9a883e9a1649277edce97adca40bca2874df7b5312c70e4ac6f6d4a1c860841 packages/tasks/src/fields.mjs
38e7b85650247759f06c09fce205b2970b8368bc81491f51dc6b3c90ba2a846d packages/tasks/src/requirements.mjs
4ebf6c2b5d71c23d85cbde83f69aa671058dc2195c9ae4bdda624f6940729d1b packages/webui/src/bus.mjs
3a5321a5f492a98d342e4ddcc1e9da3522cfff89a4f9bc3f51d2ab1426d3de1b packages/webui/src/chat-http.mjs
93d4d0c36d0b74eaace24bce4c3e7179b7418377eb4df6d0f6a9ca89d5eb8e39 packages/webui/src/decision-http.mjs
c3825a02c3b4f4e5537db4a945439d707e177e74c3e8b1fc2cb777515e610b64 packages/webui/src/processing-http.mjs
a09028cd5ca57367f597d0681e84926ca871fd4626769e9947927d949c2b6ab7 packages/webui/src/proxy-http.mjs
3c7a35e25b4c1cfda19ac9466d4b2fbc86c880761a1d04ad3ece8bc485f60f93 packages/webui/src/public/bus.js
46defeb3b4be0e1a22e4b89445872ad6b15cdee182076e9e6222219ae29997f4 packages/webui/src/reads.mjs
7b7bee91604b7bd973027b177de83205db9aed366e694072fc6343b46465b5ba packages/webui/src/serve.mjs
1c1fe0c795adac97f28502564a75f26d5666d9be5ae51169f7dd5bb7741fad16 packages/webui/src/tester-socket.mjs
b35d3f3471d6d83ef2d19d6102eaecce2ddec9330f337d7194f1d7be03cbd216 packages/webui/tests/fixture.mjs
39f50991578b98594183390a00efbca84fda90ef61617eea4215e2c75f90b82c packages/webui/tests/usage-render.test.mjs
f96d06974bc83051c0d5c9000e38161ea0cc231997410bcc6c42ed7f55718dfd packages/webui/tests/usage.test.mjs
5f63ff52aaccf06a0f2415ffdd9d1903c202679cf953bef5266a6841b5e39ab7 roles/assistant.json
@@ -0,0 +1,202 @@
agents/codex/work/queue-333/trace-inputs.mjs: OK
packages/bus/schema.sql: OK
packages/bus/src/address.mjs: OK
packages/bus/src/broker.mjs: OK
packages/bus/src/business.mjs: OK
packages/bus/src/client.mjs: OK
packages/bus/src/credential-verbs.mjs: OK
packages/bus/src/credentials.mjs: OK
packages/bus/src/gitea-grant.mjs: OK
packages/bus/src/host-grant.mjs: OK
packages/bus/src/host-run.mjs: OK
packages/bus/src/human.mjs: OK
packages/bus/src/interpreter.mjs: OK
packages/bus/src/landing.mjs: OK
packages/bus/src/limits.mjs: OK
packages/bus/src/migrations/3b-3c.sql: OK
packages/bus/src/migrations/3b.sql: OK
packages/bus/src/migrations/3c-3d.sql: OK
packages/bus/src/migrations/3d-3e.sql: OK
packages/bus/src/migrations/3e-3f.sql: OK
packages/bus/src/migrations/3f-3g.sql: OK
packages/bus/src/migrations/3g-3h.sql: OK
packages/bus/src/migrations/3h-3i.sql: OK
packages/bus/src/migrations/3i-3j.sql: OK
packages/bus/src/migrations/3j-3k.sql: OK
packages/bus/src/migrations/3k-3l.sql: OK
packages/bus/src/migrations/3l-3m.sql: OK
packages/bus/src/migrations/3m-3n.sql: OK
packages/bus/src/model-keys.mjs: OK
packages/bus/src/peercred.mjs: OK
packages/bus/src/principal.mjs: OK
packages/bus/src/process.mjs: OK
packages/bus/src/proxy-page-vocabulary.mjs: OK
packages/bus/src/proxy-page.mjs: OK
packages/bus/src/proxy-usage.mjs: OK
packages/bus/src/runtime.mjs: OK
packages/bus/src/server.mjs: OK
packages/bus/src/store.mjs: OK
packages/bus/src/tester.mjs: OK
packages/bus/src/usage.mjs: OK
packages/bus/src/views.mjs: OK
packages/bus/src/web.mjs: OK
packages/bus/tests/daily-quota-runtime.test.mjs: OK
packages/bus/tests/limit-checks.test.mjs: OK
packages/bus/tests/limit-stop.test.mjs: OK
packages/bus/tests/limits-runtime.test.mjs: OK
packages/bus/tests/p5-key-context.test.mjs: OK
packages/bus/tests/p5-runtime.test.mjs: OK
packages/bus/tests/plugins-verb.test.mjs: OK
packages/bus/tests/proxy-usage.test.mjs: OK
packages/bus/tests/usage-broker.test.mjs: OK
packages/bus/tests/usage-runtime.test.mjs: OK
packages/bus/tests/usage.test.mjs: OK
packages/business/src/access.mjs: OK
packages/business/src/business.mjs: OK
packages/business/src/credentials.mjs: OK
packages/business/src/errors.mjs: OK
packages/business/src/hosts.mjs: OK
packages/business/src/index.mjs: OK
packages/business/src/instance-settings.mjs: OK
packages/business/src/launch-settings.mjs: OK
packages/business/src/launch.mjs: OK
packages/business/src/library-seats.mjs: OK
packages/business/src/migrate-launch.mjs: OK
packages/business/src/organization.mjs: OK
packages/business/src/plugin-settings.mjs: OK
packages/business/src/project.mjs: OK
packages/business/src/resolve.mjs: OK
packages/business/src/role.mjs: OK
packages/business/src/util.mjs: OK
packages/business/src/vars.mjs: OK
packages/business/src/vocabulary.mjs: OK
packages/business/tests/helpers.mjs: OK
packages/business/tests/plugin-settings.test.mjs: OK
packages/business/tests/token-limit-settings.test.mjs: OK
packages/cli/src/access.mjs: OK
packages/cli/src/app.mjs: OK
packages/cli/src/boot-status.mjs: OK
packages/cli/src/cli.mjs: OK
packages/cli/src/config.mjs: OK
packages/cli/src/credentials.mjs: OK
packages/cli/src/errors.mjs: OK
packages/cli/src/format.mjs: OK
packages/cli/src/git-socket.mjs: OK
packages/cli/src/grants.mjs: OK
packages/cli/src/host.mjs: OK
packages/cli/src/hosts.mjs: OK
packages/cli/src/instances.mjs: OK
packages/cli/src/launcher.mjs: OK
packages/cli/src/limits.mjs: OK
packages/cli/src/model-proxy.mjs: OK
packages/cli/src/model-stall.mjs: OK
packages/cli/src/plugins.mjs: OK
packages/cli/src/project.mjs: OK
packages/cli/src/screens.mjs: OK
packages/cli/src/session.mjs: OK
packages/cli/src/thread.mjs: OK
packages/cli/src/transport.mjs: OK
packages/cli/src/usage.mjs: OK
packages/control-board/src/discord.mjs: OK
packages/control-board/src/scan.mjs: OK
packages/control-board/src/serve.mjs: OK
packages/conversation/src/client.mjs: OK
packages/conversation/src/framing.mjs: OK
packages/conversation/src/parts.mjs: OK
packages/conversation/src/pi.mjs: OK
packages/conversation/src/reader.mjs: OK
packages/conversation/src/records.mjs: OK
packages/conversation/src/safe-fs.mjs: OK
packages/conversation/src/terminal.mjs: OK
packages/conversation/src/transcript.mjs: OK
packages/discord/src/binding.mjs: OK
packages/discord/src/errors.mjs: OK
packages/discord/src/git.mjs: OK
packages/discord/src/journal.mjs: OK
packages/discord/src/processing.mjs: OK
packages/discord/src/setspark.mjs: OK
packages/discord/src/tools.mjs: OK
packages/discord/src/web.mjs: OK
packages/harness/src/bundle.mjs: OK
packages/harness/src/gate.mjs: OK
packages/harness/src/tools.mjs: OK
packages/library/src/guard.mjs: OK
packages/library/src/index-build.mjs: OK
packages/library/src/index.mjs: OK
packages/library/src/limits.mjs: OK
packages/library/src/links.mjs: OK
packages/library/src/mapping.mjs: OK
packages/library/src/mirror.mjs: OK
packages/library/src/problems.mjs: OK
packages/library/src/query.mjs: OK
packages/library/src/reader.mjs: OK
packages/library/src/render.mjs: OK
packages/library/src/reply-protocol.mjs: OK
packages/library/src/scope.mjs: OK
packages/library/src/supporting.mjs: OK
packages/library/src/survey.mjs: OK
packages/library/src/sync.mjs: OK
packages/library/src/write.mjs: OK
packages/model-proxy/PIN: OK
packages/model-proxy/src/client.mjs: OK
packages/model-proxy/src/common.mjs: OK
packages/model-proxy/src/fetch.mjs: OK
packages/model-proxy/src/settings.mjs: OK
packages/model-proxy/src/validation.mjs: OK
packages/model-proxy/tests/client-probe.test.mjs: OK
packages/model-proxy/tests/client.test.mjs: OK
packages/model-proxy/tests/management-key-encoding.test.mjs: OK
packages/model-proxy/tests/page-client.test.mjs: OK
packages/model-proxy/tests/usage-client.test.mjs: OK
packages/plugins/harness/claude-code/index.mjs: OK
packages/plugins/harness/pi/compactions.mjs: OK
packages/plugins/harness/pi/index.mjs: OK
packages/plugins/limit-check/daily-quota/index.mjs: OK
packages/plugins/limit-check/token-limit/index.mjs: OK
packages/plugins/src/channel.mjs: OK
packages/plugins/src/kinds.mjs: OK
packages/plugins/src/loader.mjs: OK
packages/plugins/tests/daily-quota.test.mjs: OK
packages/plugins/tests/helpers.mjs: OK
packages/plugins/tests/kinds.test.mjs: OK
packages/plugins/tests/loader.test.mjs: OK
packages/plugins/tests/token-limit.test.mjs: OK
packages/plugins/usage-source/transcript/index.mjs: OK
packages/plugins/usage/cliproxy-queue/index.mjs: OK
packages/processing-control/src/containers.mjs: OK
packages/processing-control/src/coordinator.mjs: OK
packages/processing-control/src/effects.mjs: OK
packages/processing-control/src/runtimes.mjs: OK
packages/processing-control/src/state.mjs: OK
packages/project/schemas/decision.schema.json: OK
packages/project/schemas/project.schema.json: OK
packages/project/schemas/requirement.schema.json: OK
packages/project/src/git.mjs: OK
packages/project/src/index.mjs: OK
packages/project/src/paths.mjs: OK
packages/project/src/read.mjs: OK
packages/project/src/validate.mjs: OK
packages/seat/src/checkout.mjs: OK
packages/seat/src/compactions.mjs: OK
packages/seat/src/landing.mjs: OK
packages/seat/src/proc.mjs: OK
packages/seat/src/sandbox.mjs: OK
packages/seat/src/seat.mjs: OK
packages/seat/src/session.mjs: OK
packages/seat/src/working.mjs: OK
packages/tasks/requirements.json: OK
packages/tasks/src/fields.mjs: OK
packages/tasks/src/requirements.mjs: OK
packages/webui/src/bus.mjs: OK
packages/webui/src/chat-http.mjs: OK
packages/webui/src/decision-http.mjs: OK
packages/webui/src/processing-http.mjs: OK
packages/webui/src/proxy-http.mjs: OK
packages/webui/src/public/bus.js: OK
packages/webui/src/reads.mjs: OK
packages/webui/src/serve.mjs: OK
packages/webui/src/tester-socket.mjs: OK
packages/webui/tests/fixture.mjs: OK
packages/webui/tests/usage-render.test.mjs: OK
packages/webui/tests/usage.test.mjs: OK
roles/assistant.json: OK
@@ -0,0 +1,26 @@
// Final scoped verification only: records paths/hashes, never file contents.
import fs from 'node:fs';
import { createHash } from 'node:crypto';
import { fileURLToPath } from 'node:url';
import { resolve, relative, isAbsolute } from 'node:path';
import { registerHooks, syncBuiltinESMExports } from 'node:module';
const root = process.env.P5_SOURCE_ROOT;
const target = process.env.P5_INPUT_TRACE;
const read = fs.readFileSync.bind(fs), append = fs.appendFileSync.bind(fs);
const seen = new Set();
function record(path) {
try {
if (path instanceof URL) path = fileURLToPath(path);
if (typeof path !== 'string') return;
path = resolve(path);
const rel = relative(root, path);
if (rel.startsWith('..') || isAbsolute(rel) || rel.startsWith('agents/codex/work/queue-333/receipts/') || rel === relative(root,target)) return;
const sha256 = createHash('sha256').update(read(path)).digest('hex');
const key = rel + ':' + sha256;
if (!seen.has(key)) { seen.add(key); append(target,JSON.stringify({path:rel,sha256})+'\n'); }
} catch {}
}
fs.readFileSync = function(path,...args) { const answer=read(path,...args);record(path);return answer; };
syncBuiltinESMExports();
registerHooks({ load(url,context,next) { const answer=next(url,context);if(url.startsWith('file:'))record(fileURLToPath(url));return answer; } });
record(fileURLToPath(import.meta.url));
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
set -euo pipefail
# Run from the repository root. Explicit current whole files; no package/full gate.
p5root=$(mktemp -d /tmp/p5-scoped-XXXXXX)
trap 'rm -rf "$p5root"' EXIT
mkdir "$p5root/home" "$p5root/config" "$p5root/tmp"
export HOME="$p5root/home" XDG_CONFIG_HOME="$p5root/config" TMPDIR="$p5root/tmp" MOSAIC_CONFIG="$p5root/config/absent.json"
export P5_SOURCE_ROOT="$PWD" P5_INPUT_TRACE="$PWD/agents/codex/work/queue-333/receipts/source-inputs.raw.jsonl"
: > "$P5_INPUT_TRACE"
printf '%s\n' 'serial nice19; private HOME/XDG_CONFIG_HOME/TMPDIR/MOSAIC_CONFIG; unchanged whole-file budgets'
nice -n 19 node --import ./agents/codex/work/queue-333/trace-inputs.mjs --test --test-concurrency=1 \
packages/model-proxy/tests/usage-client.test.mjs \
packages/model-proxy/tests/client.test.mjs \
packages/model-proxy/tests/client-probe.test.mjs \
packages/model-proxy/tests/page-client.test.mjs \
packages/model-proxy/tests/management-key-encoding.test.mjs \
packages/plugins/tests/kinds.test.mjs \
packages/plugins/tests/loader.test.mjs \
packages/plugins/tests/token-limit.test.mjs \
packages/plugins/tests/daily-quota.test.mjs \
packages/business/tests/plugin-settings.test.mjs \
packages/business/tests/token-limit-settings.test.mjs \
packages/bus/tests/usage.test.mjs \
packages/bus/tests/proxy-usage.test.mjs \
packages/bus/tests/p5-runtime.test.mjs \
packages/bus/tests/p5-key-context.test.mjs \
packages/bus/tests/limit-checks.test.mjs \
packages/bus/tests/usage-runtime.test.mjs \
packages/bus/tests/usage-broker.test.mjs \
packages/bus/tests/daily-quota-runtime.test.mjs \
packages/bus/tests/limits-runtime.test.mjs \
packages/bus/tests/limit-stop.test.mjs \
packages/bus/tests/plugins-verb.test.mjs \
packages/webui/tests/usage.test.mjs \
packages/webui/tests/usage-render.test.mjs
+10
View File
@@ -1961,3 +1961,13 @@ are never rewritten or removed; corrections are new entries.
2026-11-02 | Lead sub-agent (Claude Sonnet 5.5, under T3 c5c1e8ba) | Vikunja #780 and #781: project inspectGit race with git maintenance, closed fixture ports | Code 7e0d3c93f (#780) and 1009bbfaf (#781) on t3/fix-flakes-780-781: both flakes made deterministic, pin tests added, three mutants plus one extra each killed and restored, project, webui, control-board, stack-release and lane fixture suites green, read.test.mjs 10 of 10. Not pushed; record in BUILD-LOG.md.
2026-11-03 | Lead sub-agent (Claude Opus 5.5, under T3 c5c1e8ba) | Vikunja #780 R2: restore the fresh recursive lstat in project inspectGit | Code 1977f4ffc on t3/flakes-780-781-r2-fix: symlink and file replacement tests red on 9944100ad and green now, stale-stat mutant killed by both, project 44/0/0, read.test.mjs 5 of 5. BUILD-LOG entry corrects the R1 walk and tester-cli descriptions. Not pushed.
2026-10-26 | Codex P5 builder | row333/Mos1961 isolated t3/model-proxy-p5-quota-usage at 09a847eda; clean base verified, queue next refused linked worktree (no canonical mutation) | implementation started; local fake-only serial nice19 verification; parent owns review/full gates/landing.
2026-10-26 | Codex P5 builder | row333/Mos1961 implementation candidate on isolated base09a847eda | 174/174 scoped whole-file GREEN; upstream-value mutant killed/restored+positive; native current/retiring key ownership fail-closed and telemetry isolated; 202 consumed inputs frozen in agents/codex/work/queue-333; own scratch cleaned; parent fresh review/full/browser gate pending1014.Q264; no queue/remote/push/landing.
2026-10-26 | Codex P5 builder | row333 R1 CHANGES response on same isolated503b91e | full real review hash7c95672a30c0d5c39189c7c7d610ada89cd539dcb9413617071fbb81200fd008 verified; all three findings source-confirmed; RED-first repairs authorized; original candidate/raw history preserved; no heavy/full/browser/remote/landing.
2026-10-26 | Codex P5 builder | row333 independentR1 repair source/static packet | all3 source fixes + regression controls authored, UNCOMMITTED on503b91e; nativepriority07 drift19→16 yielded78UNVERIFIED/STOP and no local retry;01–06 priorityUNVERIFIED; held-response controls unexecuted; admittedrunner baselineRED/fixedGREEN/nativeprovenance + newR2 pending; original503/R1/raws preserved; no productcommit/heavy/full/browser/queue/push/landing.
2026-11-02 | Claude (sub-agent of Mosaic Stack lead c5c1e8ba) | row333 join onto landed row332 (#1831) | Merge c0c291cda joins 0ef269da9 onto 5df0e9d6f on t3/row-333-join-replay; two conflicts (launch.mjs imports, plugins README sections) resolved by keeping both, identical to the earlier join resolution; 9/9 suites green (business 293, plugins 129, bus 1382, model-proxy 108, harness 205, seat 223, webui 498, cli 1101 and 1 skip, federation 1); no push, queue or PR action.
2026-11-03 | Claude (sub-agent of Mosaic Stack lead c5c1e8ba) | row333 R3 rotation fix (#1831) | 3692fca52 on t3/row333-r3-fix (base b37cc5087): key quota follows the agent's key lineage across rotation and re-issue, orphaned leaves listed and logged, key-quota-no-model-key, usage module gets readUsageQueue only, fixture deadlines; bus 1393, plugins 132, business 293, webui 499, cli stack-release 225, stack-release-external 25, stack-upgrade 25, launch-limit-checks 5, no skips; 5 mutants killed; no push, queue or PR action.
2026-11-03 | Claude (sub-agent of Mosaic Stack lead c5c1e8ba) | row 333 R4 since carry fix (#1831) | f65faf9df on t3/row333-r4-fix (on R3 tip fe3ef5128): a moved key quota keeps its count through the bus's lineage lookup, orphan set updated on every refresh, real-timer barrier yield, BUILD.md R4 section a13050012; bus 1397, plugins 132, business 295, webui 499, cli stack-release 225, stack-release-external 25, stack-upgrade 25, launch-limit-checks 5, harness tools 23, no skips; 6 mutants killed; no push, queue or PR action.
+4 -3
View File
@@ -4930,7 +4930,7 @@ export class Broker {
if (!role && !s.human && !s.tester) fail("human-required");
if (!this.#organization) fail("not-configured");
if (["limits", "plugins", "instances", "routes", "organization.revision"].includes(request.verb)) keys(args, []);
else if (request.verb === "plugins.set") keys(args, ["revision", "plugins"], ["revision", "plugins"]);
else if (request.verb === "plugins.set") keys(args, ["revision", "plugins", "usage"], ["revision", "plugins"]);
// Row 165 (#1662): instances.set is human-only and outside ORGANIZATION_KEYS, so
// organization.set and the chief of staff's tool never reach it (sage-0918).
else if (request.verb === "instances.set") {
@@ -5217,7 +5217,8 @@ export class Broker {
// The bus code for an organization writer's refusal. Anything the writer didn't refuse by name is
// outcome-unknown: the write may have committed.
#organizationFail(e, verb) {
if (['proxy-revoke-revision-conflict', 'proxy-key-issue-failed', 'proxy-key-revoking', 'proxy-key-refused', 'proxy-down', 'proxy-open'].includes(e.code)) fail(e.code);
// Row 333 R3 (#1831): key-quota-no-model-key passes through with the other proxy key codes.
if (['proxy-revoke-revision-conflict', 'proxy-key-issue-failed', 'proxy-key-revoking', 'proxy-key-refused', 'key-quota-no-model-key', 'proxy-down', 'proxy-open'].includes(e.code)) fail(e.code);
// Row 239 (#1745): the writer marks an error raised after a fire's or a delete's revoke ran, so
// the human reads that the tokens may already be revoked. Without the mark, today's code.
if (e.revoked) fail(e.code === "revision-conflict" ? "revision-conflict-revoked" : "outcome-unknown-revoked");
@@ -5303,7 +5304,7 @@ export class Broker {
if (!this.#limits) return;
let answer;
try {
answer = await this.#limits.mustStop(s.business, { instance: s.role, provider: s.provider ?? null, model: s.model ?? null, account: s.account ?? null });
answer = await this.#limits.mustStop(s.business, { instance: s.role, provider: s.provider ?? null, model: s.model ?? null, account: s.account ?? null }, { run: s.run });
} catch {
answer = { stop: true, check: null, code: 'check-threw' };
}
+10 -3
View File
@@ -427,12 +427,18 @@ export class Credentials {
const keyOk = k => typeof k === 'string' && /^msk-[a-z0-9]+-[A-Za-z0-9_-]{43}$/.test(k);
const keyId = k => createHash('sha256').update(k).digest('hex').slice(0, 12);
const instant = s => typeof s === 'string' && !Number.isNaN(Date.parse(s)) && new Date(s).toISOString() === s;
if (!m || Array.isArray(m) || Object.keys(m).some(k => !['key', 'keyId', 'issuedAt', 'rotateBy', 'state', 'revokingAt', 'retiring'].includes(k))
// Row 333 R3 (#1831): `previous` lists the agent's earlier key ids, ids only, oldest first, at
// most 64. It is absent until a key first leaves the record, so a record a pre-R3 bus wrote
// still loads. A pre-R3 bus refuses a record that carries it, credential-format.
if (!m || Array.isArray(m) || Object.keys(m).some(k => !['key', 'keyId', 'issuedAt', 'rotateBy', 'state', 'revokingAt', 'retiring', 'previous'].includes(k))
|| !keyOk(m.key) || m.keyId !== keyId(m.key) || !instant(m.issuedAt) || !day(m.rotateBy)
|| !['valid', 'revoking'].includes(m.state) || (m.state === 'revoking' ? !instant(m.revokingAt) : m.revokingAt !== undefined)
|| !Array.isArray(m.retiring) || m.retiring.length > 64 || m.retiring.some(r => !r || Array.isArray(r)
|| Object.keys(r).sort().join(',') !== 'issuedAt,key,keyId,retireAt'
|| !keyOk(r.key) || r.keyId !== keyId(r.key) || !instant(r.issuedAt) || !instant(r.retireAt))) deny('credential-format');
|| !keyOk(r.key) || r.keyId !== keyId(r.key) || !instant(r.issuedAt) || !instant(r.retireAt))
|| (m.previous !== undefined && (!Array.isArray(m.previous) || !m.previous.length || m.previous.length > 64
|| m.previous.some(r => !r || Array.isArray(r) || typeof r !== 'object' || Object.keys(r).sort().join(',') !== 'keyId,retiredAt'
|| typeof r.keyId !== 'string' || !/^[a-f0-9]{12}$/.test(r.keyId) || !instant(r.retiredAt))))) deny('credential-format');
return { token: m.key, model: m };
}
if (isHostKind(service)) {
@@ -661,7 +667,8 @@ export class Credentials {
...(hostKey ? { fingerprint: hostKey.fingerprint, publicKey: hostKey.publicLine } : {}),
...(model ? { keyId: model.keyId, issuedAt: model.issuedAt,
...(model.revokingAt ? { revokingAt: model.revokingAt } : {}),
retiring: model.retiring.map(({ keyId, issuedAt, retireAt }) => ({ keyId, issuedAt, retireAt })) } : {}),
retiring: model.retiring.map(({ keyId, issuedAt, retireAt }) => ({ keyId, issuedAt, retireAt })),
previous: (model.previous ?? []).map(({ keyId, retiredAt }) => ({ keyId, retiredAt })) } : {}),
state: !this.#tokens.has(key)
? this.#held.has(key)
? 'held'
+129 -9
View File
@@ -12,7 +12,7 @@
//
// refresh, mayLaunch and mustStop are async: they re-read the file and reload first. report is
// sync, so the organization verbs stay sync; it uses the modules the last refresh loaded.
import { createLoader } from '../../plugins/src/loader.mjs';
import { createLoader, isDailyModelQuota } from '../../plugins/src/loader.mjs';
import { turnRecords } from './usage.mjs';
const KIND = 'limit-check';
@@ -24,6 +24,17 @@ const exact = (value, keys) => plainObject(value) && Object.keys(value).length =
const amount = value => (Number.isSafeInteger(value) && value >= 0) || (typeof value === 'string' && /^(0|[1-9]\d*)$/.test(value));
const turns = value => Number.isSafeInteger(value) && value >= 0;
const same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
const HEX12 = /^[a-f0-9]{12}$/;
// The key lookup's own refusals pass through by name; any other throw is proxy-key-refused.
const LOOKUP_CODES = ['proxy-key-refused', 'key-quota-no-model-key'];
// The ids that name a daily per-key quota (row 333), in file order.
const dailyKeyIds = limits => Object.entries(limits?.tokens?.keys ?? {}).filter(([k, entry]) => isDailyModelQuota(k, entry)).map(([k]) => k);
// Row 333 R3 (#1831): one array of key ids per hired agent, no id in two.
const validLineages = value => {
if (!Array.isArray(value) || value.some(l => !Array.isArray(l) || !l.length || l.some(id => typeof id !== 'string' || !HEX12.test(id)))) return false;
const ids = value.flat();
return new Set(ids).size === ids.length;
};
// Every token limit in launch.limits, in file order, at its schema depth only: tokens.instances.X,
// tokens.providers.X, tokens.keys.X, tokens.models.P.M and tokens.daily.A (row 126). The agent limits (total, providers,
@@ -51,9 +62,41 @@ class Failure extends Error {
}
// makeLoader is the plug-in loader's factory; tests pass a scratch tree's copy to load fixture checks.
export function createLimits({ store, read, log, makeLoader = createLoader }) {
// Row 333: keyForSubject names the subject's model key id: the agent's current key for a launch,
// the run's bound key for mustStop. R3: keyLineages lists the business's hired agents' key
// lineages, each the current, retiring and earlier ids of one agent. A daily key quota follows
// the lineage that holds its id, so it outlives rotation and re-issue. Both run only while a
// daily key quota is set and a check is switched on. Without keyLineages they refuse.
export function createLimits({ store, read, log, makeLoader = createLoader, keyForSubject = () => null,
keyLineages = () => { throw new Failure('proxy-key-refused'); } }) {
if (typeof read !== 'function' || typeof log !== 'function') throw new TypeError('createLimits needs read and log');
const loaders = new Map();
// Row 333 R3: an orphaned key quota names an id in no hired agent's lineage. It limits nothing
// and refuses nothing. One value-free log line per leaf when it becomes orphaned, not per launch.
// R4: every refresh observes too, and a business with no daily key quota left remembers none, so a
// leaf removed and added back logs again. The set lives in memory: a bus start is a fresh
// observation and may log an unchanged orphan once more.
const orphansLogged = new Map();
function noteOrphans(business, limits, lineages) {
const ids = dailyKeyIds(limits).filter(id => !lineages.some(l => l.includes(id)));
const before = orphansLogged.get(business) ?? new Set();
for (const id of ids) if (!before.has(id)) log({ event: 'limit-key-orphaned', business, path: ['tokens', 'keys', id] });
orphansLogged.set(business, new Set(ids));
return ids;
}
// The orphaned ids now, [] when no daily key quota is set, or null when the lineages can't be
// read (the remembered set then stays as it was).
function observeOrphans(business, limits) {
if (!dailyKeyIds(limits).length) { orphansLogged.set(business, new Set()); return []; }
const lineages = lineagesFor(business);
return lineages ? noteOrphans(business, limits, lineages) : null;
}
// The business's lineages, or null when they can't be read or are malformed.
function lineagesFor(business) {
let value;
try { value = keyLineages(business); } catch { return null; }
return validLineages(value) ? value : null;
}
const loaderFor = business => {
if (!loaders.has(business)) loaders.set(business, makeLoader({ log }));
return loaders.get(business);
@@ -84,6 +127,7 @@ export function createLimits({ store, read, log, makeLoader = createLoader }) {
async function refresh(business) {
let b;
try { b = read(business); } catch { return; }
observeOrphans(business, b?.launch?.limits ?? {});
await loaderFor(business).load({ [KIND]: b?.plugins?.[KIND] ?? [] });
}
@@ -111,7 +155,7 @@ export function createLimits({ store, read, log, makeLoader = createLoader }) {
// mayLaunch and mustStop: every switched-on check is asked in order; the first refusal or
// stop wins. key is the answer's boolean (allow, stop) and go its value when nothing is hit.
async function decide(business, subject, name, key, go, halt) {
async function decide(business, subject, name, key, go, halt, context = {}) {
await refresh(business);
let st;
try { st = state(business); } catch (e) {
@@ -122,8 +166,25 @@ export function createLimits({ store, read, log, makeLoader = createLoader }) {
log({ event: 'limit-check-failed', business, check: st.missing, export: name, code: 'not-loaded' });
return halt({ check: st.missing, code: 'not-loaded' });
}
if (!st.checks.length) return { [key]: go };
const leaves = limitLeaves(st.limits);
const args = { business, limits: st.limits, subject, records: st.records, now: new Date().toISOString() };
let lineages;
if (dailyKeyIds(st.limits).length) {
let modelKeyId, code = 'proxy-key-refused';
try {
if (name === 'mustStop' && (typeof context?.run !== 'string' || !context.run)) throw new Failure('proxy-key-refused');
modelKeyId = keyForSubject(business, { ...subject, ...context });
} catch (e) { if (LOOKUP_CODES.includes(e?.code)) code = e.code; }
if (typeof modelKeyId === 'string' && HEX12.test(modelKeyId)) lineages = lineagesFor(business);
// The subject's key must sit in exactly one hired agent's lineage, read in the same tick.
if (!lineages?.some(l => l.includes(modelKeyId))) {
log({ event: 'limit-check-failed', business, check: null, export: name, code });
return halt({ check: null, code });
}
subject = { ...subject, modelKeyId };
noteOrphans(business, st.limits, lineages);
}
const args = { business, limits: st.limits, subject, records: st.records, now: new Date().toISOString(), ...(lineages ? { lineages } : {}) };
for (const check of st.checks) {
const { answer, code } = ask(business, check, name, args, a =>
exact(a, [key]) ? a[key] === go : exact(a, [key, 'hit']) && a[key] === !go && validHit(a.hit, leaves));
@@ -136,14 +197,15 @@ export function createLimits({ store, read, log, makeLoader = createLoader }) {
return { [key]: go };
}
const subjectOf = ({ instance, provider = null, model = null, account = null }) => ({ instance, provider, model, account });
const subjectOf = ({ instance, provider = null, model = null, account = null }) =>
({ instance, provider, model, account });
// { allow: true } | { allow: false, check, hit } | { allow: false, check, code }
const mayLaunch = (business, subject) =>
decide(business, subjectOf(subject), 'mayLaunch', 'allow', true, why => ({ allow: false, ...why }));
// { stop: false } | { stop: true, check, hit } | { stop: true, check, code }
const mustStop = (business, subject) =>
decide(business, subjectOf(subject), 'mustStop', 'stop', false, why => ({ stop: true, ...why }));
const mustStop = (business, subject, context = {}) =>
decide(business, subjectOf(subject), 'mustStop', 'stop', false, why => ({ stop: true, ...why }), context);
const validEntry = (e, leaves) => {
const leaf = plainObject(e) && Array.isArray(e.path) && leaves.find(l => same(l.path, e.path));
@@ -166,9 +228,16 @@ export function createLimits({ store, read, log, makeLoader = createLoader }) {
let st;
try { st = state(business, b); } catch (e) { return failedAll(null, e.code); }
if (!st.checks) return failedAll(st.missing, 'not-loaded');
// Row 333 R3: a key quota's count is its whole lineage's, so a report needs the lineages too.
let lineages;
if (st.checks.length && dailyKeyIds(st.limits).length) {
lineages = lineagesFor(business);
if (!lineages) return failedAll(null, 'proxy-key-refused');
noteOrphans(business, st.limits, lineages);
}
const answers = [];
for (const check of st.checks) {
const { answer, code } = ask(business, check, 'report', { business, limits: st.limits, records: st.records, now: new Date().toISOString() },
const { answer, code } = ask(business, check, 'report', { business, limits: st.limits, records: st.records, now: new Date().toISOString(), ...(lineages ? { lineages } : {}) },
a => Array.isArray(a) && a.every(e => validEntry(e, leaves)) && new Set(a.map(e => JSON.stringify(e.path))).size === a.length);
if (code) return failedAll(check.name, code);
answers.push({ check: check.name, entries: answer });
@@ -185,5 +254,56 @@ export function createLimits({ store, read, log, makeLoader = createLoader }) {
});
}
return { refresh, mayLaunch, mustStop, report };
// Row 333 R3: the daily key quotas that match no hired agent, for the Console usage view. Null
// when the file or the lineages can't be read; the view then says nothing either way.
function orphanedKeys(business) {
let b;
try { b = read(business); } catch { return null; }
return observeOrphans(business, b?.launch?.limits ?? {});
}
return { refresh, mayLaunch, mustStop, report, orphanedKeys };
}
// Host metadata adapters, extracted from runtime so ownership cases are testable. records is
// Credentials.status(): metadata only, never a key.
// Row 333 R3: an agent's lineage is its current key id, its retiring ids and its earlier ids.
const lineageOf = record => [record.keyId, ...(record.retiring ?? []).map(r => r.keyId), ...(record.previous ?? []).map(r => r.keyId)];
export function modelUsageKey(records, runs, business, subject) {
const fail = (code = 'proxy-key-refused') => { throw new Failure(code); };
const instance = business + '/' + subject.instance;
const owners = records.filter(r => r.service === 'model' && r.instance === instance);
// Row 333 R3 ruling 2: an agent with no model key (no proxy, or not issued) can't be matched to a
// key quota. Still a refusal, under its own name.
if (!owners.length || (owners.length === 1 && owners[0].keyId === undefined)) fail('key-quota-no-model-key');
if (owners.length !== 1) fail();
const record = owners[0], ids = lineageOf(record);
if (ids.some(id => typeof id !== 'string' || !HEX12.test(id)) || new Set(ids).size !== ids.length) fail();
// A key ID must identify exactly this owner, over every generation either agent ever held.
for (const other of records.filter(r => r.service === 'model' && r !== record))
if (lineageOf(other).some(id => ids.includes(id))) fail();
if (!subject.run) return record.keyId;
// A run is bound to a key the proxy still accepts: current or retiring, never an earlier one.
const run = runs.get(business + ':' + subject.run);
if (!run || run.instance !== instance || ![record.keyId, ...(record.retiring ?? []).map(r => r.keyId)].includes(run.keyId)) fail();
return run.keyId;
}
// Every hired agent's lineage in one business. Any malformed id, or an id in two lineages
// anywhere on the host, refuses.
export function modelKeyLineages(records, business) {
const seen = new Set(), out = [];
for (const record of records.filter(r => r.service === 'model' && r.keyId !== undefined)) {
const ids = lineageOf(record);
for (const id of ids) {
if (typeof id !== 'string' || !HEX12.test(id) || seen.has(id)) throw new Failure('proxy-key-refused');
seen.add(id);
}
if (typeof record.instance === 'string' && record.instance.startsWith(business + '/')) out.push(ids);
}
return out;
}
// Row 333 R4 (#1831): the settings writer's lookup. The lineage in `business` that holds keyId, or
// [] when none does. Ids only, from the bus's own records; the same checks refuse.
export function modelKeyLineage(records, business, keyId) {
return modelKeyLineages(records, business).find(l => l.includes(keyId)) ?? [];
}
+28 -3
View File
@@ -9,6 +9,15 @@ export const REVOKE_POLL_MS = 25;
export const MODEL_STOP_TIMEOUT_MS = 5000;
const keyId = key => createHash('sha256').update(key).digest('hex').slice(0, 12);
const fail = code => { throw new BusError(code); };
// Row 333 R3 (#1831): an id that leaves the record joins the agent's earlier ids, so a daily key
// quota keeps following the agent. Ids only, never a key; at most 64, the oldest dropped first.
// The field stays absent until the first id leaves, as Credentials' format allows.
export const MAX_PREVIOUS_KEY_IDS = 64;
const withPrevious = (record, ids, retiredAt) => {
const previous = [...(record.previous ?? []), ...ids.map(id => ({ keyId: id, retiredAt }))].slice(-MAX_PREVIOUS_KEY_IDS);
const { previous: _, ...rest } = record;
return previous.length ? { ...rest, previous } : rest;
};
export class ModelKeys {
#credentials; #client; #baseUrl; #prefix; #receipt; #now; #runs; #stopRuns; #grace;
#tail = Promise.resolve(); #ready = false; #failure = 'proxy-down'; #confirmed = new Map();
@@ -36,6 +45,17 @@ export class ModelKeys {
if (this.#record(instance)?.state === 'revoking') fail('proxy-key-revoking');
if (!this.#ready) fail(this.#failure);
}
// P5's destructive queue read needs this instance's current identity, not
// an issued agent credential. A sentinel refusal stays closed until explicit
// reconcile; telemetry never retries around it or performs reconciliation.
verifyIdentity() {
return this.#exclusive(async () => {
if (!this.#ready) fail(this.#failure);
let keys;
try { keys = await this.#client.getKeys(); } catch { fail('proxy-down'); }
this.#sentinel(keys);
});
}
async #replace(before, after) {
this.#sentinel(before); this.#sentinel(after);
await this.#client.putKeys(after);
@@ -121,10 +141,14 @@ export class ModelKeys {
const key = this.#prefix + randomBytes(32).toString('base64url');
const now = this.#now(), issuedAt = new Date(now).toISOString();
const date = new Date(now + 30 * 86400_000).toISOString().slice(0, 10);
const retiring = old ? [...old.retiring, ...(rotate && before.includes(old.key) ? [{ key: old.key, keyId: old.keyId, issuedAt: old.issuedAt, retireAt: new Date(now + this.#grace).toISOString() }] : [])] : [];
const keep = rotate && before.includes(old?.key);
const retiring = old ? [...old.retiring, ...(keep ? [{ key: old.key, keyId: old.keyId, issuedAt: old.issuedAt, retireAt: new Date(now + this.#grace).toISOString() }] : [])] : [];
// A re-issue, or a rotation the proxy already lost the key for, drops the old key at once.
const record = withPrevious({ key, keyId: keyId(key), issuedAt, rotateBy: date, state: 'valid', retiring, previous: old?.previous },
old && !keep ? [old.keyId] : [], issuedAt);
try {
await this.#replace(before, [...new Set([...before, key])]);
this.#credentials.writeModel(instance, { key, keyId: keyId(key), issuedAt, rotateBy: date, state: 'valid', retiring });
this.#credentials.writeModel(instance, record);
this.#receipt({ action: rotate ? 'proxy.key.rotated' : 'proxy.key.issued', keyIds: [keyId(key)], instance });
return { baseUrl: this.#baseUrl, key };
} catch (error) {
@@ -222,7 +246,8 @@ export class ModelKeys {
await this.#removeKeys([old.key], confirm);
confirm();
const current = this.#record(instance);
this.#credentials.writeModel(instance, { ...current, retiring: current.retiring.filter(r => r.keyId !== old.keyId) });
this.#credentials.writeModel(instance, withPrevious({ ...current, retiring: current.retiring.filter(r => r.keyId !== old.keyId) },
[old.keyId], new Date(this.#now()).toISOString()));
this.#receipt({ action: 'proxy.key.retired', keyIds: [old.keyId] });
}
} catch (error) {
+98
View File
@@ -0,0 +1,98 @@
// P5: one reader per broker/data root drains the instance queue once, then routes
// safe IDs to the owning business. It never supplies records to limit checks.
import { randomUUID } from 'node:crypto';
import { createLoader } from '../../plugins/src/loader.mjs';
import { checkUsageSettings } from '../../plugins/src/kinds.mjs';
const SOURCE = '@proxy/cliproxy-queue';
const KINDS = ['input', 'output', 'cacheWrite', 'cacheRead'];
const ID = /^[a-f0-9]{12}$/;
const plain = n => n <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(n) : String(n);
// makeLoader is the plug-in loader's factory; a test wraps it to see what a module is handed.
export function createProxyUsage({ store, read, client, records, log, now = Date.now, makeLoader = createLoader }) {
const loader = makeLoader({ log });
let due = 0, previous = '', pending = null, closed = false;
const states = new Map();
function configured() {
return Object.entries(read()).filter(([, b]) => b.plugins?.usage === 'cliproxy-queue').map(([business, b]) => {
checkUsageSettings(b.usage ?? {});
return { business, pollSeconds: b.usage?.cliproxyQueue?.pollSeconds ?? 15 };
});
}
async function poll() {
let enabled;
try { enabled = configured(); }
catch { log({ action: 'proxy.usage', code: 'invalid-usage-settings' }); return; }
if (!enabled.length) { previous = ''; return; }
const signature = JSON.stringify(enabled);
if (signature !== previous) { previous = signature; due = 0; }
if (now() < due) return;
due = now() + Math.min(...enabled.map(b => b.pollSeconds)) * 1000;
try {
await loader.load({ usage: 'cliproxy-queue' });
const module = loader.modules('usage')[0], management = await client();
if (!module || !management) throw Error('unavailable');
// Row 333 R3 (#1831): the module gets the one read it needs and nothing else. No path from
// its argument reaches getKeys, putKeys, the OAuth calls or any other management call.
const events = await module.read(Object.freeze({ readUsageQueue: () => management.readUsageQueue() }));
const owners = new Map();
for (const record of records()) {
if (record.service !== 'model') continue;
const split = record.instance.indexOf('/'), business = record.instance.slice(0, split), instance = record.instance.slice(split + 1);
if (split < 1) continue;
for (const keyId of [record.keyId, ...(record.retiring ?? []).map(r => r.keyId)]) {
if (!ID.test(keyId ?? '')) continue;
if (owners.has(keyId)) throw Error('ambiguous');
owners.set(keyId, { business, instance });
}
}
// Validate all plug-in answers before writing any row or log field.
if (!Array.isArray(events) || events.length > 100 || events.some(e => !e || !ID.test(e.keyId ?? '') || !ID.test(e.accountId ?? '')
|| typeof e.managed !== 'boolean' || typeof e.failed !== 'boolean'
|| (e.statusCode !== null && (!Number.isSafeInteger(e.statusCode) || e.statusCode < 0 || e.statusCode > 599))
|| KINDS.some(k => !Number.isSafeInteger(e[k]) || e[k] < 0))) throw Error('invalid');
const unknown = [];
store.transaction(() => {
for (const e of events) {
const owner = owners.get(e.keyId);
if (!owner) { if (e.managed) unknown.push(e.keyId); continue; }
if (!enabled.some(b => b.business === owner.business)) continue;
// Whitelist fields; never persist raw plug-in results. Cursor holds only
// metadata, and turnRecords excludes SOURCE before every quota decision.
store.run(`INSERT INTO usage_records(at,business,run,instance,account,turn,source,phase,status,code,cursor,input,output,cache_write,cache_read)
VALUES (?,?,?,?,?,?,?,'end','known',?,?,?,?,?,?)`, new Date(now()).toISOString(), owner.business, '@proxy', owner.instance,
e.accountId, randomUUID(), SOURCE, e.failed ? 'proxy-upstream-failed' : null,
JSON.stringify({ modelKeyId: e.keyId, failed: e.failed, statusCode: e.statusCode }), e.input, e.output, e.cacheWrite, e.cacheRead);
}
});
for (const keyId of unknown) log({ action: 'proxy.usage.reconcile', keyId, code: 'proxy-usage-unknown-key' });
for (const { business } of enabled) states.set(business, 'available');
} catch {
for (const { business } of enabled) states.set(business, 'unavailable');
log({ action: 'proxy.usage', code: 'proxy-usage-read-failed' });
}
}
function tick() {
if (closed) return Promise.resolve();
if (pending) return pending;
pending = poll().finally(() => { pending = null; });
return pending;
}
function view(business) {
try { if (!configured().some(b => b.business === business)) return null; } catch { return null; }
const byKey = new Map(), byAccount = new Map();
for (const r of store.all('SELECT * FROM usage_records WHERE business=? AND source=? ORDER BY seq', business, SOURCE)) {
const meta = JSON.parse(r.cursor);
for (const [map, identity] of [[byKey, { keyId: meta.modelKeyId }], [byAccount, { accountId: r.account }]]) {
const id = Object.values(identity)[0];
if (!map.has(id)) map.set(id, { ...identity, input: 0n, output: 0n, cacheWrite: 0n, cacheRead: 0n, requests: 0, failures: 0, statuses: {} });
const entry = map.get(id);
for (const [key, column] of [['input','input'],['output','output'],['cacheWrite','cache_write'],['cacheRead','cache_read']]) entry[key] += BigInt(r[column]);
entry.requests++; if (meta.failed) entry.failures++;
if (meta.failed && meta.statusCode !== null) entry.statuses[meta.statusCode] = (entry.statuses[meta.statusCode] ?? 0) + 1;
}
}
const finish = map => [...map.values()].map(e => ({ ...e, ...Object.fromEntries(KINDS.map(k => [k, plain(e[k])])) }));
return { source: 'proxy', state: states.get(business) ?? 'unread', byKey: finish(byKey), byAccount: finish(byAccount) };
}
return { tick, view, async close() { closed = true; await pending; } };
}
+34 -6
View File
@@ -35,7 +35,8 @@ import { loadAccess } from '../../business/src/access.mjs';
import { inspectInterpreter, recordInterpreterStart } from './interpreter.mjs';
import { createPeerReader } from './peercred.mjs';
import { createUsage } from './usage.mjs';
import { createLimits } from './limits.mjs';
import { createProxyUsage } from './proxy-usage.mjs';
import { createLimits, modelUsageKey, modelKeyLineages, modelKeyLineage } from './limits.mjs';
import { createProcessing } from '../../processing-control/src/coordinator.mjs';
import { discordProcessingHooks } from '../../discord/src/processing.mjs';
import { createContainerStopper } from '../../processing-control/src/containers.mjs';
@@ -265,7 +266,7 @@ export async function startBroker({
|| (Object.hasOwn(librarySync, 'intervalMs') && !(Number.isSafeInteger(librarySync.intervalMs) && librarySync.intervalMs > 0))
|| (Object.hasOwn(librarySync, 'configDir') && typeof librarySync.configDir !== 'string')))
throw new BusError('invalid-host-request');
let modelProxyClient = null, proxyPage = null;
let modelProxyClient = null, proxyPage = null, proxyUsage = null, usageTimer = null;
let modelKeys = null, modelTimer = null, modelSweep = null;
const modelRuns = new Map();
let store, credentials, server, adapter, processing, syncTimer = null, syncPass = null, accessTimer = null;
@@ -339,7 +340,10 @@ export async function startBroker({
// plugins and plugins.set, logged in changes.jsonl with the actor, a missing module refused.
const plugins=organization?pluginSettings({dir:organization.dir,rolesDir:organization.rolesDir,exists:hasModule}):null;
const levels=organization?await harnessLevels():()=>null;
const settings=organization?launchSettings({...organization,sessions:()=>readSessions(dataRoot),levels}):null;
// Row 333 R4 (#1831): the writer's key lineage lookup, ids only, from this bus's own credential
// records. A daily key quota moved within one agent's lineage keeps its since and its count.
const keyLineage=(business,keyId)=>modelKeyLineage(credentials.status(),business,keyId);
const settings=organization?launchSettings({...organization,sessions:()=>readSessions(dataRoot),levels,keyLineage}):null;
// Row 194 (#1692, brief item 8, row 199 D13): a fire or a delete revokes the agent's credentials
// after the writer's checks and before its write, under the writer's lock (row 239). Fire revokes
// each service of the entry and keeps the store directory, delete calls remove (sage-1593). A
@@ -379,12 +383,26 @@ export async function startBroker({
const proxyOrganization = modelKeys ? modelOrganization({ modelKeys, writer: organizationWriter({ dir: organization.dir, rolesDir: organization.rolesDir }) }) : null;
const instances=organization?instanceSettings({dir:organization.dir,rolesDir:organization.rolesDir,system:organization.system,levels,revoke,
...(proxyOrganization ? { writer: proxyOrganization.writer, revoke: proxyOrganization.revoke(revoke) } : {})}):null;
const usage = await createUsage({ store, dataRoot, businesses,
log: entry => process.stderr.write(`usage: ${JSON.stringify(entry)}\n`) });
const usageLog = entry => process.stderr.write(`usage: ${JSON.stringify(entry)}\n`);
const keyForRun = (business, run) => modelRuns.get(business + ':' + run)?.keyId ?? null;
// Row 333 R3 (#1831): the usage view marks key quotas that match no hired agent; limits answers.
let orphanedKeys = () => null;
const usage = await createUsage({ store, dataRoot, businesses, log: usageLog, keyForRun,
proxyView: business => proxyUsage?.view(business) ?? null, keyOrphans: business => orphanedKeys(business) });
proxyUsage = createProxyUsage({ store, log: usageLog, client: async () => {
if (!modelKeys) return null;
await modelKeys.verifyIdentity();
return modelProxyClient;
},
records: () => credentials.status(),
read: () => Object.fromEntries(Object.keys(businesses).map(id => [id, settings ? settings.current(id) : businesses[id]])) });
// Row 125 (#1619, REQ-LIMIT-3, REQ-LIMIT-4): the limit checks read the organization file at
// each ask, so a limit, a reset or a switched-on check takes effect without a restart.
const limitLog = entry => process.stderr.write(`limits: ${JSON.stringify(entry)}\n`);
const limits = createLimits({ store, read: id => settings ? settings.current(id) : businesses[id], log: limitLog });
const limits = createLimits({ store, read: id => settings ? settings.current(id) : businesses[id], log: limitLog,
keyForSubject: (business, subject) => modelUsageKey(credentials.status(), modelRuns, business, subject),
keyLineages: business => modelKeyLineages(credentials.status(), business) });
orphanedKeys = business => limits.orphanedKeys(business);
for (const id of Object.keys(businesses)) await limits.refresh(id);
const withTokens = (id, result) => ({ ...result, tokens: limits.report(id) });
// Row 210 (#1707, design D7 step 6) and row 234 (#1740, r6 E2): the run dir and the host enrollment half.
@@ -853,6 +871,12 @@ export async function startBroker({
}, 1000);
modelTimer.unref();
}
// One bounded queue read at a time. The service applies the configured
// 1..59 second poll deadline; this tick only checks whether a read is due.
const usageTick = () => { proxyUsage.tick().catch(() => usageLog({ action: 'proxy.usage', code: 'proxy-usage-read-failed' })); };
usageTimer = setInterval(usageTick, 1000);
usageTimer.unref();
usageTick(); // Optional telemetry never blocks the native ready answer.
return {
broker,
credentials,
@@ -916,6 +940,8 @@ export async function startBroker({
launches: bound,
readers: readCaps,
async close() {
clearInterval(usageTimer);
await proxyUsage.close();
clearInterval(modelTimer);
await modelSweep;
clearInterval(accessTimer);
@@ -928,6 +954,8 @@ export async function startBroker({
},
};
} catch (e) {
clearInterval(usageTimer);
await proxyUsage?.close();
clearInterval(modelTimer);
clearInterval(accessTimer);
await server?.close();
+15 -5
View File
@@ -38,6 +38,7 @@ function delta(before, after) {
export function turnRecords(store, business) {
const turns = new Map();
for (const row of store.all(`SELECT * FROM usage_records WHERE business=? ORDER BY seq`, business)) {
if (row.source === '@proxy/cliproxy-queue') continue; // telemetry never drives quotas
const key = JSON.stringify([row.run, row.turn, row.source]);
if (row.phase === 'end' || !turns.has(key)) turns.set(key, row);
}
@@ -45,13 +46,14 @@ export function turnRecords(store, business) {
const known = row.phase === 'end' && row.status === 'known';
return {
at: row.at, run: row.run, turn: row.turn, source: row.source, instance: row.instance,
modelKeyId: row.cursor ? JSON.parse(row.cursor).modelKeyId ?? null : null,
provider: row.provider, model: row.model, account: row.account, status: known ? 'known' : 'unknown',
input: known ? row.input : null, output: known ? row.output : null,
cacheWrite: known ? row.cache_write : null, cacheRead: known ? row.cache_read : null,
};
});
}
export async function createUsage({ store, businesses, log }) {
export async function createUsage({ store, businesses, log, keyForRun = () => null, proxyView = () => null, keyOrphans = () => null }) {
const loaders = new Map();
for (const [id, b] of Object.entries(businesses)) {
const loader = createLoader({ log });
@@ -70,6 +72,9 @@ export async function createUsage({ store, businesses, log }) {
const sources = modules.length ? modules.map((module, i) => ({ module, name: names[i] })) : [{ name: '@none' }];
// Preserve a failed/disabled baseline even if configuration changes between calls/restarts.
for (const base of bases) if (!sources.some(s => s.name === base.source)) sources.push({ name: base.source });
const captured = bases.find(row => row.cursor && JSON.parse(row.cursor).modelKeyId)?.cursor;
const candidate = captured ? JSON.parse(captured).modelKeyId : keyForRun(business, run);
const modelKeyId = typeof candidate === 'string' && /^[a-f0-9]{12}$/.test(candidate) ? candidate : null;
const rows = [];
// Row 65 (#1558): where the run's harness keeps its session files is the module's transcript(),
// which the launcher binds into the run record. A run bound without one has no reading.
@@ -92,7 +97,7 @@ export async function createUsage({ store, businesses, log }) {
store.run(`INSERT INTO usage_records(at,business,run,instance,provider,model,account,turn,source,phase,status,code,cursor,input,output,cache_write,cache_read)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`, new Date().toISOString(), business, run, instance,
provider, model, account, turn, name, phase, result.status, result.code ?? null,
phase === 'begin' ? JSON.stringify(result) : null,
phase === 'begin' ? JSON.stringify({ ...result, ...(modelKeyId ? { modelKeyId } : {}) }) : modelKeyId ? JSON.stringify({ modelKeyId }) : null,
known ? counts.input : null, known ? counts.output : null, known ? counts.cacheWrite : null, known ? counts.cacheRead : null);
}
});
@@ -109,7 +114,7 @@ export async function createUsage({ store, businesses, log }) {
return op.finally(() => { if (pending.get(key) === tail) pending.delete(key); });
}
function view(business) {
const groups = { byRun: new Map(), byInstance: new Map(), byProvider: new Map(), byModel: new Map(), byAccount: new Map() };
const groups = { byRun: new Map(), byInstance: new Map(), byProvider: new Map(), byModel: new Map(), byAccount: new Map(), byKey: new Map() };
const total = { ...zero(), unknown: new Set() };
const add = (target, row) => {
if (row.status !== 'known') target.unknown.add(row.run + ':' + row.turn);
@@ -118,7 +123,7 @@ export async function createUsage({ store, businesses, log }) {
for (const row of turnRecords(store, business)) {
add(total, row);
for (const [name, identity] of Object.entries({ byRun: { run: row.run }, byInstance: { instance: row.instance },
byProvider: { provider: row.provider }, byModel: { provider: row.provider, model: row.model }, byAccount: { account: row.account } })) {
byKey: { modelKeyId: row.modelKeyId }, byProvider: { provider: row.provider }, byModel: { provider: row.provider, model: row.model }, byAccount: { account: row.account } })) {
const key = JSON.stringify(identity);
if (!groups[name].has(key)) groups[name].set(key, { ...identity, ...zero(), unknown: new Set() });
add(groups[name].get(key), row);
@@ -129,7 +134,12 @@ export async function createUsage({ store, businesses, log }) {
for (const kind of KINDS) rest[kind] = BigInt(rest[kind]) <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(rest[kind]) : String(rest[kind]);
return { ...rest, unknownTurns: unknown.size };
};
return { total: finish(total), ...Object.fromEntries(Object.entries(groups).map(([key, map]) => [key, [...map.values()].map(finish)])) };
const proxy = proxyView(business);
// Row 333 R3 (#1831): daily key quotas whose key id is in no hired agent's lineage. Ids only.
let orphans = null;
try { orphans = keyOrphans(business); } catch {}
const orphaned = Array.isArray(orphans) && orphans.length && orphans.every(id => typeof id === 'string' && /^[a-f0-9]{12}$/.test(id)) ? orphans : null;
return { ...(proxy ? { proxy } : {}), ...(orphaned ? { orphanedKeyQuotas: orphaned } : {}), total: finish(total), ...Object.fromEntries(Object.entries(groups).map(([key, map]) => [key, [...map.values()].map(finish)])) };
}
return { collect, view };
}
+36
View File
@@ -324,3 +324,39 @@ test('REQ-LIMIT-3 core reaches limit checks only through the plug-in loader', ()
assert.doesNotMatch(readFileSync(new URL(file, import.meta.url), 'utf8'), /limit-check\/|token-limit/, file);
}
});
test('P5 missing, ambiguous or invalid model key lookup fails closed without leaking a lookup error', async t => {
const root=mkdtempSync(join(tmpdir(),'p5-limit-')),store=new Store(root),log=[];t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
const key='012345abcdef',doc={plugins:{'limit-check':['daily-quota']},launch:{limits:{tokens:{keys:{[key]:{limit:5,since:SINCE,reset:'00:00',timeZone:'UTC'}}}}}};
for(const lookup of [()=>null,()=>['012345abcdef','abcdef012345'],()=> 'msk-private-lookup',()=>{throw Error('PRIVATE-LOOKUP-CANARY');}]) {
const l=createLimits({store,read:()=>doc,log:e=>log.push(e),keyForSubject:lookup});
assert.deepEqual(await l.mayLaunch('demo',SUBJECT),{allow:false,check:null,code:'proxy-key-refused'});
assert.deepEqual(await l.mustStop('demo',SUBJECT,{run:'old-run'}),{stop:true,check:null,code:'proxy-key-refused'});
}
assert.equal(JSON.stringify(log).includes('PRIVATE-LOOKUP-CANARY'),false);assert.equal(JSON.stringify(log).includes('msk-private-lookup'),false);
});
// Row 333 R3 (#1831): the run's own key is looked up, and its lineage decides the leaf. A leaf on
// the retiring key now limits the agent's current key too, so a launch on the current key refuses.
test('P5 trusted lookup uses the retiring run key, and the lineage carries its leaf to the current key',async t=>{
const root=mkdtempSync(join(tmpdir(),'p5-old-key-')),store=new Store(root);t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
const old='012345abcdef',current='abcdef012345',asked=[],doc={plugins:{'limit-check':['daily-quota']},launch:{limits:{tokens:{keys:{[old]:{limit:0,since:SINCE,reset:'00:00',timeZone:'UTC'}}}}}};
const l=createLimits({store,read:()=>doc,log:()=>{},keyForSubject:(_,s)=>{asked.push(s.run??null);return s.run==='old-run'?old:current;},keyLineages:()=>[[current,old]]});
const hit={path:['tokens','keys',old],limit:0,count:0,unknownTurns:0};
assert.deepEqual(await l.mayLaunch('demo',SUBJECT),{allow:false,check:'daily-quota',hit});
assert.deepEqual(await l.mustStop('demo',SUBJECT,{run:'old-run'}),{stop:true,check:'daily-quota',hit});
assert.deepEqual(asked,[null,'old-run']);
const unrelated=createLimits({store,read:()=>doc,log:()=>{},keyForSubject:()=>current,keyLineages:()=>[[current],[old]]});
assert.deepEqual(await unrelated.mayLaunch('demo',SUBJECT),{allow:true});
});
test('P5 actual model metadata lookup rejects missing/ambiguous owners and never cross-attributes a retiring run',async()=>{
const { modelUsageKey }=await import('../src/limits.mjs');
const old='012345abcdef',current='abcdef012345';
const rows=[{service:'model',instance:'demo/coder',keyId:current,retiring:[{keyId:old}]},{service:'model',instance:'other/coder',keyId:'123456abcdef',retiring:[]}];
const runs=new Map([['demo:old-run',{instance:'demo/coder',keyId:old}],['demo:foreign-run',{instance:'other/coder',keyId:'123456abcdef'}]]);
assert.equal(modelUsageKey(rows,runs,'demo',{instance:'coder'}),current);
assert.equal(modelUsageKey(rows,runs,'demo',{instance:'coder',run:'old-run'}),old);
for(const [rs,s] of [[rows,{instance:'coder',run:'absent'}],[rows,{instance:'coder',run:'foreign-run'}],[[...rows,{...rows[0]}],{instance:'coder'}],[[{...rows[0],retiring:[]}],{instance:'coder',run:'old-run'}]]) {
assert.throws(()=>modelUsageKey(rs,runs,'demo',s),{code:'proxy-key-refused'});
}
});
+2
View File
@@ -107,6 +107,8 @@ test('REQ-LIMIT-4 fail closed: a mustStop throw or a malformed answer stops the
[undefined, null], // no answer means { stop: false } from the stub
[{ stop: true, check: 'token-limit', code: 'not-loaded' }, 'limit: token-limit failed not-loaded'],
[{ stop: true, check: null, code: 'organization-unreadable' }, 'limit: bus failed organization-unreadable'],
// Row 333 R3 (#1831) ruling 2: the no-model-key refusal stops the run by its own code.
[{ stop: true, check: null, code: 'key-quota-no-model-key' }, 'limit: bus failed key-quota-no-model-key'],
]) {
const { store, broker, human } = setup(t, answer === undefined ? [] : [answer]);
const coder = broker.bindLaunch({ business: 'demo', role: 'coder', run: 'run1', harness: 'pi' });
+80
View File
@@ -0,0 +1,80 @@
// Row 333 P5 (#1831) background telemetry controls. They run with the bus package suite.
// Only fake loopback HTTP, explicit event barriers and virtual existing timers.
import test from 'node:test';
import assert from 'node:assert/strict';
import { createHash } from 'node:crypto';
import { mkdirSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { startTimeOf } from '../../seat/src/proc.mjs';
import { telemetryFixture, WAIT_MS } from './p5-telemetry-fixture.mjs';
// Captured before any test mocks timers: the outer bound on the R4 barrier test below.
const realSetTimeout=globalThis.setTimeout,realClearTimeout=globalThis.clearTimeout;
async function nativeTurn(f) {
const model=await f.bus.modelPreflight({business:'demo',role:'coder'});
const keyId=createHash('sha256').update(model.key).digest('hex').slice(0,12),dir=join(f.root,'native-transcript');mkdirSync(dir);
const {cap}=f.bus.bindLaunch({business:'demo',role:'coder',run:'held-poll-native',harness:'pi',modelKeyId:keyId,transcript:dir,
pid:process.pid,startTime:startTimeOf(process.pid)});
f.bus.broker.request(cap,{verb:'role.claim'});
assert.deepEqual(await f.bus.mayLaunch({business:'demo',instance:'coder',provider:'fixture',model:'fake'}),{allow:true});
const human=f.human(),{id}=f.bus.broker.request(human,{verb:'message.send',args:{to:'coder',body:'native work while optional queue is held'}});
f.bus.broker.request(cap,{verb:'message.receive'});
await f.bus.broker.request(cap,{verb:'usage.begin',args:{turn:id}});
writeFileSync(join(dir,'native.jsonl'),JSON.stringify({type:'message',id:'native',message:{role:'assistant',usage:{input:2,output:1,cacheRead:0,cacheWrite:0}}})+'\n');
await f.bus.broker.request(cap,{verb:'usage.end',args:{turn:id}});
const view=f.bus.broker.request(human,{verb:'usage'});
assert.equal(view.total.input,2);assert.equal(view.byKey[0].modelKeyId,keyId);
assert.deepEqual(f.bus.broker.request(cap,{verb:'message.receive'}),[]);
}
for(const fail of [false,true])test(`P5 R1 held first optional poll does not delay native startup or work; ${fail?'failure':'release'} settles safely`,async t=>{
t.mock.timers.enable({apis:['Date','setInterval'],now:Date.now()});
const f=await telemetryFixture(t,{hold:true});const started=f.start();
await f.waitQueue(1);await new Promise(setImmediate);
// Causal first guard: the queue is still held, so a ready runtime cannot
// have depended on its response. No racing timeout or longer budget.
assert.notEqual(f.bus,null,'startBroker must resolve while the first queue response is held');
await started;assert.equal(f.state.held.length,1);
assert.equal(f.bus.broker.request(f.human(),{verb:'plugins'}).plugins.usage,'cliproxy-queue');
await nativeTurn(f);assert.equal(f.queueCalls(),1);
t.mock.timers.tick(1000);await new Promise(setImmediate);assert.equal(f.queueCalls(),1,'scheduled ticks share the held first read');
const from=f.logs.length;f.release(fail);
await f.waitLog(fail?'proxy-usage-read-failed':'proxy.usage.reconcile',from);
assert.equal(f.bus.broker.request(f.human(),{verb:'usage'}).proxy.state,fail?'unavailable':'available');
await f.close();assert.equal(f.queueCalls(),1);
});
test('P5 R1 close bounds an outstanding first poll by the unchanged five-second client deadline',async t=>{
t.mock.timers.enable({apis:['Date','setInterval','setTimeout'],now:Date.now()});
const f=await telemetryFixture(t,{hold:true});const started=f.start();await f.waitQueue(1);await new Promise(setImmediate);
assert.notEqual(f.bus,null,'native readiness precedes the held optional poll');await started;
let closed=false;const closing=f.close().then(()=>{closed=true;});
t.mock.timers.tick(4999);await new Promise(setImmediate);assert.equal(closed,false);
t.mock.timers.tick(1);await closing;
assert.equal(closed,true);assert.equal(f.queueCalls(),1);
assert.ok(f.logs.some(line=>line.includes('proxy-usage-read-failed')));
});
// Row 333 R3 (#1831) ruling 5: each fixture wait races a real-timer deadline and names what it
// waited for. Every timer API is mocked here and never advanced, so only the real timer can fire.
test('R3 every telemetry fixture wait rejects by name at its real-timer deadline',async t=>{
assert.equal(WAIT_MS,5000);
t.mock.timers.enable({apis:['Date','setInterval','setTimeout','setImmediate'],now:Date.now()});
const f=await telemetryFixture(t,{waitMs:50});
const started=performance.now();
await assert.rejects(f.waitLog('never-logged'),{message:'p5 fixture: no log line with "never-logged" within 50 ms'});
await assert.rejects(f.waitQueue(1),{message:'p5 fixture: no usage queue read number 1 within 50 ms'});
await assert.rejects(f.settleInitial(),{message:'p5 fixture: no proxy-usage-read-failed or proxy.usage.reconcile log line within 50 ms'});
await assert.rejects(f.pollSettledAfterTick(t),{message:'p5 fixture: no usage queue read number 1 or proxy-usage-read-failed log line within 50 ms'});
assert.ok(performance.now()-started<WAIT_MS,'the four waits ended on the short deadline');
assert.equal(f.queueCalls(),0);
});
// Row 333 R4 (#1831) ruling 3: the successful poll barrier, with every timer API mocked and no virtual
// tick after the one pollSettledAfterTick makes. Its final yield runs inside the deadline on the real
// setImmediate, so it settles. A mocked yield would never fire; the outer real bound names that.
test('R4 a successful poll barrier settles with every timer API mocked and no later virtual tick',async t=>{
t.mock.timers.enable({apis:['Date','setInterval','setTimeout','setImmediate'],now:Date.now()});
const f=await telemetryFixture(t);await f.start();await f.settleInitial();
assert.equal(f.queueCalls(),1);
let bound;
const outer=new Promise((_,reject)=>{bound=realSetTimeout(()=>reject(new Error('pollSettledAfterTick did not settle')),WAIT_MS*2);});
try{await Promise.race([f.pollSettledAfterTick(t),outer]);}finally{realClearTimeout(bound);}
assert.equal(f.queueCalls(),2);
assert.equal(f.bus.broker.request(f.human(),{verb:'usage'}).proxy.state,'available');
});
+38
View File
@@ -0,0 +1,38 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { telemetryFixture } from './p5-telemetry-fixture.mjs';
for(const foreign of [true,false])test(`P5 R1 boot identity ${foreign?'refusal prevents queue consumption':'matching sentinel permits telemetry without an agent key'}`,async t=>{
t.mock.timers.enable({apis:['Date','setInterval'],now:Date.now()});
const f=await telemetryFixture(t,{foreign});await f.start();await f.settleInitial();
const human=f.human();assert.equal(f.bus.broker.request(human,{verb:'plugins'}).plugins.usage,'cliproxy-queue');
if(foreign){
await assert.rejects(f.bus.modelPreflight({business:'demo',role:'coder'}),{code:'proxy-open'});
assert.equal(f.queueCalls(),0);assert.equal(f.state.queued.length,1);
await f.pollSettledAfterTick(t);assert.equal(f.queueCalls(),0);assert.equal(f.state.queued.length,1);
assert.equal(f.bus.broker.request(human,{verb:'usage'}).proxy.state,'unavailable');
}else{
assert.equal(f.queueCalls(),1);assert.equal(f.state.queued.length,0);
assert.equal(f.bus.broker.request(human,{verb:'usage'}).proxy.state,'available');
assert.equal(f.bus.credentials.status().some(r=>r.service==='model'&&r.keyId),false);
}
});
test('P5 R1 later sentinel refusal fences every subsequent queue poll while preserving human control',async t=>{
t.mock.timers.enable({apis:['Date','setInterval'],now:Date.now()});
const f=await telemetryFixture(t);await f.start();await f.settleInitial();assert.equal(f.queueCalls(),1);
f.state.keys=[f.other];
await assert.rejects(f.bus.modelPreflight({business:'demo',role:'coder'}),{code:'proxy-open'});
await f.pollSettledAfterTick(t);assert.equal(f.queueCalls(),1);
await f.pollSettledAfterTick(t);assert.equal(f.queueCalls(),1);
const human=f.human();assert.equal(f.bus.broker.request(human,{verb:'plugins'}).plugins.usage,'cliproxy-queue');
assert.equal(f.bus.broker.request(human,{verb:'usage'}).proxy.state,'unavailable');
});
test('P5 R1 every drain verifies fresh sentinel before consuming a changed listener',async t=>{
t.mock.timers.enable({apis:['Date','setInterval'],now:Date.now()});
const f=await telemetryFixture(t);await f.start();await f.settleInitial();assert.equal(f.queueCalls(),1);
f.state.keys=[f.other];await f.pollSettledAfterTick(t);assert.equal(f.queueCalls(),1);
await assert.rejects(f.bus.modelPreflight({business:'demo',role:'coder'}),{code:'proxy-open'});
const lists=f.state.calls.filter(p=>p==='/v8/management/config/access/api-keys').length;
f.state.keys=[f.own];await f.pollSettledAfterTick(t);assert.equal(f.queueCalls(),1);
assert.equal(f.state.calls.filter(p=>p==='/v8/management/config/access/api-keys').length,lists,'no retry around sticky identity refusal');
});
@@ -0,0 +1,68 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { mkdtempSync, rmSync, readFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { Store } from '../src/store.mjs';
import { createLimits, modelUsageKey } from '../src/limits.mjs';
import * as token from '../../plugins/limit-check/token-limit/index.mjs';
import * as daily from '../../plugins/limit-check/daily-quota/index.mjs';
import { launchSettings } from '../../business/src/launch-settings.mjs';
import { businessDoc, rolesCopy, writeJson, systemFor } from '../../business/tests/helpers.mjs';
const key='abcdefabcdef',other='012345abcdef',since='2026-01-01T00:00:00.000Z';
const quota={limit:10,since,reset:'00:00',timeZone:'UTC'};
const native={at:'2026-10-26T12:00:00.000Z',run:'legacy-run',turn:'turn',account:key,modelKeyId:other,status:'known',input:10,output:0,cacheWrite:0,cacheRead:0};
test('P5 R1 plain twelve-hex account leaves retain matching and original account report even with another model ID',()=>{
const a={limits:{tokens:{keys:{[key]:{limit:10,since}}}},subject:{account:key,modelKeyId:other},records:[native]};
assert.equal(token.mayLaunch(a).allow,false);assert.equal(token.mustStop(a).stop,true);
assert.equal(token.report(a)[0].count,10);assert.deepEqual(token.report(a)[0].path,['tokens','keys',key]);
assert.equal(token.mayLaunch({...a,records:[{...native,input:9}]}).allow,true);
assert.deepEqual(daily.report({...a,now:native.at}),[]);
});
for(const proxy of [false,true])test(`P5 R1 legacy account core lookup stays independent of ${proxy?'unrelated proxy metadata':'missing proxy metadata'}`,async t=>{
const root=mkdtempSync(join(tmpdir(),'p5-legacy-')),store=new Store(root);t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
let lookups=0;
const b={launch:{account:{name:key,credential:'FAKE_TOKEN_NAME'},limits:{tokens:{keys:{[key]:{limit:10,since}}}}},plugins:{'limit-check':['token-limit']}};
const limits=createLimits({store,read:()=>b,log:()=>{},keyForSubject:(...args)=>{lookups++;return proxy?modelUsageKey([{service:'model',instance:'demo/coder',keyId:other,retiring:[]}],new Map(),'demo',args[1]):null;}});
assert.deepEqual(await limits.mayLaunch('demo',{instance:'coder',account:key}),{allow:true});
store.run(`INSERT INTO usage_records(at,business,run,instance,account,turn,source,phase,status,cursor,input,output,cache_write,cache_read)
VALUES (?,'demo','legacy-run','coder',?,'turn','transcript','end','known',?,10,0,0,0)`,native.at,key,JSON.stringify({modelKeyId:other}));
const hit={path:['tokens','keys',key],limit:10,count:10,unknownTurns:0};
assert.deepEqual(await limits.mayLaunch('demo',{instance:'coder',account:key}),{allow:false,check:'token-limit',hit});
assert.deepEqual(await limits.mustStop('demo',{instance:'coder',account:key}),{stop:true,check:'token-limit',hit});
assert.equal(limits.report('demo')[0].count,10);assert.equal(lookups,0);
});
for(const leaf of [{limit:0,since},quota])test(`P5 R1 empty checks bypass model metadata for ${leaf.reset?'daily model':'legacy hex account'} leaves`,async t=>{
const root=mkdtempSync(join(tmpdir(),'p5-no-checks-')),store=new Store(root);t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
let lookups=0;const limits=createLimits({store,read:()=>({plugins:{'limit-check':[]},launch:{limits:{tokens:{keys:{[key]:leaf}}}}}),log:()=>{},keyForSubject:()=>{lookups++;throw Error('MUST-NOT-LOOK-UP');}});
assert.deepEqual(await limits.mayLaunch('demo',{instance:'coder',account:key}),{allow:true});
assert.deepEqual(await limits.mustStop('demo',{instance:'coder',account:key}),{stop:false});assert.equal(lookups,0);
});
test('P5 R1 legacy hex account chief resets stay allowed; daily model old/new/removal/reset transitions stay human-only',t=>{
const root=mkdtempSync(join(tmpdir(),'p5-fence-'));t.after(()=>rmSync(root,{recursive:true,force:true}));
const rolesDir=rolesCopy(root),doc=businessDoc(root,'demo'),file=join(root,'businesses/demo.json');
doc.launch.account={name:key,credential:'FAKE_TOKEN_NAME'};doc.launch.limits={tokens:{keys:{[key]:{limit:10,since}}}};writeJson(file,doc);
let now='2026-10-26T12:00:00.000Z';const settings=launchSettings({dir:root,rolesDir,system:systemFor(root),now:()=>now});let v=settings.read('demo');
v=settings.set('demo',{revision:v.revision,reset:[['tokens','keys',key]]},'chief');
assert.equal(JSON.parse(readFileSync(file,'utf8')).launch.limits.tokens.keys[key].since,now);
const dailyLeaf={limit:10,reset:'00:00',timeZone:'UTC'};
assert.throws(()=>settings.set('demo',{revision:v.revision,limits:{tokens:{keys:{[key]:dailyLeaf}}}},'chief'),{code:'organization-model-quota-human-only'});
v=settings.set('demo',{revision:v.revision,limits:{tokens:{keys:{[key]:dailyLeaf}}}},'jason');now='2026-10-26T13:00:00.000Z';
for(const args of [{reset:[['tokens','keys',key]]},{limits:{}},{limits:{tokens:{keys:{[key]:{limit:10}}}}}])
assert.throws(()=>settings.set('demo',{revision:v.revision,...args},'chief'),{code:'organization-model-quota-human-only'});
v=settings.set('demo',{revision:v.revision,limits:{tokens:{keys:{[key]:{limit:10}}}}},'jason');
v=settings.set('demo',{revision:v.revision,reset:[['tokens','keys',key]]},'chief');
assert.equal(JSON.parse(readFileSync(file,'utf8')).launch.limits.tokens.keys[key].since,now);
});
test('P5 R1 daily model matching/report is separate from legacy account and schema refuses partial or invalid daily shapes',async()=>{
const {checkTokenLimits}=await import('../../business/src/launch.mjs');
assert.deepEqual(checkTokenLimits({keys:{[key]:quota}}).keys[key],quota);
const args={limits:{tokens:{keys:{[key]:quota}}},records:[native],subject:{account:key,modelKeyId:other},now:native.at,lineages:[[key],[other]]};
assert.deepEqual(token.report(args),[]);
assert.equal(daily.mayLaunch(args).allow,true);assert.equal(daily.report(args)[0].count,0);
const owned={...args,subject:{account:'other-account',modelKeyId:key},records:[{...native,account:'other-account',modelKeyId:key}]};
assert.equal(daily.mayLaunch(owned).allow,false);assert.equal(daily.mustStop(owned).stop,true);assert.equal(daily.report(owned)[0].count,10);
for(const leaf of [{...quota,reset:'25:00'},{...quota,timeZone:'Mars/Phobos'},{limit:10,since,reset:'00:00'},{limit:10,since,timeZone:'UTC'}])
assert.throws(()=>checkTokenLimits({keys:{[key]:leaf}}));
});
@@ -0,0 +1,45 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { mkdtempSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { Store } from '../src/store.mjs';
import { Broker } from '../src/broker.mjs';
import { createLimits, modelUsageKey } from '../src/limits.mjs';
const key='012345abcdef';
test('P5 broker preserves original plugin subject and derives internal run context from authenticated native caller',async t=>{
const root=mkdtempSync(join(tmpdir(),'p5-context-')),store=new Store(root),asked=[];t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
const b=new Broker({store,businesses:{demo:{id:'demo',human:'jason',arbiters:{technical:'coder',delivery:'coder'},roles:{coder:{authority:{withinRole:[],crossRole:[]}}}}},
limits:{mustStop:async(...args)=>{asked.push(args);return {stop:false};}},usage:{collect:async()=>({recorded:true}),view:()=>({})}});
const human=b.bindHuman({business:'demo',human:'jason',via:'cli',outsideAgent:true});
const cap=b.bindLaunch({business:'demo',role:'coder',run:'native-run',harness:'pi',provider:'fixture',model:'fake'});b.request(cap,{verb:'role.claim'});
const {id}=b.request(human,{verb:'message.send',args:{to:'coder',body:'work'}});b.request(cap,{verb:'message.receive'});
await b.request(cap,{verb:'usage.begin',args:{turn:id}});
await assert.rejects(b.request(cap,{verb:'usage.end',args:{turn:id,run:'forged-run'}}),{code:'invalid-request'});
assert.equal(asked.length,0);
await b.request(cap,{verb:'usage.end',args:{turn:id}});
assert.deepEqual(asked,[['demo',{instance:'coder',provider:'fixture',model:'fake',account:null},{run:'native-run'}]]);
});
test('P5 configured key quotas never use a supplied safe-looking ID when trusted metadata lookup is missing',async t=>{
const root=mkdtempSync(join(tmpdir(),'p5-no-bypass-')),store=new Store(root);t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
const doc={plugins:{'limit-check':['daily-quota']},launch:{limits:{tokens:{keys:{[key]:{limit:10,since:'2026-01-01T00:00:00.000Z',reset:'00:00',timeZone:'UTC'}}}}}};
const limits=createLimits({store,read:()=>doc,log:()=>{},keyForSubject:()=>null});
assert.deepEqual(await limits.mustStop('demo',{instance:'coder',modelKeyId:key},{run:'forged-run'}),{stop:true,check:null,code:'proxy-key-refused'});
});
test('P5 internal context resolves exactly current or retained generation; wrong business, instance, run and owner refuse',()=>{
// Row 333 R3 ruling 2: no owner record at all is key-quota-no-model-key; a wrong run stays proxy-key-refused.
const newer='abcdef012345',rows=[{instance:'demo/coder',service:'model',keyId:newer,retiring:[{keyId:key}]}];
const runs=new Map([['demo:old',{instance:'demo/coder',keyId:key}],['demo:new',{instance:'demo/coder',keyId:newer}],['other:wrong',{instance:'demo/coder',keyId:key}]]);
assert.equal(modelUsageKey(rows,runs,'demo',{instance:'coder'}),newer);
assert.equal(modelUsageKey(rows,runs,'demo',{instance:'coder',run:'old'}),key);
assert.equal(modelUsageKey(rows,runs,'demo',{instance:'coder',run:'new'}),newer);
for(const [business,subject,code] of [['other',{instance:'coder',run:'wrong'},'key-quota-no-model-key'],['demo',{instance:'other',run:'old'},'key-quota-no-model-key'],['demo',{instance:'coder',run:'wrong'},'proxy-key-refused']])
assert.throws(()=>modelUsageKey(rows,runs,business,subject),{code});
});
test('P5 model-key mustStop without native run context fails closed even when the current key resolves',async t=>{
const root=mkdtempSync(join(tmpdir(),'p5-missing-context-')),store=new Store(root);t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
const doc={plugins:{'limit-check':['daily-quota']},launch:{limits:{tokens:{keys:{[key]:{limit:10,since:'2026-01-01T00:00:00.000Z',reset:'00:00',timeZone:'UTC'}}}}}};
const limits=createLimits({store,read:()=>doc,log:()=>{},keyForSubject:()=>key});
assert.deepEqual(await limits.mustStop('demo',{instance:'coder'}),{stop:true,check:null,code:'proxy-key-refused'});
});
+368
View File
@@ -0,0 +1,368 @@
// Row 333 R3 (#1831): a daily key quota follows the agent its key belongs to, across rotation and
// re-issue, for as long as the agent stays hired. Real Credentials, ModelKeys, Store, createLimits,
// modelUsageKey, modelKeyLineages and the shipped daily-quota check, against a fake loopback
// management server in a fresh temp root. No live config, key, proxy or data root.
import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import http from 'node:http';
import { join } from 'node:path';
import { tmpdir } from 'node:os';
import { createHash, randomBytes } from 'node:crypto';
import { Credentials } from '../src/credentials.mjs';
import { ManagementClient } from '../../model-proxy/src/client.mjs';
import { ModelKeys, MAX_PREVIOUS_KEY_IDS } from '../src/model-keys.mjs';
import { Store } from '../src/store.mjs';
import { createLimits, modelUsageKey, modelKeyLineages, modelKeyLineage } from '../src/limits.mjs';
import { createUsage } from '../src/usage.mjs';
import { launchSettings } from '../../business/src/launch-settings.mjs';
import { businessDoc, rolesCopy, systemFor, writeJson } from '../../business/tests/helpers.mjs';
const hash = s => createHash('sha256').update(s).digest('hex').slice(0, 12);
const START = Date.parse('2026-10-24T12:00:00.000Z');
const GRACE = 120 * 60_000;
const DAY_START = '2026-10-24T00:00:00.000Z';
const SUBJECT = { instance: 'coder', provider: 'fixture', model: 'fake' };
const quota = (limit, since = DAY_START) => ({ limit, since, reset: '00:00', timeZone: 'UTC' });
const quotaDoc = keys => ({ plugins: { 'limit-check': ['daily-quota'] }, launch: { limits: { tokens: { keys } } } });
const hitOf = (id, limit, count) => ({ path: ['tokens', 'keys', id], limit, count, unknownTurns: 0 });
const iso = ms => new Date(ms).toISOString();
async function fixture(t) {
t.mock.timers.enable({ apis: ['Date'], now: START });
const root = fs.mkdtempSync(join(tmpdir(), 'p5-lineage-'));
const configDir = join(root, 'config'), storeRoot = join(configDir, 'secrets', 'agents'), storeDir = join(root, 'store');
fs.mkdirSync(storeRoot, { recursive: true, mode: 0o700 }); fs.mkdirSync(storeDir, { mode: 0o700 });
const prefix = `msk-${hash(configDir)}-`, sentinel = prefix + 'sentinel-' + randomBytes(32).toString('base64url');
const proxy = { keys: [sentinel] };
const server = http.createServer(async (req, res) => {
if (req.url === '/v8/management/config/access/api-keys') {
if (req.headers.authorization !== 'Bearer fx333-manage') { res.writeHead(401); res.end('{}'); return; }
if (req.method === 'GET') { res.end(JSON.stringify(proxy.keys)); return; }
const chunks = []; for await (const c of req) chunks.push(c);
proxy.keys = JSON.parse(Buffer.concat(chunks)); res.end('{"status":"ok"}'); return;
}
res.writeHead(proxy.keys.includes(req.headers.authorization?.slice(7)) ? 200 : 401); res.end('{}');
});
await new Promise(resolve => server.listen(0, '127.0.0.1', resolve));
const baseUrl = `http://127.0.0.1:${server.address().port}`;
const runs = new Map(), stopped = [], logs = [], receipts = [];
let turn = 0;
const f = {
root, configDir, storeRoot, storeDir, proxy, runs, stopped, logs, receipts, prefix,
doc: quotaDoc({}),
read: () => f.doc,
start() {
f.store = new Store(storeDir);
f.credentials = new Credentials({ storeRoot, dataRoot: join(root, 'data'), modelAgents: ['demo/coder', 'demo/other'] });
const client = new ManagementClient({ baseUrl, key: 'fx333-manage', receipt: r => receipts.push(r) });
f.keys = new ModelKeys({ credentials: f.credentials, client, configDir, baseUrl, receipt: r => receipts.push(r),
runs: instance => [...runs.values()].filter(r => r.instance === instance),
stopRuns: async rs => { for (const r of rs) { stopped.push(r.run); runs.delete('demo:' + r.run); } } });
f.limits = createLimits({ store: f.store, read: business => f.read(business), log: e => logs.push(e),
keyForSubject: (business, subject) => modelUsageKey(f.credentials.status(), runs, business, subject),
keyLineages: business => modelKeyLineages(f.credentials.status(), business) });
},
stop() { f.credentials.close(); f.store.close(); },
// A bus restart: every in-memory object goes; the record, the store and the file come back from disk.
restart() { f.stop(); f.start(); },
advance: ms => t.mock.timers.tick(ms),
record: (instance = 'demo/coder') => f.credentials.modelRecord(instance),
status: (instance = 'demo/coder') => f.credentials.status().find(s => s.instance === instance && s.service === 'model'),
bind: (run, keyId) => runs.set('demo:' + run, { business: 'demo', run, instance: 'demo/coder', keyId }),
use: (keyId, tokens, run = 'run-' + (turn + 1)) => f.store.run(`INSERT INTO usage_records(at,business,run,instance,account,turn,source,phase,status,cursor,input,output,cache_write,cache_read)
VALUES (?,'demo',?,'coder',NULL,?,'transcript','end','known',?,?,0,0,0)`, iso(Date.now()), run, 'turn-' + ++turn, JSON.stringify({ modelKeyId: keyId }), tokens),
};
f.start();
t.after(async () => {
f.stop(); server.closeAllConnections(); await new Promise(resolve => server.close(resolve));
fs.rmSync(root, { recursive: true, force: true });
});
return f;
}
const refused = (id, limit, count) => ({ allow: false, check: 'daily-quota', hit: hitOf(id, limit, count) });
test('R3 rotation mid-day: a hit leaf named A refuses before, right after, after the grace and after a restart', async t => {
const f = await fixture(t); await f.keys.reconcile();
await f.keys.ensure('demo/coder'); await f.keys.ensure('demo/other');
const { key: aKey, keyId: A } = f.record();
f.doc = quotaDoc({ [A]: quota(100) }); f.use(A, 100);
// Before the rotation: A is current and spent.
assert.deepEqual(await f.limits.mayLaunch('demo', SUBJECT), refused(A, 100, 100));
// Another hired agent is not under A's quota.
assert.deepEqual(await f.limits.mayLaunch('demo', { ...SUBJECT, instance: 'other' }), { allow: true });
f.bind('run-a', A); f.advance(60_000);
await f.keys.rotate('demo/coder');
const B = f.record().keyId;
assert.notEqual(B, A);
assert.deepEqual(f.record().retiring.map(r => r.keyId), [A]);
assert.equal(f.record().previous, undefined);
// Right after the rotation: B is current, A is retiring, and B has no usage of its own.
assert.deepEqual(await f.limits.mayLaunch('demo', SUBJECT), refused(A, 100, 100));
// The run bound to A still stops at its turn end.
assert.deepEqual(await f.limits.mustStop('demo', SUBJECT, { run: 'run-a' }), { stop: true, check: 'daily-quota', hit: hitOf(A, 100, 100) });
// A sweep inside the grace keeps A retiring while its run is bound.
await f.keys.sweep(); assert.deepEqual(f.record().retiring.map(r => r.keyId), [A]); assert.deepEqual(f.stopped, []);
// After the grace: the sweep stops the run, removes A from the proxy and keeps only its id.
f.advance(GRACE);
await f.keys.sweep();
assert.deepEqual(f.stopped, ['run-a']);
assert.equal(f.proxy.keys.includes(aKey), false);
assert.deepEqual(f.record().retiring, []);
assert.deepEqual(f.record().previous, [{ keyId: A, retiredAt: iso(START + 60_000 + GRACE) }]);
assert.deepEqual(f.status().previous, [{ keyId: A, retiredAt: iso(START + 60_000 + GRACE) }]);
assert.deepEqual(await f.limits.mayLaunch('demo', SUBJECT), refused(A, 100, 100));
// A run still claiming A after A left the proxy is not a key the proxy accepts: it stops.
f.bind('stale', A);
assert.deepEqual(await f.limits.mustStop('demo', SUBJECT, { run: 'stale' }), { stop: true, check: null, code: 'proxy-key-refused' });
f.runs.delete('demo:stale');
// After a bus restart that reloads the record from disk.
f.restart();
assert.deepEqual(f.status().previous, [{ keyId: A, retiredAt: iso(START + 60_000 + GRACE) }]);
assert.deepEqual(await f.limits.mayLaunch('demo', SUBJECT), refused(A, 100, 100));
assert.deepEqual(await f.limits.mayLaunch('demo', { ...SUBJECT, instance: 'other' }), { allow: true });
assert.equal(JSON.stringify([f.receipts, f.logs, f.credentials.status()]).includes(aKey), false);
});
test('R3 re-issue: the proxy no longer lists A at preflight, so B is issued, A joins the earlier ids and the leaf still refuses', async t => {
const f = await fixture(t); await f.keys.reconcile(); await f.keys.ensure('demo/coder');
const { key: aKey, keyId: A } = f.record();
f.doc = quotaDoc({ [A]: quota(100) }); f.use(A, 100);
assert.deepEqual(await f.limits.mayLaunch('demo', SUBJECT), refused(A, 100, 100));
f.proxy.keys = f.proxy.keys.filter(k => k !== aKey); f.advance(60_000);
const issued = await f.keys.preflight('demo/coder');
const B = f.record().keyId;
assert.notEqual(B, A); assert.equal(issued.key === aKey, false);
assert.deepEqual(f.record().retiring, []);
assert.deepEqual(f.record().previous, [{ keyId: A, retiredAt: iso(START + 60_000) }]);
assert.deepEqual(await f.limits.mayLaunch('demo', SUBJECT), refused(A, 100, 100));
f.restart();
assert.deepEqual(await f.limits.mayLaunch('demo', SUBJECT), refused(A, 100, 100));
// Under the limit the agent launches on B again, so the refusal is the count, not the lineage.
f.doc = quotaDoc({ [A]: quota(101) });
assert.deepEqual(await f.limits.mayLaunch('demo', SUBJECT), { allow: true });
});
test('R3 a leaf moved from A to B on rotation day still refuses: the tally sums A and B', async t => {
const f = await fixture(t); await f.keys.reconcile(); await f.keys.ensure('demo/coder');
const A = f.record().keyId;
f.use(A, 60); f.bind('run-a', A); f.advance(60_000);
await f.keys.rotate('demo/coder');
const B = f.record().keyId;
f.use(A, 30, 'run-a'); f.use(B, 70);
// The leaf now names B, with the day's start as since: every turn today on A or B counts.
f.doc = quotaDoc({ [B]: quota(160) });
assert.deepEqual(await f.limits.mayLaunch('demo', SUBJECT), refused(B, 160, 160));
assert.deepEqual(await f.limits.mustStop('demo', SUBJECT, { run: 'run-a' }), { stop: true, check: 'daily-quota', hit: hitOf(B, 160, 160) });
const [entry] = f.limits.report('demo');
assert.equal(entry.status, 'counted'); assert.equal(entry.count, 160);
f.doc = quotaDoc({ [B]: quota(161) });
assert.deepEqual(await f.limits.mayLaunch('demo', SUBJECT), { allow: true });
});
// The settings writer on a scratch organization file, with the lineage lookup the runtime passes it.
function writerFor(f, lookup = (business, id) => modelKeyLineage(f.credentials.status(), business, id)) {
const org = join(f.root, 'org'), file = join(org, 'businesses/demo.json');
const doc = businessDoc(org, 'demo'); doc.plugins = { ...doc.plugins, 'limit-check': ['daily-quota'] }; writeJson(file, doc);
const settings = launchSettings({ dir: org, rolesDir: rolesCopy(org), system: systemFor(org), now: () => iso(Date.now()), keyLineage: lookup });
f.read = id => settings.current(id);
return { settings, file, sinceOf: id => JSON.parse(fs.readFileSync(file, 'utf8')).launch.limits.tokens.keys[id].since };
}
// R4 (#1831) ruling 1: the writer gives the moved leaf the earliest since in its lineage, not the move time.
test('R4 the settings writer keeps a moved leaf\'s since, so the tally sums A and B from the first set; a reset after the move restarts it', async t => {
const f = await fixture(t); await f.keys.reconcile(); await f.keys.ensure('demo/coder');
const A = f.record().keyId, { settings, sinceOf } = writerFor(f);
const leaf = { limit: 100, reset: '00:00', timeZone: 'UTC' };
let v = settings.read('demo');
v = settings.set('demo', { revision: v.revision, limits: { tokens: { keys: { [A]: leaf } } } }, 'jason');
const first = sinceOf(A);
assert.equal(first, iso(START));
f.use(A, 60); f.bind('run-a', A); f.advance(60_000);
await f.keys.rotate('demo/coder');
const B = f.record().keyId;
v = settings.set('demo', { revision: v.revision, limits: { tokens: { keys: { [B]: leaf } } } }, 'jason');
assert.equal(sinceOf(B), first);
f.advance(1000); f.use(A, 30, 'run-a'); f.use(B, 70);
// The 60 before the move count with the 100 after it, on A and B.
assert.deepEqual(await f.limits.mayLaunch('demo', SUBJECT), refused(B, 100, 160));
assert.equal(f.limits.report('demo')[0].count, 160);
// An explicit reset after the move sets now and restarts the count.
f.advance(1000);
v = settings.set('demo', { revision: v.revision, reset: [['tokens', 'keys', B]] }, 'jason');
assert.equal(sinceOf(B), iso(Date.now()));
assert.equal(f.limits.report('demo')[0].count, 0);
assert.deepEqual(await f.limits.mayLaunch('demo', SUBJECT), { allow: true });
});
test('R4 the writer refuses a new key quota when the lineages can\'t be read, and a write that adds none never asks', async t => {
const f = await fixture(t); await f.keys.reconcile(); await f.keys.ensure('demo/coder'); await f.keys.ensure('demo/other');
const A = f.record().keyId, other = f.record('demo/other');
let asked = 0;
const { settings, file, sinceOf } = writerFor(f, (business, id) => { asked++; return modelKeyLineage(f.credentials.status(), business, id); });
const leaf = { limit: 100, reset: '00:00', timeZone: 'UTC' };
let v = settings.read('demo');
v = settings.set('demo', { revision: v.revision, limits: { tokens: { keys: { [A]: leaf } } } }, 'jason');
assert.equal(asked, 1); assert.equal(sinceOf(A), iso(START));
// A key id in two agents' lineages: the lookup throws, and a write adding a key quota refuses unwritten.
f.credentials.writeModel('demo/other', { ...other, previous: [{ keyId: A, retiredAt: iso(START) }] });
assert.throws(() => modelKeyLineage(f.credentials.status(), 'demo', A), { code: 'proxy-key-refused' });
f.advance(1000);
const bytes = fs.readFileSync(file, 'utf8');
assert.throws(() => settings.set('demo', { revision: v.revision, limits: { tokens: { keys: { [A]: { ...leaf }, [other.keyId]: { ...leaf } } } } }, 'jason'),
{ code: 'proxy-key-refused' });
assert.equal(fs.readFileSync(file, 'utf8'), bytes);
assert.equal(asked, 2);
// A write that adds no new key quota (a changed limit, a legacy account limit) saves and never asks.
v = settings.set('demo', { revision: v.revision, limits: { tokens: { keys: { [A]: { ...leaf, limit: 50 }, [hash('acct')]: { limit: 5 } } } } }, 'jason');
assert.equal(asked, 2);
assert.equal(sinceOf(A), iso(START)); assert.equal(sinceOf(hash('acct')), iso(Date.now()));
});
test('R3 lineage uniqueness: a key id in two agents\' lineages refuses', async t => {
const f = await fixture(t); await f.keys.reconcile(); await f.keys.ensure('demo/coder'); await f.keys.ensure('demo/other');
const A = f.record().keyId;
f.doc = quotaDoc({ [A]: quota(100) });
assert.deepEqual(await f.limits.mayLaunch('demo', SUBJECT), { allow: true });
const other = f.record('demo/other');
f.credentials.writeModel('demo/other', { ...other, previous: [{ keyId: A, retiredAt: iso(START) }] });
assert.throws(() => modelKeyLineages(f.credentials.status(), 'demo'), { code: 'proxy-key-refused' });
assert.throws(() => modelUsageKey(f.credentials.status(), f.runs, 'demo', { instance: 'coder' }), { code: 'proxy-key-refused' });
assert.throws(() => modelUsageKey(f.credentials.status(), f.runs, 'demo', { instance: 'other' }), { code: 'proxy-key-refused' });
for (const instance of ['coder', 'other'])
assert.deepEqual(await f.limits.mayLaunch('demo', { ...SUBJECT, instance }), { allow: false, check: null, code: 'proxy-key-refused' });
assert.ok(f.limits.report('demo').every(e => e.status === 'check-failed' && e.code === 'proxy-key-refused'));
// The same id twice in one agent's own lineage refuses too.
f.credentials.writeModel('demo/other', { ...other, previous: [{ keyId: other.keyId, retiredAt: iso(START) }] });
assert.throws(() => modelKeyLineages(f.credentials.status(), 'demo'), { code: 'proxy-key-refused' });
});
test('R3 format: a record without previous loads, a malformed one refuses credential-format, 64 load and 65 refuse', async t => {
const f = await fixture(t);
const file = join(f.storeRoot, 'demo', 'coder', 'model');
const key = () => f.prefix + randomBytes(32).toString('base64url');
const base = (k = key()) => ({ key: k, keyId: hash(k), issuedAt: iso(START), rotateBy: '2026-11-23', state: 'valid', retiring: [] });
const ids = n => Array.from({ length: n }, (_, i) => ({ keyId: hash('earlier-' + i), retiredAt: iso(START - (n - i) * 1000) }));
// A record a pre-R3 bus wrote: no previous field. It loads, and status shows an empty list.
const old = base(); f.credentials.writeModel('demo/coder', old); f.restart();
assert.deepEqual(f.record(), old); assert.deepEqual(f.status().previous, []);
const malformed = [[], 'abc', {}, [null], [[]], [{ keyId: hash('x') }], [{ keyId: hash('x'), retiredAt: iso(START), extra: 1 }],
[{ keyId: 'ABCDEF012345', retiredAt: iso(START) }], [{ keyId: hash('x').slice(0, 11), retiredAt: iso(START) }],
[{ keyId: key(), retiredAt: iso(START) }], [{ keyId: hash('x'), retiredAt: '2026-10-24' }],
[{ keyId: hash('x'), retiredAt: '2026-10-24T12:00:00Z' }], ids(MAX_PREVIOUS_KEY_IDS + 1)];
for (const previous of malformed) {
assert.throws(() => f.credentials.writeModel('demo/coder', { ...old, previous }), { code: 'credential-format' }, JSON.stringify(previous).slice(0, 80));
// The same record found on disk refuses the start rather than being repaired.
fs.writeFileSync(file, JSON.stringify({ ...old, previous }) + '\n', { mode: 0o600 }); fs.chmodSync(file, 0o600);
f.stop();
assert.throws(() => new Credentials({ storeRoot: f.storeRoot, dataRoot: join(f.root, 'data'), modelAgents: ['demo/coder'] }), { code: 'credential-format' });
fs.writeFileSync(file, JSON.stringify(old) + '\n'); f.start();
}
assert.equal(MAX_PREVIOUS_KEY_IDS, 64);
// 64 earlier ids load, with 64 retiring keys beside them, inside the revocation snapshot's 16384 bytes.
const retiring = Array.from({ length: 64 }, () => { const k = key(); return { key: k, keyId: hash(k), issuedAt: iso(START), retireAt: iso(START + GRACE) }; });
const full = { ...old, retiring, previous: ids(64) };
f.credentials.writeModel('demo/coder', full); f.restart();
assert.deepEqual(f.record(), full);
assert.ok(fs.statSync(file).size <= 16384, `model file is ${fs.statSync(file).size} bytes`);
const status = JSON.stringify(f.credentials.status());
assert.equal([old.key, ...retiring.map(r => r.key)].some(k => status.includes(k)), false);
});
test('R3 the earlier ids keep the newest 64: a re-issue on a record holding 64 drops the oldest', async t => {
const f = await fixture(t); await f.keys.reconcile(); await f.keys.ensure('demo/coder');
const now = f.record(), earlier = Array.from({ length: 64 }, (_, i) => ({ keyId: hash('earlier-' + i), retiredAt: iso(START - (64 - i) * 1000) }));
f.credentials.writeModel('demo/coder', { ...now, previous: earlier });
f.proxy.keys = f.proxy.keys.filter(k => k !== now.key); f.advance(1000);
await f.keys.preflight('demo/coder');
const previous = f.record().previous;
assert.equal(previous.length, 64);
assert.deepEqual(previous, [...earlier.slice(1), { keyId: now.keyId, retiredAt: iso(START + 1000) }]);
});
test('R3 fire and re-hire: the old leaf is orphaned, launches go ahead, the view marks it, and no key value is logged or stored', async t => {
const f = await fixture(t); await f.keys.reconcile(); await f.keys.ensure('demo/coder');
const first = f.record(), A = first.keyId;
f.bind('run-a', A); f.advance(60_000); await f.keys.rotate('demo/coder');
f.runs.delete('demo:run-a'); f.advance(1000); await f.keys.sweep();
const fired = f.record();
assert.deepEqual(fired.previous.map(p => p.keyId), [A]);
f.doc = quotaDoc({ [A]: quota(100) }); f.use(A, 100); f.use(fired.keyId, 5);
assert.deepEqual(await f.limits.mayLaunch('demo', SUBJECT), refused(A, 100, 105));
// The fire: revocation proofs compare the whole record, previous included, and still hold.
await f.keys.prepareRevoke('demo/coder'); f.keys.completeRevoke('demo/coder');
assert.equal(f.record(), null);
// Fired and not yet re-hired: no model key, so a key quota can't be matched. Its own code.
f.logs.length = 0;
assert.deepEqual(await f.limits.mayLaunch('demo', SUBJECT), { allow: false, check: null, code: 'key-quota-no-model-key' });
// R4: the refresh before that ask already saw A in no lineage, so A's line comes at the fire.
assert.deepEqual(f.logs.map(e => e.event), ['limit-key-orphaned', 'limit-check-failed']);
// The re-hire starts a new lineage.
await f.keys.ensure('demo/coder');
const C = f.record().keyId;
assert.equal(f.record().previous, undefined);
assert.deepEqual(modelKeyLineages(f.credentials.status(), 'demo'), [[C]]);
f.logs.splice(1);
for (let i = 0; i < 3; i++) assert.deepEqual(await f.limits.mayLaunch('demo', SUBJECT), { allow: true });
assert.deepEqual(f.logs, [{ event: 'limit-key-orphaned', business: 'demo', path: ['tokens', 'keys', A] }]);
assert.deepEqual(f.limits.orphanedKeys('demo'), [A]);
// An orphaned leaf counts its own id only.
const [entry] = f.limits.report('demo');
assert.equal(entry.status, 'counted'); assert.equal(entry.count, 100);
const usage = await createUsage({ store: f.store, businesses: { demo: f.doc }, log: e => f.logs.push(e), keyOrphans: b => f.limits.orphanedKeys(b) });
const view = usage.view('demo');
assert.deepEqual(view.orphanedKeyQuotas, [A]);
assert.deepEqual(f.logs, [{ event: 'limit-key-orphaned', business: 'demo', path: ['tokens', 'keys', A] }]);
// A leaf that matches again leaves the list and logs nothing new.
f.doc = quotaDoc({ [C]: quota(100) });
assert.deepEqual(f.limits.orphanedKeys('demo'), []);
assert.equal(usage.view('demo').orphanedKeyQuotas, undefined);
// No key value anywhere: logs, view, receipts, status, or the store's files.
const values = [first.key, fired.key, f.record().key];
const seen = JSON.stringify([f.logs, view, f.receipts, f.credentials.status()]);
assert.equal(values.some(k => seen.includes(k)), false);
f.store.close();
for (const name of fs.readdirSync(join(f.storeDir, 'bus'))) {
const bytes = fs.readFileSync(join(f.storeDir, 'bus', name)).toString('latin1');
assert.equal(values.some(k => bytes.includes(k)), false, name);
}
f.store = new Store(f.storeDir);
});
test('R3 ruling 2: an agent with no model key under a key quota refuses key-quota-no-model-key, launch and turn end', async t => {
const f = await fixture(t);
f.doc = quotaDoc({ [hash('some-key')]: quota(100) });
assert.equal(f.status().state, 'not-issued');
assert.throws(() => modelUsageKey(f.credentials.status(), f.runs, 'demo', { instance: 'coder' }), { code: 'key-quota-no-model-key' });
assert.deepEqual(await f.limits.mayLaunch('demo', SUBJECT), { allow: false, check: null, code: 'key-quota-no-model-key' });
f.bind('run-x', hash('some-key'));
assert.deepEqual(await f.limits.mustStop('demo', SUBJECT, { run: 'run-x' }), { stop: true, check: null, code: 'key-quota-no-model-key' });
// R4: the refresh before the first ask logs the leaf no agent holds, once.
assert.deepEqual(f.logs.map(e => e.code ?? e.event), ['limit-key-orphaned', 'key-quota-no-model-key', 'key-quota-no-model-key']);
// A business with no key quota never asks.
f.doc = quotaDoc({});
assert.deepEqual(await f.limits.mayLaunch('demo', SUBJECT), { allow: true });
});
// R4 (#1831) ruling 2: every refresh observes the orphans, and no daily key quota left remembers none.
test('R4 an orphaned leaf removed and added back logs twice; repeated refreshes of an unchanged orphan log once; a restart observes afresh', async t => {
const f = await fixture(t); await f.keys.reconcile(); await f.keys.ensure('demo/coder');
const X = hash('fired-agent-key'), line = { event: 'limit-key-orphaned', business: 'demo', path: ['tokens', 'keys', X] };
f.doc = quotaDoc({ [X]: quota(100) });
assert.deepEqual(f.limits.orphanedKeys('demo'), [X]);
assert.deepEqual(f.logs, [line]);
// Removed: the refresh after the write sees no daily key quota. Added back: the next refresh logs again.
f.doc = quotaDoc({}); await f.limits.refresh('demo');
f.doc = quotaDoc({ [X]: quota(100) }); await f.limits.refresh('demo');
assert.deepEqual(await f.limits.mayLaunch('demo', SUBJECT), { allow: true });
assert.deepEqual(f.logs, [line, line]);
// Unchanged: refreshes, launches and views add nothing.
for (let i = 0; i < 3; i++) await f.limits.refresh('demo');
assert.deepEqual(await f.limits.mayLaunch('demo', SUBJECT), { allow: true });
assert.deepEqual(f.limits.orphanedKeys('demo'), [X]);
assert.deepEqual(f.logs, [line, line]);
// A bus restart remembers nothing: its first refresh logs the unchanged orphan once more, then no more.
f.restart();
for (let i = 0; i < 3; i++) await f.limits.refresh('demo');
assert.deepEqual(f.logs, [line, line, line]);
});
+110
View File
@@ -0,0 +1,110 @@
// P5 end-to-end within one process: only fresh fake config, credentials and loopback HTTP.
import test from 'node:test';
import assert from 'node:assert/strict';
import http from 'node:http';
import { createHash, randomBytes } from 'node:crypto';
import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { startBroker } from '../src/runtime.mjs';
import { Registry } from '../../seat/src/session.mjs';
import { startTimeOf } from '../../seat/src/proc.mjs';
import { businessDoc, rolesCopy, systemFor, writeJson } from '../../business/tests/helpers.mjs';
const hash=s=>createHash('sha256').update(s).digest('hex').slice(0,12);
test('P5 real runtime binds stack usage to issued key, daily stops at stack count and human-only telemetry settings pass broker contract',async t=>{
const root=mkdtempSync(join(tmpdir(),'p5-runtime-')),config=join(root,'config'),data=join(root,'data');
mkdirSync(config,{mode:0o700});mkdirSync(data,{mode:0o700});const rolesDir=rolesCopy(config),doc=businessDoc(config,'demo');
doc.plugins={'usage-source':['transcript'],'limit-check':['daily-quota'],harness:['pi']};
writeJson(join(config,'businesses/demo.json'),doc);mkdirSync(join(config,'secrets'),{recursive:true,mode:0o700});
writeFileSync(join(config,'secrets/proxy-management.key'),'p5-fake-management',{mode:0o600});
new Registry(data);
let keys=[`msk-${hash(config)}-sentinel-${randomBytes(32).toString('base64url')}`],queue=[],calls=[];
const server=http.createServer(async(req,res)=>{
calls.push(req.url);
if(req.url==='/v8/management/config/access/api-keys') {
if(req.method==='PUT'){let b='';for await(const c of req)b+=c;keys=JSON.parse(b);res.end('{"status":"ok"}');}
else res.end(JSON.stringify(keys));return;
}
if(req.url==='/v8/management/observability/usage/queue?count=100'){res.end(JSON.stringify(queue));queue=[];return;}
res.writeHead(keys.includes(req.headers.authorization?.slice(7))?200:401);res.end('{}');
});
await new Promise(r=>server.listen(0,'127.0.0.1',r));let bus;
t.after(async()=>{await bus?.close();await new Promise(r=>server.close(r));rmSync(root,{recursive:true,force:true});});
bus=await startBroker({dataRoot:data,businesses:{demo:{id:'demo',human:'jason',plugins:doc.plugins,arbiters:{technical:'coder',delivery:'coder'},roles:{coder:{definition:'coder',authority:{withinRole:[],crossRole:[]}}}}},
organization:{dir:config,rolesDir,system:systemFor(config)},proxy:{port:server.address().port,binary:'/fixture-unused'}});
assert.equal(calls.some(p=>p.includes('usage/queue')),false);
const model=await bus.modelPreflight({business:'demo',role:'coder'}),keyId=hash(model.key);
const human=bus.broker.bindHuman({business:'demo',human:'jason',via:'cli',outsideAgent:true});
let limits=bus.broker.request(human,{verb:'limits'});
bus.broker.request(human,{verb:'limits.set',args:{revision:limits.revision,limits:{tokens:{keys:{[keyId]:{limit:2,reset:'00:00',timeZone:'UTC'}}}}}});
assert.equal((await bus.mayLaunch({business:'demo',instance:'coder',provider:'fixture',model:'fake'})).allow,true);
const dir=join(root,'transcript');mkdirSync(dir);
const {cap}=bus.bindLaunch({business:'demo',role:'coder',run:'p5-run',harness:'pi',modelKeyId:keyId,transcript:dir,pid:process.pid,startTime:startTimeOf(process.pid)});
bus.broker.request(cap,{verb:'role.claim'});
const {id}=bus.broker.request(human,{verb:'message.send',args:{to:'coder',body:'fake work'}});
bus.broker.request(cap,{verb:'message.receive'});
await bus.broker.request(cap,{verb:'usage.begin',args:{turn:id}});
writeFileSync(join(dir,'s.jsonl'),JSON.stringify({type:'message',id:'fake',message:{role:'assistant',usage:{input:2,output:0,cacheWrite:0,cacheRead:0}}})+'\n');
await bus.broker.request(cap,{verb:'usage.end',args:{turn:id}});
const view=bus.broker.request(human,{verb:'usage'});assert.equal(view.byKey[0].modelKeyId,keyId);assert.equal(view.byKey[0].input,2);
assert.equal((await bus.mayLaunch({business:'demo',instance:'coder',provider:'fixture',model:'fake'})).allow,false);
assert.throws(()=>bus.broker.request(cap,{verb:'message.receive'}),{code:'not-holder'});
let plugins=bus.broker.request(human,{verb:'plugins'});
plugins=bus.broker.request(human,{verb:'plugins.set',args:{revision:plugins.revision,plugins:{usage:'cliproxy-queue'},usage:{cliproxyQueue:{pollSeconds:7}}}});
assert.equal(plugins.plugins.usage,'cliproxy-queue');assert.equal(plugins.usage.cliproxyQueue.pollSeconds,7);
const history=readFileSync(join(config,'businesses/.history/demo/changes.jsonl'),'utf8');
for(const value of [model.key,'p5-fake-management'])assert.equal(JSON.stringify([view,history]).includes(value),false);
});
// Row 333 R4 (#1831): the writer the runtime builds keeps a moved quota's since through the runtime's
// own key lineage lookup. The runtime keeps its ModelKeys inside, so the move follows a re-issue: the
// fake proxy stops listing A and the next preflight issues B with A among its earlier ids.
test('R4 real runtime: a quota spent on A and moved to B with no reset still refuses the next launch', async t => {
const root=mkdtempSync(join(tmpdir(),'p5-runtime-')),config=join(root,'config'),data=join(root,'data');
mkdirSync(config,{mode:0o700});mkdirSync(data,{mode:0o700});const rolesDir=rolesCopy(config),doc=businessDoc(config,'demo');
doc.plugins={'usage-source':['transcript'],'limit-check':['daily-quota'],harness:['pi']};
writeJson(join(config,'businesses/demo.json'),doc);mkdirSync(join(config,'secrets'),{recursive:true,mode:0o700});
writeFileSync(join(config,'secrets/proxy-management.key'),'p5-fake-management',{mode:0o600});
new Registry(data);
let keys=[`msk-${hash(config)}-sentinel-${randomBytes(32).toString('base64url')}`];
const server=http.createServer(async(req,res)=>{
if(req.url==='/v8/management/config/access/api-keys') {
if(req.method==='PUT'){let b='';for await(const c of req)b+=c;keys=JSON.parse(b);res.end('{"status":"ok"}');}
else res.end(JSON.stringify(keys));return;
}
if(req.url==='/v8/management/observability/usage/queue?count=100'){res.end('[]');return;}
res.writeHead(keys.includes(req.headers.authorization?.slice(7))?200:401);res.end('{}');
});
await new Promise(r=>server.listen(0,'127.0.0.1',r));let bus;
t.after(async()=>{await bus?.close();await new Promise(r=>server.close(r));rmSync(root,{recursive:true,force:true});});
bus=await startBroker({dataRoot:data,businesses:{demo:{id:'demo',human:'jason',plugins:doc.plugins,arbiters:{technical:'coder',delivery:'coder'},roles:{coder:{definition:'coder',authority:{withinRole:[],crossRole:[]}}}}},
organization:{dir:config,rolesDir,system:systemFor(config)},proxy:{port:server.address().port,binary:'/fixture-unused'}});
const stored=()=>JSON.parse(readFileSync(join(config,'businesses/demo.json'),'utf8')).launch.limits.tokens.keys;
const may=async()=>(await bus.mayLaunch({business:'demo',instance:'coder',provider:'fixture',model:'fake'})).allow;
const a=await bus.modelPreflight({business:'demo',role:'coder'}),A=hash(a.key);
const human=bus.broker.bindHuman({business:'demo',human:'jason',via:'cli',outsideAgent:true});
const leaf={limit:2,reset:'00:00',timeZone:'UTC'};
let limits=bus.broker.request(human,{verb:'limits'});
limits=bus.broker.request(human,{verb:'limits.set',args:{revision:limits.revision,limits:{tokens:{keys:{[A]:{...leaf}}}}}});
const since=stored()[A].since;assert.equal(await may(),true);
// The agent spends the whole allowance on A.
const dir=join(root,'transcript');mkdirSync(dir);
const {cap}=bus.bindLaunch({business:'demo',role:'coder',run:'r4-run',harness:'pi',modelKeyId:A,transcript:dir,pid:process.pid,startTime:startTimeOf(process.pid)});
bus.broker.request(cap,{verb:'role.claim'});
const {id}=bus.broker.request(human,{verb:'message.send',args:{to:'coder',body:'fake work'}});
bus.broker.request(cap,{verb:'message.receive'});
await bus.broker.request(cap,{verb:'usage.begin',args:{turn:id}});
writeFileSync(join(dir,'s.jsonl'),JSON.stringify({type:'message',id:'fake',message:{role:'assistant',usage:{input:2,output:0,cacheWrite:0,cacheRead:0}}})+'\n');
await bus.broker.request(cap,{verb:'usage.end',args:{turn:id}});
assert.equal(await may(),false);
// The proxy loses A, so the next preflight issues B; then the human moves the unchanged quota to B.
keys=keys.filter(k=>k!==a.key);
const b=await bus.modelPreflight({business:'demo',role:'coder'}),B=hash(b.key);assert.notEqual(B,A);
await new Promise(r=>setTimeout(r,20)); // a fresh `now` would fall after the turn's record
limits=bus.broker.request(human,{verb:'limits'});
bus.broker.request(human,{verb:'limits.set',args:{revision:limits.revision,limits:{tokens:{keys:{[B]:{...leaf}}}}}});
assert.deepEqual(stored(),{[B]:{...leaf,since}});
const report=bus.broker.request(human,{verb:'limits'});
assert.equal(JSON.stringify(report).includes(a.key)||JSON.stringify(report).includes(b.key),false);
assert.equal(await may(),false);
});
@@ -0,0 +1,78 @@
// Fresh, made-up instance and local management listener only; no worker/provider.
import http from 'node:http';
import { createHash, randomBytes } from 'node:crypto';
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { startBroker } from '../src/runtime.mjs';
import { Registry } from '../../seat/src/session.mjs';
import { businessDoc, rolesCopy, systemFor, writeJson } from '../../business/tests/helpers.mjs';
// Row 333 R3 (#1831): every wait races a real-timer deadline, captured here before any test mocks
// setTimeout, so a missed event fails by name instead of hanging the file. R4: the real setImmediate
// too, for the yield after a poll, which now runs inside that poll's deadline.
const realSetTimeout = globalThis.setTimeout, realClearTimeout = globalThis.clearTimeout, realSetImmediate = globalThis.setImmediate;
export const WAIT_MS = 5000;
function deadline(promise, what, ms) {
let timer;
const expired = new Promise((_, reject) => { timer = realSetTimeout(() => reject(new Error(`p5 fixture: ${what} within ${ms} ms`)), ms); });
return Promise.race([promise, expired]).finally(() => realClearTimeout(timer));
}
export async function telemetryFixture(t, { foreign = false, hold = false, waitMs = WAIT_MS } = {}) {
const root = mkdtempSync(join(tmpdir(), 'p5-telemetry-')), config = join(root,'config'), data = join(root,'data');
mkdirSync(config,{mode:0o700}); mkdirSync(data,{mode:0o700});
const rolesDir = rolesCopy(config), doc = businessDoc(config,'demo');
doc.plugins = { usage:'cliproxy-queue', harness:['pi'], 'usage-source':['transcript'], 'limit-check':['token-limit'] };
doc.usage = { cliproxyQueue:{pollSeconds:1} };
writeJson(join(config,'businesses/demo.json'),doc);
mkdirSync(join(config,'secrets'),{recursive:true,mode:0o700});
writeFileSync(join(config,'secrets/proxy-management.key'),'p5-r1-made-up-management',{mode:0o600});
new Registry(data);
const tag = createHash('sha256').update(config).digest('hex').slice(0,12);
const own = `msk-${tag}-sentinel-${randomBytes(32).toString('base64url')}`;
const other = `msk-ffffffffffff-sentinel-${randomBytes(32).toString('base64url')}`;
const state = { keys:[foreign?other:own], calls:[], queued:[{api_key:'msk-r1-unknown-fake',source:'p5-r1-upstream-canary',failed:false,tokens:{input_tokens:1,output_tokens:2}}], held:[], hold };
const logs=[], waiters=[];
const stderr = process.stderr.write;
t.mock.method(process.stderr,'write',function(chunk,...args) {
const text=String(chunk);logs.push(text);
for(const waiter of [...waiters]) if(text.includes(waiter.fragment) && logs.length>waiter.from) { waiters.splice(waiters.indexOf(waiter),1);waiter.resolve(); }
return stderr.call(this,chunk,...args);
});
const logSeen=(fragment,from=0)=> {
if(logs.slice(from).some(line=>line.includes(fragment)))return Promise.resolve();
return new Promise(resolve=>waiters.push({fragment,from,resolve}));
};
const waitLog=(fragment,from=0)=>deadline(logSeen(fragment,from),`no log line with "${fragment}"`,waitMs);
let queueWaiters=[];
const queueSeen=(count)=> state.calls.filter(p=>p.includes('/usage/queue')).length>=count?Promise.resolve():new Promise(resolve=>queueWaiters.push({count,resolve}));
const waitQueue=(count)=>deadline(queueSeen(count),`no usage queue read number ${count}`,waitMs);
const answerQueue=res=>{res.end(JSON.stringify(state.queued));state.queued=[];};
const server=http.createServer(async(req,res)=>{
state.calls.push(req.url);
if(req.headers.authorization!=='Bearer p5-r1-made-up-management' && req.url.startsWith('/v8/management/')) {res.writeHead(401);res.end('{}');return;}
if(req.url==='/v8/management/config/access/api-keys') {
if(req.method==='PUT'){let body='';for await(const c of req)body+=c;state.keys=JSON.parse(body);res.end('{"status":"ok"}');}
else res.end(JSON.stringify(state.keys));return;
}
if(req.url==='/v8/management/observability/usage/queue?count=100') {
if(state.hold)state.held.push(res);else answerQueue(res);
const count=state.calls.filter(p=>p.includes('/usage/queue')).length;
for(const waiter of queueWaiters.filter(w=>count>=w.count))waiter.resolve();
queueWaiters=queueWaiters.filter(w=>count<w.count);return;
}
res.writeHead(state.keys.includes(req.headers.authorization?.slice(7))?200:401);res.end('{}');
});
await new Promise(resolve=>server.listen(0,'127.0.0.1',resolve));
let bus=null,startPromise=null,closePromise=null;
const start=()=>startPromise??=(startBroker({dataRoot:data,businesses:{demo:{id:'demo',human:'jason',plugins:doc.plugins,arbiters:{technical:'coder',delivery:'coder'},roles:{coder:{definition:'coder',authority:{withinRole:[],crossRole:[]}}}}},
organization:{dir:config,rolesDir,system:systemFor(config)},proxy:{port:server.address().port,binary:'/fixture-unused'}}).then(value=>(bus=value)));
const release=(fail=false)=>{state.hold=false;for(const res of state.held.splice(0)){if(res.destroyed)continue;if(fail){res.writeHead(503);res.end('{}');}else answerQueue(res);}};
const close=()=>bus?(closePromise??=bus.close()):Promise.resolve();
t.after(async()=>{release();await startPromise?.catch(()=>{});await close();server.closeAllConnections();await new Promise(r=>server.close(r));rmSync(root,{recursive:true,force:true});});
return {root,data,config,state,logs,own,other,start,waitLog,waitQueue,release,close,
settleInitial:()=>deadline(Promise.race([logSeen('proxy-usage-read-failed'),logSeen('proxy.usage.reconcile')]),'no proxy-usage-read-failed or proxy.usage.reconcile log line',waitMs),
get bus(){return bus;},queueCalls:()=>state.calls.filter(p=>p.includes('/usage/queue')).length,
human:()=>bus.broker.bindHuman({business:'demo',human:'jason',via:'cli',outsideAgent:true}),
async pollSettledAfterTick(t){const from=logs.length,next=state.calls.filter(p=>p.includes('/usage/queue')).length+1;t.mock.timers.tick(1000);await deadline(Promise.race([queueSeen(next),logSeen('proxy-usage-read-failed',from)]).then(()=>new Promise(resolve=>realSetImmediate(resolve))),`no usage queue read number ${next} or proxy-usage-read-failed log line`,waitMs);},
};
}
+111
View File
@@ -0,0 +1,111 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import http from 'node:http';
import { mkdtempSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { createHash } from 'node:crypto';
import { Store } from '../src/store.mjs';
import { createUsage, turnRecords } from '../src/usage.mjs';
import { createLimits } from '../src/limits.mjs';
import { createProxyUsage } from '../src/proxy-usage.mjs';
import { ManagementClient } from '../../model-proxy/src/client.mjs';
import { createLoader } from '../../plugins/src/loader.mjs';
const id = s => createHash('sha256').update(s).digest('hex').slice(0,12);
const key='msk-fake-client-value',source='fake-upstream-value',keyId=id(key);
async function fixture(t,{makeLoader}={}) {
const root=mkdtempSync(join(tmpdir(),'proxy-usage-')),store=new Store(root),logs=[],calls=[];
let events=[],now=0,fail=false;
const server=http.createServer((req,res)=>{calls.push(req.url);res.writeHead(fail?500:200);res.end(JSON.stringify(events));events=[];});
await new Promise(r=>server.listen(0,'127.0.0.1',r));
const client=new ManagementClient({baseUrl:`http://127.0.0.1:${server.address().port}`,key:'fake-management',receipt:e=>logs.push(e)});
let doc={plugins:{},launch:{limits:{tokens:{keys:{[keyId]:{limit:1,since:'2026-01-01T00:00:00.000Z'}}}}}};
const reader=createProxyUsage({store,read:()=>({demo:doc}),client:()=>client,...(makeLoader?{makeLoader}:{}),records:()=>[{instance:'demo/coder',service:'model',keyId,retiring:[]}],log:e=>logs.push(e),now:()=>now});
t.after(async()=>{await reader.close();await new Promise(r=>server.close(r));store.close();rmSync(root,{recursive:true,force:true});});
const event=(over={})=>({api_key:key,source,failed:true,fail:{status_code:503,body:source},tokens:{input_tokens:9,output_tokens:2},...over});
return {store,logs,calls,reader,client,event,setEvents:v=>{events=v;},clock:v=>{now=v;},enable:(pollSeconds)=>{doc={...doc,plugins:{usage:'cliproxy-queue','limit-check':['token-limit']},...(pollSeconds===undefined?{}:{usage:{cliproxyQueue:{pollSeconds}}})};},doc:()=>doc,fail:()=>{fail=true;}};
}
test('P5 usage plugin off by default, default poll is 15 seconds and configured polls skip early ticks',async t=>{
const f=await fixture(t);await f.reader.tick();assert.equal(f.calls.length,0);assert.equal(f.reader.view('demo'),null);
f.enable();await f.reader.tick();assert.equal(f.calls.length,1);
f.clock(14999);await f.reader.tick();assert.equal(f.calls.length,1);
f.clock(15000);await f.reader.tick();assert.equal(f.calls.length,2);
f.enable(7);f.clock(16000);await f.reader.tick();assert.equal(f.calls.length,3);
f.clock(22999);await f.reader.tick();assert.equal(f.calls.length,3);
f.clock(23000);await f.reader.tick();assert.equal(f.calls.length,4);
});
test('P5 safe telemetry stores failures per key and proxy-labelled accounts; no client/upstream value enters store/log/view or quota records',async t=>{
const f=await fixture(t);f.enable();f.setEvents([f.event()]);await f.reader.tick();
const v=f.reader.view('demo');assert.equal(v.source,'proxy');assert.equal(v.byKey[0].keyId,keyId);assert.equal(v.byKey[0].failures,1);assert.deepEqual(v.byKey[0].statuses,{'503':1});
assert.equal(v.byAccount[0].accountId,id(source));assert.equal(v.byAccount[0].input,9);
const usage=await createUsage({store:f.store,businesses:{demo:f.doc()},log:()=>{},proxyView:b=>f.reader.view(b)});
assert.equal(usage.view('demo').proxy.source,'proxy');assert.equal(usage.view('demo').total.input,0);
assert.deepEqual(turnRecords(f.store,'demo'),[]);
const limits=createLimits({store:f.store,read:()=>f.doc(),log:()=>{},keyForSubject:()=>keyId});
assert.equal((await limits.mayLaunch('demo',{instance:'coder',modelKeyId:keyId})).allow,true);
for(const value of [key,source,'fake-management']) assert.equal(JSON.stringify([f.store.all('SELECT * FROM usage_records'),f.logs,usage.view('demo')]).includes(value),false);
});
test('P5 unknown msk key goes only to value-free reconcile log and other businesses stay isolated',async t=>{
const f=await fixture(t);f.enable();f.setEvents([f.event({api_key:'msk-unknown-canary'}),f.event({api_key:'external-canary'})]);await f.reader.tick();
assert.deepEqual(f.logs.find(e=>e.action==='proxy.usage.reconcile'),{action:'proxy.usage.reconcile',keyId:id('msk-unknown-canary'),code:'proxy-usage-unknown-key'});
assert.equal(f.reader.view('demo').byKey.length,0);assert.equal(f.reader.view('other'),null);
assert.equal(JSON.stringify(f.logs).includes('msk-unknown-canary'),false);
assert.equal(f.store.all('SELECT * FROM usage_records').length,0);
});
test('P5 queue failure is safe, does not enforce and does not retry before poll deadline',async t=>{
const f=await fixture(t);f.enable();f.fail();await f.reader.tick();await f.reader.tick();
assert.equal(f.calls.length,1);assert.equal(f.logs.at(-1).code,'proxy-usage-read-failed');assert.equal(f.reader.view('demo').state,'unavailable');
});
test('P5 retiring key keeps attribution and telemetry rows remain append-only across reader restart',async t=>{
const f=await fixture(t);f.enable();f.setEvents([f.event()]);await f.reader.tick();
const before=f.reader.view('demo');await f.reader.close();
const again=createProxyUsage({store:f.store,read:()=>({demo:f.doc()}),client:()=>null,records:()=>[],log:()=>{}});
assert.deepEqual(again.view('demo').byKey,before.byKey);await again.close();
assert.throws(()=>f.store.run('DELETE FROM usage_records'),/append-only/);
});
test('P5 malformed queue batch is atomic: no valid prefix, body or credential can reach store/log/view',async t=>{
const f=await fixture(t);f.enable();f.setEvents([f.event(),f.event({source:'malformed-upstream-canary',tokens:{input_tokens:-1}})]);await f.reader.tick();
assert.equal(f.store.all('SELECT * FROM usage_records').length,0);
for(const secret of [key,source,'malformed-upstream-canary'])assert.equal(JSON.stringify([f.logs,f.reader.view('demo')]).includes(secret),false);
});
test('P5 concurrent ticks issue one bounded queue read and a closed collector never polls again',async t=>{
const f=await fixture(t);f.enable();await Promise.all([f.reader.tick(),f.reader.tick(),f.reader.tick()]);assert.equal(f.calls.length,1);
await f.reader.close();f.clock(90000);await f.reader.tick();assert.equal(f.calls.length,1);
});
// Row 333 R3 (#1831) ruling 4: the usage module's argument is { readUsageQueue } and nothing else.
// Nothing reachable from it by reflection is the management client or any of its other calls.
test('R3 the usage module is handed one function, readUsageQueue, and no path to the management client',async t=>{
const handed=[];
const makeLoader=opts=>{const loader=createLoader(opts);return {...loader,modules:kind=>loader.modules(kind).map(m=>kind==='usage'&&m?{interfaceVersion:m.interfaceVersion,read:arg=>{handed.push(arg);return m.read(arg);}}:m)};};
const f=await fixture(t,{makeLoader});
const methods=Object.getOwnPropertyNames(ManagementClient.prototype).filter(n=>n!=='constructor');
for(const name of ['readUsageQueue','getKeys','putKeys','oauthStart','oauthCallback','oauthStatus','oauthCancel']) assert.ok(methods.includes(name),name);
const called=[];
for(const name of methods){const real=f.client[name].bind(f.client);Object.defineProperty(f.client,name,{value:(...a)=>{called.push(name);return real(...a);}});}
f.enable();f.setEvents([f.event()]);await f.reader.tick();
assert.equal(handed.length,1);
const [arg]=handed;
assert.deepEqual(Reflect.ownKeys(arg),['readUsageQueue']);
assert.equal(typeof arg.readUsageQueue,'function');assert.equal(Object.isFrozen(arg),true);
assert.equal(Object.getPrototypeOf(arg),Object.prototype);
// Walk every own property, accessor and prototype reachable from the argument without calling it.
const stop=new Set([Object.prototype,Function.prototype]),seen=new Set(),queue=[arg],names=new Set();
while(queue.length){
const v=queue.shift();
if(v===null||(typeof v!=='object'&&typeof v!=='function')||seen.has(v)||stop.has(v))continue;
seen.add(v);
assert.notEqual(v,f.client);assert.notEqual(v,ManagementClient.prototype);assert.notEqual(v,ManagementClient);
for(const key of Reflect.ownKeys(v)){
names.add(key);
const d=Reflect.getOwnPropertyDescriptor(v,key);
queue.push(d.value,d.get,d.set);
}
queue.push(Object.getPrototypeOf(v));
}
for(const name of methods.filter(n=>n!=='readUsageQueue')) assert.equal(names.has(name),false,name);
for(const name of methods) for(const v of seen) assert.notEqual(v,ManagementClient.prototype[name],name);
// The one call the module made was the queue read.
assert.deepEqual(called,['readUsageQueue']);
assert.equal(f.reader.view('demo').byKey[0].failures,1);
});
+18
View File
@@ -153,3 +153,21 @@ test('row 65 a run bound without a transcript directory records no-transcript',
assert.equal(f.usage.view('demo').total.unknownTurns, 1);
assert.ok(transcript);
});
test('P5 immutable stack key attribution survives rotation and restart without key values', async t => {
const f=await fixture(t),keyId='012345abcdef';let current=keyId;
const usage=await createUsage({store:f.store,businesses:{demo:{plugins:{'usage-source':['transcript']}}},log:()=>{},keyForRun:()=>current});
f.save([]);await usage.collect(f.session,'begin','key-turn');current='abcdef012345';
f.save([f.put('new')]);await usage.collect(f.session,'end','key-turn');
assert.equal(usage.view('demo').byKey[0].modelKeyId,keyId);
assert.equal(usage.view('demo').byKey[0].input,2);
const again=await createUsage({store:f.store,businesses:{demo:{plugins:{}}},log:()=>{}});
assert.equal(again.view('demo').byKey[0].modelKeyId,keyId);
});
test('P5 malformed key metadata is dropped rather than stored or exposed as a key value',async t=>{
const f=await fixture(t);
const usage=await createUsage({store:f.store,businesses:{demo:{plugins:{}}},log:e=>f.logs.push(e),keyForRun:()=> 'msk-fake-invalid-metadata-canary'});
await usage.collect(f.session,'begin','invalid-key');await usage.collect(f.session,'end','invalid-key');
assert.equal(JSON.stringify([f.store.all('SELECT * FROM usage_records'),f.logs,usage.view('demo')]).includes('msk-fake-invalid-metadata-canary'),false);
});
+17
View File
@@ -124,6 +124,23 @@ launcher's check. `launch.limits.tokens.daily` maps an account to
name `Intl` accepts. A daily quota for any name but `launch.account.name`
refuses the file, since it would count nothing.
`launch.limits.tokens.keys` holds token limits by key name. A leaf named by a
twelve-hex model key id with `{limit, since, reset, timeZone}` is a daily quota
on one agent's model key (row 333); a plain `{limit, since}` leaf stays a
cumulative account limit, even when its name is twelve hex characters. Only the
human sets or resets a model-key quota. The settings writer stamps `since` as
for every token limit (a new limit gets now, a changed one keeps its time, a
caller's different time refuses, a reset moves it to now), with one rule for a
new model-key quota: it takes the earliest `since` among the old file's
model-key quotas whose ids are in the same agent's key lineage, so moving a
quota to the agent's new key id keeps its count, and takes now only when none
of them holds one. A quota removed in one write and added back in a later one
is new and gets now. The bus host passes `keyLineage(business, keyId)`, which
answers ids only from the bus's own credential records. A writer built without
it, a lookup that throws, or an answer that is neither an empty list nor a list
of key ids holding the asked id refuses a write that adds a model-key quota with `proxy-key-refused`.
A write that adds none never calls it.
`launch.threadIdleSeconds` (optional, row 121) is how long a thread's
session runs with nothing pending and no new message or open before the
launcher stops it. Absent means 900 (`THREAD_IDLE_SECONDS` in
+4 -3
View File
@@ -10,7 +10,7 @@ import { checkVars } from "./vars.mjs";
import { parseCredentialRef } from "./credentials.mjs";
import { loadRole } from "./role.mjs";
import { END_PROTECTED } from "./vocabulary.mjs";
import { checkPlugins } from "../../plugins/src/kinds.mjs";
import { checkPlugins, checkUsageSettings } from "../../plugins/src/kinds.mjs";
import { checkMapping } from "../../library/src/mapping.mjs";
import { forkProblem, giteaName, parseGiteaUrl, HOST_SERVICE, CREATIVE_DEFINITIONS } from "./vocabulary.mjs";
import {
@@ -21,7 +21,7 @@ const BOT_NAME = /^bot-[a-z0-9][a-z0-9._-]{0,60}$/;
// How long a thread's session stays up with no turn before the launcher stops
// it, when launch.threadIdleSeconds is absent (REQ-THREAD-2, row 121).
export const THREAD_IDLE_SECONDS = 900;
const TOP_KEYS = ["businessVersion", "id", "human", "arbiters", "projects", "vars", "tracker", "roles", "launch", "plugins", "hosts", "retired", "replyLimits"];
const TOP_KEYS = ["businessVersion", "id", "human", "arbiters", "projects", "vars", "tracker", "roles", "launch", "plugins", "hosts", "retired", "replyLimits", "usage"];
// The config directory: next to the system config, $MOSAIC_CONFIG or
// ~/.config/mosaic-dev/config.json, the same rule mosaic-config.mjs uses.
@@ -312,11 +312,12 @@ export function validateBusinessDocument(document, file, { rolesDir }) {
// here; whether each module loads is the loader's check, at load time.
const plugins = document.plugins === undefined ? {}
: structuredClone(checkPlugins(document.plugins, `${file} plugins`, { fail: (_code, message) => refuse(message) }));
const usage = document.usage === undefined ? undefined : checkUsageSettings(document.usage);
const retired = document.retired === undefined ? undefined : checkRetired(document.retired, roles, file);
return deepFreeze({
businessVersion: 1, id: document.id, file, human, arbiters, projects, vars, tracker, roles, launch, plugins, definitions,
...(retired ? { retired } : {}),
...(retired ? { retired } : {}), ...(usage === undefined ? {} : { usage }),
});
}
+32 -4
View File
@@ -6,6 +6,7 @@ import { usageCounts } from "./launch.mjs";
import { canonicalJson, isPlainObject, requireObject, rejectUnknownKeys } from "./util.mjs";
import { FALLBACK_VARS } from "./vars.mjs";
import { THREAD_DEFINITION, CREATIVE_DEFINITIONS } from "./vocabulary.mjs";
import { isDailyModelQuota } from "../../plugins/src/model-quota.mjs";
// Row 213 (C2-08, Case 2 design 4, M10): a creative instance, its persona included, is the
// human's. A write that touches one is accepted only when its actor is the business file's
@@ -62,16 +63,39 @@ const at = (value, path) => path.reduce((v, part) => (own(v, part) ? v[part] : u
// The writer, not the caller, sets a token limit's `since`. A new limit gets now; a changed or
// unchanged one keeps its stored time; a caller-supplied time that differs from the stored one is
// refused, so only a reset moves it. An entry that isn't an object is left for the schema to refuse.
function stamp(next, old, now) {
// Row 333 R4 (#1831): a new daily key quota carries its agent's count (carried, below).
function stamp(next, old, now, lineage) {
for (const { path, entry } of tokenLeaves(next)) {
if (!plain(entry)) continue;
const before = at(old, path);
const kept = plain(before) ? before.since : undefined;
if (own(entry, "since") && entry.since !== kept) throw new OrganizationError("invalid-request");
entry.since = kept ?? now;
entry.since = kept ?? carried(path, entry, old, now, lineage) ?? now;
}
}
// Row 333 R4 (#1831): a new tokens.keys leaf in the daily quota shape is a quota on one agent's model
// key. It takes the earliest stored `since` of the old document's daily key quotas whose ids are in
// that key's lineage, so moving a quota from A to B after a rotation or re-issue keeps the day's
// count, whether or not the same write removes A. With none it is new and gets now (undefined
// here). lineage(id) answers the ids of the agent holding id, read from the bus's own credential
// records, or [] when no agent holds it. A lookup that throws or answers malformed refuses the write.
// A quota removed in one write and added back in a later one finds no old leaf, so it gets now.
const KEY_ID = /^[a-f0-9]{12}$/;
function carried(path, entry, old, now, lineage) {
const [, kind, id] = path;
if (kind !== "keys" || !isDailyModelQuota(id, { ...entry, since: now })) return undefined;
let ids;
try { ids = lineage(id); } catch { throw new OrganizationError("proxy-key-refused"); }
if (!Array.isArray(ids) || ids.some(x => typeof x !== "string" || !KEY_ID.test(x)) || (ids.length && !ids.includes(id))) {
throw new OrganizationError("proxy-key-refused");
}
const keys = at(old, ["tokens", "keys"]);
const times = Object.entries(plain(keys) ? keys : {})
.filter(([key, value]) => ids.includes(key) && isDailyModelQuota(key, value)).map(([, value]) => value.since);
return times.sort((a, b) => Date.parse(a) - Date.parse(b))[0];
}
// A reset names token limit paths, e.g. ["tokens", "instances", "coder-1"]; each gets since = now.
// Any other path, a concurrency limit's included, is refused.
function reset(limits, paths, now) {
@@ -122,7 +146,11 @@ export function checkRoutes({ proposed, old = null, levels }) {
const ROUTE_FIELDS = Object.freeze(["harness", "model", "thinking"]);
// levels(name): the thinking levels harness module `name` applies, or null (checkRoutes).
export function launchSettings({ dir, rolesDir, system, sessions = () => [], now = () => new Date().toISOString(), levels = () => null }) {
// Row 333 R4 (#1831): keyLineage(business, keyId) answers the key ids in the lineage of the agent
// that holds keyId (carried, above). The bus runtime passes one read from its credential records.
// Without it, a write that adds a daily key quota refuses proxy-key-refused; no other write asks.
export function launchSettings({ dir, rolesDir, system, sessions = () => [], now = () => new Date().toISOString(), levels = () => null,
keyLineage = () => { throw new OrganizationError("proxy-key-refused"); } }) {
const writer = organizationWriter({ dir, rolesDir });
// The validated business as the file stands now (row 125: the limit checks read it at each ask).
@@ -182,7 +210,7 @@ export function launchSettings({ dir, rolesDir, system, sessions = () => [], now
const at = now();
if (Object.hasOwn(args, "limits")) {
next.launch.limits = structuredClone(args.limits);
stamp(next.launch.limits, old.document.launch.limits, at);
stamp(next.launch.limits, old.document.launch.limits, at, key => keyLineage(id, key));
}
if (Object.hasOwn(args, "reset")) reset(next.launch.limits, args.reset, at);
if (Object.hasOwn(args, "models")) {
+11 -2
View File
@@ -1,5 +1,6 @@
// REQ-LIMIT-1: editable concurrency policy, never a compiled-in capacity ceiling.
import { requireObject, requireId, requireString, rejectUnknownKeys } from "./util.mjs";
import { isDailyModelQuota } from "../../plugins/src/model-quota.mjs";
import { BusinessError, refuse } from "./errors.mjs";
const name = (value, at) => requireString(value, at, { max: 200 });
@@ -76,8 +77,16 @@ export function checkTokenLimits(value, where = "launch.limits.tokens") {
if (Object.hasOwn(value, "models")) {
out.models = tokenMap(value.models, `${where}.models`, name, (models, at) => tokenMap(models, at, name, tokenLimit));
}
// A key is a name until row 126 names the accounts.
if (Object.hasOwn(value, "keys")) out.keys = tokenMap(value.keys, `${where}.keys`, requireId, tokenLimit);
// P5 adds daily model leaves, including digit-leading IDs; plain keys keep
// their existing account-name schema and cumulative account semantics.
if (Object.hasOwn(value, "keys")) {
requireObject(value.keys, `${where}.keys`);
out.keys = Object.fromEntries(Object.entries(value.keys).map(([key, entry]) => {
const at = `${where}.keys.${key}`;
if (isDailyModelQuota(key, entry)) return [key, dailyQuota(entry, at)];
return [requireId(key, `${where}.keys`), tokenLimit(entry, at)];
}));
}
// One quota per account; the business read checks each key names launch.account.
if (Object.hasOwn(value, "daily")) out.daily = tokenMap(value.daily, `${where}.daily`, requireId, dailyQuota);
return out;
+25
View File
@@ -8,6 +8,7 @@ import { join, dirname } from "node:path";
import { randomUUID } from "node:crypto";
import { businessFilePath, validateBusinessDocument } from "./business.mjs";
import { requireId, sha256, canonicalJson } from "./util.mjs";
import { isDailyModelQuota } from "../../plugins/src/model-quota.mjs";
import { checkReplyLimits } from "../../library/src/limits.mjs";
export class OrganizationError extends Error {
@@ -81,6 +82,26 @@ function changes(old, next, path = "") {
}];
}
// P5/Q222: every writer protects per-model-key quotas, including removal/reset.
function modelQuotaFence(old, document, actor) {
const keys = doc => Object.fromEntries(Object.entries(doc?.launch?.limits?.tokens?.keys ?? {})
.filter(([key, entry]) => isDailyModelQuota(key, entry)));
if (canonicalJson(keys(old)) === canonicalJson(keys(document))) return;
const agents = Object.entries(old.roles ?? {}).flatMap(([instance, entry]) => [instance, `${entry?.definition}.${instance}`]);
if (actor === old.human && actor !== "tester" && !agents.includes(actor)) return;
fail("organization-model-quota-human-only");
}
// P5: the optional queue reader and polling setting are human changes even on
// the tester organization path. This guards every writer, not only the UI verb.
function usageFence(old, document, actor) {
const setting = doc => ({ plugin: doc?.plugins?.usage ?? null, usage: doc?.usage ?? null });
if (canonicalJson(setting(old)) === canonicalJson(setting(document))) return;
const agents = Object.entries(old.roles ?? {}).flatMap(([instance, entry]) => [instance, `${entry?.definition}.${instance}`]);
if (actor === old.human && actor !== "tester" && !agents.includes(actor)) return;
fail("organization-usage-human-only");
}
// C2-06 M11: replyLimits is the human's alone. Any setter that changes it refuses unless the actor is
// the business's human as the file stood before the write, and no agent or the tester under that
// name. Compared as M9 compares projects, on the document and again on what lands on disk.
@@ -240,6 +261,8 @@ export function organizationWriter({ dir, rolesDir, barrier = () => {} }) {
if (canonicalJson(document?.projects) !== canonicalJson(old.projects))
fail('organization-projects-protected');
replyLimitsFence(old, document, actor);
modelQuotaFence(old, document, actor);
usageFence(old, document, actor);
validateBusinessDocument(document, file, { rolesDir });
const bytes = JSON.stringify(document, null, 2) + "\n";
// Check and log exactly what lands on disk, for every setter: a value JSON
@@ -248,6 +271,8 @@ export function organizationWriter({ dir, rolesDir, barrier = () => {} }) {
if (canonicalJson(written.projects) !== canonicalJson(old.projects))
fail('organization-projects-protected');
replyLimitsFence(old, written, actor);
modelQuotaFence(old, written, actor);
usageFence(old, written, actor);
validateBusinessDocument(written, file, { rolesDir });
if (beforeWrite) {
beforeWrite();
+8 -3
View File
@@ -5,7 +5,7 @@
// like a limit change. A write is a patch per kind (see set()): kinds it doesn't name are kept. A refused write throws a code and logs nothing.
import { organizationWriter, OrganizationError } from "./organization.mjs";
import { isPlainObject } from "./util.mjs";
import { KINDS, PluginError, checkPlugins } from "../../plugins/src/kinds.mjs";
import { KINDS, PluginError, checkPlugins, checkUsageSettings } from "../../plugins/src/kinds.mjs";
// `exists(kind, name)`, when given, refuses a name no module answers to (the host passes the
// loader's hasModule). Without it the setter checks only the shape, as before.
@@ -14,11 +14,12 @@ export function pluginSettings({ dir, rolesDir, exists = null }) {
function read(id) {
const { document, revision } = writer.read(id);
return { business: id, revision, plugins: structuredClone(document.plugins ?? {}) };
return { business: id, revision, plugins: structuredClone(document.plugins ?? {}),
...(document.usage === undefined ? {} : { usage: structuredClone(document.usage) }) };
}
function set(id, args, actor) {
if (!isPlainObject(args) || Object.keys(args).some(key => key !== "revision" && key !== "plugins")) {
if (!isPlainObject(args) || Object.keys(args).some(key => key !== "revision" && key !== "plugins" && key !== "usage")) {
throw new OrganizationError("invalid-request");
}
if (typeof args.revision !== "string" || !/^[a-f0-9]{64}$/.test(args.revision)) {
@@ -55,6 +56,10 @@ export function pluginSettings({ dir, rolesDir, exists = null }) {
}
}
const next = structuredClone(writer.read(id).document);
if (Object.hasOwn(args, "usage")) {
if (args.usage === null) delete next.usage;
else next.usage = checkUsageSettings(args.usage);
}
next.plugins = { ...structuredClone(next.plugins ?? {}), ...structuredClone(sets) };
for (const kind of removals) delete next.plugins[kind];
const receipt = writer.write(id, next, { revision: args.revision, actor });
@@ -144,3 +144,26 @@ test("vikunja:19/305 with an exists check, the setter refuses a module no tree f
assert.equal(events(f).length, before);
assert.deepEqual(settings.set("acme", { revision: view.revision, plugins: { "usage-source": ["meter"] } }, "jason").plugins, { "usage-source": ["meter"] });
});
test('P5 optional usage kind and pollSeconds configure through plugins.set; default stays absent and retention bound is strict', () => {
const f=fixture();let v=f.settings.read('acme');assert.equal(v.plugins.usage,undefined);assert.equal(v.usage,undefined);
v=f.settings.set('acme',{revision:v.revision,plugins:{usage:'cliproxy-queue'},usage:{cliproxyQueue:{pollSeconds:7}}},'jason');
assert.equal(v.plugins.usage,'cliproxy-queue');assert.equal(v.usage.cliproxyQueue.pollSeconds,7);
for(const pollSeconds of [0,60,61,-1,1.5,'15',null]) {
const before=readFileSync(f.file,'utf8');
assert.throws(()=>f.settings.set('acme',{revision:v.revision,plugins:{usage:'cliproxy-queue'},usage:{cliproxyQueue:{pollSeconds}}},'jason'));
assert.equal(readFileSync(f.file,'utf8'),before);
}
v=f.settings.set('acme',{revision:v.revision,plugins:{usage:null},usage:null},'jason');
assert.equal(v.plugins.usage,undefined);assert.equal(v.usage,undefined);
});
test('P5 only human can enable/disable telemetry or change polling, including direct organization writes', () => {
const f=fixture();let v=f.settings.read('acme');const patch={plugins:{usage:'cliproxy-queue'},usage:{cliproxyQueue:{pollSeconds:15}}};
for(const actor of ['tester','chief','coder']) assert.throws(()=>f.settings.set('acme',{revision:v.revision,...patch},actor),{code:'organization-usage-human-only'});
v=f.settings.set('acme',{revision:v.revision,...patch},'jason');
for(const actor of ['tester','chief','coder']) {
assert.throws(()=>f.settings.set('acme',{revision:v.revision,plugins:{usage:null}},actor),{code:'organization-usage-human-only'});
assert.throws(()=>f.settings.set('acme',{revision:v.revision,plugins:{usage:'cliproxy-queue'},usage:{cliproxyQueue:{pollSeconds:1}}},actor),{code:'organization-usage-human-only'});
}
});
@@ -10,13 +10,14 @@ import {launchSettings} from '../src/launch-settings.mjs';
const roots=[];after(()=>roots.forEach(root=>rmSync(root,{recursive:true,force:true})));
const T0='2026-10-18T07:00:00.000Z',T1='2026-10-18T08:00:00.000Z',T2='2026-10-18T09:00:00.000Z';
function fixture(){
// keyLineage, when given, is the writer's lineage lookup (row 333 R4); without it the writer's default refuses.
function fixture(keyLineage){
const root=makeRoot();roots.push(root);const rolesDir=rolesCopy(root),doc=businessDoc(root,'acme');
for(const r of Object.values(doc.roles))r.vars={...r.vars,model:'sonnet'};
doc.launch={by:'chief',instances:['coder','reviewer'],models:{sonnet:{provider:'anthropic',model:'claude-sonnet-5-5'}},limits:{}};
const file=join(root,'businesses/acme.json');writeJson(file,doc);
const system={environment:'development',dataRoot:join(root,'data'),'execution.backend':'docker','execution.provider':'anthropic','execution.model':'sonnet','execution.adapter':'pi'};
let clock=T0;const settings=launchSettings({dir:root,rolesDir,system,now:()=>clock});
let clock=T0;const settings=launchSettings({dir:root,rolesDir,system,now:()=>clock,...(keyLineage?{keyLineage}:{})});
return {root,rolesDir,doc,file,settings,tick:at=>{clock=at;}};
}
const stored=f=>JSON.parse(readFileSync(f.file,'utf8')).launch.limits.tokens;
@@ -150,3 +151,76 @@ test('REQ-LIMIT-2 the writer stamps a daily quota\'s since, keeps its reset and
// The account itself stays a hand edit: the file's account is untouched by the writes.
assert.deepEqual(JSON.parse(readFileSync(f.file,'utf8')).launch.account,ACCOUNT);
});
test('P5 per-model-key quotas are unset by default, accept digit-leading IDs and only the human changes or resets them', () => {
const f=fixture(()=>[]),key='012345abcdef'; let view=f.settings.read('acme');
assert.equal(view.limits.tokens,undefined);
const limits={tokens:{keys:{[key]:{limit:20,reset:'05:00',timeZone:'America/Chicago'}}}};
view=f.settings.set('acme',{revision:view.revision,limits},'jason');
assert.deepEqual(stored(f).keys[key],{...limits.tokens.keys[key],since:T0});
const bytes=readFileSync(f.file,'utf8');f.tick(T1);
for(const actor of ['chief','tester','coder']) {
assert.throws(()=>f.settings.set('acme',{revision:view.revision,limits:{tokens:{keys:{}}}},actor),{code:'organization-model-quota-human-only'});
assert.throws(()=>f.settings.set('acme',{revision:view.revision,reset:[['tokens','keys',key]]},actor),{code:'organization-model-quota-human-only'});
}
assert.equal(readFileSync(f.file,'utf8'),bytes);
f.tick(T1);view=f.settings.set('acme',{revision:view.revision,reset:[['tokens','keys',key]]},'jason');
assert.equal(stored(f).keys[key].since,T1);
view=f.settings.set('acme',{revision:view.revision,limits:{}},'jason');
assert.equal(view.limits.tokens,undefined);
});
// Row 333 R4 (#1831): a new daily key quota takes the earliest since of the old document's daily key
// quotas in its key's lineage. A, B and C are one agent's keys, oldest first; X is no agent's.
const A='aaaaaaaaaaa1',B='bbbbbbbbbbb2',C='ccccccccccc3',X='ddddddddddd4',T3='2026-10-18T10:00:00.000Z';
const daily=(limit=20)=>({limit,reset:'05:00',timeZone:'America/Chicago'});
const lineageOf=(business,id)=>{assert.equal(business,'acme');return [C,B,A].includes(id)?[C,B,A]:[];};
test('R4 a moved daily key quota keeps the earliest since in its lineage; a reset, a new key and a re-add get now; a caller time refuses',()=>{
const f=fixture(lineageOf);let view=f.settings.read('acme');
view=f.settings.set('acme',{revision:view.revision,limits:{tokens:{keys:{[A]:daily()}}}},'jason');
assert.equal(stored(f).keys[A].since,T0);
// B joins while A stays: it carries A's time. Then B alone is reset, so A and B differ.
f.tick(T1);view=f.settings.set('acme',{revision:view.revision,limits:{tokens:{keys:{[A]:daily(),[B]:daily(30)}}}},'jason');
assert.equal(stored(f).keys[B].since,T0);
view=f.settings.set('acme',{revision:view.revision,reset:[['tokens','keys',B]]},'jason');
assert.deepEqual([stored(f).keys[A].since,stored(f).keys[B].since],[T0,T1]);
// The move to C drops both: C takes the earlier of the two, not the later. X matches no agent: now.
f.tick(T2);view=f.settings.set('acme',{revision:view.revision,limits:{tokens:{keys:{[C]:daily(),[X]:daily()}}}},'jason');
assert.deepEqual(stored(f).keys,{[C]:{...daily(),since:T0},[X]:{...daily(),since:T2}});
// A caller-supplied since refuses, on a moved leaf too, even when it is the time the writer would carry.
const bytes=readFileSync(f.file,'utf8');
for(const keys of [{[C]:daily(),[X]:daily(),[B]:{...daily(),since:T0}},{[C]:daily(),[X]:daily(),[A]:{...daily(),since:T2}},{[C]:{...daily(),since:T1},[X]:daily()}])
assert.throws(()=>f.settings.set('acme',{revision:view.revision,limits:{tokens:{keys}}},'jason'),{code:'invalid-request'},JSON.stringify(keys));
assert.equal(readFileSync(f.file,'utf8'),bytes);
// An explicit reset after the move sets now, in the same write as a move or in its own.
f.tick(T3);view=f.settings.set('acme',{revision:view.revision,limits:{tokens:{keys:{[B]:daily(),[X]:daily()}}},reset:[['tokens','keys',B]]},'jason');
assert.equal(stored(f).keys[B].since,T3);
// Removed in one write and added back in a later one: a new quota, so now.
view=f.settings.set('acme',{revision:view.revision,limits:{tokens:{keys:{[X]:daily()}}}},'jason');
f.tick('2026-10-18T11:00:00.000Z');view=f.settings.set('acme',{revision:view.revision,limits:{tokens:{keys:{[X]:daily(),[A]:daily()}}}},'jason');
assert.equal(stored(f).keys[A].since,'2026-10-18T11:00:00.000Z');
});
test('R4 the writer asks the lineage only for a new daily key quota, and a lookup that fails or answers malformed refuses',()=>{
let asked=[];const answer={value:null};
const f=fixture((business,id)=>{asked.push(id);if(answer.value instanceof Error)throw answer.value;return answer.value??lineageOf(business,id);});
let view=f.settings.read('acme');
// Writes adding no new daily key quota never ask: account limits, a hex-named legacy limit, a changed quota.
view=f.settings.set('acme',{revision:view.revision,limits:{tokens:{instances:{coder:{limit:5}},keys:{k1:{limit:5},[X]:{limit:5}}}}},'jason');
assert.deepEqual(asked,[]);
view=f.settings.set('acme',{revision:view.revision,limits:{tokens:{keys:{[A]:daily()}}}},'jason');
assert.deepEqual(asked,[A]);
f.tick(T1);view=f.settings.set('acme',{revision:view.revision,limits:{tokens:{keys:{[A]:daily(99)}}}},'jason');
view=f.settings.set('acme',{revision:view.revision,reset:[['tokens','keys',A]]},'jason');
assert.deepEqual(asked,[A]);
const bytes=readFileSync(f.file,'utf8');
for(const bad of [Object.assign(new Error('records unreadable'),{code:'credential-format'}),new Error('plain'),'nope',[42],['ABCDEFABCDEF'],[A],{0:B}]){
answer.value=bad;
assert.throws(()=>f.settings.set('acme',{revision:view.revision,limits:{tokens:{keys:{[A]:daily(99),[B]:daily()}}}},'jason'),{code:'proxy-key-refused'},String(bad));
}
assert.equal(readFileSync(f.file,'utf8'),bytes);
// Without a lookup, the default refuses a new daily key quota and nothing else.
const g=fixture();let gv=g.settings.read('acme');
gv=g.settings.set('acme',{revision:gv.revision,limits:{tokens:{instances:{coder:{limit:5}},keys:{[X]:{limit:5}}}}},'jason');
assert.throws(()=>g.settings.set('acme',{revision:gv.revision,limits:{tokens:{keys:{[X]:{limit:5},[A]:daily()}}}},'jason'),{code:'proxy-key-refused'});
});
Loaded 100 of 122 files, more files were not shown because too many files have changed in this diff. Show more