@iowarp/clio-coder 0.3.3 → 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 +39 -0
- package/CONTRIBUTING.md +1 -1
- package/README.md +3 -3
- package/dist/{acp-P2AQILE2.js → acp-S5R4RR5B.js} +7 -6
- package/dist/{agents-72W3BI7I.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-2DJ2KNFG.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-4XUGQOHA.js → chunk-35MKKU5R.js} +4 -4
- package/dist/{chunk-LM5TQCJZ.js → chunk-3HZ5RWN2.js} +5 -5
- package/dist/{chunk-AGYYIBLL.js → chunk-3JLKSKD7.js} +2 -2
- package/dist/{chunk-KZWTDYJF.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-X6IAEBZR.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-V6RTAOC2.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-DUYJ5IO6.js → chunk-EDRHSCIE.js} +4 -4
- package/dist/{chunk-XBXAASKX.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-FNTMWMX5.js → chunk-HV5X7OR2.js} +14 -12
- package/dist/{chunk-TZTZS7QK.js → chunk-HXG4IURW.js} +5 -3
- package/dist/{chunk-5UFT4SUX.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-OC7FIQPC.js → chunk-KRPY7NTG.js} +10 -7
- package/dist/chunk-LL4KHSZI.js +22 -0
- package/dist/{chunk-DSELYM6W.js → chunk-MEQ45TQ4.js} +15 -9
- package/dist/{chunk-5UUP6MWO.js → chunk-MV3K5QF2.js} +5 -436
- package/dist/{chunk-6SGHMWE3.js → chunk-N4CZJQRK.js} +5 -5
- package/dist/{chunk-TZK7PACC.js → chunk-NILBFAPG.js} +14 -8
- package/dist/chunk-OZNBF4L3.js +23 -0
- package/dist/{verify-375KUB3Y.js → chunk-PCZJO5TI.js} +127 -42
- package/dist/chunk-QQK64KLB.js +1360 -0
- package/dist/{chunk-SRDMMSEP.js → chunk-QQL5RT5M.js} +979 -1619
- package/dist/{chunk-LZSJBIVT.js → chunk-QWU7ZBO7.js} +70 -720
- package/dist/{chunk-2TLUCQVG.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-PIWWS5BL.js → chunk-UZHIZC5S.js} +7 -7
- package/dist/{chunk-UFIIWP2H.js → chunk-VAWWTKDP.js} +8 -8
- package/dist/{chunk-COU2UHX6.js → chunk-VEZEGCGW.js} +170 -2
- package/dist/{chunk-LW6DSM3M.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-PAJK6MAQ.js → chunk-X6COSD2O.js} +5 -5
- package/dist/chunk-ZGVHUX3M.js +66 -0
- package/dist/{chunk-LWLEKMDQ.js → chunk-ZYKPLLNQ.js} +510 -547
- package/dist/cli/index.js +27 -23
- package/dist/{clio-JOU4FXVA.js → clio-J5JIOIDS.js} +7 -6
- package/dist/{code-nav-7AX6FYE6.js → code-nav-AXCXSBHX.js} +5 -3
- package/dist/{config-XCDVKR23.js → config-OEBMIN2U.js} +37 -27
- package/dist/{configure-4GAP54ZW.js → configure-PUQOSIXQ.js} +16 -13
- package/dist/{context-5VKGUVJJ.js → context-EKDCKUUZ.js} +82 -7
- package/dist/{context-4UOGGLQ5.js → context-MGSE4Z2T.js} +33 -23
- package/dist/{context-77FM5DV5.js → context-URSXPBCK.js} +17 -9
- package/dist/{context-clear-XXJRLCJJ.js → context-clear-KDAJRNUK.js} +33 -23
- package/dist/context-working-set-SBKMPPI2.js +1552 -0
- package/dist/{dispatch-runner-QPRDDBDX.js → dispatch-runner-MSWN72NK.js} +43 -29
- package/dist/{doctor-HR46URBJ.js → doctor-7BSE27PJ.js} +10 -10
- package/dist/{eval-XSSNATB4.js → eval-IZGDOO4H.js} +9 -8
- package/dist/{evidence-6HG2PY2B.js → evidence-SR7WXB5B.js} +51 -23
- package/dist/{evolve-K7YU3NCY.js → evolve-K7VE2CBX.js} +30 -20
- package/dist/{fleet-VY3HHKN6.js → fleet-7XMJNQNF.js} +48 -38
- package/dist/{fleet-preflight-DDN536IT.js → fleet-preflight-AQNAH644.js} +3 -3
- package/dist/{init-JYGXI3FK.js → init-JGNPAYXT.js} +41 -31
- package/dist/{memory-WFZMGYHX.js → memory-4ALKDJ4Q.js} +32 -22
- package/dist/{models-I5QWSEOM.js → models-ZMMLFJNN.js} +22 -19
- package/dist/{monitor-GE4ID3IA.js → monitor-2F3T5KHP.js} +55 -43
- package/dist/{orchestrator-EM5MC3HM.js → orchestrator-ORHT43JB.js} +572 -388
- package/dist/{reset-L2FQEE3E.js → reset-NXGTYNUO.js} +4 -3
- package/dist/{run-ZU3QMZPZ.js → run-RF4WJGMT.js} +51 -41
- package/dist/{share-S5BZQC5I.js → share-UT3W6E4M.js} +5 -4
- package/dist/{skills-X5VXCRNQ.js → skills-PSACKC5Q.js} +2 -2
- package/dist/{skills-eval-WKIHWTHR.js → skills-eval-WJSI55RZ.js} +34 -24
- package/dist/{targets-SNCPI2NR.js → targets-PIIRAOYS.js} +23 -20
- package/dist/{terminal-lease-BNAHVHBS.js → terminal-lease-ULWXWNVY.js} +4 -3
- package/dist/{upgrade-JQHHPQ4K.js → upgrade-346TZ6AV.js} +18 -17
- package/dist/{usage-OR4O5SMZ.js → usage-6KKXR32N.js} +34 -24
- package/dist/verifiers-4UUM6TEE.js +1214 -0
- package/dist/verify-X5HDROLA.js +25 -0
- package/dist/{wiki-generate-UEXP2ARI.js → wiki-generate-7STOCIFZ.js} +42 -31
- package/dist/worker/entry.js +33 -24
- package/docs/README.md +7 -6
- 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 +2 -2
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +7 -9
- package/docs/observability.md +4 -4
- 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 +31 -31
- 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 +1 -1
- 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/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/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 +17 -1
- package/src/interactive/chat-renderer.ts +30 -21
- 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/interactive-slash-runtime.ts +37 -1
- 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/renderers/tool-execution.ts +18 -2
- package/src/interactive/session-transcript.ts +2 -2
- package/src/interactive/slash-commands.ts +29 -2
- 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 +11 -5
- 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/registry.ts +59 -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-J7CWMCQD.js +0 -255
- package/dist/chunk-T6YILFSB.js +0 -80
- package/dist/chunk-VAKQQHWR.js +0 -434
- package/dist/chunk-VPAYEGVX.js +0 -184
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { rawDurationMs } from "../../core/timers.js";
|
|
4
|
-
import { isVerificationScriptName } from "../../core/verification-scripts.js";
|
|
4
|
+
import { isProjectVerifierCheckId, isVerificationScriptName } from "../../core/verification-scripts.js";
|
|
5
5
|
import type {
|
|
6
6
|
RunEnvelope,
|
|
7
7
|
RunKind,
|
|
@@ -10,12 +10,7 @@ import type {
|
|
|
10
10
|
RunStatus,
|
|
11
11
|
ToolCallStat,
|
|
12
12
|
} from "../dispatch/index.js";
|
|
13
|
-
import {
|
|
14
|
-
type ExecutionRole,
|
|
15
|
-
isExecutionRole,
|
|
16
|
-
readGateDecisionArtifactsForRunIds,
|
|
17
|
-
verifyReceiptIntegrity,
|
|
18
|
-
} from "../dispatch/index.js";
|
|
13
|
+
import { type ExecutionRole, isExecutionRole, readGateDecisionArtifactsForRunIds } from "../dispatch/index.js";
|
|
19
14
|
import { detectValidationCommand } from "../safety/protected-artifacts.js";
|
|
20
15
|
import {
|
|
21
16
|
type AuditJsonRow,
|
|
@@ -29,9 +24,13 @@ import {
|
|
|
29
24
|
type SessionEntry,
|
|
30
25
|
} from "../session/index.js";
|
|
31
26
|
import { attributeEvidenceFailure } from "./failure-attribution.js";
|
|
27
|
+
import { compareCodepoints as compareStrings } from "./ordering.js";
|
|
32
28
|
import { extractRunProvenance, provenanceTranscriptLines } from "./provenance.js";
|
|
33
29
|
import { createRedactionTally, redactSecretsDeep, redactSecretsText } from "./redact.js";
|
|
30
|
+
import { buildEvidenceTrustStatusFile } from "./run-trust.js";
|
|
34
31
|
import { EVIDENCE_FILES, evidenceDirectory, findingsFile } from "./store.js";
|
|
32
|
+
import type { TrustArtifactReference } from "./trust-status.js";
|
|
33
|
+
import { inspectRunReceiptTrustStatus } from "./trust-status.js";
|
|
35
34
|
import {
|
|
36
35
|
EVIDENCE_VERSION,
|
|
37
36
|
type EvidenceAuditLinkedRow,
|
|
@@ -48,6 +47,7 @@ import {
|
|
|
48
47
|
type EvidenceRunSource,
|
|
49
48
|
type EvidenceTag,
|
|
50
49
|
type EvidenceToolEvent,
|
|
50
|
+
type EvidenceTrustStatusFile,
|
|
51
51
|
} from "./types.js";
|
|
52
52
|
|
|
53
53
|
const MAX_TASK_CHARS = 500;
|
|
@@ -153,7 +153,15 @@ export async function buildEvidence(options: BuildEvidenceOptions): Promise<Evid
|
|
|
153
153
|
const auditLinks = await linkAuditRows(options.stateDir, source, runSources, sessionLinks);
|
|
154
154
|
const toolEventRows = toolEvents(runSources, sessionLinks, auditLinks);
|
|
155
155
|
const protectedArtifactsRaw = protectedArtifactsFile(sessionLinks);
|
|
156
|
-
const
|
|
156
|
+
const validationEvidence = validationEvidenceByRun(sessionLinks.entries, runSources);
|
|
157
|
+
const trustStatusRaw = buildEvidenceTrustStatusFile({
|
|
158
|
+
evidenceId,
|
|
159
|
+
runSources,
|
|
160
|
+
gateDecisions: gateDecisions.decisions,
|
|
161
|
+
auditRows: auditLinks.rows,
|
|
162
|
+
validationEvidence,
|
|
163
|
+
});
|
|
164
|
+
const findings = buildFindings(runSources, trustStatusRaw, sessionLinks, auditLinks, protectedArtifactsRaw);
|
|
157
165
|
// Export-boundary redaction (cold path): secret-shaped values are scrubbed
|
|
158
166
|
// from everything the bundle serializes: envelopes, receipts (including
|
|
159
167
|
// delegation toolCallLog arguments), tool-event previews, audit rows,
|
|
@@ -176,6 +184,7 @@ export async function buildEvidence(options: BuildEvidenceOptions): Promise<Evid
|
|
|
176
184
|
readErrors: auditLinks.readErrors,
|
|
177
185
|
};
|
|
178
186
|
const protectedArtifacts = redactSecretsDeep(protectedArtifactsRaw, tally);
|
|
187
|
+
const trustStatus = redactSecretsDeep(trustStatusRaw, tally);
|
|
179
188
|
const overview = buildOverview(
|
|
180
189
|
evidenceId,
|
|
181
190
|
source,
|
|
@@ -197,10 +206,11 @@ export async function buildEvidence(options: BuildEvidenceOptions): Promise<Evid
|
|
|
197
206
|
redactedAuditLinks,
|
|
198
207
|
redactedToolEvents,
|
|
199
208
|
gateDecisions,
|
|
209
|
+
trustStatus,
|
|
200
210
|
protectedArtifacts,
|
|
201
211
|
transcript,
|
|
202
212
|
);
|
|
203
|
-
return { evidenceId, directory, overview: finalOverview, findings };
|
|
213
|
+
return { evidenceId, directory, overview: finalOverview, findings, trustStatus };
|
|
204
214
|
}
|
|
205
215
|
|
|
206
216
|
function buildOverview(
|
|
@@ -264,18 +274,24 @@ function buildOverview(
|
|
|
264
274
|
|
|
265
275
|
function buildFindings(
|
|
266
276
|
runSources: ReadonlyArray<EvidenceRunSource>,
|
|
277
|
+
trustStatus: EvidenceTrustStatusFile,
|
|
267
278
|
sessionLinks: SessionLinkResult,
|
|
268
279
|
auditLinks: AuditLinkResult,
|
|
269
280
|
protectedArtifacts: EvidenceProtectedArtifactsFile,
|
|
270
281
|
): EvidenceFinding[] {
|
|
271
282
|
const findings: EvidenceFinding[] = [];
|
|
272
|
-
const
|
|
283
|
+
const trustByRun = new Map(trustStatus.runs.map((entry) => [entry.runId, entry.status]));
|
|
273
284
|
for (const source of runSources) {
|
|
285
|
+
const status = trustByRun.get(source.envelope.id);
|
|
286
|
+
if (status === undefined) throw new Error(`canonical trust status missing for run ${source.envelope.id}`);
|
|
274
287
|
if (source.receiptError !== null) {
|
|
275
288
|
const tag = source.receiptIntegrityFailed ? "receipt-integrity" : "unknown";
|
|
276
289
|
findings.push(finding(findings.length, "warn", tag, source.envelope.id, source.receiptError));
|
|
277
290
|
}
|
|
278
|
-
if (
|
|
291
|
+
if (
|
|
292
|
+
isSuccessfulRun(source) &&
|
|
293
|
+
(status.validationGrounding.state === "absent" || status.validationGrounding.state === "unknown")
|
|
294
|
+
) {
|
|
279
295
|
findings.push(
|
|
280
296
|
finding(
|
|
281
297
|
findings.length,
|
|
@@ -286,10 +302,21 @@ function buildFindings(
|
|
|
286
302
|
),
|
|
287
303
|
);
|
|
288
304
|
}
|
|
305
|
+
if (status.validationGrounding.state === "ungrounded") {
|
|
306
|
+
findings.push(
|
|
307
|
+
finding(
|
|
308
|
+
findings.length,
|
|
309
|
+
"warn",
|
|
310
|
+
"proxy-validation",
|
|
311
|
+
source.envelope.id,
|
|
312
|
+
"run claimed validation that was not grounded in an observed execution",
|
|
313
|
+
),
|
|
314
|
+
);
|
|
315
|
+
}
|
|
289
316
|
if (source.envelope.cwd.trim().length === 0) {
|
|
290
317
|
findings.push(finding(findings.length, "warn", "cwd-missing", source.envelope.id, "run ledger cwd is empty"));
|
|
291
318
|
}
|
|
292
|
-
const receipt = source
|
|
319
|
+
const receipt = authenticatedReceipt(source);
|
|
293
320
|
const blocked = receipt?.toolStats.reduce((total, stat) => total + stat.blocked, 0) ?? 0;
|
|
294
321
|
if (blocked > 0) {
|
|
295
322
|
findings.push(
|
|
@@ -311,15 +338,17 @@ function buildFindings(
|
|
|
311
338
|
),
|
|
312
339
|
);
|
|
313
340
|
}
|
|
314
|
-
|
|
315
|
-
if (autonomyEnforcement?.dangerousBypass === true) {
|
|
341
|
+
if (status.autonomyEnforcement.state === "bypassed") {
|
|
316
342
|
const message =
|
|
317
|
-
autonomyEnforcement.
|
|
343
|
+
status.autonomyEnforcement.authority.id === "agent-managed"
|
|
318
344
|
? "run used external agent-managed governance; Clio safety blocks were not enforced"
|
|
319
345
|
: "run executed with external permission bypass (CLIO_CODER_ALLOW_EXTERNAL_FULL_ACCESS=1); Clio safety blocks were not enforced";
|
|
320
346
|
findings.push(finding(findings.length, "warn", "external-bypass", source.envelope.id, message));
|
|
321
|
-
} else if (autonomyEnforcement
|
|
322
|
-
const mode =
|
|
347
|
+
} else if (status.autonomyEnforcement.state === "approximated") {
|
|
348
|
+
const mode =
|
|
349
|
+
status.autonomyEnforcement.authority.id === "external-runtime"
|
|
350
|
+
? ""
|
|
351
|
+
: ` via ${status.autonomyEnforcement.authority.id}`;
|
|
323
352
|
findings.push(
|
|
324
353
|
finding(
|
|
325
354
|
findings.length,
|
|
@@ -410,25 +439,28 @@ function buildFindings(
|
|
|
410
439
|
interface ValidationToolCallCandidate {
|
|
411
440
|
toolCallId: string;
|
|
412
441
|
runId: string | null;
|
|
442
|
+
artifact: TrustArtifactReference;
|
|
413
443
|
}
|
|
414
444
|
|
|
415
|
-
function
|
|
445
|
+
function validationEvidenceByRun(
|
|
416
446
|
entries: ReadonlyArray<LinkedSessionEntry>,
|
|
417
447
|
runSources: ReadonlyArray<EvidenceRunSource>,
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const runIds = new Set<string>();
|
|
421
|
-
const sourceRunIds = new Set(runSources.map((source) => source.envelope.id));
|
|
448
|
+
): Map<string, TrustArtifactReference[]> {
|
|
449
|
+
const evidence = new Map<string, TrustArtifactReference[]>();
|
|
422
450
|
const calls = new Map<string, ValidationToolCallCandidate>();
|
|
423
451
|
for (const linked of entries) {
|
|
424
452
|
const runId = validationRunIdFor(linked, runSources);
|
|
425
453
|
const entry = linked.entry;
|
|
426
454
|
if (entry.kind === "bashExecution") {
|
|
427
|
-
if (runId !== null && isSuccessfulValidationBashExecution(entry))
|
|
455
|
+
if (runId !== null && isSuccessfulValidationBashExecution(entry)) {
|
|
456
|
+
addValidationEvidence(evidence, runId, { kind: "session_entry", id: entry.turnId });
|
|
457
|
+
}
|
|
428
458
|
continue;
|
|
429
459
|
}
|
|
430
460
|
if (entry.kind === "protectedArtifact") {
|
|
431
|
-
if (runId !== null && isValidationProtectedArtifact(entry))
|
|
461
|
+
if (runId !== null && isValidationProtectedArtifact(entry)) {
|
|
462
|
+
addValidationEvidence(evidence, runId, { kind: "session_entry", id: entry.turnId });
|
|
463
|
+
}
|
|
432
464
|
continue;
|
|
433
465
|
}
|
|
434
466
|
if (entry.kind !== "message") continue;
|
|
@@ -441,16 +473,21 @@ function validationEvidenceRunIds(
|
|
|
441
473
|
const result = extractSessionToolResult(entry, linked);
|
|
442
474
|
if (result.id === null || !isSuccessfulSessionToolResult(result)) continue;
|
|
443
475
|
const candidate = calls.get(result.id);
|
|
444
|
-
if (candidate?.runId !== null && candidate?.runId !== undefined)
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
if (linked.auditKind !== "completion_contract") continue;
|
|
448
|
-
if (linked.runId === null || !sourceRunIds.has(linked.runId)) continue;
|
|
449
|
-
if (readOptionalString(linked.row.decision) !== "ok") continue;
|
|
450
|
-
if (readOptionalString(linked.row.reason) !== "validation_evidence") continue;
|
|
451
|
-
runIds.add(linked.runId);
|
|
476
|
+
if (candidate?.runId !== null && candidate?.runId !== undefined) {
|
|
477
|
+
addValidationEvidence(evidence, candidate.runId, candidate.artifact);
|
|
478
|
+
}
|
|
452
479
|
}
|
|
453
|
-
return
|
|
480
|
+
return evidence;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function addValidationEvidence(
|
|
484
|
+
evidence: Map<string, TrustArtifactReference[]>,
|
|
485
|
+
runId: string,
|
|
486
|
+
reference: TrustArtifactReference,
|
|
487
|
+
): void {
|
|
488
|
+
const current = evidence.get(runId) ?? [];
|
|
489
|
+
current.push(reference);
|
|
490
|
+
evidence.set(runId, current);
|
|
454
491
|
}
|
|
455
492
|
|
|
456
493
|
function validationRunIdFor(linked: LinkedSessionEntry, runSources: ReadonlyArray<EvidenceRunSource>): string | null {
|
|
@@ -463,12 +500,19 @@ function validationRunIdFor(linked: LinkedSessionEntry, runSources: ReadonlyArra
|
|
|
463
500
|
}
|
|
464
501
|
|
|
465
502
|
function isSuccessfulRun(source: EvidenceRunSource): boolean {
|
|
466
|
-
const
|
|
503
|
+
const receipt = authenticatedReceipt(source);
|
|
504
|
+
const outcome = receipt?.outcome ?? source.envelope.outcome ?? null;
|
|
467
505
|
if (outcome !== null) return outcome === "succeeded";
|
|
468
|
-
const exitCode =
|
|
506
|
+
const exitCode = receipt?.exitCode ?? source.envelope.exitCode;
|
|
469
507
|
return source.envelope.status === "completed" && exitCode === 0;
|
|
470
508
|
}
|
|
471
509
|
|
|
510
|
+
function authenticatedReceipt(source: EvidenceRunSource): RunReceipt | null {
|
|
511
|
+
return source.receipt !== null && source.receiptError === null && !source.receiptIntegrityFailed
|
|
512
|
+
? source.receipt
|
|
513
|
+
: null;
|
|
514
|
+
}
|
|
515
|
+
|
|
472
516
|
function isSuccessfulValidationBashExecution(entry: BashExecutionEntry): boolean {
|
|
473
517
|
if (entry.cancelled || entry.exitCode !== 0) return false;
|
|
474
518
|
return detectValidationCommand(entry.command).kind === "validation";
|
|
@@ -490,6 +534,7 @@ function validationToolCallCandidate(
|
|
|
490
534
|
return {
|
|
491
535
|
toolCallId: call.id,
|
|
492
536
|
runId: validationRunIdFor(linked, runSources),
|
|
537
|
+
artifact: { kind: "session_entry", id: entry.turnId },
|
|
493
538
|
};
|
|
494
539
|
}
|
|
495
540
|
|
|
@@ -508,8 +553,10 @@ function validationToolCallSummary(toolName: string, args: unknown): string | nu
|
|
|
508
553
|
const target = readOptionalString(argRecord?.path) ?? "artifact";
|
|
509
554
|
return `verify frontend ${target}`;
|
|
510
555
|
}
|
|
511
|
-
if (check === null
|
|
512
|
-
return `npm run ${check}`;
|
|
556
|
+
if (check === null) return null;
|
|
557
|
+
if (isVerificationScriptName(check)) return `npm run ${check}`;
|
|
558
|
+
if (isProjectVerifierCheckId(check)) return `verify ${check}`;
|
|
559
|
+
return null;
|
|
513
560
|
}
|
|
514
561
|
return null;
|
|
515
562
|
}
|
|
@@ -546,6 +593,7 @@ async function writeEvidenceFiles(
|
|
|
546
593
|
auditLinks: AuditLinkResult,
|
|
547
594
|
toolEventRows: ReadonlyArray<EvidenceToolEvent>,
|
|
548
595
|
gateDecisions: EvidenceGateDecisionsFile,
|
|
596
|
+
trustStatus: EvidenceTrustStatusFile,
|
|
549
597
|
protectedArtifacts: EvidenceProtectedArtifactsFile,
|
|
550
598
|
transcript?: string,
|
|
551
599
|
): Promise<void> {
|
|
@@ -562,6 +610,7 @@ async function writeEvidenceFiles(
|
|
|
562
610
|
await writeJsonl(join(directory, "audit-linked.jsonl"), auditLinks.rows);
|
|
563
611
|
await writeJson(join(directory, "receipt.json"), receiptsFile(runSources));
|
|
564
612
|
await writeJson(join(directory, "gate-decisions.json"), gateDecisions);
|
|
613
|
+
await writeJson(join(directory, "trust-status.json"), trustStatus);
|
|
565
614
|
await writeJson(join(directory, "protected-artifacts.json"), protectedArtifacts);
|
|
566
615
|
await writeJson(join(directory, "findings.json"), findingsFile(overview.evidenceId, [...findings]));
|
|
567
616
|
await writeFile(join(directory, "findings.md"), renderFindings(findings), "utf8");
|
|
@@ -1151,7 +1200,7 @@ function compareAuditLinkedRows(a: EvidenceAuditLinkedRow, b: EvidenceAuditLinke
|
|
|
1151
1200
|
const aCorrelation = readOptionalString(a.row.correlationId) ?? "";
|
|
1152
1201
|
const bCorrelation = readOptionalString(b.row.correlationId) ?? "";
|
|
1153
1202
|
if (aCorrelation !== bCorrelation) return compareStrings(aCorrelation, bCorrelation);
|
|
1154
|
-
return JSON.stringify(a.row)
|
|
1203
|
+
return compareStrings(JSON.stringify(a.row), JSON.stringify(b.row));
|
|
1155
1204
|
}
|
|
1156
1205
|
|
|
1157
1206
|
function receiptsFile(runSources: ReadonlyArray<EvidenceRunSource>): EvidenceReceiptFile {
|
|
@@ -1372,6 +1421,19 @@ function renderSessionTranscriptEntry(linked: LinkedSessionEntry): string[] {
|
|
|
1372
1421
|
];
|
|
1373
1422
|
}
|
|
1374
1423
|
if (entry.kind === "custom") return [`${prefix} custom:${entry.customType} ${previewUnknown(entry.data)}`];
|
|
1424
|
+
if (entry.kind === "contextEviction") {
|
|
1425
|
+
const pressure = entry.pressureBefore === null ? "" : ` pressure=${entry.pressureBefore.toFixed(3)}`;
|
|
1426
|
+
return [
|
|
1427
|
+
`${prefix} contextEviction policy=${entry.policyId} trigger=${entry.trigger} items=${entry.evicted.length} tokens=${entry.tokensBefore}->${entry.tokensAfter}${pressure}`,
|
|
1428
|
+
...entry.evicted.map(
|
|
1429
|
+
(item) =>
|
|
1430
|
+
` evicted ref=${item.ref.entry} reason=${item.reason}${item.by === undefined ? "" : ` by=${item.by}`} freed=${item.tokensFreed}`,
|
|
1431
|
+
),
|
|
1432
|
+
];
|
|
1433
|
+
}
|
|
1434
|
+
if (entry.kind === "contextRecall") {
|
|
1435
|
+
return [`${prefix} contextRecall ref=${entry.ref.entry} trigger=${entry.trigger} tokens=${entry.tokensReadmitted}`];
|
|
1436
|
+
}
|
|
1375
1437
|
const _exhaustive: never = entry;
|
|
1376
1438
|
return [`${prefix} ${String(_exhaustive)}`];
|
|
1377
1439
|
}
|
|
@@ -1432,9 +1494,18 @@ async function readReceipt(
|
|
|
1432
1494
|
}
|
|
1433
1495
|
return { receipt: null, error: `receipt read error: ${err.message ?? String(err)}`, integrityFailed: false };
|
|
1434
1496
|
}
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1497
|
+
let receipt: RunReceipt;
|
|
1498
|
+
try {
|
|
1499
|
+
const parsed = parseJson(raw, receiptPath);
|
|
1500
|
+
receipt = parseRunReceipt(parsed, receiptPath);
|
|
1501
|
+
} catch (error) {
|
|
1502
|
+
return {
|
|
1503
|
+
receipt: null,
|
|
1504
|
+
error: `receipt invalid: ${error instanceof Error ? error.message : String(error)}`,
|
|
1505
|
+
integrityFailed: true,
|
|
1506
|
+
};
|
|
1507
|
+
}
|
|
1508
|
+
const integrity = inspectRunReceiptTrustStatus(receipt, envelope).integrity;
|
|
1438
1509
|
if (!integrity.ok) {
|
|
1439
1510
|
return { receipt, error: `receipt integrity: ${integrity.reason}`, integrityFailed: true };
|
|
1440
1511
|
}
|
|
@@ -1709,10 +1780,6 @@ function uniqueTags(values: ReadonlyArray<EvidenceTag>): EvidenceTag[] {
|
|
|
1709
1780
|
return [...new Set(values)].sort(compareStrings);
|
|
1710
1781
|
}
|
|
1711
1782
|
|
|
1712
|
-
function compareStrings(a: string, b: string): number {
|
|
1713
|
-
return a.localeCompare(b);
|
|
1714
|
-
}
|
|
1715
|
-
|
|
1716
1783
|
function compareNullableStrings(a: string | null, b: string | null): number {
|
|
1717
1784
|
if (a === b) return 0;
|
|
1718
1785
|
if (a === null) return 1;
|
|
@@ -5,6 +5,8 @@ import { readGateDecisionArtifactsForRunIds } from "../dispatch/index.js";
|
|
|
5
5
|
import { redactArtifactForStorage } from "../eval/artifacts/redact.js";
|
|
6
6
|
import type { EvalCommandResult, EvalRunArtifact, EvalRunRecord } from "../eval/index.js";
|
|
7
7
|
import { loadEvalArtifact } from "../eval/index.js";
|
|
8
|
+
import { compareCodepoints as compareStrings } from "./ordering.js";
|
|
9
|
+
import { buildEvidenceTrustStatusFile } from "./run-trust.js";
|
|
8
10
|
import { evidenceDirectory, findingsFile } from "./store.js";
|
|
9
11
|
import {
|
|
10
12
|
EVIDENCE_VERSION,
|
|
@@ -21,6 +23,7 @@ import {
|
|
|
21
23
|
type EvidenceReceiptFile,
|
|
22
24
|
type EvidenceTag,
|
|
23
25
|
type EvidenceToolEvent,
|
|
26
|
+
type EvidenceTrustStatusFile,
|
|
24
27
|
} from "./types.js";
|
|
25
28
|
|
|
26
29
|
const EVAL_EVIDENCE_FILES = [
|
|
@@ -32,6 +35,7 @@ const EVAL_EVIDENCE_FILES = [
|
|
|
32
35
|
"audit-linked.jsonl",
|
|
33
36
|
"receipt.json",
|
|
34
37
|
"gate-decisions.json",
|
|
38
|
+
"trust-status.json",
|
|
35
39
|
"protected-artifacts.json",
|
|
36
40
|
"eval-result.json",
|
|
37
41
|
"findings.json",
|
|
@@ -87,8 +91,23 @@ export async function buildEvalEvidence(options: BuildEvalEvidenceOptions): Prom
|
|
|
87
91
|
options.stateDir,
|
|
88
92
|
).map((entry) => entry.artifact),
|
|
89
93
|
};
|
|
90
|
-
|
|
91
|
-
|
|
94
|
+
const trustStatus = buildEvidenceTrustStatusFile({
|
|
95
|
+
evidenceId,
|
|
96
|
+
runSources: linkedRuns.runSources,
|
|
97
|
+
gateDecisions: gateDecisions.decisions,
|
|
98
|
+
auditRows: linkedRuns.auditRows,
|
|
99
|
+
});
|
|
100
|
+
await writeEvalEvidenceFiles(
|
|
101
|
+
directory,
|
|
102
|
+
artifact,
|
|
103
|
+
overview,
|
|
104
|
+
findings,
|
|
105
|
+
toolEventRows,
|
|
106
|
+
linkedRuns,
|
|
107
|
+
gateDecisions,
|
|
108
|
+
trustStatus,
|
|
109
|
+
);
|
|
110
|
+
return { evidenceId, directory, overview, findings, trustStatus };
|
|
92
111
|
}
|
|
93
112
|
|
|
94
113
|
export function evalEvidenceId(evalId: string): string {
|
|
@@ -218,6 +237,7 @@ async function writeEvalEvidenceFiles(
|
|
|
218
237
|
toolEventRows: ReadonlyArray<EvidenceToolEvent>,
|
|
219
238
|
linkedRuns: EvalLinkedRuns,
|
|
220
239
|
gateDecisions: EvidenceGateDecisionsFile,
|
|
240
|
+
trustStatus: EvidenceTrustStatusFile,
|
|
221
241
|
): Promise<void> {
|
|
222
242
|
const emptyProtected: EvidenceProtectedArtifactsFile = { version: EVIDENCE_VERSION, artifacts: [], events: [] };
|
|
223
243
|
const receiptsFile: EvidenceReceiptFile = {
|
|
@@ -234,6 +254,7 @@ async function writeEvalEvidenceFiles(
|
|
|
234
254
|
await writeJsonl(join(directory, "audit-linked.jsonl"), linkedRuns.auditRows);
|
|
235
255
|
await writeJson(join(directory, "receipt.json"), receiptsFile);
|
|
236
256
|
await writeJson(join(directory, "gate-decisions.json"), gateDecisions);
|
|
257
|
+
await writeJson(join(directory, "trust-status.json"), trustStatus);
|
|
237
258
|
await writeJson(join(directory, "protected-artifacts.json"), emptyProtected);
|
|
238
259
|
await writeJson(join(directory, "eval-result.json"), redactedArtifact);
|
|
239
260
|
await writeJson(join(directory, "findings.json"), findingsFile(overview.evidenceId, [...findings]));
|
|
@@ -576,7 +597,7 @@ function compareAuditRows(a: EvidenceAuditLinkedRow, b: EvidenceAuditLinkedRow):
|
|
|
576
597
|
return (
|
|
577
598
|
compareNullableStrings(a.ts, b.ts) ||
|
|
578
599
|
compareNullableStrings(a.runId, b.runId) ||
|
|
579
|
-
JSON.stringify(a.row)
|
|
600
|
+
compareStrings(JSON.stringify(a.row), JSON.stringify(b.row))
|
|
580
601
|
);
|
|
581
602
|
}
|
|
582
603
|
|
|
@@ -596,10 +617,6 @@ function sanitizeEvidenceId(value: string): string {
|
|
|
596
617
|
return sanitized.length === 0 ? "unknown" : sanitized;
|
|
597
618
|
}
|
|
598
619
|
|
|
599
|
-
function compareStrings(a: string, b: string): number {
|
|
600
|
-
return a.localeCompare(b);
|
|
601
|
-
}
|
|
602
|
-
|
|
603
620
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
604
621
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
605
622
|
}
|
|
@@ -20,7 +20,56 @@ export {
|
|
|
20
20
|
listEvidenceOverviews,
|
|
21
21
|
loadEvidenceGateDecisions,
|
|
22
22
|
loadEvidenceRunProvenance,
|
|
23
|
+
loadEvidenceTrustStatus,
|
|
23
24
|
} from "./store.js";
|
|
25
|
+
export type {
|
|
26
|
+
AbsentTrustStatus,
|
|
27
|
+
AdaptFinishContractTrustOptions,
|
|
28
|
+
AdaptRunReceiptTrustOptions,
|
|
29
|
+
ArtifactIntegrityStatus,
|
|
30
|
+
AttributedTrustStatus,
|
|
31
|
+
AutonomyEnforcementStatus,
|
|
32
|
+
CanonicalTrustStatus,
|
|
33
|
+
CompletionEvidenceStatus,
|
|
34
|
+
ContextProvenanceStatus,
|
|
35
|
+
GroundedEvidenceValidationInput,
|
|
36
|
+
IndependentReviewStatus,
|
|
37
|
+
PersistedRunReceiptTrustFacts,
|
|
38
|
+
RunReceiptTrustInspection,
|
|
39
|
+
TrustAbsenceReason,
|
|
40
|
+
TrustArtifactKind,
|
|
41
|
+
TrustArtifactReference,
|
|
42
|
+
TrustStatusAuthority,
|
|
43
|
+
TrustStatusAuthorityKind,
|
|
44
|
+
TrustStatusAxes,
|
|
45
|
+
TrustStatusAxis,
|
|
46
|
+
TrustStatusProjection,
|
|
47
|
+
TrustStatusSource,
|
|
48
|
+
TrustStatusSourceKind,
|
|
49
|
+
TrustStatusValidation,
|
|
50
|
+
ValidationGroundingStatus,
|
|
51
|
+
} from "./trust-status.js";
|
|
52
|
+
export {
|
|
53
|
+
absentTrustStatus,
|
|
54
|
+
adaptFinishContractCompletionStatus,
|
|
55
|
+
adaptGateDecisionReviewStatus,
|
|
56
|
+
adaptGroundedEvidenceValidationStatus,
|
|
57
|
+
adaptReceiptIntegrityStatus,
|
|
58
|
+
adaptRunReceiptAutonomyStatus,
|
|
59
|
+
adaptRunReceiptContextStatus,
|
|
60
|
+
adaptRunReceiptTrustStatus,
|
|
61
|
+
adaptRunReceiptValidationStatus,
|
|
62
|
+
composeTrustStatus,
|
|
63
|
+
inspectRunReceiptTrustStatus,
|
|
64
|
+
normalizeTrustStatus,
|
|
65
|
+
projectTrustStatus,
|
|
66
|
+
TRUST_STATUS_AXES,
|
|
67
|
+
TRUST_STATUS_MAX_ARTIFACT_REFERENCES,
|
|
68
|
+
TRUST_STATUS_MAX_IDENTIFIER_LENGTH,
|
|
69
|
+
TRUST_STATUS_STATES,
|
|
70
|
+
TRUST_STATUS_VERSION,
|
|
71
|
+
validateTrustStatus,
|
|
72
|
+
} from "./trust-status.js";
|
|
24
73
|
export type {
|
|
25
74
|
EvidenceAuditLinkedRow,
|
|
26
75
|
EvidenceBuildResult,
|
|
@@ -39,13 +88,17 @@ export type {
|
|
|
39
88
|
EvidenceRawTraceRow,
|
|
40
89
|
EvidenceReceiptFile,
|
|
41
90
|
EvidenceRunSource,
|
|
91
|
+
EvidenceRunTrustStatus,
|
|
42
92
|
EvidenceSeverity,
|
|
43
93
|
EvidenceSource,
|
|
44
94
|
EvidenceTag,
|
|
45
95
|
EvidenceToolEvent,
|
|
46
96
|
EvidenceToolEventSource,
|
|
47
97
|
EvidenceTotals,
|
|
98
|
+
EvidenceTrustStatusFile,
|
|
99
|
+
EvidenceTrustStatusView,
|
|
48
100
|
FailureCauseTag,
|
|
101
|
+
HistoricalEvidenceTrustStatus,
|
|
49
102
|
} from "./types.js";
|
|
50
103
|
export {
|
|
51
104
|
EVIDENCE_TAGS,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ordinal string comparison for determinism-critical orderings.
|
|
3
|
+
*
|
|
4
|
+
* `String.prototype.localeCompare` collates through ICU, so its answer depends
|
|
5
|
+
* on the process locale and the ICU build. Evidence rows, "latest" selectors,
|
|
6
|
+
* and verifier catalogs must order identically on every machine that rebuilds
|
|
7
|
+
* them, so they compare UTF-16 code units instead. That order is the code
|
|
8
|
+
* point order for all BMP text and never reads the environment.
|
|
9
|
+
*/
|
|
10
|
+
export function compareCodepoints(left: string, right: string): number {
|
|
11
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
12
|
+
}
|