core/workbench-ui/src/app/EvidenceChainRail.tsx
Shay 5474a15205 feat(workbench): CORE-Logos Studio LG-4 — Alignment tab + holonomy-absent guard
The trilingual resonance centerpiece, read-only over GET /logos/packs/{id}/alignment:
- deterministic DagViewer (he -> grc -> en longest-path) + selectable edge list;
  alignmentToDag is a pure projection pinned by a golden-file layout test
- invalid alignment targets surfaced honestly (the undeclared en-collapse-*
  anchors render a warning, never smoothed over)
- logos_alignment_edge evidence subject (logos_alignment_edge:<packId>/<edgeId>)
  with RightInspector projection + EvidenceChainRail derivation
- holonomy stays absent: no tab, no proof card, no success element (guard test)

Full workbench-ui vitest: 516 passed, clean exit; build clean.
2026-06-14 12:59:35 -07:00

416 lines
15 KiB
TypeScript

import type { CSSProperties } from "react";
import type { EvidenceSubject } from "./evidenceContext";
/**
* EvidenceChainRail — the spine's seven stages rendered for the selected
* subject (Wave R brief R1):
*
* intent -> subject -> provenance -> admissibility -> replay -> authority -> action
*
* HONESTY CONTRACT: a stage's status derives ONLY from fields the subject
* actually carries. `lit` = the named field holds evidence. `hollow` = the
* stage applies to this subject kind but no evidence is recorded/loaded.
* `dim` = the stage does not apply to this kind. Nothing is ever inferred:
* a recorded trace hash lights "replay" as "trace hash recorded" — it does
* NOT claim replay was verified.
*/
export type StageStatus = "lit" | "hollow" | "dim";
export interface RailStage {
id: string;
label: string;
status: StageStatus;
/** What the status derives from — shown in the tooltip, audit-honest. */
derivation: string;
}
const STAGE_IDS = [
"intent",
"subject",
"provenance",
"admissibility",
"replay",
"authority",
"action",
] as const;
function stage(
id: (typeof STAGE_IDS)[number],
status: StageStatus,
derivation: string,
): RailStage {
return { id, label: id, status, derivation };
}
function evidenceOf(value: unknown): "lit" | "hollow" {
if (value === null || value === undefined || value === "") return "hollow";
return "lit";
}
function evidenceAny(...values: unknown[]): "lit" | "hollow" {
return values.some((value) => evidenceOf(value) === "lit") ? "lit" : "hollow";
}
/** Pure derivation — exported for the meaningfully-fail tests. */
export function deriveStages(subject: EvidenceSubject): RailStage[] | null {
switch (subject.kind) {
case "none":
return null;
case "turn": {
const d = subject.data;
return [
stage("intent", d ? evidenceOf(d.prompt) : "hollow", "prompt"),
stage("subject", "lit", "selected turn"),
stage("provenance", d ? evidenceOf(d.grounding_source) : "hollow", "grounding_source"),
stage(
"admissibility",
d ? evidenceOf(d.epistemic_state) : "hollow",
"epistemic_state + normative_clearance",
),
stage("replay", d ? evidenceOf(d.trace_hash) : "hollow", "trace_hash recorded (not a verification claim)"),
stage(
"authority",
d
? evidenceOf("mutation_mode" in d ? d.mutation_mode : d.checkpoint_emitted)
: "hollow",
"mutation_mode / checkpoint_emitted",
),
stage("action", "dim", "not applicable to a completed turn"),
];
}
case "proposal": {
const d = subject.data;
const provenance = d
? "source_kind" in d
? d.source_kind
: d.proposed_change_kind
: undefined;
const replayEvidence = d
? "replay_equivalent" in d
? d.replay_equivalent
: d.replay_equivalence_hash
: undefined;
const authority = d ? ("state" in d ? d.state : d.handler_name) : undefined;
const action = d
? "suggested_cli" in d
? d.suggested_cli
: d.suggested_ratify_cli
: undefined;
return [
stage("intent", "dim", "not applicable — proposals originate in contemplation"),
stage("subject", "lit", "selected proposal"),
stage("provenance", evidenceOf(provenance), "source_kind / proposed_change_kind"),
stage(
"admissibility",
replayEvidence === null ? "hollow" : evidenceOf(replayEvidence),
"replay_equivalent / replay_equivalence_hash recorded",
),
stage(
"replay",
replayEvidence === null ? "hollow" : evidenceOf(replayEvidence),
"replay evidence value (false is recorded evidence)",
),
stage("authority", evidenceOf(authority), "review state / handler_name"),
stage("action", evidenceOf(action), "suggested_cli / suggested_ratify_cli"),
];
}
case "run": {
const d = subject.data;
const hasGapField = !!d && Object.prototype.hasOwnProperty.call(d, "evidence_gap");
const gapped = evidenceOf(d?.evidence_gap) === "lit";
return [
stage("intent", "dim", "not applicable to recorded runs"),
stage("subject", "lit", "selected run"),
stage("provenance", gapped ? "dim" : d ? evidenceOf(d.source) : "hollow", "source / evidence_gap"),
stage(
"admissibility",
!d || !hasGapField ? "hollow" : gapped ? "dim" : "lit",
"evidence_gap absent means no gap recorded",
),
stage(
"replay",
!d
? "hollow"
: gapped
? "dim"
: d?.checkpoint_present
? evidenceOf(d.checkpoint_revision)
: "hollow",
"checkpoint_present + checkpoint_revision",
),
stage("authority", "dim", "not applicable to read-only run evidence"),
stage("action", "dim", "not applicable to recorded runs"),
];
}
case "pack": {
const d = subject.data;
return [
stage("intent", "dim", "not applicable to semantic packs"),
stage("subject", "lit", "selected pack"),
stage(
"provenance",
d ? evidenceAny(d.checksum, d.manifest_digest) : "hollow",
"checksum / manifest_digest",
),
stage("admissibility", d ? evidenceOf(d.determinism_class) : "hollow", "determinism_class"),
stage("replay", "dim", "not applicable to pack metadata"),
stage("authority", "dim", "not applicable to pack metadata"),
stage("action", "dim", "not applicable to pack metadata"),
];
}
case "logos_pack": {
const d = subject.data;
return [
stage("intent", "dim", "not applicable to read-only Logos pack inspection"),
stage("subject", "lit", "selected CORE-Logos pack"),
stage(
"provenance",
d ? evidenceAny(d.manifest_digest, d.manifest_path) : "hollow",
"manifest_digest / manifest_path",
),
stage(
"admissibility",
d ? evidenceAny(d.safety_status, d.checksum_status) : "hollow",
"safety_status / checksum_status",
),
stage(
"replay",
d && d.holonomy_case_count && d.holonomy_case_count > 0 ? "lit" : "hollow",
"holonomy_case_count (0 means missing_evidence)",
),
stage("authority", "dim", "read-only Logos Studio has no mutation authority"),
stage("action", "dim", "proposal mode none"),
];
}
case "logos_entry": {
const d = subject.data;
return [
stage("intent", "dim", "not applicable to read-only Logos entry inspection"),
stage("subject", "lit", "selected CORE-Logos lexical entry"),
stage(
"provenance",
d ? evidenceAny(...d.provenance_ids) : "hollow",
"provenance_ids",
),
stage(
"admissibility",
d ? evidenceOf(d.epistemic_status) : "hollow",
"epistemic_status (ADR-0021 revision position)",
),
stage("replay", "dim", "not applicable to a static lexicon row"),
stage("authority", "dim", "read-only Logos Studio has no mutation authority"),
stage("action", "dim", "proposal mode none"),
];
}
case "logos_gloss": {
const d = subject.data;
return [
stage("intent", "dim", "not applicable to read-only Logos gloss inspection"),
stage("subject", "lit", "selected CORE-Logos gloss"),
stage(
"provenance",
d ? evidenceAny(...d.provenance_ids) : "hollow",
"provenance_ids",
),
stage(
"admissibility",
d ? evidenceOf(d.epistemic_status) : "hollow",
"epistemic_status",
),
stage(
"replay",
d ? evidenceAny(...d.entry_ids) : "hollow",
"linked entry_ids",
),
stage("authority", "dim", "read-only Logos Studio has no mutation authority"),
stage("action", "dim", "proposal mode none"),
];
}
case "logos_morphology": {
const d = subject.data;
return [
stage("intent", "dim", "not applicable to read-only Logos morphology inspection"),
stage("subject", "lit", "selected CORE-Logos morphology record"),
stage(
"provenance",
d ? evidenceAny(d.root, d.stem) : "hollow",
"root / stem",
),
stage(
"admissibility",
d ? evidenceOf(d.morphology_id) : "hollow",
"morphology_id (lexicon link target)",
),
stage("replay", "dim", "not applicable to a static morphology row"),
stage("authority", "dim", "read-only Logos Studio has no mutation authority"),
stage("action", "dim", "proposal mode none"),
];
}
case "logos_alignment_edge": {
const d = subject.data;
return [
stage("intent", "dim", "not applicable to read-only Logos alignment inspection"),
stage("subject", "lit", "selected CORE-Logos alignment edge"),
stage(
"provenance",
d ? evidenceAny(...d.evidence_ids) : "hollow",
"evidence_ids (cross-language attestations)",
),
stage(
"admissibility",
d ? (d.invalid_target ? "hollow" : evidenceOf(d.target_pack_id)) : "hollow",
"target resolves to a declared lexicon entry (invalid_target = dangling)",
),
stage(
"replay",
d ? evidenceOf(d.relation) : "hollow",
"relation + weight (deterministic resonance edge)",
),
stage("authority", "dim", "read-only Logos Studio has no mutation authority"),
stage("action", "dim", "proposal mode none"),
];
}
case "vault_entry": {
const d = subject.data;
return [
stage("intent", "dim", "not applicable to vault entries"),
stage("subject", "lit", "selected vault entry"),
stage("provenance", d ? evidenceOf(d.versor_digest) : "hollow", "versor_digest"),
stage("admissibility", d ? evidenceOf(d.epistemic_state) : "hollow", "epistemic_state"),
stage("replay", "dim", "not applicable to vault entries"),
stage("authority", "dim", "not applicable to vault entries"),
stage("action", "dim", "not applicable to vault entries"),
];
}
case "audit_event": {
const d = subject.data;
return [
stage("intent", "dim", "not applicable to audit events"),
stage("subject", "lit", "selected audit event"),
stage("provenance", d ? evidenceOf(d.payload_digest) : "hollow", "payload_digest"),
stage("admissibility", "dim", "not applicable to audit events"),
stage("replay", "dim", "not applicable to audit events"),
stage("authority", "dim", "not applicable to audit events"),
stage("action", d ? evidenceOf(d.mutation_boundary) : "hollow", "mutation_boundary"),
];
}
case "calibration_class": {
const d = subject.data;
return [
stage("intent", "dim", "not applicable — calibration is serving-discipline evidence, not runtime truth"),
stage("subject", "lit", "selected calibration class"),
stage(
"provenance",
d ? evidenceAny(d.source_digest, d.source_path) : "hollow",
"practice report source_digest / source_path",
),
stage(
"admissibility",
d ? evidenceOf(d.reliability_floor) : "hollow",
"Wilson floor + theta gate from core.reliability_gate",
),
stage("replay", "dim", "not a runtime replay claim"),
stage(
"authority",
d ? evidenceAny(d.propose_licensed, d.serve_licensed) : "hollow",
"PROPOSE/SERVE license verdict; read-only, not mutation authority",
),
stage("action", "dim", "calibration view is read-only"),
];
}
case "artifact": {
const d = subject.data;
return [
stage("intent", "dim", "not applicable to stored artifacts"),
stage("subject", "lit", "selected artifact"),
stage("provenance", d ? evidenceOf(d.path) : "hollow", "path"),
stage("admissibility", "dim", "not applicable to stored artifacts"),
stage("replay", d ? evidenceOf(d.digest) : "hollow", "digest"),
stage("authority", "dim", "not applicable to stored artifacts"),
stage("action", "dim", "not applicable to stored artifacts"),
];
}
case "eval_result": {
const d = subject.data;
return [
stage("intent", "dim", "not applicable to eval runs"),
stage("subject", "lit", "selected eval result"),
stage("provenance", d ? evidenceOf(d.lane) : "hollow", "lane + version"),
stage("admissibility", d ? evidenceOf(d.split) : "hollow", "split (lane discipline)"),
stage("replay", d ? evidenceOf(d.source_digest) : "hollow", "source_digest"),
stage("authority", "dim", "not applicable to read-only lanes"),
stage("action", d ? (d.passed === null ? "hollow" : "lit") : "hollow", "pass/fail recorded"),
];
}
}
}
const STATUS_STYLE: Record<StageStatus, { dot: CSSProperties; text: string }> = {
lit: {
dot: {
background: "var(--color-state-evidenced)",
border: "1px solid var(--color-state-evidenced)",
},
text: "text-[var(--color-text-secondary)]",
},
hollow: {
dot: {
background: "transparent",
border: "1px solid var(--color-border-strong)",
},
text: "text-[var(--color-text-muted)]",
},
dim: {
dot: {
background: "var(--color-border-subtle)",
border: "1px solid var(--color-border-subtle)",
opacity: 0.5,
},
text: "text-[var(--color-text-muted)] opacity-60",
},
};
const STATUS_WORD: Record<StageStatus, string> = {
lit: "evidence present",
hollow: "not recorded",
dim: "not applicable",
};
export function EvidenceChainRail({ subject }: { subject: EvidenceSubject }) {
const stages = deriveStages(subject);
if (!stages) return null;
return (
<ol
className="m-0 flex list-none flex-wrap items-center gap-x-1 gap-y-1 border-b p-0 pb-2"
style={{ borderColor: "var(--color-border-subtle)" }}
aria-label="Evidence chain"
data-testid="evidence-chain-rail"
>
{stages.map((s, i) => (
<li
key={s.id}
className="flex items-center gap-1"
title={`${s.label}: ${STATUS_WORD[s.status]}${s.derivation}`}
data-stage={s.id}
data-status={s.status}
>
<span
aria-hidden
className="inline-block h-2 w-2 shrink-0 rounded-full"
style={STATUS_STYLE[s.status].dot}
/>
<span className={`text-[10px] ${STATUS_STYLE[s.status].text}`}>
{s.label}
</span>
{i < stages.length - 1 && (
<span aria-hidden className="text-[10px] text-[var(--color-text-muted)]">
</span>
)}
</li>
))}
</ol>
);
}