Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,17 @@ se-trace visualize examples/legal-summarization.cots.json -o ./out

# Quick conformance check
se-trace validate examples/legal-summarization.cots.json

# Surface the Layer 2 (Runtime Validation) record of a COTS (RFC-0001)
se-trace validate-runtime examples/legal-summarization.cots.json
```

## What is in this repository

- `src/inspect.ts` - the inspect command. Prints a human-readable summary of a COTS.
- `src/cite.ts` - the cite command. Prints the evidence chain for a specific decision.
- `src/visualize.ts` - the visualize command. Renders a COTS as a Mermaid diagram + HTML page.
- `src/cli/se-trace.ts` - the CLI entry point.
- `src/cli/se-trace.ts` - the CLI entry point, including `validate-runtime` (Layer 2 ValidationFlags surfacing, RFC-0001).
- `tests/tools.test.ts` - the test suite.

## SDKs
Expand Down
35 changes: 35 additions & 0 deletions src/cli/se-trace.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/**
* The se-trace CLI. Three subcommands:
* - validate <file> Run the conformance suite against a COTS.
* - validate-runtime <file> Surface the Layer 2 ValidationFlags of a COTS.
* - inspect <file> Print a human-readable summary of a COTS.
* - cite <file> <decision-id> Print the evidence chain for a specific decision.
* - visualize <file> Render a COTS as a Reasoning Roadmap (Mermaid + HTML).
Expand Down Expand Up @@ -68,6 +69,40 @@ program
}
});

program
.command("validate-runtime")
.description("Surface the Layer 2 (Runtime Validation) record of a COTS (RFC-0001, COTS schema v1.1.0)")
.argument("<path>", "Path to a COTS JSON file")
.action((path: string) => {
const cots = loadCots(path);
let withRecord = 0;
let flagged = 0;
for (const decision of cots.decisions) {
const v = decision.validation;
if (v === undefined) {
console.log(`${decision.id}\n No Layer 2 Validation record (the producer has not floored Layer 2).`);
continue;
}
withRecord++;
console.log(`${decision.id}`);
console.log(` decision_on_validation: ${v.decision_on_validation}`);
console.log(` validated_at: ${v.validated_at} by: ${v.validated_by}`);
if (v.flags.length === 0) {
console.log(" flags: none");
} else {
if (v.decision_on_validation !== "passed") flagged++;
for (const flag of v.flags) {
console.log(` [${flag.flag_type}] ${flag.message} (detected ${flag.detected_at})`);
}
}
}
console.log(`\nDecisions with a Validation record: ${withRecord}/${cots.decisions.length}`);
if (flagged > 0) {
console.log(`Flagged decisions: ${flagged} (flags are warnings, not rejections; Layer 3 decides)`);
process.exit(2);
}
});

program
.command("inspect")
.description("Print a human-readable summary of a COTS")
Expand Down
23 changes: 23 additions & 0 deletions src/cots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,27 @@ export interface Constraint {
value: string;
}

export type FlagType =
| "drift-detected"
| "segment-signal-divergence"
| "parameter-set-out-of-range"
| "temporal-validity-expired";

export type DecisionOnValidation = "passed" | "flagged" | "escalated";

export interface ValidationFlag {
flag_type: FlagType;
message: string;
detected_at: ISO8601;
}

export interface Layer2Validation {
flags: ValidationFlag[];
decision_on_validation: DecisionOnValidation;
validated_at: ISO8601;
validated_by: string;
}

export interface DecisionRecord {
id: URI;
decision_text: string;
Expand All @@ -56,6 +77,8 @@ export interface DecisionRecord {
responsible_authority: { authority_id: string; authority_type: string };
audit_history: AuditEntry[];
created_at: ISO8601;
/** Layer 2 Validation record (COTS schema v1.1.0, RFC-0001). Optional. */
validation?: Layer2Validation;
}

export interface AuditEntry {
Expand Down
42 changes: 42 additions & 0 deletions tests/tools.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,45 @@ describe("visualize", () => {
expect(html).toContain("Reasoning Roadmap");
});
});

describe("validate-runtime", () => {
it("reports a Layer 2 Validation record when present", async () => {
const cots = loadFixture("legal-summarization.cots.json");
cots.decisions[0].validation = {
flags: [
{
flag_type: "drift-detected",
message: "Calibration drift detected on segment 'contract-law' (0.14 divergence, threshold 0.10).",
detected_at: "2026-10-11T12:00:00Z",
},
],
decision_on_validation: "flagged",
validated_at: "2026-10-11T12:00:00Z",
validated_by: "layer2-runtime-validation",
};
const { execFileSync } = await import("node:child_process");
const tmp = resolve(__dirname, "..", "examples", "tmp-validate-runtime.cots.json");
const { writeFileSync, rmSync } = await import("node:fs");
writeFileSync(tmp, JSON.stringify(cots));
try {
try {
execFileSync("node", [resolve(__dirname, "..", "dist", "cli", "se-trace.js"), "validate-runtime", tmp], { encoding: "utf-8" });
throw new Error("expected exit code 2 for a flagged decision");
} catch (e) {
const err = e as { stdout?: string; status?: number };
expect(err.status).toBe(2);
const out = err.stdout ?? "";
expect(out).toContain("decision_on_validation: flagged");
expect(out).toContain("[drift-detected]");
expect(out).toContain("Flagged decisions: 1");
}
} finally {
rmSync(tmp, { force: true });
}
});

it("reports the absence of a Validation record without failing", () => {
const cots = loadFixture("legal-summarization.cots.json");
expect(cots.decisions[0].validation).toBeUndefined();
});
});
Loading