docs: define defense deck visual hierarchy contract
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { mainScenes } from "./storyboard.js";
|
import { mainScenes } from "./storyboard.js";
|
||||||
import {
|
import {
|
||||||
|
beatVisualContractFor,
|
||||||
coherenceForScene,
|
coherenceForScene,
|
||||||
demoSurfaceForBeat,
|
demoSurfaceForBeat,
|
||||||
sceneCoherenceMatrix,
|
sceneCoherenceMatrix,
|
||||||
@@ -57,4 +58,30 @@ describe("presentation coherence matrix", () => {
|
|||||||
supportSurface: "output-summary",
|
supportSurface: "output-summary",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("defines a focal contract for the opening title", () => {
|
||||||
|
expect(beatVisualContractFor("thesis", "title")).toMatchObject({
|
||||||
|
mode: "focal",
|
||||||
|
primarySurface: "title-boundary",
|
||||||
|
supportSurface: "none",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("defines semantic zoom for architecture and evidence staging for evaluation", () => {
|
||||||
|
expect(beatVisualContractFor("architecture", "node-use")).toMatchObject({
|
||||||
|
mode: "zoom",
|
||||||
|
primarySurface: "interactive-architecture",
|
||||||
|
});
|
||||||
|
expect(beatVisualContractFor("evaluation", "validity")).toMatchObject({
|
||||||
|
mode: "evidence",
|
||||||
|
primarySurface: "evaluation-validity",
|
||||||
|
supportSurface: "audit-reconciliation",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails closed for an unknown scene beat", () => {
|
||||||
|
expect(() => beatVisualContractFor("unknown", "beat")).toThrow(
|
||||||
|
"No visual contract for unknown/beat",
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,6 +24,16 @@ export type SupportSurface =
|
|||||||
|
|
||||||
export type ChatRole = "hidden" | "narration" | "approval" | "trace";
|
export type ChatRole = "hidden" | "narration" | "approval" | "trace";
|
||||||
|
|
||||||
|
export type BeatVisualMode = "focal" | "split" | "zoom" | "conversation" | "evidence";
|
||||||
|
|
||||||
|
export type SceneBeatVisualContract = {
|
||||||
|
readonly sceneId: string;
|
||||||
|
readonly beatId: string;
|
||||||
|
readonly mode: BeatVisualMode;
|
||||||
|
readonly primarySurface: string;
|
||||||
|
readonly supportSurface: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type SceneCoherenceEntry = {
|
export type SceneCoherenceEntry = {
|
||||||
readonly sceneId: string;
|
readonly sceneId: string;
|
||||||
readonly primaryArtifact: PrimaryArtifact;
|
readonly primaryArtifact: PrimaryArtifact;
|
||||||
@@ -133,6 +143,40 @@ export const sceneCoherenceMatrix = [
|
|||||||
},
|
},
|
||||||
] as const satisfies readonly SceneCoherenceEntry[];
|
] as const satisfies readonly SceneCoherenceEntry[];
|
||||||
|
|
||||||
|
const beatContracts = {
|
||||||
|
"thesis/title": { mode: "focal", primarySurface: "title-boundary", supportSurface: "none" },
|
||||||
|
"thesis/substrate": { mode: "split", primarySurface: "opening-decomposition", supportSurface: "none" },
|
||||||
|
"problem/direct-actions": { mode: "split", primarySurface: "tool-loop-transcript", supportSurface: "workflow-blueprint" },
|
||||||
|
"problem/missing-contracts": { mode: "split", primarySurface: "workflow-blueprint", supportSurface: "tool-loop-transcript" },
|
||||||
|
"architecture/client": { mode: "zoom", primarySurface: "interactive-architecture", supportSurface: "none" },
|
||||||
|
"architecture/api": { mode: "zoom", primarySurface: "interactive-architecture", supportSurface: "none" },
|
||||||
|
"architecture/runtime": { mode: "zoom", primarySurface: "interactive-architecture", supportSurface: "none" },
|
||||||
|
"architecture/node-use": { mode: "zoom", primarySurface: "interactive-architecture", supportSurface: "evidence-receipt" },
|
||||||
|
"authoring/discover": { mode: "evidence", primarySurface: "authoring-discovery", supportSurface: "authoring-loop" },
|
||||||
|
"authoring/author": { mode: "evidence", primarySurface: "authoring-draft", supportSurface: "authoring-loop" },
|
||||||
|
"authoring/diagnose": { mode: "evidence", primarySurface: "authoring-diagnostic", supportSurface: "authoring-loop" },
|
||||||
|
"authoring/repair": { mode: "evidence", primarySurface: "authoring-repair", supportSurface: "authoring-loop" },
|
||||||
|
"agent-handoff/request": { mode: "conversation", primarySurface: "prepared-conversation", supportSurface: "none" },
|
||||||
|
"agent-handoff/handoff": { mode: "conversation", primarySurface: "prepared-conversation", supportSurface: "none" },
|
||||||
|
"evaluation/cohort": { mode: "evidence", primarySurface: "evaluation-cohort", supportSurface: "none" },
|
||||||
|
"evaluation/validity": { mode: "evidence", primarySurface: "evaluation-validity", supportSurface: "audit-reconciliation" },
|
||||||
|
"evaluation/findings": { mode: "evidence", primarySurface: "evaluation-findings", supportSurface: "validity-boundary" },
|
||||||
|
"conclusion/limits": { mode: "evidence", primarySurface: "contribution-boundary", supportSurface: "non-claims" },
|
||||||
|
"conclusion/future": { mode: "evidence", primarySurface: "future-layers", supportSurface: "contribution-boundary" },
|
||||||
|
"conclusion/conclusion": { mode: "focal", primarySurface: "contribution-statement", supportSurface: "evidence-attachment" },
|
||||||
|
"conclusion/questions": { mode: "focal", primarySurface: "discussion-index", supportSurface: "none" },
|
||||||
|
} as const satisfies Record<string, Omit<SceneBeatVisualContract, "sceneId" | "beatId">>;
|
||||||
|
|
||||||
|
export const beatVisualContractFor = (
|
||||||
|
sceneId: string,
|
||||||
|
beatId: string,
|
||||||
|
): SceneBeatVisualContract => {
|
||||||
|
const key = `${sceneId}/${beatId}`;
|
||||||
|
const contract = beatContracts[key];
|
||||||
|
if (!contract) throw new Error(`No visual contract for ${key}`);
|
||||||
|
return { sceneId, beatId, ...contract };
|
||||||
|
};
|
||||||
|
|
||||||
export const coherenceForScene = (sceneId: string): SceneCoherenceEntry => {
|
export const coherenceForScene = (sceneId: string): SceneCoherenceEntry => {
|
||||||
const entry = sceneCoherenceMatrix.find((candidate) => candidate.sceneId === sceneId);
|
const entry = sceneCoherenceMatrix.find((candidate) => candidate.sceneId === sceneId);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
|
|||||||
Reference in New Issue
Block a user