@iowarp/clio-coder 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/README.md +50 -53
- package/dist/acp-FPR54DGL.js +138 -0
- package/dist/{agents-Q4MYPMUW.js → agents-OGPIHPJH.js} +33 -25
- package/dist/assets/codewiki.json +1 -0
- package/dist/assets/grammars/notices/@vscode__tree-sitter-wasm/LICENSE +21 -0
- package/dist/assets/grammars/notices/@vscode__tree-sitter-wasm/cgmanifest.json +16 -0
- package/dist/assets/grammars/notices/tree-sitter-wasms/LICENSE +24 -0
- package/dist/assets/grammars/tree-sitter-c-sharp.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-c.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-cpp.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-go.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-java.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-javascript.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-python.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-ruby.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-rust.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-tsx.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-typescript.wasm +0 -0
- package/dist/assets/grammars/tree-sitter.wasm +0 -0
- package/dist/{auth-O6HYIJ6J.js → auth-IC3K6NIZ.js} +22 -15
- package/dist/{chunk-KKKPTZLM.js → chunk-2STGEDFV.js} +8 -1
- package/dist/chunk-3I7MS7N2.js +40 -0
- package/dist/chunk-3R73A4XB.js +69 -0
- package/dist/{chunk-26BZQOAD.js → chunk-474KN5II.js} +86 -115
- package/dist/{chunk-NI4DEJMC.js → chunk-4QKXUHSR.js} +26 -3
- package/dist/{chunk-X3BR7HWV.js → chunk-5WIGXA4T.js} +7 -1
- package/dist/{chunk-TFSSEXL6.js → chunk-673JJUWJ.js} +14 -4
- package/dist/{chunk-GNGDQYDU.js → chunk-7SS2CTV2.js} +27922 -1249
- package/dist/{chunk-7RBKDI66.js → chunk-ASND7OZK.js} +104 -12
- package/dist/{chunk-X3NE4WVW.js → chunk-BNAZZHFG.js} +7 -1
- package/dist/{chunk-RQDWMVRB.js → chunk-BSU2YIWB.js} +9 -3
- package/dist/{chunk-CLJ5HLUD.js → chunk-C4PTHK7P.js} +24 -5
- package/dist/{chunk-QV47YRF4.js → chunk-CGKSTWHD.js} +7 -1
- package/dist/{chunk-BYEU76JP.js → chunk-DKGKUHFA.js} +34 -9
- package/dist/chunk-EYOKLTMF.js +170 -0
- package/dist/{chunk-PS4PFJQP.js → chunk-FCIH3BIZ.js} +15258 -14130
- package/dist/{chunk-2J63S4SF.js → chunk-FST4FYJB.js} +82 -14
- package/dist/{chunk-3DANZDGR.js → chunk-G34LV2PF.js} +34 -9
- package/dist/{chunk-BBUH4VAA.js → chunk-GAEBEQVI.js} +34 -21
- package/dist/chunk-GB6QRBXN.js +8543 -0
- package/dist/chunk-GEP36Y4X.js +12796 -0
- package/dist/{chunk-TKHQ4DGZ.js → chunk-H6F6BYOH.js} +496 -121
- package/dist/{chunk-UGYAX5YI.js → chunk-HQQID6OA.js} +10 -5
- package/dist/chunk-IHXBNWMM.js +137 -0
- package/dist/{chunk-ME6DNWIU.js → chunk-IS3ONKU3.js} +7 -1
- package/dist/{chunk-DXQNI4PC.js → chunk-IWHMRKLL.js} +8 -1
- package/dist/chunk-K2ITRMHZ.js +642 -0
- package/dist/{chunk-KBR4MZZR.js → chunk-K5XEMXTI.js} +7 -1
- package/dist/{chunk-AMFR5YA3.js → chunk-KKNLWXI6.js} +24 -10
- package/dist/{chunk-JWHCJDCI.js → chunk-KY56HMHH.js} +145 -61
- package/dist/{chunk-E3NYWENM.js → chunk-LU4TK2PR.js} +52 -7
- package/dist/{chunk-UWIJNAOB.js → chunk-M5T5VO65.js} +109 -42
- package/dist/{chunk-JPOWPFCU.js → chunk-MAR7Y6HW.js} +38 -16
- package/dist/chunk-N6F52NLF.js +6951 -0
- package/dist/{chunk-UHTSULZS.js → chunk-NMOX6HFD.js} +20 -7
- package/dist/{chunk-WD6AJM35.js → chunk-OLBBMFRD.js} +30 -13
- package/dist/{chunk-VOO7NYPP.js → chunk-PFEFKVGL.js} +22 -6
- package/dist/{chunk-6CWDTGUC.js → chunk-PIUMUEMV.js} +7 -1
- package/dist/chunk-PV4JUBVJ.js +462 -0
- package/dist/{chunk-527KG6XR.js → chunk-Q3RUPKEJ.js} +22 -4
- package/dist/{chunk-D5YD55AR.js → chunk-Q5WJOSJ7.js} +11 -1
- package/dist/{chunk-5N2FG33Q.js → chunk-R346GLFC.js} +7 -1
- package/dist/{chunk-4UQA7NCT.js → chunk-R5KLMSBV.js} +7 -2
- package/dist/{chunk-PIDUD6M2.js → chunk-RDLVBZEO.js} +11 -6
- package/dist/{chunk-O4EJEDHO.js → chunk-RPTR2H26.js} +40 -31
- package/dist/{chunk-HBU5MTAM.js → chunk-SVNXH4L2.js} +7 -1
- package/dist/{chunk-XNISANGE.js → chunk-TEKV33Q5.js} +122 -57
- package/dist/chunk-TXOTCRLG.js +15 -0
- package/dist/{chunk-VPAWTYLY.js → chunk-WEPFGWHJ.js} +7 -1
- package/dist/{chunk-HMYNFFY4.js → chunk-XPLRXC72.js} +7 -2
- package/dist/{chunk-UU3R62TT.js → chunk-XYWBQRDM.js} +13 -4
- package/dist/{chunk-7BHLZB3A.js → chunk-ZPY3JZ5E.js} +32 -10
- package/dist/cli/index.js +39 -33
- package/dist/clio-BZVGEUFJ.js +58 -0
- package/dist/{components-JVHMUBEB.js → components-DMAOEKFB.js} +26 -9
- package/dist/{config-ZFCDBMDC.js → config-IRUQ7SE4.js} +42 -31
- package/dist/configure-S7S6F6CL.js +32 -0
- package/dist/{context-CDXTP2MP.js → context-3KWFLHJG.js} +17 -11
- package/dist/{context-E3KIFVXI.js → context-5RADCKTR.js} +33 -28
- package/dist/{context-clear-3F4PLXOS.js → context-clear-7TSNPAAI.js} +36 -28
- package/dist/{context-index-Q7YSYTR3.js → context-index-W4RLWOQH.js} +10 -4
- package/dist/{docs-YIETIWZI.js → docs-5AWSPS37.js} +16 -10
- package/dist/doctor-UC5NAJYQ.js +77 -0
- package/dist/{eval-B3KZZESM.js → eval-U6TJHRLX.js} +77 -24
- package/dist/{evidence-V67CHM35.js → evidence-YEGUW4L3.js} +34 -26
- package/dist/{evolve-YDZSUQYA.js → evolve-TXARCTPG.js} +39 -26
- package/dist/{extensions-SRG7XCAH.js → extensions-OZFJ3A3G.js} +13 -7
- package/dist/{fleet-CA2CRTVG.js → fleet-6G3DHNYE.js} +45 -37
- package/dist/fleet-preflight-DSNT37JK.js +23 -0
- package/dist/{init-2OZDJE2D.js → init-KZ5QTF6M.js} +42 -34
- package/dist/{memory-3PIQQAKX.js → memory-73ESV5YC.js} +35 -27
- package/dist/{models-DY35XI7Y.js → models-A4PVNWJK.js} +34 -23
- package/dist/{paths-5OMXW7Z4.js → paths-C4H6IV77.js} +12 -6
- package/dist/preload-6WVMHX3A.js +13 -0
- package/dist/{reset-PIFYNOS3.js → reset-BGW6OGMV.js} +17 -11
- package/dist/{run-3VSPP24F.js → run-YTPEYQOH.js} +60 -48
- package/dist/{share-D36RQCXM.js → share-YIFFV4NQ.js} +16 -10
- package/dist/{skills-F2MRLELY.js → skills-2V6RA3OQ.js} +18 -11
- package/dist/{skills-eval-E2ZTW4PL.js → skills-eval-S2TVJO4F.js} +45 -36
- package/dist/{targets-DZMEZAH4.js → targets-TYXLPB23.js} +61 -59
- package/dist/{trace-7NYCUI2J.js → trace-GGOJ6Q6Z.js} +9 -3
- package/dist/{uninstall-AD3JWHBB.js → uninstall-LLLT4F4W.js} +14 -8
- package/dist/{upgrade-WYYBKGDY.js → upgrade-33G2LMM5.js} +45 -23
- package/dist/{usage-ULIDAGFF.js → usage-ZAFSXKKG.js} +35 -27
- package/dist/version-KGEG7EPO.js +21 -0
- package/dist/{wiki-generate-PKFIX6OB.js → wiki-generate-NUQCVOQ3.js} +55 -45
- package/dist/worker/entry.js +101 -43
- package/docs/README.md +12 -9
- package/docs/acp.md +28 -5
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +23 -2
- package/docs/artifact-placement.md +101 -0
- package/docs/artifact-versions.md +1 -1
- package/docs/built-in-agents.md +4 -2
- package/docs/capacity-and-scheduling.md +1 -1
- package/docs/commands-and-modes.md +125 -41
- package/docs/configuration-and-targets.md +88 -18
- package/docs/context-engine.md +6 -2
- package/docs/development-pipeline.md +77 -0
- package/docs/documentation-coverage.md +4 -4
- package/docs/documentation-guide.md +3 -3
- package/docs/environment-variables.md +2 -1
- package/docs/eval-runner.md +3 -3
- package/docs/evals-internal.md +2 -2
- package/docs/evidence-and-memory.md +6 -2
- package/docs/evolution.md +1 -1
- package/docs/exit-codes-and-output.md +1 -1
- package/docs/extensions-and-sharing.md +18 -11
- package/docs/fleet-demo-runbook.md +22 -23
- package/docs/fleet-dispatch.md +111 -12
- package/docs/glossary.md +107 -15
- package/docs/html/agents_blueprint.html +3 -3
- package/docs/html/alcf_blueprint.html +3 -3
- package/docs/html/architecture_blueprint.html +3 -3
- package/docs/html/commands_blueprint.html +187 -42
- package/docs/html/configuration_blueprint.html +7 -7
- package/docs/html/context_blueprint.html +3 -3
- package/docs/html/documentation_blueprint.html +1 -1
- package/docs/html/environment_blueprint.html +3 -3
- package/docs/html/eval_blueprint.html +4 -4
- package/docs/html/evals_internal_blueprint.html +3 -3
- package/docs/html/evolution_blueprint.html +3 -3
- package/docs/html/extensions_blueprint.html +3 -3
- package/docs/html/fleet_dispatch_blueprint.html +8 -8
- package/docs/html/index.html +5 -5
- package/docs/html/lifecycle_blueprint.html +4 -4
- package/docs/html/memory_blueprint.html +3 -3
- package/docs/html/middleware_blueprint.html +3 -3
- package/docs/html/models_blueprint.html +2 -2
- package/docs/html/observability_blueprint.html +2 -2
- package/docs/html/provider_adapter_blueprint.html +3 -3
- package/docs/html/safety_blueprint.html +3 -3
- package/docs/html/skills_blueprint.html +2 -2
- package/docs/html/soak_blueprint.html +3 -3
- package/docs/html/tool_usage_blueprint.html +4 -4
- package/docs/html/tools_blueprint.html +2 -2
- package/docs/html/trace_blueprint.html +3 -3
- package/docs/html/tui_design_blueprint.html +100 -40
- package/docs/html/validation_blueprint.html +1 -1
- package/docs/html/worker_dispatch_blueprint.html +3 -3
- package/docs/installation-and-lifecycle.md +62 -11
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +2 -2
- package/docs/observability.md +3 -3
- package/docs/proactive-memory.md +12 -12
- package/docs/prompt-envelope-and-tools.md +2 -2
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/release-cut-checklist.md +4 -0
- package/docs/safety-model.md +21 -5
- package/docs/scientific-validation.md +3 -3
- package/docs/session-lifecycle.md +2 -2
- package/docs/skills-marketplace.md +1 -1
- package/docs/time-conventions.md +101 -0
- package/docs/tool-usage.md +5 -4
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +1 -1
- package/docs/tui-design.md +83 -27
- package/docs/worker-dispatch-mechanics.md +3 -3
- package/package.json +16 -16
- package/skills/README.md +5 -6
- package/skills/git/file-ticket/SKILL.md +107 -0
- package/skills/git/file-ticket/evals.md +54 -0
- package/skills/git/fix-issue/SKILL.md +106 -0
- package/skills/git/fix-issue/evals.md +71 -0
- package/skills/git/ship/SKILL.md +92 -0
- package/skills/git/ship/evals.md +72 -0
- package/skills/skill-marketplace.json +12 -20
- package/src/cli/acp.ts +88 -0
- package/src/cli/agents.ts +60 -0
- package/src/cli/args.ts +280 -0
- package/src/cli/argv.ts +170 -0
- package/src/cli/ask.ts +34 -0
- package/src/cli/auth.ts +468 -0
- package/src/cli/bootstrap-generate.ts +498 -0
- package/src/cli/clio.ts +34 -0
- package/src/cli/components.ts +195 -0
- package/src/cli/config-inspect.ts +330 -0
- package/src/cli/config.ts +72 -0
- package/src/cli/configure-interop.ts +67 -0
- package/src/cli/configure-layout.ts +172 -0
- package/src/cli/configure.ts +1487 -0
- package/src/cli/context-clear.ts +76 -0
- package/src/cli/context-index.ts +102 -0
- package/src/cli/context.ts +316 -0
- package/src/cli/default-target.ts +63 -0
- package/src/cli/docs.ts +340 -0
- package/src/cli/doctor.ts +54 -0
- package/src/cli/eval.ts +315 -0
- package/src/cli/evidence.ts +222 -0
- package/src/cli/evolve.ts +219 -0
- package/src/cli/extensions.ts +205 -0
- package/src/cli/fleet.ts +827 -0
- package/src/cli/index.ts +309 -0
- package/src/cli/init.ts +219 -0
- package/src/cli/initial-message.ts +47 -0
- package/src/cli/internal-dispatch.ts +55 -0
- package/src/cli/memory.ts +180 -0
- package/src/cli/models.ts +257 -0
- package/src/cli/modes/json-stream.ts +85 -0
- package/src/cli/modes/jsonl.ts +9 -0
- package/src/cli/modes/print.ts +589 -0
- package/src/cli/oauth-manual-input.ts +72 -0
- package/src/cli/oauth-select.ts +36 -0
- package/src/cli/output-guard.ts +48 -0
- package/src/cli/paths.ts +44 -0
- package/src/cli/provider-target.ts +113 -0
- package/src/cli/removal.ts +72 -0
- package/src/cli/reset.ts +253 -0
- package/src/cli/run.ts +497 -0
- package/src/cli/share.ts +243 -0
- package/src/cli/shared.ts +60 -0
- package/src/cli/skills-eval.ts +1225 -0
- package/src/cli/skills.ts +470 -0
- package/src/cli/steer-channel.ts +86 -0
- package/src/cli/targets.ts +1150 -0
- package/src/cli/text-layout.ts +102 -0
- package/src/cli/trace.ts +274 -0
- package/src/cli/uninstall.ts +405 -0
- package/src/cli/upgrade.ts +270 -0
- package/src/cli/usage.ts +869 -0
- package/src/cli/validate-model.ts +28 -0
- package/src/cli/version.ts +7 -0
- package/src/cli/wiki-generate.ts +509 -0
- package/src/core/artifact-paths.ts +43 -0
- package/src/core/bash-exec.ts +242 -0
- package/src/core/boot-trace.ts +37 -0
- package/src/core/bus-events.ts +728 -0
- package/src/core/bus-trace.ts +53 -0
- package/src/core/c-header-language.ts +265 -0
- package/src/core/clio-repo.ts +78 -0
- package/src/core/config.ts +1593 -0
- package/src/core/context-floor.ts +33 -0
- package/src/core/defaults.ts +625 -0
- package/src/core/domain-loader.ts +170 -0
- package/src/core/event-bus.ts +94 -0
- package/src/core/file-references.ts +282 -0
- package/src/core/guardrails.ts +185 -0
- package/src/core/headless-permission.ts +21 -0
- package/src/core/init.ts +223 -0
- package/src/core/json-payload.ts +58 -0
- package/src/core/package-root.ts +54 -0
- package/src/core/path-canonical.ts +37 -0
- package/src/core/process-identity.ts +41 -0
- package/src/core/recent-models.ts +91 -0
- package/src/core/release.ts +2 -0
- package/src/core/residency-protection.ts +56 -0
- package/src/core/resolve-config-value.ts +88 -0
- package/src/core/response-schema.ts +279 -0
- package/src/core/run-overrides.ts +77 -0
- package/src/core/safe-exec.ts +193 -0
- package/src/core/safe-id.ts +37 -0
- package/src/core/safe-resource-write.ts +162 -0
- package/src/core/session-routing.ts +339 -0
- package/src/core/settings-layers.ts +220 -0
- package/src/core/shared-bus.ts +8 -0
- package/src/core/shell-quote.ts +26 -0
- package/src/core/skill-activation.ts +190 -0
- package/src/core/startup-timer.ts +37 -0
- package/src/core/state-file-lock.ts +207 -0
- package/src/core/termination.ts +202 -0
- package/src/core/timers.ts +38 -0
- package/src/core/tool-names.ts +65 -0
- package/src/core/verification-scripts.ts +13 -0
- package/src/core/workspace-files.ts +492 -0
- package/src/core/xdg.ts +177 -0
- package/src/domains/agents/builtins/architect.md +4 -4
- package/src/domains/agents/builtins/coder.md +3 -2
- package/src/domains/agents/builtins/debugger.md +1 -1
- package/src/domains/agents/builtins/documenter.md +1 -1
- package/src/domains/agents/builtins/git-master.md +3 -3
- package/src/domains/agents/builtins/provenance.md +1 -1
- package/src/domains/agents/builtins/researcher.md +1 -1
- package/src/domains/agents/builtins/scout.md +1 -1
- package/src/domains/agents/builtins/tester.md +1 -1
- package/src/domains/agents/builtins/verifier.md +1 -1
- package/src/domains/agents/builtins/wiki-writer.md +1 -1
- package/src/domains/agents/catalog.ts +172 -0
- package/src/domains/agents/contract.ts +16 -0
- package/src/domains/agents/extension.ts +110 -0
- package/src/domains/agents/fleet-commands.ts +154 -0
- package/src/domains/agents/fleet-contract.ts +797 -0
- package/src/domains/agents/frontmatter.ts +40 -0
- package/src/domains/agents/index.ts +102 -0
- package/src/domains/agents/manifest.ts +6 -0
- package/src/domains/agents/recipe-schema.ts +202 -0
- package/src/domains/agents/recipe.ts +125 -0
- package/src/domains/agents/registry.ts +111 -0
- package/src/domains/agents/result-contract.ts +1265 -0
- package/src/domains/agents/spec.ts +371 -0
- package/src/domains/agents/write-boundary.ts +109 -0
- package/src/domains/components/diff.ts +99 -0
- package/src/domains/components/hash.ts +21 -0
- package/src/domains/components/index.ts +3 -0
- package/src/domains/components/scan.ts +304 -0
- package/src/domains/components/snapshot.ts +108 -0
- package/src/domains/components/types.ts +82 -0
- package/src/domains/config/agent-namespace.ts +13 -0
- package/src/domains/config/classify.ts +94 -0
- package/src/domains/config/contract.ts +22 -0
- package/src/domains/config/extension.ts +136 -0
- package/src/domains/config/index.ts +13 -0
- package/src/domains/config/keybindings.ts +164 -0
- package/src/domains/config/manifest.ts +6 -0
- package/src/domains/config/watcher.ts +41 -0
- package/src/domains/context/adoption.ts +880 -0
- package/src/domains/context/bootstrap-prompt.ts +273 -0
- package/src/domains/context/bootstrap.ts +1409 -0
- package/src/domains/context/clear.ts +86 -0
- package/src/domains/context/clio-md.ts +327 -0
- package/src/domains/context/codewiki/cmake.ts +356 -0
- package/src/domains/context/codewiki/cooperative.ts +46 -0
- package/src/domains/context/codewiki/digest.ts +135 -0
- package/src/domains/context/codewiki/grammar-assets.ts +33 -0
- package/src/domains/context/codewiki/indexer.ts +1614 -0
- package/src/domains/context/codewiki/tree-sitter.ts +771 -0
- package/src/domains/context/contract.ts +62 -0
- package/src/domains/context/excluded-dirs.ts +1 -0
- package/src/domains/context/extension.ts +407 -0
- package/src/domains/context/fingerprint.ts +196 -0
- package/src/domains/context/index.ts +164 -0
- package/src/domains/context/init-options.ts +69 -0
- package/src/domains/context/manifest.ts +6 -0
- package/src/domains/context/operator-profile.ts +157 -0
- package/src/domains/context/project-metadata.ts +510 -0
- package/src/domains/context/project-rules.ts +227 -0
- package/src/domains/context/prompt-context.ts +62 -0
- package/src/domains/context/refresh.ts +170 -0
- package/src/domains/context/sibling-files.ts +10 -0
- package/src/domains/context/state.ts +237 -0
- package/src/domains/context/wiki/assemble.ts +303 -0
- package/src/domains/context/wiki/frontmatter.ts +210 -0
- package/src/domains/context/wiki/generate.ts +590 -0
- package/src/domains/context/wiki/layout.ts +111 -0
- package/src/domains/context/wiki/meta.ts +221 -0
- package/src/domains/context/wiki/plan-store.ts +217 -0
- package/src/domains/context/wiki/plan.ts +250 -0
- package/src/domains/context/wiki/prompts.ts +270 -0
- package/src/domains/context/wiki/staleness.ts +198 -0
- package/src/domains/dispatch/active-route-planner.ts +168 -0
- package/src/domains/dispatch/admission-queue.ts +150 -0
- package/src/domains/dispatch/admission.ts +334 -0
- package/src/domains/dispatch/agent-candidates.ts +307 -0
- package/src/domains/dispatch/agent-ledger-hub.ts +71 -0
- package/src/domains/dispatch/agent-ledger-store.ts +257 -0
- package/src/domains/dispatch/agent-ledger.ts +212 -0
- package/src/domains/dispatch/agent-plan-adapter.ts +85 -0
- package/src/domains/dispatch/assignment-events.ts +132 -0
- package/src/domains/dispatch/assignment-reconcile.ts +76 -0
- package/src/domains/dispatch/assignment-store.ts +162 -0
- package/src/domains/dispatch/assignment.ts +278 -0
- package/src/domains/dispatch/backoff.ts +59 -0
- package/src/domains/dispatch/batch-store.ts +134 -0
- package/src/domains/dispatch/batch-tracker.ts +66 -0
- package/src/domains/dispatch/capability-match.ts +155 -0
- package/src/domains/dispatch/capacity-lease.ts +413 -0
- package/src/domains/dispatch/code-step-store.ts +52 -0
- package/src/domains/dispatch/code-step.ts +368 -0
- package/src/domains/dispatch/contract.ts +278 -0
- package/src/domains/dispatch/dedup.ts +133 -0
- package/src/domains/dispatch/event-pump.ts +251 -0
- package/src/domains/dispatch/execution-handoff.ts +29 -0
- package/src/domains/dispatch/execution-plan.ts +328 -0
- package/src/domains/dispatch/execution-role.ts +277 -0
- package/src/domains/dispatch/execution-scheduler.ts +583 -0
- package/src/domains/dispatch/extension.ts +5869 -0
- package/src/domains/dispatch/failure-classification.ts +141 -0
- package/src/domains/dispatch/fleet-plan.ts +225 -0
- package/src/domains/dispatch/fleet-preflight.ts +394 -0
- package/src/domains/dispatch/gate-decisions.ts +1040 -0
- package/src/domains/dispatch/gate-role-prompts.ts +58 -0
- package/src/domains/dispatch/heartbeat.ts +27 -0
- package/src/domains/dispatch/index.ts +137 -0
- package/src/domains/dispatch/joint-route-adapter.ts +114 -0
- package/src/domains/dispatch/joint-route-resolver.ts +283 -0
- package/src/domains/dispatch/manifest.ts +6 -0
- package/src/domains/dispatch/orphan-recovery.ts +224 -0
- package/src/domains/dispatch/outcome.ts +109 -0
- package/src/domains/dispatch/phase-timing.ts +47 -0
- package/src/domains/dispatch/placement.ts +202 -0
- package/src/domains/dispatch/receipt-findings.ts +255 -0
- package/src/domains/dispatch/receipt-integrity.ts +378 -0
- package/src/domains/dispatch/recovery-candidates.ts +74 -0
- package/src/domains/dispatch/reproducibility.ts +48 -0
- package/src/domains/dispatch/reservation-store.ts +501 -0
- package/src/domains/dispatch/route-approval.ts +177 -0
- package/src/domains/dispatch/route-candidates.ts +57 -0
- package/src/domains/dispatch/route-decision.ts +1079 -0
- package/src/domains/dispatch/route-facts.ts +187 -0
- package/src/domains/dispatch/route-history.ts +238 -0
- package/src/domains/dispatch/route-observer.ts +488 -0
- package/src/domains/dispatch/route-policy.ts +327 -0
- package/src/domains/dispatch/route-quality.ts +256 -0
- package/src/domains/dispatch/route-readiness.ts +120 -0
- package/src/domains/dispatch/routing-intent.ts +287 -0
- package/src/domains/dispatch/run-identity.ts +56 -0
- package/src/domains/dispatch/scout-transition.ts +130 -0
- package/src/domains/dispatch/state.ts +277 -0
- package/src/domains/dispatch/tool-stats.ts +132 -0
- package/src/domains/dispatch/transport.ts +209 -0
- package/src/domains/dispatch/types.ts +785 -0
- package/src/domains/dispatch/validation-grounding.ts +154 -0
- package/src/domains/dispatch/validation.ts +721 -0
- package/src/domains/dispatch/worker-protocol.ts +275 -0
- package/src/domains/dispatch/worker-spawn.ts +566 -0
- package/src/domains/dispatch/write-boundary-enforcer.ts +97 -0
- package/src/domains/dispatch/write-boundary.ts +426 -0
- package/src/domains/eval/artifacts/redact.ts +42 -0
- package/src/domains/eval/artifacts/store.ts +173 -0
- package/src/domains/eval/compare/compare.ts +33 -0
- package/src/domains/eval/compare/gates.ts +66 -0
- package/src/domains/eval/compare/thresholds.ts +92 -0
- package/src/domains/eval/harness-metrics.ts +62 -0
- package/src/domains/eval/index.ts +66 -0
- package/src/domains/eval/metrics/chaos-stream.ts +93 -0
- package/src/domains/eval/metrics/context.ts +34 -0
- package/src/domains/eval/metrics/coverage.ts +21 -0
- package/src/domains/eval/metrics/evidence.ts +182 -0
- package/src/domains/eval/metrics/fleet-loop-stream.ts +196 -0
- package/src/domains/eval/metrics/invariants.ts +736 -0
- package/src/domains/eval/metrics/latency.ts +4 -0
- package/src/domains/eval/metrics/token-stream.ts +139 -0
- package/src/domains/eval/metrics/tokens.ts +51 -0
- package/src/domains/eval/metrics/tool-calls.ts +7 -0
- package/src/domains/eval/proactive-memory.ts +279 -0
- package/src/domains/eval/provenance.ts +35 -0
- package/src/domains/eval/report.ts +234 -0
- package/src/domains/eval/reports/json.ts +5 -0
- package/src/domains/eval/reports/junit.ts +23 -0
- package/src/domains/eval/reports/markdown.ts +20 -0
- package/src/domains/eval/reports/swe-jsonl.ts +16 -0
- package/src/domains/eval/reports/text.ts +25 -0
- package/src/domains/eval/run-compare.ts +274 -0
- package/src/domains/eval/runner.ts +244 -0
- package/src/domains/eval/runners/clio-run.ts +148 -0
- package/src/domains/eval/runners/context-index.ts +56 -0
- package/src/domains/eval/runners/context-init.ts +203 -0
- package/src/domains/eval/runners/external-command.ts +350 -0
- package/src/domains/eval/runtime-paths.ts +171 -0
- package/src/domains/eval/schema/artifact.ts +75 -0
- package/src/domains/eval/schema/suite.ts +235 -0
- package/src/domains/eval/schema/validate.ts +339 -0
- package/src/domains/eval/store.ts +392 -0
- package/src/domains/eval/suites/load.ts +74 -0
- package/src/domains/eval/suites/matrix.ts +19 -0
- package/src/domains/eval/suites/resolve.ts +44 -0
- package/src/domains/eval/suites/run.ts +325 -0
- package/src/domains/eval/task-file.ts +186 -0
- package/src/domains/eval/types.ts +141 -0
- package/src/domains/eval/verifiers/command.ts +27 -0
- package/src/domains/eval/verifiers/file-exists.ts +6 -0
- package/src/domains/eval/verifiers/patch.ts +22 -0
- package/src/domains/eval/workspaces/git.ts +41 -0
- package/src/domains/eval/workspaces/local.ts +17 -0
- package/src/domains/eval/workspaces/temp-copy.ts +29 -0
- package/src/domains/evidence/build.ts +1714 -0
- package/src/domains/evidence/eval.ts +605 -0
- package/src/domains/evidence/failure-attribution.ts +54 -0
- package/src/domains/evidence/finish-contract-map.ts +42 -0
- package/src/domains/evidence/index.ts +55 -0
- package/src/domains/evidence/provenance.ts +200 -0
- package/src/domains/evidence/redact.ts +81 -0
- package/src/domains/evidence/store.ts +291 -0
- package/src/domains/evidence/types.ts +325 -0
- package/src/domains/evolution/SELF_EDIT_GATE.md +91 -0
- package/src/domains/evolution/index.ts +26 -0
- package/src/domains/evolution/manifest.ts +154 -0
- package/src/domains/evolution/validate.ts +304 -0
- package/src/domains/extensions/contract.ts +22 -0
- package/src/domains/extensions/discovery.ts +193 -0
- package/src/domains/extensions/extension.ts +46 -0
- package/src/domains/extensions/index.ts +34 -0
- package/src/domains/extensions/manager.ts +30 -0
- package/src/domains/extensions/manifest.ts +6 -0
- package/src/domains/extensions/resources.ts +38 -0
- package/src/domains/extensions/state.ts +224 -0
- package/src/domains/extensions/types.ts +83 -0
- package/src/domains/interop/consent.ts +185 -0
- package/src/domains/interop/contract.ts +29 -0
- package/src/domains/interop/detect.ts +173 -0
- package/src/domains/interop/extension.ts +59 -0
- package/src/domains/interop/index.ts +34 -0
- package/src/domains/interop/manifest.ts +6 -0
- package/src/domains/interop/registry.ts +139 -0
- package/src/domains/interop/state.ts +92 -0
- package/src/domains/interop/types.ts +109 -0
- package/src/domains/lifecycle/contract.ts +11 -0
- package/src/domains/lifecycle/doctor.ts +536 -0
- package/src/domains/lifecycle/extension.ts +23 -0
- package/src/domains/lifecycle/index.ts +21 -0
- package/src/domains/lifecycle/install-method.ts +51 -0
- package/src/domains/lifecycle/manifest.ts +6 -0
- package/src/domains/lifecycle/migrations/index.ts +94 -0
- package/src/domains/lifecycle/state.ts +93 -0
- package/src/domains/lifecycle/upgrade-notice.ts +35 -0
- package/src/domains/lifecycle/version.ts +35 -0
- package/src/domains/memory/index.ts +128 -0
- package/src/domains/memory/operations.ts +143 -0
- package/src/domains/memory/prompt-section.ts +86 -0
- package/src/domains/memory/proposal.ts +180 -0
- package/src/domains/memory/store.ts +163 -0
- package/src/domains/memory/task-bank.ts +229 -0
- package/src/domains/memory/task-memory-handoff.ts +222 -0
- package/src/domains/memory/task-memory-policy.ts +602 -0
- package/src/domains/memory/task-memory-status.ts +58 -0
- package/src/domains/memory/task-memory-telemetry.ts +346 -0
- package/src/domains/memory/task-memory-trace.ts +89 -0
- package/src/domains/memory/types.ts +74 -0
- package/src/domains/memory/validate.ts +297 -0
- package/src/domains/middleware/budget.ts +216 -0
- package/src/domains/middleware/contract.ts +35 -0
- package/src/domains/middleware/dispatch-nudge.ts +469 -0
- package/src/domains/middleware/extension.ts +129 -0
- package/src/domains/middleware/hook-receipts.ts +70 -0
- package/src/domains/middleware/hooks-io.ts +174 -0
- package/src/domains/middleware/hooks.ts +432 -0
- package/src/domains/middleware/index.ts +154 -0
- package/src/domains/middleware/manifest.ts +6 -0
- package/src/domains/middleware/memory-intervention.ts +701 -0
- package/src/domains/middleware/rules.ts +42 -0
- package/src/domains/middleware/runtime.ts +333 -0
- package/src/domains/middleware/skills-reminder.ts +187 -0
- package/src/domains/middleware/snapshot.ts +71 -0
- package/src/domains/middleware/stalled-turn.ts +71 -0
- package/src/domains/middleware/task-board-reminder.ts +87 -0
- package/src/domains/middleware/task-nudge.ts +77 -0
- package/src/domains/middleware/tool-choice-control.ts +42 -0
- package/src/domains/middleware/types.ts +131 -0
- package/src/domains/middleware/validate.ts +329 -0
- package/src/domains/observability/accountability.ts +67 -0
- package/src/domains/observability/contract.ts +168 -0
- package/src/domains/observability/cost.ts +206 -0
- package/src/domains/observability/evidence-index.ts +123 -0
- package/src/domains/observability/extension.ts +281 -0
- package/src/domains/observability/index.ts +78 -0
- package/src/domains/observability/manifest.ts +10 -0
- package/src/domains/observability/metrics.ts +37 -0
- package/src/domains/observability/projection.ts +477 -0
- package/src/domains/observability/telemetry.ts +89 -0
- package/src/domains/observability/trace-store.ts +1454 -0
- package/src/domains/prompts/compiler.ts +556 -0
- package/src/domains/prompts/contract.ts +30 -0
- package/src/domains/prompts/extension.ts +304 -0
- package/src/domains/prompts/fragment-loader.ts +139 -0
- package/src/domains/prompts/fragments/identity/clio.md +3 -2
- package/src/domains/prompts/fragments/identity/self-awareness.md +63 -0
- package/src/domains/prompts/fragments/operating/contract.md +10 -1
- package/src/domains/prompts/hash.ts +73 -0
- package/src/domains/prompts/index.ts +32 -0
- package/src/domains/prompts/manifest.ts +8 -0
- package/src/domains/prompts/memory-intervention.ts +57 -0
- package/src/domains/prompts/preload.ts +82 -0
- package/src/domains/providers/auth/api-key.ts +47 -0
- package/src/domains/providers/auth/backend-file.ts +69 -0
- package/src/domains/providers/auth/backend-memory.ts +17 -0
- package/src/domains/providers/auth/index.ts +37 -0
- package/src/domains/providers/auth/oauth.ts +36 -0
- package/src/domains/providers/auth/storage.ts +667 -0
- package/src/domains/providers/capabilities.ts +50 -0
- package/src/domains/providers/catalog.ts +162 -0
- package/src/domains/providers/contract.ts +151 -0
- package/src/domains/providers/credentials.ts +20 -0
- package/src/domains/providers/eligibility.ts +24 -0
- package/src/domains/providers/errors.ts +64 -0
- package/src/domains/providers/extension.ts +536 -0
- package/src/domains/providers/index.ts +142 -0
- package/src/domains/providers/knowledge-base-path.ts +102 -0
- package/src/domains/providers/manifest.ts +6 -0
- package/src/domains/providers/model-capabilities.ts +136 -0
- package/src/domains/providers/model-discovery.ts +144 -0
- package/src/domains/providers/model-family.ts +32 -0
- package/src/domains/providers/model-runtime-capabilities.ts +712 -0
- package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +2 -2
- package/src/domains/providers/plugins.ts +59 -0
- package/src/domains/providers/probe/fingerprint.ts +44 -0
- package/src/domains/providers/probe/http.ts +114 -0
- package/src/domains/providers/probe/reasoning.ts +111 -0
- package/src/domains/providers/registry.ts +166 -0
- package/src/domains/providers/resolver.ts +156 -0
- package/src/domains/providers/runtime-resolution.ts +720 -0
- package/src/domains/providers/runtimes/antigravity/antigravity-code.ts +90 -0
- package/src/domains/providers/runtimes/builtins.ts +78 -0
- package/src/domains/providers/runtimes/claude/claude-code.ts +38 -0
- package/src/domains/providers/runtimes/claude/claude-sdk.ts +38 -0
- package/src/domains/providers/runtimes/claude/common.ts +55 -0
- package/src/domains/providers/runtimes/cloud/alcf.ts +171 -0
- package/src/domains/providers/runtimes/cloud/anthropic-max.ts +71 -0
- package/src/domains/providers/runtimes/cloud/anthropic.ts +43 -0
- package/src/domains/providers/runtimes/cloud/bedrock.ts +35 -0
- package/src/domains/providers/runtimes/cloud/deepseek.ts +50 -0
- package/src/domains/providers/runtimes/cloud/google.ts +41 -0
- package/src/domains/providers/runtimes/cloud/groq.ts +46 -0
- package/src/domains/providers/runtimes/cloud/mistral.ts +46 -0
- package/src/domains/providers/runtimes/cloud/openai-codex.ts +49 -0
- package/src/domains/providers/runtimes/cloud/openai.ts +46 -0
- package/src/domains/providers/runtimes/cloud/openrouter.ts +111 -0
- package/src/domains/providers/runtimes/common/lmstudio-logger.ts +32 -0
- package/src/domains/providers/runtimes/common/local-synth.ts +165 -0
- package/src/domains/providers/runtimes/common/probe-helpers.ts +474 -0
- package/src/domains/providers/runtimes/local-native/lemonade-anthropic.ts +27 -0
- package/src/domains/providers/runtimes/local-native/lemonade-openai.ts +26 -0
- package/src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts +88 -0
- package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +207 -0
- package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +180 -0
- package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +126 -0
- package/src/domains/providers/runtimes/local-native/llamacpp.ts +98 -0
- package/src/domains/providers/runtimes/local-native/lmstudio-native.ts +491 -0
- package/src/domains/providers/runtimes/local-native/ollama-native.ts +117 -0
- package/src/domains/providers/runtimes/local-native/sglang.ts +26 -0
- package/src/domains/providers/runtimes/local-native/vllm.ts +27 -0
- package/src/domains/providers/runtimes/protocol/anthropic-compat.ts +104 -0
- package/src/domains/providers/runtimes/protocol/anthropic-messages.ts +28 -0
- package/src/domains/providers/runtimes/protocol/bedrock.ts +26 -0
- package/src/domains/providers/runtimes/protocol/google.ts +27 -0
- package/src/domains/providers/runtimes/protocol/openai-compat.ts +145 -0
- package/src/domains/providers/support.ts +238 -0
- package/src/domains/providers/thinking-control-policy.ts +85 -0
- package/src/domains/providers/types/capability-flags.ts +114 -0
- package/src/domains/providers/types/cost-provenance.ts +7 -0
- package/src/domains/providers/types/inference.ts +41 -0
- package/src/domains/providers/types/knowledge-base.ts +156 -0
- package/src/domains/providers/types/local-model-quirks.ts +218 -0
- package/src/domains/providers/types/runtime-descriptor.ts +170 -0
- package/src/domains/providers/types/target-descriptor.ts +38 -0
- package/src/domains/resources/collision.ts +92 -0
- package/src/domains/resources/common-loader.ts +140 -0
- package/src/domains/resources/contract.ts +25 -0
- package/src/domains/resources/extension.ts +61 -0
- package/src/domains/resources/index.ts +74 -0
- package/src/domains/resources/loader.ts +86 -0
- package/src/domains/resources/manifest.ts +6 -0
- package/src/domains/resources/prompts/loader.ts +232 -0
- package/src/domains/resources/prompts/substitute.ts +65 -0
- package/src/domains/resources/skills/content-hash.ts +105 -0
- package/src/domains/resources/skills/evals.ts +175 -0
- package/src/domains/resources/skills/install.ts +410 -0
- package/src/domains/resources/skills/loader.ts +978 -0
- package/src/domains/resources/skills/marketplace.ts +255 -0
- package/src/domains/resources/skills/provenance-pin.ts +115 -0
- package/src/domains/safety/action-classifier.ts +268 -0
- package/src/domains/safety/approval-axis.ts +23 -0
- package/src/domains/safety/audit.ts +487 -0
- package/src/domains/safety/autonomy.ts +174 -0
- package/src/domains/safety/call-target.ts +59 -0
- package/src/domains/safety/contract.ts +65 -0
- package/src/domains/safety/damage-control.ts +44 -0
- package/src/domains/safety/default-path-policy.ts +117 -0
- package/src/domains/safety/extension.ts +383 -0
- package/src/domains/safety/finish-contract-registration.ts +128 -0
- package/src/domains/safety/finish-contract.ts +554 -0
- package/src/domains/safety/index.ts +44 -0
- package/src/domains/safety/loop-detector.ts +143 -0
- package/src/domains/safety/manifest.ts +6 -0
- package/src/domains/safety/path-policy.ts +164 -0
- package/src/domains/safety/policy-engine.ts +994 -0
- package/src/domains/safety/project-policy.ts +391 -0
- package/src/domains/safety/protected-artifacts-registration.ts +189 -0
- package/src/domains/safety/protected-artifacts.ts +993 -0
- package/src/domains/safety/rejection-feedback.ts +102 -0
- package/src/domains/safety/rigor.ts +72 -0
- package/src/domains/safety/rule-compiler.ts +48 -0
- package/src/domains/safety/rule-pack-loader.ts +92 -0
- package/src/domains/safety/run-effects.ts +197 -0
- package/src/domains/safety/scope.ts +61 -0
- package/src/domains/scheduling/budget.ts +35 -0
- package/src/domains/scheduling/cluster.ts +175 -0
- package/src/domains/scheduling/contract.ts +30 -0
- package/src/domains/scheduling/extension.ts +91 -0
- package/src/domains/scheduling/index.ts +12 -0
- package/src/domains/scheduling/manifest.ts +6 -0
- package/src/domains/session/archive-readers.ts +208 -0
- package/src/domains/session/checkpoint.ts +38 -0
- package/src/domains/session/compaction/auto.ts +89 -0
- package/src/domains/session/compaction/branch-summary.ts +186 -0
- package/src/domains/session/compaction/compact.ts +493 -0
- package/src/domains/session/compaction/cut-point.ts +171 -0
- package/src/domains/session/compaction/defaults.ts +34 -0
- package/src/domains/session/compaction/mask-observations.ts +265 -0
- package/src/domains/session/compaction/session-entries.ts +18 -0
- package/src/domains/session/compaction/tokens.ts +147 -0
- package/src/domains/session/context-accounting.ts +583 -0
- package/src/domains/session/context-ledger.ts +348 -0
- package/src/domains/session/contract.ts +144 -0
- package/src/domains/session/cwd-fallback.ts +65 -0
- package/src/domains/session/entries.ts +509 -0
- package/src/domains/session/extension.ts +322 -0
- package/src/domains/session/history.ts +172 -0
- package/src/domains/session/index.ts +84 -0
- package/src/domains/session/manager.ts +128 -0
- package/src/domains/session/manifest.ts +6 -0
- package/src/domains/session/migrations/index.ts +27 -0
- package/src/domains/session/prompt-manifest.ts +173 -0
- package/src/domains/session/protected-artifact-journal.ts +241 -0
- package/src/domains/session/protected-artifacts.ts +90 -0
- package/src/domains/session/retry.ts +238 -0
- package/src/domains/session/task-board.ts +375 -0
- package/src/domains/session/tree/active-path.ts +98 -0
- package/src/domains/session/tree/fork.ts +160 -0
- package/src/domains/session/tree/manager.ts +128 -0
- package/src/domains/session/tree/navigator.ts +177 -0
- package/src/domains/session/tree/preview.ts +259 -0
- package/src/domains/session/usage.ts +148 -0
- package/src/domains/session/workspace/git-probe.ts +161 -0
- package/src/domains/session/workspace/index.ts +4 -0
- package/src/domains/session/workspace/project-type.ts +217 -0
- package/src/domains/session/workspace/snapshot.ts +74 -0
- package/src/domains/share/archive.ts +684 -0
- package/src/domains/share/contract.ts +9 -0
- package/src/domains/share/extension.ts +26 -0
- package/src/domains/share/index.ts +28 -0
- package/src/domains/share/manifest.ts +6 -0
- package/src/engine/acp/adapter.ts +397 -0
- package/src/engine/acp/errors.ts +32 -0
- package/src/engine/acp/event-mapper.ts +154 -0
- package/src/engine/acp/server.ts +656 -0
- package/src/engine/acp/tool-mediator.ts +686 -0
- package/src/engine/acp/transport.ts +654 -0
- package/src/engine/acp/types.ts +170 -0
- package/src/engine/agent.ts +29 -0
- package/src/engine/ai.ts +202 -0
- package/src/engine/alcf-oauth.ts +198 -0
- package/src/engine/antigravity/subprocess-runtime.ts +205 -0
- package/src/engine/apis/degraded-inference.ts +95 -0
- package/src/engine/apis/index.ts +20 -0
- package/src/engine/apis/llamacpp-residency.ts +252 -0
- package/src/engine/apis/lmstudio-native.ts +1438 -0
- package/src/engine/apis/lmstudio-residency.ts +92 -0
- package/src/engine/apis/ollama-native.ts +507 -0
- package/src/engine/apis/openai-completions.ts +716 -0
- package/src/engine/apis/output-budget.ts +99 -0
- package/src/engine/apis/residency-lock.ts +29 -0
- package/src/engine/apis/residency.ts +640 -0
- package/src/engine/apis/resident-models.ts +42 -0
- package/src/engine/apis/sampling-overrides.ts +38 -0
- package/src/engine/apis/thinking-replay.ts +11 -0
- package/src/engine/claude/sdk-runtime.ts +685 -0
- package/src/engine/claude/session-id.ts +5 -0
- package/src/engine/claude/subprocess-runtime.ts +316 -0
- package/src/engine/claude/tool-safety.ts +400 -0
- package/src/engine/external-subprocess.ts +23 -0
- package/src/engine/harmony-response.ts +165 -0
- package/src/engine/loop-guard.ts +1127 -0
- package/src/engine/oauth.ts +192 -0
- package/src/engine/pi-mono-names.ts +13 -0
- package/src/engine/provider-payload.ts +315 -0
- package/src/engine/select-list.ts +53 -0
- package/src/engine/session.ts +834 -0
- package/src/engine/strip-tokenizer-sentinels.ts +125 -0
- package/src/engine/tui.ts +103 -0
- package/src/engine/types.ts +66 -0
- package/src/engine/worker-events.ts +100 -0
- package/src/engine/worker-runtime.ts +1022 -0
- package/src/engine/worker-tools.ts +203 -0
- package/src/entry/orchestrator.ts +1873 -0
- package/src/interactive/application-controller.ts +346 -0
- package/src/interactive/bus-notices.ts +265 -0
- package/src/interactive/chat-loop-messages.ts +626 -0
- package/src/interactive/chat-loop-policy.ts +18 -0
- package/src/interactive/chat-loop.ts +865 -0
- package/src/interactive/chat-panel.ts +1694 -0
- package/src/interactive/chat-renderer.ts +1038 -0
- package/src/interactive/clio-editor.ts +166 -0
- package/src/interactive/command-fallbacks.ts +23 -0
- package/src/interactive/command-output.ts +85 -0
- package/src/interactive/context-activity.ts +203 -0
- package/src/interactive/context-meter.ts +223 -0
- package/src/interactive/context-overlay.ts +220 -0
- package/src/interactive/cost-overlay.ts +279 -0
- package/src/interactive/dispatch-board.ts +1319 -0
- package/src/interactive/dispatch-steering.ts +86 -0
- package/src/interactive/editor-bash.ts +46 -0
- package/src/interactive/editor-steer.ts +51 -0
- package/src/interactive/editor-submit.ts +303 -0
- package/src/interactive/external-editor.ts +67 -0
- package/src/interactive/follow-up-queue-panel.ts +75 -0
- package/src/interactive/footer/dashboard.ts +534 -0
- package/src/interactive/footer/notifications.ts +275 -0
- package/src/interactive/footer/widgets.ts +1246 -0
- package/src/interactive/footer-panel.ts +187 -0
- package/src/interactive/format-time.ts +85 -0
- package/src/interactive/index.ts +11 -0
- package/src/interactive/interactive-application.ts +755 -0
- package/src/interactive/interactive-event-projection.ts +380 -0
- package/src/interactive/interactive-input-runtime.ts +261 -0
- package/src/interactive/interactive-presentation.ts +452 -0
- package/src/interactive/interactive-shell.ts +134 -0
- package/src/interactive/interactive-slash-runtime.ts +492 -0
- package/src/interactive/interactive-subscriptions.ts +111 -0
- package/src/interactive/interactive-tickers.ts +152 -0
- package/src/interactive/keybinding-manager.ts +496 -0
- package/src/interactive/layout.ts +20 -0
- package/src/interactive/leader-key.ts +143 -0
- package/src/interactive/loop-guard-interrupt.ts +101 -0
- package/src/interactive/memory-overlay.ts +280 -0
- package/src/interactive/overlay-ask-user-lifecycle.ts +110 -0
- package/src/interactive/overlay-auth-lifecycle.ts +308 -0
- package/src/interactive/overlay-frame.ts +502 -0
- package/src/interactive/overlay-general-openers.ts +217 -0
- package/src/interactive/overlay-key-routing.ts +213 -0
- package/src/interactive/overlay-lifecycle.ts +413 -0
- package/src/interactive/overlay-model-selectors.ts +127 -0
- package/src/interactive/overlay-permission-lifecycle.ts +344 -0
- package/src/interactive/overlay-resource-openers.ts +112 -0
- package/src/interactive/overlay-session-lifecycle.ts +270 -0
- package/src/interactive/overlay-transitions.ts +57 -0
- package/src/interactive/overlays/agents.ts +69 -0
- package/src/interactive/overlays/ask-user.ts +921 -0
- package/src/interactive/overlays/auth-dialog.ts +221 -0
- package/src/interactive/overlays/context-reset.ts +108 -0
- package/src/interactive/overlays/cwd-fallback.ts +141 -0
- package/src/interactive/overlays/extensions.ts +54 -0
- package/src/interactive/overlays/help-reference.ts +140 -0
- package/src/interactive/overlays/interop.ts +139 -0
- package/src/interactive/overlays/keybinding-detail.ts +90 -0
- package/src/interactive/overlays/list-overlay.ts +606 -0
- package/src/interactive/overlays/message-picker.ts +155 -0
- package/src/interactive/overlays/model-selector.ts +1091 -0
- package/src/interactive/overlays/prompts.ts +72 -0
- package/src/interactive/overlays/session-selector-search.ts +31 -0
- package/src/interactive/overlays/session-selector.ts +266 -0
- package/src/interactive/overlays/settings.ts +3363 -0
- package/src/interactive/overlays/skills-hub.ts +237 -0
- package/src/interactive/overlays/tree-selector.ts +387 -0
- package/src/interactive/permission-overlay.ts +170 -0
- package/src/interactive/render-trace.ts +125 -0
- package/src/interactive/renderers/branch-summary.ts +86 -0
- package/src/interactive/renderers/code-ink.ts +420 -0
- package/src/interactive/renderers/compaction-summary.ts +112 -0
- package/src/interactive/renderers/diff.ts +126 -0
- package/src/interactive/renderers/notice.ts +28 -0
- package/src/interactive/renderers/retry-status.ts +31 -0
- package/src/interactive/renderers/structured.ts +89 -0
- package/src/interactive/renderers/tool-execution.ts +1104 -0
- package/src/interactive/renderers/worker-entry.ts +264 -0
- package/src/interactive/session-last-turn.ts +186 -0
- package/src/interactive/session-transcript.ts +105 -0
- package/src/interactive/session-usage-reseed.ts +74 -0
- package/src/interactive/slash-autocomplete.ts +364 -0
- package/src/interactive/slash-commands.ts +1319 -0
- package/src/interactive/slash-spec.ts +453 -0
- package/src/interactive/status/controller.ts +256 -0
- package/src/interactive/status/index.ts +23 -0
- package/src/interactive/status/state-machine.ts +530 -0
- package/src/interactive/status/summary.ts +170 -0
- package/src/interactive/status/types.ts +121 -0
- package/src/interactive/status/verbs.ts +163 -0
- package/src/interactive/status/watchdog.ts +24 -0
- package/src/interactive/tasks-overlay.ts +186 -0
- package/src/interactive/theme/components.ts +55 -0
- package/src/interactive/theme/glyphs.ts +70 -0
- package/src/interactive/theme/index.ts +15 -0
- package/src/interactive/theme/labels.ts +88 -0
- package/src/interactive/theme/rules.ts +138 -0
- package/src/interactive/theme/segments.ts +88 -0
- package/src/interactive/theme/tokens.ts +121 -0
- package/src/interactive/thinking-level-policy.ts +6 -0
- package/src/interactive/tool-prose-loop.ts +122 -0
- package/src/interactive/tool-prose-registration.ts +48 -0
- package/src/interactive/turn-context.ts +854 -0
- package/src/interactive/turn-middleware.ts +283 -0
- package/src/interactive/turn-persistence.ts +441 -0
- package/src/interactive/turn-queues.ts +169 -0
- package/src/interactive/turn-recovery.ts +306 -0
- package/src/interactive/turn-runtime.ts +802 -0
- package/src/interactive/turn-state.ts +123 -0
- package/src/interactive/view/artifacts.ts +1342 -0
- package/src/interactive/view/view-overlay.ts +732 -0
- package/src/interactive/welcome-dashboard.ts +536 -0
- package/src/interactive/worker-receipts.ts +94 -0
- package/src/interactive/worker-replay.ts +111 -0
- package/src/interactive/worker-share.ts +100 -0
- package/src/interactive/worker-stream.ts +442 -0
- package/src/interactive/workspace-facts.ts +141 -0
- package/src/tools/agent-tools.ts +382 -0
- package/src/tools/artifact.ts +103 -0
- package/src/tools/ask-user.ts +656 -0
- package/src/tools/bash.ts +176 -0
- package/src/tools/bootstrap.ts +474 -0
- package/src/tools/codewiki/code-nav.ts +563 -0
- package/src/tools/codewiki/shared.ts +115 -0
- package/src/tools/compete-worktrees.ts +898 -0
- package/src/tools/context/docs-engine.ts +619 -0
- package/src/tools/context/index.ts +435 -0
- package/src/tools/credential-present.ts +151 -0
- package/src/tools/dispatch-arguments.ts +228 -0
- package/src/tools/dispatch-plan.ts +741 -0
- package/src/tools/dispatch-scout.ts +461 -0
- package/src/tools/dispatch.ts +3338 -0
- package/src/tools/edit-diff.ts +534 -0
- package/src/tools/edit.ts +128 -0
- package/src/tools/executables.ts +22 -0
- package/src/tools/file-mutation-queue.ts +35 -0
- package/src/tools/find.ts +292 -0
- package/src/tools/grep.ts +495 -0
- package/src/tools/ignore-policy.ts +169 -0
- package/src/tools/ledger.ts +206 -0
- package/src/tools/ls.ts +110 -0
- package/src/tools/monitor.ts +797 -0
- package/src/tools/network-policy.ts +29 -0
- package/src/tools/observation.ts +421 -0
- package/src/tools/observers.ts +99 -0
- package/src/tools/path-utils.ts +79 -0
- package/src/tools/policy.ts +154 -0
- package/src/tools/profiles.ts +108 -0
- package/src/tools/read.ts +173 -0
- package/src/tools/registry.ts +1157 -0
- package/src/tools/result-shaping.ts +204 -0
- package/src/tools/safe-exec.ts +128 -0
- package/src/tools/spawn-hygiene.ts +182 -0
- package/src/tools/steer.ts +88 -0
- package/src/tools/string-enum.ts +15 -0
- package/src/tools/tasks.ts +168 -0
- package/src/tools/truncate-utf8.ts +17 -0
- package/src/tools/truncate.ts +202 -0
- package/src/tools/verify/frontend.ts +685 -0
- package/src/tools/verify/index.ts +66 -0
- package/src/tools/verify/scripts.ts +108 -0
- package/src/tools/web-fetch.ts +777 -0
- package/src/tools/worker-evidence.ts +215 -0
- package/src/tools/write.ts +52 -0
- package/src/utils/exif-orientation.ts +192 -0
- package/src/utils/git.ts +24 -0
- package/src/utils/image-resize.ts +148 -0
- package/src/utils/photon.ts +103 -0
- package/src/worker/control-lane.ts +22 -0
- package/src/worker/entry.ts +257 -0
- package/src/worker/event-projection.ts +56 -0
- package/src/worker/heartbeat.ts +24 -0
- package/src/worker/ledger-mirror.ts +95 -0
- package/src/worker/ndjson.ts +40 -0
- package/src/worker/protocol.ts +529 -0
- package/src/worker/resource-facts.ts +79 -0
- package/src/worker/runtime-registry.ts +12 -0
- package/src/worker/spec-contract.ts +654 -0
- package/src/worker/stdin-demux.ts +316 -0
- package/dist/acp-UMLFVA3F.js +0 -92
- package/dist/chunk-262G75JS.js +0 -35
- package/dist/chunk-5LDRNKX2.js +0 -1063
- package/dist/chunk-67MTHP2E.js +0 -135
- package/dist/chunk-GOTUR54M.js +0 -9
- package/dist/chunk-TPOCL34A.js +0 -2876
- package/dist/chunk-XV4ZJ6ZM.js +0 -3177
- package/dist/clio-KIQ5SNDS.js +0 -53
- package/dist/configure-G4E3A2PG.js +0 -27
- package/dist/doctor-M5HJJZOL.js +0 -61
- package/dist/domains/agents/builtins/architect.md +0 -33
- package/dist/domains/agents/builtins/coder.md +0 -31
- package/dist/domains/agents/builtins/context-bootstrap.md +0 -38
- package/dist/domains/agents/builtins/debugger.md +0 -30
- package/dist/domains/agents/builtins/documenter.md +0 -31
- package/dist/domains/agents/builtins/git-master.md +0 -30
- package/dist/domains/agents/builtins/provenance.md +0 -30
- package/dist/domains/agents/builtins/researcher.md +0 -71
- package/dist/domains/agents/builtins/scout.md +0 -42
- package/dist/domains/agents/builtins/tester.md +0 -31
- package/dist/domains/agents/builtins/verifier.md +0 -30
- package/dist/domains/agents/builtins/wiki-writer.md +0 -41
- package/dist/fleet-preflight-CLIAX7YR.js +0 -21
- package/dist/preload-KZVHET2B.js +0 -11
- package/dist/version-ROZ6CZKH.js +0 -16
- package/skills/git/commit-crafting/SKILL.md +0 -79
- package/skills/git/commit-crafting/evals.md +0 -92
- package/skills/git/create-pr/SKILL.md +0 -116
- package/skills/git/create-pr/evals.md +0 -114
- package/skills/git/investigate-issue/SKILL.md +0 -139
- package/skills/git/investigate-issue/evals.md +0 -94
- package/skills/git/review-changes/SKILL.md +0 -103
- package/skills/git/review-changes/evals.md +0 -85
|
@@ -0,0 +1,1079 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RouteDecisionV1: the sealed, explainable artifact behind one route choice.
|
|
3
|
+
*
|
|
4
|
+
* A routing decision selects an admissible execution system, not a difficulty
|
|
5
|
+
* label for a prompt. The selectable object is the whole tuple of agent,
|
|
6
|
+
* target, model, runtime, node, and operational composition, and the operator
|
|
7
|
+
* chooses the operating point on the cost-quality-latency frontier by naming a
|
|
8
|
+
* posture.
|
|
9
|
+
*
|
|
10
|
+
* Three invariants hold at every mode:
|
|
11
|
+
*
|
|
12
|
+
* - Hard constraints eliminate. A candidate the admission chain rejected can
|
|
13
|
+
* never appear as `selected` or in `approvedFallbacks`, at any posture,
|
|
14
|
+
* for any score. It stays in `candidateEvaluations` with its reason, which
|
|
15
|
+
* is what makes the decision explainable rather than merely recorded.
|
|
16
|
+
* - The decision is deterministic. `decisionHash` covers the inputs, not the
|
|
17
|
+
* wall clock, so equal inputs produce an equal hash and an offline replay
|
|
18
|
+
* of a stored decision reproduces it exactly.
|
|
19
|
+
* - Shadow mode is advisory. In shadow mode the caller has already resolved
|
|
20
|
+
* and is already executing a route; this module records what the policy
|
|
21
|
+
* would have chosen and never returns anything the caller feeds back into
|
|
22
|
+
* placement. `executedRoute` is carried in the artifact precisely so regret
|
|
23
|
+
* is computable later without re-running the decision.
|
|
24
|
+
*
|
|
25
|
+
* Pure by construction: no I/O, no clock, no engine state.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { createHash } from "node:crypto";
|
|
29
|
+
import { isAgentCapabilityClass } from "../agents/spec.js";
|
|
30
|
+
import type { AgentCandidateEvaluation, AgentRoleReadinessReport } from "./agent-candidates.js";
|
|
31
|
+
import {
|
|
32
|
+
type ExecutionRole,
|
|
33
|
+
gateRouteCorrelation,
|
|
34
|
+
isExecutionRole,
|
|
35
|
+
type RouteCorrelationFacts,
|
|
36
|
+
} from "./execution-role.js";
|
|
37
|
+
import {
|
|
38
|
+
clearsPostureFloors,
|
|
39
|
+
compareRankedRoutes,
|
|
40
|
+
DEFAULT_ROUTE_PRIOR,
|
|
41
|
+
dominatesRoute,
|
|
42
|
+
estimateRoute,
|
|
43
|
+
ROUTE_POLICY_VERSION,
|
|
44
|
+
type RouteEstimate,
|
|
45
|
+
type RoutingPosture,
|
|
46
|
+
routeScoreScale,
|
|
47
|
+
scoreRoute,
|
|
48
|
+
} from "./route-policy.js";
|
|
49
|
+
import { evaluateRouteReadiness, type RouteReadinessReport } from "./route-readiness.js";
|
|
50
|
+
|
|
51
|
+
function routeCorrelationFacts(candidate: RouteCandidate): RouteCorrelationFacts {
|
|
52
|
+
return {
|
|
53
|
+
agentId: candidate.agentId,
|
|
54
|
+
targetId: candidate.targetId,
|
|
55
|
+
wireModelId: candidate.modelId,
|
|
56
|
+
runtimeId: candidate.runtimeId,
|
|
57
|
+
nodeId: candidate.nodeId,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The unit of selection. It is the agent and its whole operational
|
|
63
|
+
* composition, not a model name: a cheap model that strips the Coder's editing
|
|
64
|
+
* tools is not a cheap route, so the tool surface and prompt composition are
|
|
65
|
+
* part of the candidate's identity.
|
|
66
|
+
*/
|
|
67
|
+
export interface RouteCandidate {
|
|
68
|
+
agentId: string;
|
|
69
|
+
specFingerprint: string;
|
|
70
|
+
executionRole: ExecutionRole;
|
|
71
|
+
targetId: string;
|
|
72
|
+
modelId: string;
|
|
73
|
+
runtimeId: string;
|
|
74
|
+
nodeId: string;
|
|
75
|
+
thinkingLevel?: string;
|
|
76
|
+
toolSignature: string;
|
|
77
|
+
promptCompositionHash: string;
|
|
78
|
+
/** Hash of the effective endpoint URL. Raw endpoint data never enters the decision. */
|
|
79
|
+
endpointIdentityHash: string;
|
|
80
|
+
/** Fingerprint of the immutable settings snapshot used to construct this route. */
|
|
81
|
+
settingsFingerprint: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export type RouteDecisionMode = "fixed" | "shadow" | "active";
|
|
85
|
+
|
|
86
|
+
export type AgentSelectionAuthorityBasis = "operator-plan-approval" | "full-auto-policy";
|
|
87
|
+
|
|
88
|
+
export interface RouteDecisionAgentSelectionInput {
|
|
89
|
+
request: "explicit" | "auto";
|
|
90
|
+
baselineAgentId: string;
|
|
91
|
+
evaluations: ReadonlyArray<AgentCandidateEvaluation>;
|
|
92
|
+
readiness: ReadonlyArray<AgentRoleReadinessReport>;
|
|
93
|
+
authorityBasis: AgentSelectionAuthorityBasis | null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface RouteDecisionAgentSelection {
|
|
97
|
+
request: "explicit" | "auto";
|
|
98
|
+
activation: "shadow" | "active";
|
|
99
|
+
baselineAgentId: string;
|
|
100
|
+
recommendedAgentId: string;
|
|
101
|
+
evaluations: AgentCandidateEvaluation[];
|
|
102
|
+
readiness: AgentRoleReadinessReport[];
|
|
103
|
+
/** Input authority provenance is retained even when no transition was selected, so replay can reproduce the hash. */
|
|
104
|
+
authorityBasis: AgentSelectionAuthorityBasis | null;
|
|
105
|
+
authorityTransition: null | {
|
|
106
|
+
from: string;
|
|
107
|
+
to: string;
|
|
108
|
+
basis: "same-authority" | AgentSelectionAuthorityBasis;
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function exactKeys(value: Record<string, unknown>, keys: ReadonlyArray<string>): boolean {
|
|
113
|
+
return Object.keys(value).sort().join("\u0000") === [...keys].sort().join("\u0000");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function decisionRecord(value: unknown): value is Record<string, unknown> {
|
|
117
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const READINESS_GAPS = new Set([
|
|
121
|
+
"hard-constraint-validity-below-one",
|
|
122
|
+
"integrity-failures-in-window",
|
|
123
|
+
"insufficient-quality-labels",
|
|
124
|
+
"quality-lower-bound-below-posture-floor",
|
|
125
|
+
"quality-lower-bound-below-requested-minimum",
|
|
126
|
+
"reliability-below-posture-floor",
|
|
127
|
+
"cost-upper-bound-unknown",
|
|
128
|
+
"route-facts-stale",
|
|
129
|
+
"decision-latency-above-budget",
|
|
130
|
+
]);
|
|
131
|
+
|
|
132
|
+
function decisionRouteCandidate(value: unknown): value is RouteCandidate {
|
|
133
|
+
if (!decisionRecord(value)) return false;
|
|
134
|
+
const required = [
|
|
135
|
+
"agentId",
|
|
136
|
+
"specFingerprint",
|
|
137
|
+
"executionRole",
|
|
138
|
+
"targetId",
|
|
139
|
+
"modelId",
|
|
140
|
+
"runtimeId",
|
|
141
|
+
"nodeId",
|
|
142
|
+
"toolSignature",
|
|
143
|
+
"promptCompositionHash",
|
|
144
|
+
"endpointIdentityHash",
|
|
145
|
+
"settingsFingerprint",
|
|
146
|
+
];
|
|
147
|
+
const keys = Object.keys(value);
|
|
148
|
+
if (keys.some((key) => !required.includes(key) && key !== "thinkingLevel")) return false;
|
|
149
|
+
if (required.some((key) => !Object.hasOwn(value, key))) return false;
|
|
150
|
+
return (
|
|
151
|
+
isExecutionRole(value.executionRole) &&
|
|
152
|
+
required
|
|
153
|
+
.filter((key) => key !== "executionRole")
|
|
154
|
+
.every((key) => typeof value[key] === "string" && String(value[key]).length > 0) &&
|
|
155
|
+
(value.thinkingLevel === undefined || (typeof value.thinkingLevel === "string" && value.thinkingLevel.length > 0))
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function decisionReadinessReport(value: unknown): value is RouteReadinessReport {
|
|
160
|
+
if (!decisionRecord(value) || !exactKeys(value, ["ready", "gaps", "labelsNeeded"])) return false;
|
|
161
|
+
return (
|
|
162
|
+
typeof value.ready === "boolean" &&
|
|
163
|
+
Array.isArray(value.gaps) &&
|
|
164
|
+
value.gaps.length <= READINESS_GAPS.size &&
|
|
165
|
+
value.gaps.every((gap) => typeof gap === "string" && READINESS_GAPS.has(gap)) &&
|
|
166
|
+
new Set(value.gaps).size === value.gaps.length &&
|
|
167
|
+
value.ready === (value.gaps.length === 0) &&
|
|
168
|
+
Number.isInteger(value.labelsNeeded) &&
|
|
169
|
+
Number(value.labelsNeeded) >= 0
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Strict validator for the required agent-selection evidence sealed in decisions and approvals. */
|
|
174
|
+
export function isRouteDecisionAgentSelection(value: unknown): value is RouteDecisionAgentSelection {
|
|
175
|
+
if (!decisionRecord(value)) return false;
|
|
176
|
+
if (
|
|
177
|
+
!exactKeys(value, [
|
|
178
|
+
"request",
|
|
179
|
+
"activation",
|
|
180
|
+
"baselineAgentId",
|
|
181
|
+
"recommendedAgentId",
|
|
182
|
+
"evaluations",
|
|
183
|
+
"readiness",
|
|
184
|
+
"authorityBasis",
|
|
185
|
+
"authorityTransition",
|
|
186
|
+
]) ||
|
|
187
|
+
(value.request !== "explicit" && value.request !== "auto") ||
|
|
188
|
+
(value.activation !== "shadow" && value.activation !== "active") ||
|
|
189
|
+
typeof value.baselineAgentId !== "string" ||
|
|
190
|
+
value.baselineAgentId.length === 0 ||
|
|
191
|
+
typeof value.recommendedAgentId !== "string" ||
|
|
192
|
+
value.recommendedAgentId.length === 0 ||
|
|
193
|
+
(value.authorityBasis !== null &&
|
|
194
|
+
value.authorityBasis !== "operator-plan-approval" &&
|
|
195
|
+
value.authorityBasis !== "full-auto-policy") ||
|
|
196
|
+
!Array.isArray(value.evaluations) ||
|
|
197
|
+
value.evaluations.length === 0 ||
|
|
198
|
+
value.evaluations.length > 64 ||
|
|
199
|
+
!Array.isArray(value.readiness) ||
|
|
200
|
+
value.readiness.length === 0 ||
|
|
201
|
+
value.readiness.length > 64
|
|
202
|
+
)
|
|
203
|
+
return false;
|
|
204
|
+
const priorKeys = [
|
|
205
|
+
"qualityMean",
|
|
206
|
+
"firstPassSuccessProbability",
|
|
207
|
+
"costUpperBoundUsd",
|
|
208
|
+
"expectedEndToEndMs",
|
|
209
|
+
"reliability",
|
|
210
|
+
"queueWaitMs",
|
|
211
|
+
];
|
|
212
|
+
if (
|
|
213
|
+
!value.evaluations.every((entry) => {
|
|
214
|
+
if (
|
|
215
|
+
!decisionRecord(entry) ||
|
|
216
|
+
!exactKeys(entry, [
|
|
217
|
+
"agentId",
|
|
218
|
+
"specFingerprint",
|
|
219
|
+
"executionRole",
|
|
220
|
+
"authority",
|
|
221
|
+
"rejections",
|
|
222
|
+
"coldPrior",
|
|
223
|
+
"priorReasons",
|
|
224
|
+
])
|
|
225
|
+
)
|
|
226
|
+
return false;
|
|
227
|
+
const prior = entry.coldPrior;
|
|
228
|
+
if (
|
|
229
|
+
typeof entry.agentId !== "string" ||
|
|
230
|
+
entry.agentId.length === 0 ||
|
|
231
|
+
typeof entry.specFingerprint !== "string" ||
|
|
232
|
+
entry.specFingerprint.length === 0 ||
|
|
233
|
+
!isExecutionRole(entry.executionRole) ||
|
|
234
|
+
!isAgentCapabilityClass(entry.authority) ||
|
|
235
|
+
!Array.isArray(entry.rejections) ||
|
|
236
|
+
entry.rejections.length > 64 ||
|
|
237
|
+
!entry.rejections.every((reason) => typeof reason === "string") ||
|
|
238
|
+
!Array.isArray(entry.priorReasons) ||
|
|
239
|
+
entry.priorReasons.length > 64 ||
|
|
240
|
+
!entry.priorReasons.every((reason) => typeof reason === "string") ||
|
|
241
|
+
!decisionRecord(prior) ||
|
|
242
|
+
!exactKeys(prior, priorKeys) ||
|
|
243
|
+
!priorKeys.every((key) => typeof prior[key] === "number" && Number.isFinite(prior[key]))
|
|
244
|
+
)
|
|
245
|
+
return false;
|
|
246
|
+
return true;
|
|
247
|
+
})
|
|
248
|
+
)
|
|
249
|
+
return false;
|
|
250
|
+
if (
|
|
251
|
+
!value.readiness.every((entry) => {
|
|
252
|
+
if (
|
|
253
|
+
!decisionRecord(entry) ||
|
|
254
|
+
!exactKeys(entry, [
|
|
255
|
+
"agentId",
|
|
256
|
+
"specFingerprint",
|
|
257
|
+
"executionRole",
|
|
258
|
+
"ready",
|
|
259
|
+
"candidateCount",
|
|
260
|
+
"readyCandidateCount",
|
|
261
|
+
"routes",
|
|
262
|
+
])
|
|
263
|
+
)
|
|
264
|
+
return false;
|
|
265
|
+
if (
|
|
266
|
+
!Array.isArray(entry.routes) ||
|
|
267
|
+
entry.routes.length === 0 ||
|
|
268
|
+
entry.routes.length > 64 ||
|
|
269
|
+
!entry.routes.every(
|
|
270
|
+
(route) =>
|
|
271
|
+
decisionRecord(route) &&
|
|
272
|
+
exactKeys(route, ["candidate", "report"]) &&
|
|
273
|
+
decisionRouteCandidate(route.candidate) &&
|
|
274
|
+
decisionReadinessReport(route.report) &&
|
|
275
|
+
route.candidate.agentId === entry.agentId &&
|
|
276
|
+
route.candidate.specFingerprint === entry.specFingerprint &&
|
|
277
|
+
route.candidate.executionRole === entry.executionRole,
|
|
278
|
+
)
|
|
279
|
+
)
|
|
280
|
+
return false;
|
|
281
|
+
const readyCandidateCount = entry.routes.filter(
|
|
282
|
+
(route) => decisionRecord(route) && decisionRecord(route.report) && route.report.ready === true,
|
|
283
|
+
).length;
|
|
284
|
+
return (
|
|
285
|
+
typeof entry.agentId === "string" &&
|
|
286
|
+
entry.agentId.length > 0 &&
|
|
287
|
+
typeof entry.specFingerprint === "string" &&
|
|
288
|
+
entry.specFingerprint.length > 0 &&
|
|
289
|
+
isExecutionRole(entry.executionRole) &&
|
|
290
|
+
typeof entry.ready === "boolean" &&
|
|
291
|
+
Number.isInteger(entry.candidateCount) &&
|
|
292
|
+
Number(entry.candidateCount) === entry.routes.length &&
|
|
293
|
+
Number.isInteger(entry.readyCandidateCount) &&
|
|
294
|
+
Number(entry.readyCandidateCount) === readyCandidateCount &&
|
|
295
|
+
entry.ready === readyCandidateCount > 0
|
|
296
|
+
);
|
|
297
|
+
})
|
|
298
|
+
)
|
|
299
|
+
return false;
|
|
300
|
+
if (value.authorityTransition !== null) {
|
|
301
|
+
const transition = value.authorityTransition;
|
|
302
|
+
if (
|
|
303
|
+
!decisionRecord(transition) ||
|
|
304
|
+
!exactKeys(transition, ["from", "to", "basis"]) ||
|
|
305
|
+
typeof transition.from !== "string" ||
|
|
306
|
+
transition.from.length === 0 ||
|
|
307
|
+
typeof transition.to !== "string" ||
|
|
308
|
+
transition.to.length === 0 ||
|
|
309
|
+
(transition.basis !== "same-authority" &&
|
|
310
|
+
transition.basis !== "operator-plan-approval" &&
|
|
311
|
+
transition.basis !== "full-auto-policy")
|
|
312
|
+
) {
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
if (
|
|
316
|
+
value.request !== "auto" ||
|
|
317
|
+
value.activation !== "active" ||
|
|
318
|
+
transition.from !== value.baselineAgentId ||
|
|
319
|
+
transition.to !== value.recommendedAgentId
|
|
320
|
+
)
|
|
321
|
+
return false;
|
|
322
|
+
const from = value.evaluations.find((entry) => entry.agentId === transition.from);
|
|
323
|
+
const to = value.evaluations.find((entry) => entry.agentId === transition.to);
|
|
324
|
+
if (from === undefined || to === undefined) return false;
|
|
325
|
+
if (transition.basis === "same-authority") {
|
|
326
|
+
if (from.authority !== to.authority) return false;
|
|
327
|
+
} else if (transition.basis !== value.authorityBasis) return false;
|
|
328
|
+
}
|
|
329
|
+
return (
|
|
330
|
+
(value.request !== "explicit" || value.authorityBasis === null) &&
|
|
331
|
+
new Set(
|
|
332
|
+
value.evaluations.map((entry) => `${entry.agentId}\u0000${entry.specFingerprint}\u0000${entry.executionRole}`),
|
|
333
|
+
).size === value.evaluations.length &&
|
|
334
|
+
value.evaluations.some((entry) => entry.agentId === value.baselineAgentId) &&
|
|
335
|
+
value.evaluations.some((entry) => entry.agentId === value.recommendedAgentId)
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export interface CandidateEvaluation {
|
|
340
|
+
candidate: RouteCandidate;
|
|
341
|
+
estimate: RouteEstimate;
|
|
342
|
+
/** Exact prerequisite report used by active admission for this tuple. */
|
|
343
|
+
activeReadiness: RouteReadinessReport;
|
|
344
|
+
/** Null when every hard constraint passed; otherwise the constraint that rejected it. */
|
|
345
|
+
rejection: string | null;
|
|
346
|
+
/** Posture score. Null for a rejected candidate: a rejected route is never scored. */
|
|
347
|
+
score: number | null;
|
|
348
|
+
/** True when an admissible candidate is no worse on all three objectives and better on one. */
|
|
349
|
+
dominated: boolean;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export interface RouteDecisionV1 {
|
|
353
|
+
policyVersion: string;
|
|
354
|
+
mode: RouteDecisionMode;
|
|
355
|
+
posture: RoutingPosture;
|
|
356
|
+
selected: RouteCandidate;
|
|
357
|
+
approvedFallbacks: RouteCandidate[];
|
|
358
|
+
hardConstraints: string[];
|
|
359
|
+
candidateEvaluations: CandidateEvaluation[];
|
|
360
|
+
reasonCodes: string[];
|
|
361
|
+
decisionDurationMs: number;
|
|
362
|
+
confidence: number;
|
|
363
|
+
decisionHash: string;
|
|
364
|
+
/** Required agent hard-filter, prior, readiness, and authority explanation. */
|
|
365
|
+
agentSelection: RouteDecisionAgentSelection;
|
|
366
|
+
/**
|
|
367
|
+
* The route the caller actually ran. Equal to `selected` at fixed and active
|
|
368
|
+
* mode; in shadow mode it is the production route the decision did not
|
|
369
|
+
* touch, and the pair is what route regret is computed from.
|
|
370
|
+
*/
|
|
371
|
+
executedRoute: RouteCandidate;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/** Candidate plus verdict, before scoring. The caller owns hard-filter truth. */
|
|
375
|
+
export interface RouteCandidateInput {
|
|
376
|
+
candidate: RouteCandidate;
|
|
377
|
+
estimate: RouteEstimate;
|
|
378
|
+
activeReadiness: RouteReadinessReport;
|
|
379
|
+
rejection: string | null;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
export interface RouteDecisionInput {
|
|
383
|
+
mode: RouteDecisionMode;
|
|
384
|
+
posture: RoutingPosture;
|
|
385
|
+
/** The route the production pipeline resolved and is executing. */
|
|
386
|
+
executedRoute: RouteCandidate;
|
|
387
|
+
/** Every enumerated tuple with its hard-filter verdict; order is the caller's approval order. */
|
|
388
|
+
candidates: ReadonlyArray<RouteCandidateInput>;
|
|
389
|
+
/** Builder route being judged or reviewed, for the post-filter independence tie-break. */
|
|
390
|
+
independenceSubject: RouteCorrelationFacts | null;
|
|
391
|
+
/** Names of the hard constraints the caller applied, for the explanation. */
|
|
392
|
+
hardConstraints: ReadonlyArray<string>;
|
|
393
|
+
/** Envelope width; the selected route does not count against it. */
|
|
394
|
+
maxFallbacks: number;
|
|
395
|
+
/** Measured resolver duration. Excluded from the hash: it is not an input. */
|
|
396
|
+
decisionDurationMs: number;
|
|
397
|
+
agentSelection: RouteDecisionAgentSelectionInput;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* The dimensions history aggregates over: what the route can do, not how this
|
|
402
|
+
* particular run was worded or configured. Two candidates with equal capability
|
|
403
|
+
* keys are the same route for the purpose of accumulating quality evidence.
|
|
404
|
+
*
|
|
405
|
+
* Editing the session prompt or an unrelated settings key must not restart the
|
|
406
|
+
* evidence count for an unchanged agent, model, runtime, and node. Measured on
|
|
407
|
+
* real history, prompt-composition edits alone sharded 28 observations into
|
|
408
|
+
* buckets no larger than four, which no posture floor can ever clear.
|
|
409
|
+
*/
|
|
410
|
+
export function routeCapabilityKey(candidate: RouteCandidate): string {
|
|
411
|
+
return [
|
|
412
|
+
candidate.agentId,
|
|
413
|
+
candidate.specFingerprint,
|
|
414
|
+
candidate.executionRole,
|
|
415
|
+
candidate.targetId,
|
|
416
|
+
candidate.modelId,
|
|
417
|
+
candidate.runtimeId,
|
|
418
|
+
candidate.nodeId,
|
|
419
|
+
candidate.thinkingLevel ?? "",
|
|
420
|
+
].join("\u0000");
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* The remaining identity dimensions. They are sealed on every observation so
|
|
425
|
+
* offline replay reconstructs exactly which prompt and settings produced it,
|
|
426
|
+
* and they are checked for staleness, but they do not create parallel buckets.
|
|
427
|
+
*/
|
|
428
|
+
export interface RouteDriftGuard {
|
|
429
|
+
promptCompositionHash: string;
|
|
430
|
+
settingsFingerprint: string;
|
|
431
|
+
toolSignature: string;
|
|
432
|
+
endpointIdentityHash: string;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
export function routeDriftGuard(candidate: RouteCandidate): RouteDriftGuard {
|
|
436
|
+
return {
|
|
437
|
+
promptCompositionHash: candidate.promptCompositionHash,
|
|
438
|
+
settingsFingerprint: candidate.settingsFingerprint,
|
|
439
|
+
toolSignature: candidate.toolSignature,
|
|
440
|
+
endpointIdentityHash: candidate.endpointIdentityHash,
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Whether drift between an observation and the route being estimated makes that
|
|
446
|
+
* observation stale. The rule is deliberately written out rather than folded
|
|
447
|
+
* into a hash, because which drift matters is a judgement and a hash hides it.
|
|
448
|
+
*
|
|
449
|
+
* Invalidating, because the route no longer does the same work:
|
|
450
|
+
*
|
|
451
|
+
* - `toolSignature`. An agent that gained or lost a tool solves a different
|
|
452
|
+
* problem. Evidence from the old surface does not describe the new one.
|
|
453
|
+
* - `endpointIdentityHash`. The target id is stable but the URL behind it moved,
|
|
454
|
+
* so the observations describe some other physical service.
|
|
455
|
+
*
|
|
456
|
+
* Not invalidating, because the route behaves the same:
|
|
457
|
+
*
|
|
458
|
+
* - `promptCompositionHash`. Session-prompt and skill-framing wording. It
|
|
459
|
+
* changes what the model is told, not what the route is capable of, and it
|
|
460
|
+
* changes on nearly every release.
|
|
461
|
+
* - `settingsFingerprint`. It covers the whole settings snapshot, almost all of
|
|
462
|
+
* which is unrelated to this route. Every part of settings that does change
|
|
463
|
+
* this route's behavior is already in the capability key or in one of the two
|
|
464
|
+
* invalidating guards above, so treating the whole fingerprint as drift only
|
|
465
|
+
* discards evidence for edits to unrelated targets.
|
|
466
|
+
*/
|
|
467
|
+
export function routeDriftInvalidates(observed: RouteDriftGuard, current: RouteDriftGuard): boolean {
|
|
468
|
+
return (
|
|
469
|
+
observed.toolSignature !== current.toolSignature || observed.endpointIdentityHash !== current.endpointIdentityHash
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/** Exact identity of a tuple. Two candidates with equal keys are the same route. */
|
|
474
|
+
export function routeCandidateKey(candidate: RouteCandidate): string {
|
|
475
|
+
return [
|
|
476
|
+
candidate.agentId,
|
|
477
|
+
candidate.specFingerprint,
|
|
478
|
+
candidate.executionRole,
|
|
479
|
+
candidate.targetId,
|
|
480
|
+
candidate.modelId,
|
|
481
|
+
candidate.runtimeId,
|
|
482
|
+
candidate.nodeId,
|
|
483
|
+
candidate.thinkingLevel ?? "",
|
|
484
|
+
candidate.toolSignature,
|
|
485
|
+
candidate.promptCompositionHash,
|
|
486
|
+
candidate.endpointIdentityHash,
|
|
487
|
+
candidate.settingsFingerprint,
|
|
488
|
+
].join("\u0000");
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
export function sameRouteIdentity(left: RouteCandidate, right: RouteCandidate): boolean {
|
|
492
|
+
return routeCandidateKey(left) === routeCandidateKey(right);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/** The route facts a resolved or probed tuple supplies, in the resolver's shape. */
|
|
496
|
+
export interface RouteIdentityInput {
|
|
497
|
+
agentId: string;
|
|
498
|
+
specFingerprint: string;
|
|
499
|
+
targetId: string;
|
|
500
|
+
wireModelId: string;
|
|
501
|
+
runtimeId: string;
|
|
502
|
+
nodeId: string;
|
|
503
|
+
thinkingLevel: string | null;
|
|
504
|
+
toolSignature: string;
|
|
505
|
+
endpointIdentityHash: string;
|
|
506
|
+
settingsFingerprint: string;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* The request facts that decide a tuple's prompt composition. The role itself is
|
|
511
|
+
* derived once by `execution-role.ts` and passed in, so candidate construction
|
|
512
|
+
* cannot invent a second, divergent role policy.
|
|
513
|
+
*/
|
|
514
|
+
export interface RouteRoleInput {
|
|
515
|
+
executionRole: ExecutionRole;
|
|
516
|
+
/** Persona override prompt when the request substituted one, else undefined. */
|
|
517
|
+
personaPrompt?: string;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Prompt composition identity for a tuple that may never have run.
|
|
522
|
+
*
|
|
523
|
+
* The real compiled prompt hash requires composing the prompt, which is async
|
|
524
|
+
* and would multiply the cost of enumerating alternates. This is the identity
|
|
525
|
+
* of the composition's inputs instead: the recipe surface, the tool surface the
|
|
526
|
+
* runtime actually leaves, and any persona override. Two candidates with the
|
|
527
|
+
* same value would compose the same worker prompt, which is the grouping route
|
|
528
|
+
* statistics need, and it is computable for a tuple never dispatched.
|
|
529
|
+
*/
|
|
530
|
+
function promptCompositionIdentity(identity: RouteIdentityInput, role: RouteRoleInput): string {
|
|
531
|
+
const persona =
|
|
532
|
+
role.personaPrompt !== undefined ? createHash("sha256").update(role.personaPrompt, "utf8").digest("hex") : null;
|
|
533
|
+
return createHash("sha256")
|
|
534
|
+
.update(
|
|
535
|
+
JSON.stringify({
|
|
536
|
+
specFingerprint: identity.specFingerprint,
|
|
537
|
+
toolSignature: identity.toolSignature,
|
|
538
|
+
persona,
|
|
539
|
+
}),
|
|
540
|
+
"utf8",
|
|
541
|
+
)
|
|
542
|
+
.digest("hex");
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
export function toRouteCandidate(identity: RouteIdentityInput, role: RouteRoleInput): RouteCandidate {
|
|
546
|
+
return {
|
|
547
|
+
agentId: identity.agentId,
|
|
548
|
+
specFingerprint: identity.specFingerprint,
|
|
549
|
+
executionRole: role.executionRole,
|
|
550
|
+
targetId: identity.targetId,
|
|
551
|
+
modelId: identity.wireModelId,
|
|
552
|
+
runtimeId: identity.runtimeId,
|
|
553
|
+
nodeId: identity.nodeId,
|
|
554
|
+
...(identity.thinkingLevel !== null ? { thinkingLevel: identity.thinkingLevel } : {}),
|
|
555
|
+
toolSignature: identity.toolSignature,
|
|
556
|
+
promptCompositionHash: promptCompositionIdentity(identity, role),
|
|
557
|
+
endpointIdentityHash: identity.endpointIdentityHash,
|
|
558
|
+
settingsFingerprint: identity.settingsFingerprint,
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
function hashNumber(value: number): number {
|
|
563
|
+
if (!Number.isFinite(value)) throw new Error(`route decision: non-finite number ${String(value)}`);
|
|
564
|
+
// Estimates are floats derived from division; a fixed precision keeps the
|
|
565
|
+
// hash stable against the last bits of otherwise-equal computations.
|
|
566
|
+
return Number(value.toFixed(9));
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function estimateHashProjection(estimate: RouteEstimate): ReadonlyArray<number> {
|
|
570
|
+
return [
|
|
571
|
+
hashNumber(estimate.qualityLabeledCount),
|
|
572
|
+
hashNumber(estimate.unmeasuredCount),
|
|
573
|
+
hashNumber(estimate.qualityCoverage),
|
|
574
|
+
hashNumber(estimate.qualityMean),
|
|
575
|
+
hashNumber(estimate.qualityLowerBound),
|
|
576
|
+
hashNumber(estimate.firstPassSuccessProbability),
|
|
577
|
+
hashNumber(estimate.expectedCostUsd),
|
|
578
|
+
hashNumber(estimate.costUpperBoundUsd),
|
|
579
|
+
hashNumber(estimate.expectedEndToEndMs),
|
|
580
|
+
hashNumber(estimate.p95EndToEndMs),
|
|
581
|
+
hashNumber(estimate.reliability),
|
|
582
|
+
hashNumber(estimate.cacheHitProbability),
|
|
583
|
+
hashNumber(estimate.queueWaitMs),
|
|
584
|
+
hashNumber(estimate.sampleCount),
|
|
585
|
+
hashNumber(estimate.confidence),
|
|
586
|
+
];
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
function readinessHashProjection(report: RouteReadinessReport): readonly [boolean, ReadonlyArray<string>, number] {
|
|
590
|
+
return [report.ready, report.gaps, hashNumber(report.labelsNeeded)];
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* The hash covers exactly the decision's inputs: policy version, mode, posture,
|
|
595
|
+
* the executed route, the enumerated candidates with their estimates and
|
|
596
|
+
* verdicts, the declared hard constraints, and the envelope width. It excludes
|
|
597
|
+
* `decisionDurationMs`, which is a measurement of the decision rather than an
|
|
598
|
+
* input to it, so a replay on a faster machine still reproduces the hash.
|
|
599
|
+
*/
|
|
600
|
+
export function routeDecisionHash(input: RouteDecisionInput): string {
|
|
601
|
+
// Arrays give every field an explicit position, so native JSON serialization
|
|
602
|
+
// is deterministic without recursively sorting hundreds of short-lived
|
|
603
|
+
// objects at the maximum universe bound. Candidate identity uses the same
|
|
604
|
+
// exact-route key as admission, ranking, and fallback selection.
|
|
605
|
+
const candidates = input.candidates.map((entry) => [
|
|
606
|
+
routeCandidateKey(entry.candidate),
|
|
607
|
+
estimateHashProjection(entry.estimate),
|
|
608
|
+
readinessHashProjection(entry.activeReadiness),
|
|
609
|
+
entry.rejection,
|
|
610
|
+
]);
|
|
611
|
+
const agentSelection = [
|
|
612
|
+
input.agentSelection.request,
|
|
613
|
+
input.agentSelection.baselineAgentId,
|
|
614
|
+
input.agentSelection.evaluations.map((entry) => [
|
|
615
|
+
entry.agentId,
|
|
616
|
+
entry.specFingerprint,
|
|
617
|
+
entry.executionRole,
|
|
618
|
+
entry.authority,
|
|
619
|
+
entry.rejections,
|
|
620
|
+
[
|
|
621
|
+
hashNumber(entry.coldPrior.qualityMean),
|
|
622
|
+
hashNumber(entry.coldPrior.firstPassSuccessProbability),
|
|
623
|
+
hashNumber(entry.coldPrior.costUpperBoundUsd),
|
|
624
|
+
hashNumber(entry.coldPrior.expectedEndToEndMs),
|
|
625
|
+
hashNumber(entry.coldPrior.reliability),
|
|
626
|
+
hashNumber(entry.coldPrior.queueWaitMs),
|
|
627
|
+
],
|
|
628
|
+
entry.priorReasons,
|
|
629
|
+
]),
|
|
630
|
+
input.agentSelection.readiness.map((entry) => [
|
|
631
|
+
entry.agentId,
|
|
632
|
+
entry.specFingerprint,
|
|
633
|
+
entry.executionRole,
|
|
634
|
+
entry.ready,
|
|
635
|
+
hashNumber(entry.candidateCount),
|
|
636
|
+
hashNumber(entry.readyCandidateCount),
|
|
637
|
+
entry.routes.map((route) => [routeCandidateKey(route.candidate), readinessHashProjection(route.report)]),
|
|
638
|
+
]),
|
|
639
|
+
input.agentSelection.authorityBasis,
|
|
640
|
+
];
|
|
641
|
+
const independenceSubject =
|
|
642
|
+
input.independenceSubject === null
|
|
643
|
+
? null
|
|
644
|
+
: [
|
|
645
|
+
input.independenceSubject.agentId,
|
|
646
|
+
input.independenceSubject.targetId,
|
|
647
|
+
input.independenceSubject.wireModelId,
|
|
648
|
+
input.independenceSubject.runtimeId,
|
|
649
|
+
input.independenceSubject.nodeId,
|
|
650
|
+
];
|
|
651
|
+
return createHash("sha256")
|
|
652
|
+
.update(
|
|
653
|
+
JSON.stringify([
|
|
654
|
+
ROUTE_POLICY_VERSION,
|
|
655
|
+
input.mode,
|
|
656
|
+
input.posture,
|
|
657
|
+
routeCandidateKey(input.executedRoute),
|
|
658
|
+
candidates,
|
|
659
|
+
independenceSubject,
|
|
660
|
+
agentSelection,
|
|
661
|
+
input.hardConstraints,
|
|
662
|
+
hashNumber(input.maxFallbacks),
|
|
663
|
+
]),
|
|
664
|
+
"utf8",
|
|
665
|
+
)
|
|
666
|
+
.digest("hex");
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Build the decision.
|
|
671
|
+
*
|
|
672
|
+
* Order of operations is the whole point: hard filters eliminate, then floors
|
|
673
|
+
* eliminate, then the remaining candidates are scored and ordered. A candidate
|
|
674
|
+
* that never cleared a hard filter is scored `null` and cannot reach `selected`
|
|
675
|
+
* or `approvedFallbacks` regardless of how attractive its estimate looks.
|
|
676
|
+
*
|
|
677
|
+
* At `manual` posture the operator named the route, so the executed route is
|
|
678
|
+
* selected and the alternates are recorded but never promoted.
|
|
679
|
+
*/
|
|
680
|
+
export function decideRoute(input: RouteDecisionInput): RouteDecisionV1 {
|
|
681
|
+
const reasonCodes: string[] = [];
|
|
682
|
+
const candidateKeys = new Map(input.candidates.map((entry) => [entry, routeCandidateKey(entry.candidate)]));
|
|
683
|
+
const candidateKey = (entry: RouteCandidateInput): string => candidateKeys.get(entry) as string;
|
|
684
|
+
const hardAdmissible = input.candidates.filter((entry) => entry.rejection === null);
|
|
685
|
+
const rejectedCount = input.candidates.length - hardAdmissible.length;
|
|
686
|
+
if (rejectedCount > 0) reasonCodes.push(`hard-filter-rejected-${rejectedCount}`);
|
|
687
|
+
const readinessExcluded =
|
|
688
|
+
input.mode === "active" ? hardAdmissible.filter((entry) => !entry.activeReadiness.ready).length : 0;
|
|
689
|
+
if (readinessExcluded > 0) reasonCodes.push(`active-readiness-excluded-${readinessExcluded}`);
|
|
690
|
+
const admissible =
|
|
691
|
+
input.mode === "active" ? hardAdmissible.filter((entry) => entry.activeReadiness.ready) : hardAdmissible;
|
|
692
|
+
|
|
693
|
+
const scale = routeScoreScale(admissible.map((entry) => entry.estimate));
|
|
694
|
+
const clearing = admissible.filter((entry) => clearsPostureFloors(entry.estimate, input.posture));
|
|
695
|
+
if (clearing.length < admissible.length) {
|
|
696
|
+
reasonCodes.push(`posture-floor-excluded-${admissible.length - clearing.length}`);
|
|
697
|
+
}
|
|
698
|
+
if (clearing.length === 0 && admissible.length > 0) {
|
|
699
|
+
reasonCodes.push("posture-floors-unsatisfiable");
|
|
700
|
+
// Shadow reports the failed floor without changing execution. Active mode
|
|
701
|
+
// must fail closed instead of reviving a merely hard-admissible route.
|
|
702
|
+
if (input.mode === "active") throw new Error("route decision: posture-floors-unsatisfiable");
|
|
703
|
+
}
|
|
704
|
+
const selectable = clearing.length > 0 ? clearing : admissible;
|
|
705
|
+
|
|
706
|
+
// Approval order is the caller's enumeration order, with the resolved route
|
|
707
|
+
// first, so it is the stable tie-break the comparator needs.
|
|
708
|
+
const approvalOrder = new Map(input.candidates.map((entry, index) => [candidateKey(entry), index]));
|
|
709
|
+
const ranked = selectable
|
|
710
|
+
.map((entry) => {
|
|
711
|
+
const key = candidateKey(entry);
|
|
712
|
+
return {
|
|
713
|
+
entry,
|
|
714
|
+
ranked: {
|
|
715
|
+
key,
|
|
716
|
+
order: approvalOrder.get(key) ?? input.candidates.length,
|
|
717
|
+
estimate: entry.estimate,
|
|
718
|
+
score: scoreRoute(entry.estimate, input.posture, scale),
|
|
719
|
+
},
|
|
720
|
+
};
|
|
721
|
+
})
|
|
722
|
+
.sort((left, right) => {
|
|
723
|
+
const policyOrder = compareRankedRoutes(
|
|
724
|
+
{ ...left.ranked, key: "", order: 0 },
|
|
725
|
+
{ ...right.ranked, key: "", order: 0 },
|
|
726
|
+
);
|
|
727
|
+
if (policyOrder !== 0) return policyOrder;
|
|
728
|
+
if (
|
|
729
|
+
input.independenceSubject !== null &&
|
|
730
|
+
(input.executedRoute.executionRole === "reviewer" || input.executedRoute.executionRole === "judge")
|
|
731
|
+
) {
|
|
732
|
+
const leftIndependent = gateRouteCorrelation(
|
|
733
|
+
input.independenceSubject,
|
|
734
|
+
routeCorrelationFacts(left.entry.candidate),
|
|
735
|
+
).independent;
|
|
736
|
+
const rightIndependent = gateRouteCorrelation(
|
|
737
|
+
input.independenceSubject,
|
|
738
|
+
routeCorrelationFacts(right.entry.candidate),
|
|
739
|
+
).independent;
|
|
740
|
+
if (leftIndependent !== rightIndependent) return leftIndependent ? -1 : 1;
|
|
741
|
+
}
|
|
742
|
+
return compareRankedRoutes(left.ranked, right.ranked);
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
const dominatedKeys = new Set<string>();
|
|
746
|
+
for (const outer of admissible) {
|
|
747
|
+
for (const inner of admissible) {
|
|
748
|
+
if (inner === outer) continue;
|
|
749
|
+
if (dominatesRoute(inner.estimate, outer.estimate)) {
|
|
750
|
+
dominatedKeys.add(candidateKey(outer));
|
|
751
|
+
break;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
const scores = new Map(ranked.map((entry) => [entry.ranked.key, entry.ranked.score]));
|
|
757
|
+
const candidateEvaluations: CandidateEvaluation[] = input.candidates.map((entry) => {
|
|
758
|
+
const key = candidateKey(entry);
|
|
759
|
+
return {
|
|
760
|
+
candidate: { ...entry.candidate },
|
|
761
|
+
estimate: { ...entry.estimate },
|
|
762
|
+
activeReadiness: { ...entry.activeReadiness, gaps: [...entry.activeReadiness.gaps] },
|
|
763
|
+
rejection: entry.rejection,
|
|
764
|
+
score: entry.rejection === null ? (scores.get(key) ?? null) : null,
|
|
765
|
+
dominated: entry.rejection === null && dominatedKeys.has(key),
|
|
766
|
+
};
|
|
767
|
+
});
|
|
768
|
+
|
|
769
|
+
const executedKey = routeCandidateKey(input.executedRoute);
|
|
770
|
+
const executedAdmissible = admissible.some((entry) => candidateKey(entry) === executedKey);
|
|
771
|
+
const manual = input.posture === "manual";
|
|
772
|
+
const best = ranked[0]?.entry.candidate;
|
|
773
|
+
if (input.mode === "active" && best === undefined) {
|
|
774
|
+
const gaps = hardAdmissible.flatMap((entry) => entry.activeReadiness.gaps);
|
|
775
|
+
const detail = [...new Set(gaps)].join(", ") || "no-hard-admissible-candidate";
|
|
776
|
+
throw new Error(`route decision: no-active-eligible-candidate (${detail})`);
|
|
777
|
+
}
|
|
778
|
+
const selected = manual || best === undefined ? { ...input.executedRoute } : { ...best };
|
|
779
|
+
if (manual) reasonCodes.push("manual-posture-exact-route");
|
|
780
|
+
if (best === undefined) reasonCodes.push("no-admissible-candidate");
|
|
781
|
+
if (!executedAdmissible) reasonCodes.push("executed-route-not-admissible");
|
|
782
|
+
if (input.mode === "shadow") reasonCodes.push("shadow-advisory-only");
|
|
783
|
+
if (input.mode !== "active" && best !== undefined && routeCandidateKey(selected) !== executedKey) {
|
|
784
|
+
reasonCodes.push("shadow-differs-from-executed");
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
const selectedKey = routeCandidateKey(selected);
|
|
788
|
+
const approvedFallbacks: RouteCandidate[] = [];
|
|
789
|
+
if (!manual) {
|
|
790
|
+
for (const entry of ranked) {
|
|
791
|
+
if (approvedFallbacks.length >= Math.max(0, input.maxFallbacks)) break;
|
|
792
|
+
if (entry.ranked.key === selectedKey) continue;
|
|
793
|
+
approvedFallbacks.push({ ...entry.entry.candidate });
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
const selectedEstimate = candidateEvaluations.find(
|
|
798
|
+
(evaluation) => routeCandidateKey(evaluation.candidate) === selectedKey,
|
|
799
|
+
)?.estimate;
|
|
800
|
+
const coldShare =
|
|
801
|
+
admissible.length === 0
|
|
802
|
+
? 1
|
|
803
|
+
: admissible.filter((entry) => entry.estimate.sampleCount === 0).length / admissible.length;
|
|
804
|
+
const confidence = Math.max(0, Math.min(1, (selectedEstimate?.confidence ?? 0) * (1 - coldShare) + coldShare * 0));
|
|
805
|
+
const recommendedAgentId = best?.agentId ?? input.agentSelection.baselineAgentId;
|
|
806
|
+
let authorityTransition: RouteDecisionAgentSelection["authorityTransition"] = null;
|
|
807
|
+
if (input.mode === "active" && selected.agentId !== input.agentSelection.baselineAgentId) {
|
|
808
|
+
if (input.agentSelection.request !== "auto") {
|
|
809
|
+
throw new Error("route decision: explicit agent selection cannot change authority");
|
|
810
|
+
}
|
|
811
|
+
const from = input.agentSelection.evaluations.find(
|
|
812
|
+
(evaluation) => evaluation.agentId === input.agentSelection.baselineAgentId,
|
|
813
|
+
)?.authority;
|
|
814
|
+
const to = input.agentSelection.evaluations.find((evaluation) => evaluation.agentId === selected.agentId)?.authority;
|
|
815
|
+
const basis =
|
|
816
|
+
from !== undefined && to !== undefined && from === to ? "same-authority" : input.agentSelection.authorityBasis;
|
|
817
|
+
if (basis === null) throw new Error("route decision: active agent authority transition lacks trusted approval");
|
|
818
|
+
authorityTransition = { from: input.agentSelection.baselineAgentId, to: selected.agentId, basis };
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
return {
|
|
822
|
+
policyVersion: ROUTE_POLICY_VERSION,
|
|
823
|
+
mode: input.mode,
|
|
824
|
+
posture: input.posture,
|
|
825
|
+
selected,
|
|
826
|
+
approvedFallbacks,
|
|
827
|
+
hardConstraints: [...input.hardConstraints],
|
|
828
|
+
candidateEvaluations,
|
|
829
|
+
reasonCodes,
|
|
830
|
+
decisionDurationMs: input.decisionDurationMs,
|
|
831
|
+
confidence,
|
|
832
|
+
agentSelection: {
|
|
833
|
+
request: input.agentSelection.request,
|
|
834
|
+
activation: input.mode === "active" ? "active" : "shadow",
|
|
835
|
+
baselineAgentId: input.agentSelection.baselineAgentId,
|
|
836
|
+
recommendedAgentId,
|
|
837
|
+
evaluations: structuredClone([...input.agentSelection.evaluations]),
|
|
838
|
+
readiness: structuredClone([...input.agentSelection.readiness]),
|
|
839
|
+
authorityBasis: input.agentSelection.authorityBasis,
|
|
840
|
+
authorityTransition,
|
|
841
|
+
},
|
|
842
|
+
decisionHash: routeDecisionHash({
|
|
843
|
+
...input,
|
|
844
|
+
executedRoute: input.mode === "active" ? selected : input.executedRoute,
|
|
845
|
+
}),
|
|
846
|
+
executedRoute: { ...(input.mode === "active" ? selected : input.executedRoute) },
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
/**
|
|
851
|
+
* Failure-isolated production fallback. Observation cannot make a receipt lose
|
|
852
|
+
* its routing evidence, so callers seal this exact one-candidate decision when
|
|
853
|
+
* the shadow observer or its durable inputs fail.
|
|
854
|
+
*/
|
|
855
|
+
export function fixedRouteDecision(
|
|
856
|
+
executedRoute: RouteCandidate,
|
|
857
|
+
reasonCode = "observer-failure-fixed-route",
|
|
858
|
+
): RouteDecisionV1 {
|
|
859
|
+
const estimate = estimateRoute([], DEFAULT_ROUTE_PRIOR);
|
|
860
|
+
const activeReadiness = evaluateRouteReadiness({
|
|
861
|
+
estimate,
|
|
862
|
+
posture: "manual",
|
|
863
|
+
hardConstraintValidity: 1,
|
|
864
|
+
integrityFailures: 0,
|
|
865
|
+
costUpperBoundUsd: null,
|
|
866
|
+
factsFresh: false,
|
|
867
|
+
decisionP95Ms: Number.POSITIVE_INFINITY,
|
|
868
|
+
requestedMinimumQuality: null,
|
|
869
|
+
});
|
|
870
|
+
const input: RouteDecisionInput = {
|
|
871
|
+
mode: "fixed",
|
|
872
|
+
posture: "manual",
|
|
873
|
+
executedRoute,
|
|
874
|
+
candidates: [
|
|
875
|
+
{
|
|
876
|
+
candidate: executedRoute,
|
|
877
|
+
estimate,
|
|
878
|
+
activeReadiness,
|
|
879
|
+
rejection: null,
|
|
880
|
+
},
|
|
881
|
+
],
|
|
882
|
+
independenceSubject: null,
|
|
883
|
+
hardConstraints: ["fixed-executed-route"],
|
|
884
|
+
maxFallbacks: 0,
|
|
885
|
+
decisionDurationMs: 0,
|
|
886
|
+
agentSelection: {
|
|
887
|
+
request: "explicit",
|
|
888
|
+
baselineAgentId: executedRoute.agentId,
|
|
889
|
+
evaluations: [
|
|
890
|
+
{
|
|
891
|
+
agentId: executedRoute.agentId,
|
|
892
|
+
specFingerprint: executedRoute.specFingerprint,
|
|
893
|
+
executionRole: executedRoute.executionRole,
|
|
894
|
+
authority: "internal",
|
|
895
|
+
rejections: [],
|
|
896
|
+
coldPrior: { ...DEFAULT_ROUTE_PRIOR },
|
|
897
|
+
priorReasons: ["fixed-route"],
|
|
898
|
+
},
|
|
899
|
+
],
|
|
900
|
+
readiness: [
|
|
901
|
+
{
|
|
902
|
+
agentId: executedRoute.agentId,
|
|
903
|
+
specFingerprint: executedRoute.specFingerprint,
|
|
904
|
+
executionRole: executedRoute.executionRole,
|
|
905
|
+
ready: activeReadiness.ready,
|
|
906
|
+
candidateCount: 1,
|
|
907
|
+
readyCandidateCount: activeReadiness.ready ? 1 : 0,
|
|
908
|
+
routes: [{ candidate: { ...executedRoute }, report: { ...activeReadiness, gaps: [...activeReadiness.gaps] } }],
|
|
909
|
+
},
|
|
910
|
+
],
|
|
911
|
+
authorityBasis: null,
|
|
912
|
+
},
|
|
913
|
+
};
|
|
914
|
+
const decision = decideRoute(input);
|
|
915
|
+
return { ...decision, reasonCodes: [...decision.reasonCodes, reasonCode] };
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
// ---------------------------------------------------------------------------
|
|
919
|
+
// Decision evaluation, computed from a stored decision and its settled receipt
|
|
920
|
+
// ---------------------------------------------------------------------------
|
|
921
|
+
|
|
922
|
+
/**
|
|
923
|
+
* What the run actually did, read back off its own receipt. Every field here
|
|
924
|
+
* exists on a sealed receipt, which is what lets an offline replay reproduce
|
|
925
|
+
* the metrics below without the process that made the decision.
|
|
926
|
+
*/
|
|
927
|
+
export interface RouteRealizedOutcome {
|
|
928
|
+
route: RouteCandidate;
|
|
929
|
+
outcome: string;
|
|
930
|
+
qualityLabel: "pass" | "fail" | "unmeasured";
|
|
931
|
+
/** True when the assignment's first attempt is the one that settled it. */
|
|
932
|
+
firstPass: boolean;
|
|
933
|
+
/** Zero-based attempt index of the settling run. */
|
|
934
|
+
attempt: number;
|
|
935
|
+
costUsd: number;
|
|
936
|
+
endToEndMs: number;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
/**
|
|
940
|
+
* Distance between the operating point the policy chose and the one that ran.
|
|
941
|
+
* Zero regret means the executed route was the policy's own pick. Regret is
|
|
942
|
+
* measured against the decision's own recorded estimates, never against a
|
|
943
|
+
* re-estimation, so it is stable under replay.
|
|
944
|
+
*/
|
|
945
|
+
export interface RouteRegret {
|
|
946
|
+
/** Selected score minus executed score. Zero when they are the same route. */
|
|
947
|
+
score: number;
|
|
948
|
+
/** Selected expected cost minus executed expected cost; negative means the executed route was cheaper. */
|
|
949
|
+
expectedCostUsd: number;
|
|
950
|
+
expectedLatencyMs: number;
|
|
951
|
+
/** True when the executed route was dominated by an admissible alternate. */
|
|
952
|
+
executedOffFrontier: boolean;
|
|
953
|
+
/** True when the policy would have run a different route. */
|
|
954
|
+
routeDiffered: boolean;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
function evaluationFor(decision: RouteDecisionV1, candidate: RouteCandidate): CandidateEvaluation | undefined {
|
|
958
|
+
const key = routeCandidateKey(candidate);
|
|
959
|
+
return decision.candidateEvaluations.find((evaluation) => routeCandidateKey(evaluation.candidate) === key);
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
function routeRegret(decision: RouteDecisionV1): RouteRegret {
|
|
963
|
+
const selected = evaluationFor(decision, decision.selected);
|
|
964
|
+
const executed = evaluationFor(decision, decision.executedRoute);
|
|
965
|
+
return {
|
|
966
|
+
score: (selected?.score ?? 0) - (executed?.score ?? 0),
|
|
967
|
+
expectedCostUsd: (selected?.estimate.expectedCostUsd ?? 0) - (executed?.estimate.expectedCostUsd ?? 0),
|
|
968
|
+
expectedLatencyMs: (selected?.estimate.expectedEndToEndMs ?? 0) - (executed?.estimate.expectedEndToEndMs ?? 0),
|
|
969
|
+
executedOffFrontier: executed?.dominated ?? false,
|
|
970
|
+
routeDiffered: !sameRouteIdentity(decision.selected, decision.executedRoute),
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* Did the decision respect its own hard constraints? This is the check that
|
|
976
|
+
* replaces "did Clio dispatch to the agent it was asked for", which was true by
|
|
977
|
+
* construction and therefore measured nothing.
|
|
978
|
+
*/
|
|
979
|
+
export interface RouteConstraintValidity {
|
|
980
|
+
selectedAdmissible: boolean;
|
|
981
|
+
executedAdmissible: boolean;
|
|
982
|
+
fallbacksAdmissible: boolean;
|
|
983
|
+
/** True when all three hold, which is the invariant the router must never break. */
|
|
984
|
+
valid: boolean;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
export function routeConstraintValidity(decision: RouteDecisionV1): RouteConstraintValidity {
|
|
988
|
+
const admissible = (candidate: RouteCandidate): boolean => evaluationFor(decision, candidate)?.rejection === null;
|
|
989
|
+
const selectedAdmissible = admissible(decision.selected);
|
|
990
|
+
const executedAdmissible = admissible(decision.executedRoute);
|
|
991
|
+
const fallbacksAdmissible = decision.approvedFallbacks.every(admissible);
|
|
992
|
+
return {
|
|
993
|
+
selectedAdmissible,
|
|
994
|
+
executedAdmissible,
|
|
995
|
+
fallbacksAdmissible,
|
|
996
|
+
valid: selectedAdmissible && executedAdmissible && fallbacksAdmissible,
|
|
997
|
+
};
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
/**
|
|
1001
|
+
* How wrong the estimate for the route that actually ran turned out to be.
|
|
1002
|
+
* Ratios are reported alongside absolute errors because a $0.01 miss on a $0.02
|
|
1003
|
+
* route and a $0.01 miss on a $5 route are not the same kind of wrong.
|
|
1004
|
+
*/
|
|
1005
|
+
export interface RoutePredictionCalibration {
|
|
1006
|
+
costErrorUsd: number;
|
|
1007
|
+
costRatio: number;
|
|
1008
|
+
latencyErrorMs: number;
|
|
1009
|
+
latencyRatio: number;
|
|
1010
|
+
/** Squared error of the quality estimate against a measured label; null when unmeasured. */
|
|
1011
|
+
qualityBrier: number | null;
|
|
1012
|
+
firstPassBrier: number;
|
|
1013
|
+
/** Samples that backed the executed route's estimate at decision time. */
|
|
1014
|
+
sampleCount: number;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
function ratio(actual: number, expected: number): number {
|
|
1018
|
+
if (expected === 0) return actual === 0 ? 1 : Number.POSITIVE_INFINITY;
|
|
1019
|
+
return actual / expected;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
function routePredictionCalibration(
|
|
1023
|
+
decision: RouteDecisionV1,
|
|
1024
|
+
realized: RouteRealizedOutcome,
|
|
1025
|
+
): RoutePredictionCalibration {
|
|
1026
|
+
const executed = evaluationFor(decision, realized.route);
|
|
1027
|
+
const estimate = executed?.estimate;
|
|
1028
|
+
const quality = realized.qualityLabel === "unmeasured" ? null : realized.qualityLabel === "pass" ? 1 : 0;
|
|
1029
|
+
const firstPass = realized.firstPass ? 1 : 0;
|
|
1030
|
+
return {
|
|
1031
|
+
costErrorUsd: realized.costUsd - (estimate?.expectedCostUsd ?? 0),
|
|
1032
|
+
costRatio: ratio(realized.costUsd, estimate?.expectedCostUsd ?? 0),
|
|
1033
|
+
latencyErrorMs: realized.endToEndMs - (estimate?.expectedEndToEndMs ?? 0),
|
|
1034
|
+
latencyRatio: ratio(realized.endToEndMs, estimate?.expectedEndToEndMs ?? 0),
|
|
1035
|
+
qualityBrier: quality === null ? null : (quality - (estimate?.qualityMean ?? 0)) ** 2,
|
|
1036
|
+
firstPassBrier: (firstPass - (estimate?.firstPassSuccessProbability ?? 0)) ** 2,
|
|
1037
|
+
sampleCount: estimate?.sampleCount ?? 0,
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
/** What the run produced, independent of what any router predicted. */
|
|
1042
|
+
export interface RouteOutcomeMetrics {
|
|
1043
|
+
outcome: string;
|
|
1044
|
+
qualityLabel: "pass" | "fail" | "unmeasured";
|
|
1045
|
+
firstPass: boolean;
|
|
1046
|
+
escalated: boolean;
|
|
1047
|
+
attempts: number;
|
|
1048
|
+
costUsd: number;
|
|
1049
|
+
endToEndMs: number;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
function routeOutcomeMetrics(realized: RouteRealizedOutcome): RouteOutcomeMetrics {
|
|
1053
|
+
return {
|
|
1054
|
+
outcome: realized.outcome,
|
|
1055
|
+
qualityLabel: realized.qualityLabel,
|
|
1056
|
+
firstPass: realized.firstPass,
|
|
1057
|
+
escalated: realized.attempt > 0,
|
|
1058
|
+
attempts: realized.attempt + 1,
|
|
1059
|
+
costUsd: realized.costUsd,
|
|
1060
|
+
endToEndMs: realized.endToEndMs,
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
/** The four evaluation families for one settled decision, in one record. */
|
|
1065
|
+
export interface RouteEvaluation {
|
|
1066
|
+
regret: RouteRegret;
|
|
1067
|
+
validity: RouteConstraintValidity;
|
|
1068
|
+
calibration: RoutePredictionCalibration;
|
|
1069
|
+
outcome: RouteOutcomeMetrics;
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
export function evaluateRouteDecision(decision: RouteDecisionV1, realized: RouteRealizedOutcome): RouteEvaluation {
|
|
1073
|
+
return {
|
|
1074
|
+
regret: routeRegret(decision),
|
|
1075
|
+
validity: routeConstraintValidity(decision),
|
|
1076
|
+
calibration: routePredictionCalibration(decision, realized),
|
|
1077
|
+
outcome: routeOutcomeMetrics(realized),
|
|
1078
|
+
};
|
|
1079
|
+
}
|