@iowarp/clio-coder 0.3.2 → 0.3.4
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 +269 -458
- package/CONTRIBUTING.md +1 -1
- package/README.md +3 -3
- package/dist/{acp-BIYHVZIM.js → acp-S5R4RR5B.js} +7 -6
- package/dist/{agents-YT6SSRIT.js → agents-P6DMMVZY.js} +24 -21
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-5TWEIYDN.js → auth-2XCZLPKS.js} +12 -8
- package/dist/{chunk-GGXXDWE4.js → chunk-22NAGB7X.js} +2 -2
- package/dist/{chunk-WMSVI4G2.js → chunk-2LZI5CAG.js} +133 -13
- package/dist/{chunk-OAO4GE4M.js → chunk-2TZWSW76.js} +2 -2
- package/dist/{chunk-OOJYHWRB.js → chunk-34475P3I.js} +2 -2
- package/dist/{chunk-WVO7V2QY.js → chunk-35MKKU5R.js} +4 -4
- package/dist/{chunk-LBNRH5WM.js → chunk-3HZ5RWN2.js} +5 -5
- package/dist/{chunk-AGYYIBLL.js → chunk-3JLKSKD7.js} +2 -2
- package/dist/{chunk-MBS4V7ZP.js → chunk-4JUF2NNX.js} +7 -7
- package/dist/{chunk-ZDOOVTXZ.js → chunk-4OC57DA6.js} +27 -4
- package/dist/chunk-5M54SPOL.js +926 -0
- package/dist/{chunk-STBPMHSX.js → chunk-7RXG6QRZ.js} +51 -11
- package/dist/{chunk-77VKQEHF.js → chunk-A2GZF7DC.js} +5 -5
- package/dist/{chunk-A3CYT5EX.js → chunk-AD2SYQYC.js} +55 -2
- package/dist/chunk-AOCYTWAV.js +449 -0
- package/dist/chunk-BEY543CS.js +258 -0
- package/dist/{chunk-6N5PTWMY.js → chunk-BP4OYD6A.js} +32 -13
- package/dist/chunk-BPGS2WCQ.js +612 -0
- package/dist/{chunk-J5HN4RYU.js → chunk-BRXQQJFP.js} +8 -8
- package/dist/chunk-CFGTUFWB.js +67 -0
- package/dist/{chunk-CBCAPZAA.js → chunk-E25LMLRW.js} +2 -2
- package/dist/{chunk-G2DE3C7R.js → chunk-EDRHSCIE.js} +4 -4
- package/dist/{chunk-4KLWL3UC.js → chunk-EFADSJET.js} +2 -2
- package/dist/{chunk-M6SHUN7Q.js → chunk-FO5ZOVUY.js} +2 -2
- package/dist/chunk-FYYLNIL5.js +313 -0
- package/dist/{chunk-EPVUXGXG.js → chunk-HV5X7OR2.js} +14 -12
- package/dist/{chunk-TZTZS7QK.js → chunk-HXG4IURW.js} +5 -3
- package/dist/{chunk-IGLFWIYI.js → chunk-K6WL7QZT.js} +3 -3
- package/dist/chunk-K7VKOLQQ.js +15 -0
- package/dist/{chunk-BMEMKKIT.js → chunk-KOHPCX4K.js} +2 -2
- package/dist/{chunk-V4RXGQ5Q.js → chunk-KRPY7NTG.js} +10 -7
- package/dist/chunk-LL4KHSZI.js +22 -0
- package/dist/{chunk-KJ5LWLOE.js → chunk-MEQ45TQ4.js} +15 -9
- package/dist/{chunk-5UUP6MWO.js → chunk-MV3K5QF2.js} +5 -436
- package/dist/{chunk-AO4RKG4M.js → chunk-N4CZJQRK.js} +5 -5
- package/dist/{chunk-ARBGF5F7.js → chunk-NILBFAPG.js} +14 -8
- package/dist/chunk-OZNBF4L3.js +23 -0
- package/dist/{verify-G6V4D2G7.js → chunk-PCZJO5TI.js} +127 -42
- package/dist/chunk-QQK64KLB.js +1360 -0
- package/dist/{chunk-6EJV5X2W.js → chunk-QQL5RT5M.js} +979 -1619
- package/dist/{chunk-LZSJBIVT.js → chunk-QWU7ZBO7.js} +70 -720
- package/dist/{chunk-2EHAIA3X.js → chunk-RD5U66HV.js} +3 -3
- package/dist/{chunk-OKGUZO2U.js → chunk-SPULKLCF.js} +4 -3
- package/dist/{chunk-OQ33BKR3.js → chunk-TTNYS3EA.js} +3 -60
- package/dist/chunk-TW3WDMVS.js +677 -0
- package/dist/chunk-TZSKNMZG.js +434 -0
- package/dist/{chunk-7MNJORFF.js → chunk-UL3WSD3F.js} +6 -1
- package/dist/{chunk-7EYHLWU7.js → chunk-UZHIZC5S.js} +7 -7
- package/dist/{chunk-QTYWRVRA.js → chunk-VAWWTKDP.js} +8 -8
- package/dist/{chunk-X75S7HFS.js → chunk-VEZEGCGW.js} +214 -20
- package/dist/{chunk-OHHN2SO4.js → chunk-VMNQ6OZA.js} +98 -202
- package/dist/chunk-VSNATDE6.js +122 -0
- package/dist/chunk-W6GROXXM.js +69 -0
- package/dist/chunk-WPQLXFOZ.js +375 -0
- package/dist/{chunk-ORBHGJC5.js → chunk-WR67VIZY.js} +3 -3
- package/dist/{chunk-3ZXDFGR5.js → chunk-X6COSD2O.js} +5 -5
- package/dist/chunk-ZGVHUX3M.js +66 -0
- package/dist/{chunk-MAW544W2.js → chunk-ZWMF7253.js} +4 -4
- package/dist/{chunk-MQSRRFWA.js → chunk-ZYKPLLNQ.js} +563 -546
- package/dist/cli/index.js +27 -23
- package/dist/{clio-4LY5K2AC.js → clio-J5JIOIDS.js} +7 -6
- package/dist/{code-nav-7AX6FYE6.js → code-nav-AXCXSBHX.js} +5 -3
- package/dist/{config-GTLUW2PR.js → config-OEBMIN2U.js} +37 -27
- package/dist/{configure-R6A64DHX.js → configure-PUQOSIXQ.js} +16 -13
- package/dist/{context-5VKGUVJJ.js → context-EKDCKUUZ.js} +82 -7
- package/dist/{context-RW5HC47S.js → context-MGSE4Z2T.js} +33 -23
- package/dist/{context-JFZEJ7W5.js → context-URSXPBCK.js} +17 -9
- package/dist/{context-clear-6ZHBAZZT.js → context-clear-KDAJRNUK.js} +33 -23
- package/dist/context-working-set-SBKMPPI2.js +1552 -0
- package/dist/{dispatch-runner-VKBRCWQC.js → dispatch-runner-MSWN72NK.js} +43 -29
- package/dist/{doctor-KI767GSN.js → doctor-7BSE27PJ.js} +10 -10
- package/dist/{eval-XSSNATB4.js → eval-IZGDOO4H.js} +9 -8
- package/dist/{evidence-UA6AWDQQ.js → evidence-SR7WXB5B.js} +51 -23
- package/dist/{evolve-QNTFGV6Z.js → evolve-K7VE2CBX.js} +30 -20
- package/dist/{fleet-Q7UOMUSG.js → fleet-7XMJNQNF.js} +48 -38
- package/dist/{fleet-preflight-DDN536IT.js → fleet-preflight-AQNAH644.js} +3 -3
- package/dist/{init-WBB65ZHQ.js → init-JGNPAYXT.js} +41 -31
- package/dist/{memory-MD3O64RI.js → memory-4ALKDJ4Q.js} +32 -22
- package/dist/{models-BZU34YWD.js → models-ZMMLFJNN.js} +22 -19
- package/dist/{monitor-MEQA5C3I.js → monitor-2F3T5KHP.js} +55 -43
- package/dist/{orchestrator-CGFKEP27.js → orchestrator-ORHT43JB.js} +2507 -1896
- package/dist/{reset-L2FQEE3E.js → reset-NXGTYNUO.js} +4 -3
- package/dist/{run-IV4Q6RLN.js → run-RF4WJGMT.js} +51 -41
- package/dist/{share-S5BZQC5I.js → share-UT3W6E4M.js} +5 -4
- package/dist/{skills-LQEKRDTN.js → skills-PSACKC5Q.js} +2 -2
- package/dist/{skills-eval-3DC4HEWS.js → skills-eval-WJSI55RZ.js} +34 -24
- package/dist/{targets-C4SSGQOB.js → targets-PIIRAOYS.js} +23 -20
- package/dist/{terminal-lease-IT5JW2NR.js → terminal-lease-ULWXWNVY.js} +5 -4
- package/dist/{upgrade-7TT7SQ3G.js → upgrade-346TZ6AV.js} +18 -17
- package/dist/{usage-GV4PKT3M.js → usage-6KKXR32N.js} +34 -24
- package/dist/verifiers-4UUM6TEE.js +1214 -0
- package/dist/verify-X5HDROLA.js +25 -0
- package/dist/{wiki-generate-DQF6Z66B.js → wiki-generate-7STOCIFZ.js} +42 -31
- package/dist/worker/entry.js +33 -24
- package/docs/README.md +8 -7
- package/docs/acp.md +1 -1
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +2 -2
- package/docs/artifact-versions.md +1 -1
- package/docs/built-in-agents.md +1 -1
- package/docs/capacity-and-scheduling.md +1 -1
- package/docs/commands-and-modes.md +53 -21
- package/docs/config-knobs-audit.md +1 -2
- package/docs/configuration-and-targets.md +15 -1
- package/docs/context-engine.md +64 -12
- package/docs/context-working-set.md +194 -0
- package/docs/development-pipeline.md +1 -1
- package/docs/documentation-coverage.md +5 -5
- package/docs/documentation-guide.md +6 -5
- package/docs/environment-variables.md +2 -1
- package/docs/eval-runner.md +1 -1
- package/docs/evals-internal.md +14 -1
- package/docs/evidence-and-memory.md +74 -2
- package/docs/evolution.md +1 -1
- package/docs/exit-codes-and-output.md +1 -1
- package/docs/extensions-and-sharing.md +2 -2
- package/docs/fleet-dispatch.md +22 -7
- package/docs/glossary.md +21 -1
- package/docs/installation-and-lifecycle.md +6 -6
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +7 -9
- package/docs/observability.md +4 -4
- package/docs/performance-methodology.md +2 -2
- package/docs/proactive-memory.md +1 -1
- package/docs/prompt-envelope-and-tools.md +4 -4
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/release-cut-checklist.md +35 -35
- package/docs/safety-model.md +23 -4
- package/docs/scientific-validation.md +21 -3
- package/docs/session-lifecycle.md +3 -3
- package/docs/skills-marketplace.md +1 -1
- package/docs/tool-usage.md +79 -12
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +1 -1
- package/docs/tui-design.md +2 -2
- package/docs/worker-dispatch-mechanics.md +11 -1
- package/package.json +8 -11
- package/skills/meta/clio-test/SKILL.md +20 -17
- package/skills/meta/clio-test/evals.md +3 -3
- package/skills/meta/clio-test/references/harness.md +35 -6
- package/skills/meta/clio-test/references/test-map.md +20 -10
- package/skills/registry.yaml +2 -2
- package/skills/skill-marketplace.json +1 -1
- package/src/cli/context-working-set.ts +513 -0
- package/src/cli/context.ts +8 -0
- package/src/cli/evidence.ts +20 -2
- package/src/cli/index.ts +4 -0
- package/src/cli/verifiers.ts +325 -0
- package/src/core/bash-exec.ts +39 -14
- package/src/core/bus-events.ts +19 -4
- package/src/core/config.ts +54 -0
- package/src/core/defaults.ts +50 -3
- package/src/core/git-commit-attribution.ts +46 -21
- package/src/core/verification-scripts.ts +6 -0
- package/src/domains/agents/builtins/verifier.md +3 -0
- package/src/domains/config/classify.ts +1 -0
- package/src/domains/config/keybindings.ts +3 -3
- package/src/domains/context/working-set/contract.ts +161 -0
- package/src/domains/context/working-set/defaults.ts +28 -0
- package/src/domains/context/working-set/engine.ts +203 -0
- package/src/domains/context/working-set/fold.ts +62 -0
- package/src/domains/context/working-set/horizon.ts +38 -0
- package/src/domains/context/working-set/marker.ts +103 -0
- package/src/domains/context/working-set/path-index.ts +436 -0
- package/src/domains/context/working-set/payload.ts +152 -0
- package/src/domains/context/working-set/policies/age-horizon.ts +55 -0
- package/src/domains/context/working-set/policies/index.ts +21 -0
- package/src/domains/context/working-set/policies/structural.ts +160 -0
- package/src/domains/context/working-set/project.ts +132 -0
- package/src/domains/context/working-set/protect.ts +109 -0
- package/src/domains/context/working-set/recall.ts +177 -0
- package/src/domains/context/working-set/replay/controls.ts +112 -0
- package/src/domains/context/working-set/replay/load-clio.ts +199 -0
- package/src/domains/context/working-set/replay/metrics.ts +185 -0
- package/src/domains/context/working-set/replay/reference-graph.ts +79 -0
- package/src/domains/context/working-set/replay/report.ts +139 -0
- package/src/domains/context/working-set/replay/runner.ts +325 -0
- package/src/domains/context/working-set/replay/synthetic.ts +422 -0
- package/src/domains/context/working-set/replay/trace.ts +21 -0
- package/src/domains/context/working-set/visible.ts +54 -0
- package/src/domains/evidence/build.ts +112 -45
- package/src/domains/evidence/eval.ts +24 -7
- package/src/domains/evidence/index.ts +53 -0
- package/src/domains/evidence/ordering.ts +12 -0
- package/src/domains/evidence/run-trust.ts +221 -0
- package/src/domains/evidence/store.ts +46 -6
- package/src/domains/evidence/trust-status.ts +854 -0
- package/src/domains/evidence/types.ts +26 -0
- package/src/domains/middleware/memory-intervention.ts +3 -0
- package/src/domains/middleware/stalled-turn.ts +165 -4
- package/src/domains/safety/autonomy.ts +1 -1
- package/src/domains/safety/default-path-policy.ts +8 -0
- package/src/domains/safety/finish-contract.ts +4 -3
- package/src/domains/safety/policy-engine.ts +48 -6
- package/src/domains/session/compaction/compact.ts +23 -1
- package/src/domains/session/compaction/cut-point.ts +2 -0
- package/src/domains/session/compaction/tokens.ts +16 -1
- package/src/domains/session/context-ledger.ts +2 -0
- package/src/domains/session/entries.ts +107 -1
- package/src/domains/session/manager.ts +9 -2
- package/src/domains/session/migrations/index.ts +22 -3
- package/src/engine/acp/server.ts +3 -0
- package/src/engine/agent.ts +18 -1
- package/src/engine/session.ts +9 -3
- package/src/entry/orchestrator.ts +16 -4
- package/src/interactive/chat-loop-messages.ts +18 -6
- package/src/interactive/chat-panel.ts +571 -244
- package/src/interactive/chat-renderer.ts +79 -39
- package/src/interactive/context-meter.ts +10 -0
- package/src/interactive/context-overlay.ts +81 -6
- package/src/interactive/context-recall-command.ts +110 -0
- package/src/interactive/editor-submit.ts +26 -1
- package/src/interactive/footer/widgets.ts +22 -20
- package/src/interactive/footer-panel.ts +6 -1
- package/src/interactive/interactive-application.ts +2 -0
- package/src/interactive/interactive-event-projection.ts +12 -0
- package/src/interactive/interactive-slash-runtime.ts +49 -8
- package/src/interactive/model-session-replay.ts +21 -0
- package/src/interactive/overlay-general-openers.ts +6 -0
- package/src/interactive/overlay-session-lifecycle.ts +8 -4
- package/src/interactive/overlays/ask-user.ts +146 -24
- package/src/interactive/renderers/tool-execution.ts +167 -56
- package/src/interactive/session-transcript.ts +2 -2
- package/src/interactive/slash-commands.ts +29 -2
- package/src/interactive/status/index.ts +12 -1
- package/src/interactive/status/reasoning.ts +87 -0
- package/src/interactive/status/summary.ts +13 -2
- package/src/interactive/transcript-detail.ts +120 -0
- package/src/interactive/turn-context.ts +238 -88
- package/src/interactive/turn-middleware.ts +6 -6
- package/src/tools/agent-tools.ts +11 -4
- package/src/tools/bash.ts +144 -82
- package/src/tools/builtin-tool-catalog.ts +18 -6
- package/src/tools/context/index.ts +105 -3
- package/src/tools/context/surface.ts +3 -2
- package/src/tools/core-bootstrap.ts +21 -0
- package/src/tools/dispatch-runner.ts +9 -7
- package/src/tools/monitor.ts +28 -20
- package/src/tools/presentation.ts +107 -0
- package/src/tools/registry.ts +65 -7
- package/src/tools/result-disposition.ts +550 -0
- package/src/tools/result-shaping.ts +262 -19
- package/src/tools/safe-exec.ts +2 -0
- package/src/tools/verify/authoring.ts +1119 -0
- package/src/tools/verify/catalog.ts +346 -0
- package/src/tools/verify/index.ts +13 -3
- package/src/tools/verify/scripts.ts +135 -37
- package/src/tools/verify/surface.ts +9 -5
- package/src/tools/worker-evidence.ts +35 -12
- package/dist/chunk-MNA4JGU4.js +0 -255
- package/dist/chunk-SRF2PJNW.js +0 -184
- package/dist/chunk-T6YILFSB.js +0 -80
- package/dist/chunk-VAKQQHWR.js +0 -434
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { type GateDecisionArtifact, verifyGateDecisionArtifact } from "../dispatch/gate-decisions.js";
|
|
2
|
+
import type { RunEnvelope, RunReceipt } from "../dispatch/types.js";
|
|
3
|
+
import type { FinishContractAssessment, FinishContractEvidenceKind } from "../safety/finish-contract.js";
|
|
4
|
+
import { compareCodepoints as compareStrings } from "./ordering.js";
|
|
5
|
+
import {
|
|
6
|
+
adaptFinishContractCompletionStatus,
|
|
7
|
+
adaptGateDecisionReviewStatus,
|
|
8
|
+
adaptGroundedEvidenceValidationStatus,
|
|
9
|
+
type CanonicalTrustStatus,
|
|
10
|
+
composeTrustStatus,
|
|
11
|
+
inspectRunReceiptTrustStatus,
|
|
12
|
+
isTrustStatusIdentifier,
|
|
13
|
+
type TrustArtifactReference,
|
|
14
|
+
} from "./trust-status.js";
|
|
15
|
+
import { EVIDENCE_VERSION, type EvidenceAuditLinkedRow, type EvidenceTrustStatusFile } from "./types.js";
|
|
16
|
+
|
|
17
|
+
export interface EvidenceRunTrustSource {
|
|
18
|
+
envelope: RunEnvelope;
|
|
19
|
+
receipt: RunReceipt | null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface BuildEvidenceTrustStatusInput {
|
|
23
|
+
evidenceId: string;
|
|
24
|
+
runSources: ReadonlyArray<EvidenceRunTrustSource>;
|
|
25
|
+
gateDecisions: ReadonlyArray<GateDecisionArtifact>;
|
|
26
|
+
auditRows: ReadonlyArray<EvidenceAuditLinkedRow>;
|
|
27
|
+
validationEvidence?: ReadonlyMap<string, ReadonlyArray<TrustArtifactReference>>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Compose every evidence-linked trust axis at one pure boundary. Both the
|
|
32
|
+
* run/session and eval builders call this function, so the same authenticated
|
|
33
|
+
* receipt, gate decision, and exact finish-contract row cannot project
|
|
34
|
+
* differently merely because it was bundled through a different entry point.
|
|
35
|
+
*/
|
|
36
|
+
export function buildEvidenceTrustStatusFile(input: BuildEvidenceTrustStatusInput): EvidenceTrustStatusFile {
|
|
37
|
+
return {
|
|
38
|
+
version: EVIDENCE_VERSION,
|
|
39
|
+
evidenceId: input.evidenceId,
|
|
40
|
+
projection: "canonical",
|
|
41
|
+
runs: input.runSources.map((source) => ({
|
|
42
|
+
runId: source.envelope.id,
|
|
43
|
+
status: composeEvidenceRunTrustStatus({
|
|
44
|
+
evidenceId: input.evidenceId,
|
|
45
|
+
source,
|
|
46
|
+
gateDecisions: input.gateDecisions,
|
|
47
|
+
auditRows: input.auditRows,
|
|
48
|
+
validationEvidence: input.validationEvidence?.get(source.envelope.id) ?? [],
|
|
49
|
+
}),
|
|
50
|
+
})),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
interface ComposeEvidenceRunTrustInput {
|
|
55
|
+
evidenceId: string;
|
|
56
|
+
source: EvidenceRunTrustSource;
|
|
57
|
+
gateDecisions: ReadonlyArray<GateDecisionArtifact>;
|
|
58
|
+
auditRows: ReadonlyArray<EvidenceAuditLinkedRow>;
|
|
59
|
+
validationEvidence: ReadonlyArray<TrustArtifactReference>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function composeEvidenceRunTrustStatus(input: ComposeEvidenceRunTrustInput): CanonicalTrustStatus {
|
|
63
|
+
const inspection = inspectRunReceiptTrustStatus(input.source.receipt, input.source.envelope);
|
|
64
|
+
// A receipt that was presented and rejected authenticates nothing about the
|
|
65
|
+
// run it names. Its integrity failure stays on `artifactIntegrity`; no other
|
|
66
|
+
// axis may reach a trust-granting state on the strength of that run's own
|
|
67
|
+
// self-reports. A missing or unchecked receipt is not a rejection.
|
|
68
|
+
const receiptRejected = inspection.status.artifactIntegrity.state === "failed";
|
|
69
|
+
let status = inspection.status;
|
|
70
|
+
// Only independently observed executions ground validation. The
|
|
71
|
+
// completion-contract audit row is the run's own self-report: it feeds
|
|
72
|
+
// `completionEvidence` below and nothing else. The cross-axis rules this
|
|
73
|
+
// enforces are listed under "composition rules" in docs/evidence-and-memory.md.
|
|
74
|
+
const grounded = input.validationEvidence.filter((artifact) => isTrustStatusIdentifier(artifact.id));
|
|
75
|
+
if (
|
|
76
|
+
grounded.length > 0 &&
|
|
77
|
+
(status.validationGrounding.state === "absent" || status.validationGrounding.state === "unknown")
|
|
78
|
+
) {
|
|
79
|
+
status = composeTrustStatus(status, {
|
|
80
|
+
validationGrounding: adaptGroundedEvidenceValidationStatus({
|
|
81
|
+
evidenceId: input.evidenceId,
|
|
82
|
+
runId: input.source.envelope.id,
|
|
83
|
+
artifacts: grounded,
|
|
84
|
+
}),
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const gate = latestGateDecisionForRun(input.gateDecisions, input.source.envelope.id);
|
|
89
|
+
if (gate !== null) {
|
|
90
|
+
const artifactVerification = verifyGateDecisionArtifact(gate);
|
|
91
|
+
const subject = gate.subjects.find((entry) => entry.runId === input.source.envelope.id);
|
|
92
|
+
const receipt = inspection.integrity.ok ? input.source.receipt : null;
|
|
93
|
+
const verification =
|
|
94
|
+
artifactVerification.ok &&
|
|
95
|
+
subject !== undefined &&
|
|
96
|
+
receipt?.integrity !== undefined &&
|
|
97
|
+
subject.digest === receipt.integrity.digest
|
|
98
|
+
? ({ ok: true } as const)
|
|
99
|
+
: ({
|
|
100
|
+
ok: false,
|
|
101
|
+
reason: artifactVerification.ok
|
|
102
|
+
? "gate subject receipt digest unavailable or mismatched"
|
|
103
|
+
: artifactVerification.reason,
|
|
104
|
+
} as const);
|
|
105
|
+
status = composeTrustStatus(status, {
|
|
106
|
+
independentReview: adaptGateDecisionReviewStatus(gate, input.source.envelope.id, verification),
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const finish = latestFinishContractForRun(input.auditRows, input.source.envelope.id);
|
|
111
|
+
if (finish !== null) {
|
|
112
|
+
const completion = adaptFinishContractCompletionStatus(finish.assessment, {
|
|
113
|
+
sourceId: finish.sourceId,
|
|
114
|
+
artifacts: finish.artifacts,
|
|
115
|
+
});
|
|
116
|
+
status = composeTrustStatus(status, {
|
|
117
|
+
completionEvidence:
|
|
118
|
+
receiptRejected && completion.state === "evidenced"
|
|
119
|
+
? {
|
|
120
|
+
state: "unknown",
|
|
121
|
+
source: { kind: "finish_contract", id: finish.sourceId },
|
|
122
|
+
authority: { kind: "clio", id: "finish-contract" },
|
|
123
|
+
artifacts: finish.artifacts,
|
|
124
|
+
}
|
|
125
|
+
: completion,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return status;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function latestGateDecisionForRun(
|
|
132
|
+
decisions: ReadonlyArray<GateDecisionArtifact>,
|
|
133
|
+
runId: string,
|
|
134
|
+
): GateDecisionArtifact | null {
|
|
135
|
+
return (
|
|
136
|
+
decisions
|
|
137
|
+
.filter((decision) => decision.subjects.some((subject) => subject.runId === runId))
|
|
138
|
+
.sort(
|
|
139
|
+
(left, right) =>
|
|
140
|
+
compareStrings(left.createdAt, right.createdAt) || left.cycle - right.cycle || compareStrings(left.id, right.id),
|
|
141
|
+
)
|
|
142
|
+
.at(-1) ?? null
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
interface EvidenceFinishContractProjection {
|
|
147
|
+
sourceId: string;
|
|
148
|
+
assessment: FinishContractAssessment;
|
|
149
|
+
artifacts: TrustArtifactReference[];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function latestFinishContractForRun(
|
|
153
|
+
rows: ReadonlyArray<EvidenceAuditLinkedRow>,
|
|
154
|
+
runId: string,
|
|
155
|
+
): EvidenceFinishContractProjection | null {
|
|
156
|
+
const candidates = rows
|
|
157
|
+
.filter((row) => row.auditKind === "completion_contract" && row.runId === runId && row.confidence === "exact")
|
|
158
|
+
.flatMap((row) => {
|
|
159
|
+
const assessment = finishContractAssessmentFromAudit(row.row);
|
|
160
|
+
if (assessment === null) return [];
|
|
161
|
+
const correlationId = readOptionalString(row.row.correlationId) ?? `${runId}:completion-contract`;
|
|
162
|
+
// A malformed row is dropped from the trust projection rather than
|
|
163
|
+
// thrown out of the whole forensic build. `readAuditRows` already
|
|
164
|
+
// reports the malformed line, so the bundle stays honest about it.
|
|
165
|
+
if (!isTrustStatusIdentifier(correlationId)) return [];
|
|
166
|
+
const turnId = readOptionalString(row.row.turnId);
|
|
167
|
+
const artifacts: TrustArtifactReference[] = [
|
|
168
|
+
{ kind: "finish_contract_evidence", id: correlationId },
|
|
169
|
+
...(turnId === null || !isTrustStatusIdentifier(turnId) ? [] : [{ kind: "session_entry" as const, id: turnId }]),
|
|
170
|
+
];
|
|
171
|
+
return [{ sourceId: correlationId, assessment, artifacts, timestamp: row.ts ?? "" }];
|
|
172
|
+
})
|
|
173
|
+
.sort(
|
|
174
|
+
(left, right) => compareStrings(left.timestamp, right.timestamp) || compareStrings(left.sourceId, right.sourceId),
|
|
175
|
+
);
|
|
176
|
+
const latest = candidates.at(-1);
|
|
177
|
+
return latest === undefined
|
|
178
|
+
? null
|
|
179
|
+
: { sourceId: latest.sourceId, assessment: latest.assessment, artifacts: latest.artifacts };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function finishContractAssessmentFromAudit(row: Record<string, unknown>): FinishContractAssessment | null {
|
|
183
|
+
const reason = readOptionalString(row.reason);
|
|
184
|
+
const decision = readOptionalString(row.decision);
|
|
185
|
+
const mutatedPaths = Array.isArray(row.mutatedPaths)
|
|
186
|
+
? row.mutatedPaths.filter((entry): entry is string => typeof entry === "string")
|
|
187
|
+
: [];
|
|
188
|
+
const turnId = readOptionalString(row.turnId);
|
|
189
|
+
const evidenceKinds = Array.isArray(row.evidenceKinds) ? row.evidenceKinds.filter(isFinishContractEvidenceKind) : [];
|
|
190
|
+
const evidence = evidenceKinds.map((kind) => ({
|
|
191
|
+
kind,
|
|
192
|
+
summary: "recorded by the finish contract",
|
|
193
|
+
...(turnId === null ? {} : { turnId }),
|
|
194
|
+
}));
|
|
195
|
+
if (decision === "ok" && reason === "no_mutation") {
|
|
196
|
+
return { kind: "ok", reason, evidence: [], mutatedPaths };
|
|
197
|
+
}
|
|
198
|
+
if (decision === "ok" && reason === "validation_evidence") {
|
|
199
|
+
return { kind: "ok", reason, evidence, mutatedPaths };
|
|
200
|
+
}
|
|
201
|
+
if (decision === "ok" && reason === "explicit_limitation") {
|
|
202
|
+
return { kind: "ok", reason, evidence: [], mutatedPaths };
|
|
203
|
+
}
|
|
204
|
+
if (decision === "engage" && reason === "unvalidated_mutation") {
|
|
205
|
+
return { kind: "engage", reason, message: "finish contract engaged", evidence: [], mutatedPaths };
|
|
206
|
+
}
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function isFinishContractEvidenceKind(value: unknown): value is FinishContractEvidenceKind {
|
|
211
|
+
return value === "validation_command" || value === "protected_artifact" || value === "dispatch_receipt";
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* A blank or whitespace-only optional field is absent, not an identifier. The
|
|
216
|
+
* `??` fallbacks below depend on it, and an empty string would otherwise reach
|
|
217
|
+
* `normalizeArtifactReference` and abort the entire bundle.
|
|
218
|
+
*/
|
|
219
|
+
function readOptionalString(value: unknown): string | null {
|
|
220
|
+
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
|
221
|
+
}
|
|
@@ -2,8 +2,16 @@ import { readdir, readFile } from "node:fs/promises";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { assertSafeId } from "../../core/safe-id.js";
|
|
4
4
|
import { type GateDecisionArtifact, verifyGateDecisionArtifact } from "../dispatch/index.js";
|
|
5
|
+
import { compareCodepoints as compareStrings } from "./ordering.js";
|
|
5
6
|
import { hasRunProvenance, type RunProvenanceView, runProvenanceFromUnknown } from "./provenance.js";
|
|
6
|
-
import
|
|
7
|
+
import { normalizeTrustStatus } from "./trust-status.js";
|
|
8
|
+
import type {
|
|
9
|
+
EvidenceFinding,
|
|
10
|
+
EvidenceFindingsFile,
|
|
11
|
+
EvidenceInspectable,
|
|
12
|
+
EvidenceOverview,
|
|
13
|
+
EvidenceTrustStatusView,
|
|
14
|
+
} from "./types.js";
|
|
7
15
|
|
|
8
16
|
export const EVIDENCE_FILES = [
|
|
9
17
|
"overview.json",
|
|
@@ -14,6 +22,7 @@ export const EVIDENCE_FILES = [
|
|
|
14
22
|
"audit-linked.jsonl",
|
|
15
23
|
"receipt.json",
|
|
16
24
|
"gate-decisions.json",
|
|
25
|
+
"trust-status.json",
|
|
17
26
|
"protected-artifacts.json",
|
|
18
27
|
"findings.json",
|
|
19
28
|
"findings.md",
|
|
@@ -69,7 +78,42 @@ export async function inspectEvidence(dataDir: string, evidenceId: string): Prom
|
|
|
69
78
|
}
|
|
70
79
|
const findingsParsed = parseJson(findingsRaw, `${evidenceId}/findings.json`);
|
|
71
80
|
const findings = parseFindingsFile(findingsParsed, `${evidenceId}/findings.json`);
|
|
72
|
-
return { overview, findings };
|
|
81
|
+
return { overview, findings, trustStatus: await loadEvidenceTrustStatus(dataDir, evidenceId) };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Load a canonical projection, or make the missing historical boundary explicit. */
|
|
85
|
+
export async function loadEvidenceTrustStatus(dataDir: string, evidenceId: string): Promise<EvidenceTrustStatusView> {
|
|
86
|
+
let raw: string;
|
|
87
|
+
try {
|
|
88
|
+
raw = await readFile(join(evidenceDirectory(dataDir, evidenceId), "trust-status.json"), "utf8");
|
|
89
|
+
} catch (error) {
|
|
90
|
+
if (isMissingFile(error)) {
|
|
91
|
+
return { version: 1, evidenceId, projection: "historical_format", runs: [] };
|
|
92
|
+
}
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
const source = `${evidenceId}/trust-status.json`;
|
|
96
|
+
const parsed = parseJson(raw, source);
|
|
97
|
+
if (!isRecord(parsed)) throw new Error(`${source}: expected object`);
|
|
98
|
+
if (parsed.version !== 1) throw new Error(`${source}: expected version 1`);
|
|
99
|
+
if (readString(parsed, source, "evidenceId") !== evidenceId) {
|
|
100
|
+
throw new Error(`${source}.evidenceId: expected ${evidenceId}`);
|
|
101
|
+
}
|
|
102
|
+
if (parsed.projection !== "canonical") throw new Error(`${source}.projection: expected canonical`);
|
|
103
|
+
if (!Array.isArray(parsed.runs)) throw new Error(`${source}.runs: expected array`);
|
|
104
|
+
return {
|
|
105
|
+
version: 1,
|
|
106
|
+
evidenceId,
|
|
107
|
+
projection: "canonical",
|
|
108
|
+
runs: parsed.runs.map((entry, index) => {
|
|
109
|
+
const entrySource = `${source}.runs[${index}]`;
|
|
110
|
+
if (!isRecord(entry)) throw new Error(`${entrySource}: expected object`);
|
|
111
|
+
return {
|
|
112
|
+
runId: readString(entry, entrySource, "runId"),
|
|
113
|
+
status: normalizeTrustStatus(entry.status),
|
|
114
|
+
};
|
|
115
|
+
}),
|
|
116
|
+
};
|
|
73
117
|
}
|
|
74
118
|
|
|
75
119
|
/** A bundle run whose receipt carries at least one provenance field set. */
|
|
@@ -282,10 +326,6 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
282
326
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
283
327
|
}
|
|
284
328
|
|
|
285
|
-
function compareStrings(a: string, b: string): number {
|
|
286
|
-
return a.localeCompare(b);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
329
|
export function findingsFile(evidenceId: string, findings: EvidenceFinding[]): EvidenceFindingsFile {
|
|
290
330
|
return { version: 1, evidenceId, findings };
|
|
291
331
|
}
|