Lands the Phase C "make cognition legible" slice plus Phase A residue, all backend-reader-first over real engine data (no theater, read-only doctrine intact, zero serving-path imports). C1-a — Cognitive pipeline record (persistence-first, per #729 worthiness edit): - workbench/pipeline_record.py: curated CognitivePipelineRecord over the real CognitiveTurnResult (input → intent → proposition_graph → articulation_target → realizer → walk_telemetry → trace_hash). Raw field multivectors are DELIBERATELY excluded; _assert_no_raw_field_payload recursively rejects raw field keys, and validate_pipeline_record fails closed on missing/duplicate stages, non-recorded status, or dangling edges — the UI can never receive a partial record that claims to be complete. - test_workbench_pipeline_record.py: non-vacuous guards — missing stage, monkeypatched new required stage, and injected raw {"F": [...]} each raise. C2-a — Contemplation as a process: /contemplation route over real persisted contemplation/runs/*.json (glob reader; honest-empty when absent). C4-a — Identity continuity (L10/L11): RunDetail.identity_continuity + Runs Identity tab, sourced from the real core.engine_identity (engine_identity / parent_engine_identity lineage relation, re-derived to verify). Demo Theater: renders backend-owned proof-promotion + entailment DAGs. Phase A residue: density preference wired end-to-end (settings → shell → tokens); cross-route consistency touch-ups. Infra: local API CORS now echoes only validated 127.0.0.1/localhost origins (hostname-checked, not arbitrary reflection) so Vite fallback ports work. Route chunk-split keeps the build warning-free. Cleanup: corrected the stale ADR-0175 practice-lane assertions (build_report is 6 correct / 0 wrong / 44 refused after the current serving lane; wrong=0 held) and the two registry-derived count tests (LeftNav + CommandPalette 12 → 13 for the new Contemplation route). Docs: runtime_contracts.md (pipeline-record contract), UI-UX-GUIDE, api-contract-v1, data-shapes-v1, wave-M-worthiness, phase-a-residue-ledger. Validation: 106 workbench/practice Python tests green (incl. wrong=0 lane + pipeline-record fail-closed guards); 459/459 frontend; pnpm build clean; git diff --check clean. No generate.derivation / reliability_gate / stream / field.propagate / vault.store imports.
133 lines
4 KiB
TypeScript
133 lines
4 KiB
TypeScript
import { useEffect, useState, useCallback } from "react";
|
|
import { Outlet } from "react-router-dom";
|
|
import { TopBar } from "./TopBar";
|
|
import { LeftNav } from "./LeftNav";
|
|
import { StatusFooter } from "./StatusFooter";
|
|
import { RightInspector } from "./RightInspector";
|
|
import { ApiErrorBoundary } from "./ApiErrorBoundary";
|
|
import { EvidenceProvider, useEvidenceSubject } from "./evidenceContext";
|
|
import { EvidenceUrlSync } from "./evidenceUrlSync";
|
|
import { isAddressable, subjectToUrl } from "./evidenceAddress";
|
|
import { KeyboardHelp } from "./KeyboardHelp";
|
|
import { useGlobalKeyboard } from "./useGlobalKeyboard";
|
|
import { useCommandRegistry } from "./commandRegistry";
|
|
import { useWorkbenchPrefs } from "./workbenchPrefs";
|
|
import { SplitPane } from "../design/components/SplitPane/SplitPane";
|
|
|
|
function ShellInner() {
|
|
const { subject, inspectorOpen, toggleInspector, notifyAddressCopied } =
|
|
useEvidenceSubject();
|
|
const prefs = useWorkbenchPrefs();
|
|
const [helpOpen, setHelpOpen] = useState(false);
|
|
const [paletteOpen, setPaletteOpen] = useState(false);
|
|
|
|
const onTogglePalette = useCallback(() => {
|
|
setPaletteOpen((v) => !v);
|
|
}, []);
|
|
|
|
const onShowHelp = useCallback(() => {
|
|
setHelpOpen(true);
|
|
}, []);
|
|
|
|
const onCopyEvidenceLink = useCallback(() => {
|
|
if (!isAddressable(subject)) return;
|
|
if (!navigator.clipboard?.writeText) return;
|
|
const url = window.location.origin + subjectToUrl(subject);
|
|
navigator.clipboard.writeText(url).then(
|
|
() => notifyAddressCopied(),
|
|
(err) => console.error("Evidence link copy failed:", err),
|
|
);
|
|
}, [subject, notifyAddressCopied]);
|
|
|
|
useGlobalKeyboard({
|
|
onTogglePalette,
|
|
onToggleInspector: toggleInspector,
|
|
onShowHelp,
|
|
onCopyEvidenceLink,
|
|
});
|
|
|
|
// Action verbs in the palette (Wave R brief R0d): registered by the
|
|
// component that owns the behavior, unregistered on unmount.
|
|
const { register, unregister } = useCommandRegistry();
|
|
useEffect(() => {
|
|
register([
|
|
{
|
|
id: "action-toggle-inspector",
|
|
label: "Toggle inspector",
|
|
section: "Actions",
|
|
kind: "action",
|
|
shortcut: "\u2318I",
|
|
action: toggleInspector,
|
|
},
|
|
{
|
|
id: "action-copy-evidence-link",
|
|
label: "Copy evidence link",
|
|
section: "Actions",
|
|
kind: "action",
|
|
shortcut: "\u2318\u21E7C",
|
|
action: onCopyEvidenceLink,
|
|
},
|
|
]);
|
|
return () => unregister(["action-toggle-inspector", "action-copy-evidence-link"]);
|
|
}, [register, unregister, toggleInspector, onCopyEvidenceLink]);
|
|
|
|
const mainSurface = (
|
|
<main
|
|
data-region="main"
|
|
className="h-full overflow-y-auto bg-[var(--color-surface-base)] p-[var(--density-main-padding)]"
|
|
>
|
|
<ApiErrorBoundary>
|
|
<Outlet />
|
|
</ApiErrorBoundary>
|
|
</main>
|
|
);
|
|
|
|
return (
|
|
<div
|
|
className="grid h-screen"
|
|
data-density={prefs.densityMode}
|
|
style={{
|
|
gridTemplateAreas:
|
|
'"topbar topbar" "leftnav center" "footer footer"',
|
|
gridTemplateRows: "auto 1fr auto",
|
|
gridTemplateColumns: "12rem 1fr",
|
|
}}
|
|
>
|
|
<div style={{ gridArea: "topbar" }}>
|
|
<TopBar paletteOpen={paletteOpen} onPaletteOpenChange={setPaletteOpen} />
|
|
</div>
|
|
|
|
<div style={{ gridArea: "leftnav" }}>
|
|
<LeftNav />
|
|
</div>
|
|
|
|
<div style={{ gridArea: "center" }} className="min-h-0">
|
|
{inspectorOpen ? (
|
|
// Resizable main/inspector split; width persists via the
|
|
// SplitPane id (guarded storage access inside SplitPane).
|
|
<SplitPane direction="horizontal" id="inspector" defaultSplit={72} minSize={240}>
|
|
{mainSurface}
|
|
<RightInspector />
|
|
</SplitPane>
|
|
) : (
|
|
mainSurface
|
|
)}
|
|
</div>
|
|
|
|
<div style={{ gridArea: "footer" }}>
|
|
<StatusFooter />
|
|
</div>
|
|
|
|
<KeyboardHelp open={helpOpen} onOpenChange={setHelpOpen} />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function Shell() {
|
|
return (
|
|
<EvidenceProvider>
|
|
<EvidenceUrlSync />
|
|
<ShellInner />
|
|
</EvidenceProvider>
|
|
);
|
|
}
|