agentfootprint-lens 0.44.0 → 0.45.0
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/dist/{chunk-OQRL3II6.js → chunk-YEJJOPOZ.js} +113 -3
- package/dist/chunk-YEJJOPOZ.js.map +1 -0
- package/dist/core.d.cts +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/index.cjs +112 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -4
- package/dist/index.d.ts +15 -4
- package/dist/index.js +1 -1
- package/dist/{selectSkillFrameContext-CT_EKu4u.d.cts → selectSkillFrameContext-DJkvrggG.d.cts} +1 -1
- package/dist/{selectSkillFrameContext-D0xQV_px.d.ts → selectSkillFrameContext-IPsw4Pbj.d.ts} +1 -1
- package/dist/skillgraph.cjs +112 -2
- package/dist/skillgraph.cjs.map +1 -1
- package/dist/skillgraph.d.cts +2 -2
- package/dist/skillgraph.d.ts +2 -2
- package/dist/skillgraph.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-OQRL3II6.js.map +0 -1
|
@@ -608,7 +608,7 @@ var CAUSE_LABEL = {
|
|
|
608
608
|
stay: "nothing moved it",
|
|
609
609
|
none: "no skill was in play"
|
|
610
610
|
};
|
|
611
|
-
function RouteDecisionCard({ beat, lens }) {
|
|
611
|
+
function RouteDecisionCard({ beat, turnStart, lens }) {
|
|
612
612
|
return /* @__PURE__ */ jsx4(
|
|
613
613
|
"aside",
|
|
614
614
|
{
|
|
@@ -736,6 +736,7 @@ function RouteDecisionCard({ beat, lens }) {
|
|
|
736
736
|
children: beat.notes.map((n, i) => /* @__PURE__ */ jsx4("li", { children: n }, i))
|
|
737
737
|
}
|
|
738
738
|
),
|
|
739
|
+
turnStart !== void 0 && (turnStart.by === "intent" || turnStart.by === "continuity") && /* @__PURE__ */ jsx4(ScoreTable, { start: turnStart }),
|
|
739
740
|
lens === "developer" && beat.runtimeStageId !== void 0 && /* @__PURE__ */ jsx4("div", { style: { marginTop: 8, fontFamily: T.fontMono, fontSize: 10, color: T.textMuted }, children: beat.runtimeStageId })
|
|
740
741
|
] })
|
|
741
742
|
}
|
|
@@ -761,6 +762,104 @@ function Evidence({
|
|
|
761
762
|
children
|
|
762
763
|
] });
|
|
763
764
|
}
|
|
765
|
+
function ScoreTable({ start }) {
|
|
766
|
+
if (start.scores.length === 0) return null;
|
|
767
|
+
const floor = start.policy?.floor;
|
|
768
|
+
const margin = start.policy?.nearTieMargin;
|
|
769
|
+
return /* @__PURE__ */ jsxs4("div", { style: { marginTop: 8 }, children: [
|
|
770
|
+
/* @__PURE__ */ jsxs4(
|
|
771
|
+
"div",
|
|
772
|
+
{
|
|
773
|
+
style: {
|
|
774
|
+
fontSize: 10,
|
|
775
|
+
letterSpacing: "0.08em",
|
|
776
|
+
textTransform: "uppercase",
|
|
777
|
+
color: T.textMuted,
|
|
778
|
+
marginBottom: 4
|
|
779
|
+
},
|
|
780
|
+
children: [
|
|
781
|
+
"Scored",
|
|
782
|
+
start.scorer ? ` by ${start.scorer}` : "",
|
|
783
|
+
floor !== void 0 ? ` \xB7 floor ${floor}` : "",
|
|
784
|
+
start.runnerUp !== void 0 && margin !== void 0 ? ` \xB7 gap ${fmt(start.runnerUp.gap)} of ${margin} needed` : ""
|
|
785
|
+
]
|
|
786
|
+
}
|
|
787
|
+
),
|
|
788
|
+
/* @__PURE__ */ jsxs4(
|
|
789
|
+
"table",
|
|
790
|
+
{
|
|
791
|
+
style: { borderCollapse: "collapse", width: "100%", fontSize: 12 },
|
|
792
|
+
children: [
|
|
793
|
+
/* @__PURE__ */ jsx4(
|
|
794
|
+
"caption",
|
|
795
|
+
{
|
|
796
|
+
style: {
|
|
797
|
+
captionSide: "top",
|
|
798
|
+
textAlign: "left",
|
|
799
|
+
fontSize: 11,
|
|
800
|
+
color: T.textMuted,
|
|
801
|
+
paddingBottom: 3
|
|
802
|
+
},
|
|
803
|
+
children: "Every candidate this turn was scored against, best first."
|
|
804
|
+
}
|
|
805
|
+
),
|
|
806
|
+
/* @__PURE__ */ jsx4("tbody", { children: start.scores.map((row) => {
|
|
807
|
+
const belowFloor = floor !== void 0 && row.score <= floor;
|
|
808
|
+
const won = row.id === start.to;
|
|
809
|
+
return /* @__PURE__ */ jsxs4("tr", { children: [
|
|
810
|
+
/* @__PURE__ */ jsxs4(
|
|
811
|
+
"td",
|
|
812
|
+
{
|
|
813
|
+
style: {
|
|
814
|
+
padding: "2px 6px 2px 0",
|
|
815
|
+
color: belowFloor ? T.textMuted : T.textPrimary,
|
|
816
|
+
fontWeight: won ? 700 : 400,
|
|
817
|
+
fontFamily: T.fontMono
|
|
818
|
+
},
|
|
819
|
+
children: [
|
|
820
|
+
won ? "\u2192 " : " ",
|
|
821
|
+
row.id
|
|
822
|
+
]
|
|
823
|
+
}
|
|
824
|
+
),
|
|
825
|
+
/* @__PURE__ */ jsx4(
|
|
826
|
+
"td",
|
|
827
|
+
{
|
|
828
|
+
style: {
|
|
829
|
+
padding: "2px 6px",
|
|
830
|
+
textAlign: "right",
|
|
831
|
+
fontFamily: T.fontMono,
|
|
832
|
+
color: belowFloor ? T.textMuted : T.textPrimary
|
|
833
|
+
},
|
|
834
|
+
children: fmt(row.score)
|
|
835
|
+
}
|
|
836
|
+
),
|
|
837
|
+
/* @__PURE__ */ jsxs4(
|
|
838
|
+
"td",
|
|
839
|
+
{
|
|
840
|
+
style: {
|
|
841
|
+
padding: "2px 6px",
|
|
842
|
+
textAlign: "right",
|
|
843
|
+
fontFamily: T.fontMono,
|
|
844
|
+
color: T.textMuted
|
|
845
|
+
},
|
|
846
|
+
children: [
|
|
847
|
+
Math.round(row.relevance * 100),
|
|
848
|
+
"%"
|
|
849
|
+
]
|
|
850
|
+
}
|
|
851
|
+
),
|
|
852
|
+
/* @__PURE__ */ jsx4("td", { style: { padding: "2px 0 2px 6px", color: T.textMuted, fontSize: 11 }, children: belowFloor ? "below floor" : won ? "" : "beaten" })
|
|
853
|
+
] }, row.id);
|
|
854
|
+
}) })
|
|
855
|
+
]
|
|
856
|
+
}
|
|
857
|
+
)
|
|
858
|
+
] });
|
|
859
|
+
}
|
|
860
|
+
function fmt(n) {
|
|
861
|
+
return String(Math.round(n * 1e3) / 1e3);
|
|
862
|
+
}
|
|
764
863
|
|
|
765
864
|
// src/react/skillgraph/skillTopologyPositions.ts
|
|
766
865
|
function skillTopologyPositions(nodeIds, edges) {
|
|
@@ -1123,6 +1222,10 @@ function SkillGraphDebugger({
|
|
|
1123
1222
|
[beats, cursorRuntimeStageId, cursorKind]
|
|
1124
1223
|
);
|
|
1125
1224
|
const activeIndex = activeBeat?.index;
|
|
1225
|
+
const activeTurnStart = useMemo2(
|
|
1226
|
+
() => activeBeat === void 0 || route === void 0 ? void 0 : route.turns.find((t) => t.turnIndex === activeBeat.turnIndex),
|
|
1227
|
+
[route, activeBeat]
|
|
1228
|
+
);
|
|
1126
1229
|
const topology = useMemo2(
|
|
1127
1230
|
() => route !== void 0 ? selectSkillTopology({
|
|
1128
1231
|
route,
|
|
@@ -1264,7 +1367,14 @@ function SkillGraphDebugger({
|
|
|
1264
1367
|
onPickSkill: jumpToSkill
|
|
1265
1368
|
}
|
|
1266
1369
|
) }),
|
|
1267
|
-
/* @__PURE__ */ jsx6(
|
|
1370
|
+
/* @__PURE__ */ jsx6(
|
|
1371
|
+
RouteDecisionCard,
|
|
1372
|
+
{
|
|
1373
|
+
...activeBeat !== void 0 ? { beat: activeBeat } : {},
|
|
1374
|
+
...activeTurnStart !== void 0 ? { turnStart: activeTurnStart } : {},
|
|
1375
|
+
lens
|
|
1376
|
+
}
|
|
1377
|
+
)
|
|
1268
1378
|
]
|
|
1269
1379
|
}
|
|
1270
1380
|
),
|
|
@@ -1382,4 +1492,4 @@ export {
|
|
|
1382
1492
|
SKILL_GRAPH_READS,
|
|
1383
1493
|
SkillGraphDebugger
|
|
1384
1494
|
};
|
|
1385
|
-
//# sourceMappingURL=chunk-
|
|
1495
|
+
//# sourceMappingURL=chunk-YEJJOPOZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/react/skillGraphFlowLayout.ts","../src/react/skillgraph/BeatStrip.tsx","../src/react/skillgraph/FrameFactsPanel.tsx","../src/react/skillgraph/NarrativeRail.tsx","../src/react/skillgraph/RouteDecisionCard.tsx","../src/react/skillgraph/skillTopologyPositions.ts","../src/react/skillgraph/SkillTopologyCanvas.tsx","../src/react/skillgraph/SkillGraphDebugger.tsx"],"sourcesContent":["/**\n * skillGraphFlowLayout — pure layout for the interactive skill-graph view.\n *\n * Takes the STRUCTURE that `agentfootprint`'s `skillGraph().build()` produces\n * (`{ nodes, edges }` — predicate diamonds + skill boxes, branch edges) and lays\n * it out top-to-bottom with dagre into absolute positions xyflow can render.\n *\n * Pure + framework-free: no React, no agentfootprint import. The prop shapes are\n * STRUCTURAL copies of agentfootprint's `SkillNode` / `SkillEdge`, so a consumer\n * passes `graph.nodes` / `graph.edges` straight through (TypeScript structural\n * typing makes them assignable) without the lens taking a hard dependency on the\n * exact agentfootprint types. Keeping the layout here (not in the component) means\n * it unit-tests without rendering — the lens \"pure core + thin React\" convention.\n */\n\nimport dagre from 'dagre';\n\n/** A drawn node — mirrors agentfootprint's `SkillNode`. */\nexport interface SkillGraphNodeView {\n readonly id: string;\n readonly kind: 'predicate' | 'skill';\n readonly label?: string;\n}\n\n/** A drawn edge — mirrors agentfootprint's `SkillEdge`. `from: null` = START. */\nexport interface SkillGraphEdgeView {\n readonly from: string | null;\n readonly to: string;\n /** `'model'` edges draw dashed (model-reachable via read_skill); others solid. */\n readonly kind?: string;\n readonly label?: string;\n}\n\nexport interface SkillGraphInput {\n readonly nodes: readonly SkillGraphNodeView[];\n readonly edges: readonly SkillGraphEdgeView[];\n}\n\n/** The synthetic START node id (a turn's entry point). */\nexport const SKILL_GRAPH_START_ID = '__start__';\n\nexport type FlowNodeKind = 'start' | 'predicate' | 'skill';\n\n/** A positioned node ready for xyflow (`position` = top-left, not dagre center). */\nexport interface SkillFlowNode {\n readonly id: string;\n readonly kind: FlowNodeKind;\n readonly label: string;\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n}\n\nexport interface SkillFlowEdge {\n readonly id: string;\n readonly source: string;\n readonly target: string;\n readonly label?: string;\n readonly dashed: boolean;\n}\n\n/** Box sizes per node kind — predicate is taller (a diamond's usable area is its\n * inscribed rectangle, ~half), skill is a wide pill, start is a small chip. */\nconst SIZES: Record<FlowNodeKind, { width: number; height: number }> = {\n start: { width: 104, height: 40 },\n predicate: { width: 188, height: 96 },\n skill: { width: 192, height: 56 },\n};\n\nexport function sizeFor(kind: FlowNodeKind): { width: number; height: number } {\n return SIZES[kind];\n}\n\nexport interface SkillGraphLayoutOptions {\n /** Render the synthetic START chip + its entry edges. Default `true`. */\n readonly showStart?: boolean;\n /** Vertical gap between ranks. Default `64`. */\n readonly rankSep?: number;\n /** Horizontal gap between siblings. Default `40`. */\n readonly nodeSep?: number;\n}\n\n/**\n * Lay the skill graph out top-to-bottom. Dangling edges (endpoint not in\n * `nodes`) are skipped rather than throwing — a renderer should draw what it can.\n */\nexport function layoutSkillGraph(\n graph: SkillGraphInput,\n opts: SkillGraphLayoutOptions = {},\n): { nodes: SkillFlowNode[]; edges: SkillFlowEdge[] } {\n const showStart = opts.showStart ?? true;\n\n const g = new dagre.graphlib.Graph({ multigraph: true });\n g.setGraph({\n rankdir: 'TB',\n ranksep: opts.rankSep ?? 64,\n nodesep: opts.nodeSep ?? 40,\n marginx: 8,\n marginy: 8,\n });\n g.setDefaultEdgeLabel(() => ({}));\n\n // NOTE: dagre writes the computed x/y back ONTO the label object passed to\n // setNode. Pass a FRESH object per node — sharing one `SIZES[kind]` object\n // across nodes makes dagre's positions collide (every node of a kind reads the\n // last write). Spread to clone.\n const usesStart = showStart && graph.edges.some((e) => e.from === null);\n if (usesStart) g.setNode(SKILL_GRAPH_START_ID, { ...SIZES.start });\n for (const n of graph.nodes) g.setNode(n.id, { ...SIZES[n.kind] });\n\n const flowEdges: SkillFlowEdge[] = [];\n let i = 0;\n for (const e of graph.edges) {\n if (e.from === null && !usesStart) continue; // start hidden → drop entry edges\n const source = e.from === null ? SKILL_GRAPH_START_ID : e.from;\n if (!g.hasNode(source) || !g.hasNode(e.to)) continue; // skip dangling endpoints\n const id = `sge${i++}:${source}->${e.to}`;\n g.setEdge(source, e.to, {}, id);\n flowEdges.push({\n id,\n source,\n target: e.to,\n label: e.label,\n dashed: e.kind === 'model',\n });\n }\n\n dagre.layout(g);\n\n const toFlow = (id: string, kind: FlowNodeKind, label: string): SkillFlowNode => {\n const p = g.node(id) as {\n x: number;\n y: number;\n width: number;\n height: number;\n };\n return {\n id,\n kind,\n label,\n x: p.x - p.width / 2, // dagre centers; xyflow positions by top-left\n y: p.y - p.height / 2,\n width: p.width,\n height: p.height,\n };\n };\n\n const nodes: SkillFlowNode[] = [];\n if (usesStart) nodes.push(toFlow(SKILL_GRAPH_START_ID, 'start', '▶ start'));\n for (const n of graph.nodes) nodes.push(toFlow(n.id, n.kind, n.label ?? n.id));\n\n return { nodes, edges: flowEdges };\n}\n\n/** One predicate on the path that reaches a node, and the branch taken. */\nexport interface SkillRoutingPathStep {\n /** The predicate node's caption. */\n readonly predicate: string;\n /** The branch (edge caption) taken to descend toward the target. */\n readonly branch: string;\n}\n\n/**\n * Walk the graph backwards from `nodeId` to START, collecting the decision path\n * that reaches it — each predicate + the branch taken — in root→leaf order. For a\n * decision tree this is the conjunction that activates the skill; for a flat\n * entry it's empty (reached directly), for a route it's the single edge. Pure +\n * derived from the drawn edges (no agentfootprint dependency); cycle-guarded.\n */\nexport function routingPathTo(graph: SkillGraphInput, nodeId: string): SkillRoutingPathStep[] {\n const labelById = new Map(graph.nodes.map((n) => [n.id, n.label ?? n.id] as const));\n const incoming = new Map<string, { from: string | null; branch?: string }>();\n for (const e of graph.edges) incoming.set(e.to, { from: e.from, branch: e.label });\n\n const steps: SkillRoutingPathStep[] = [];\n const seen = new Set<string>([nodeId]);\n let cur: string | null = nodeId;\n while (cur) {\n const edge = incoming.get(cur);\n if (!edge || edge.from === null) break; // reached START (entry) or a root\n if (seen.has(edge.from)) break; // cycle guard\n seen.add(edge.from);\n steps.push({\n predicate: labelById.get(edge.from) ?? edge.from,\n branch: edge.branch ?? '',\n });\n cur = edge.from;\n }\n return steps.reverse(); // root → leaf\n}\n","/**\n * <BeatStrip> — the run's routing stops as one rail, under the LENS'S OWN\n * transport.\n *\n * TWO PARTS, and only one of them is new:\n *\n * THE TRANSPORT is `<TimeTravel>` — the component `<Lens>` already ships and\n * mounts (◀ ▶ ⟳Live, the drag track, ← → Home End). It is not re-implemented\n * here and must never be: one cursor also means one transport, and a second\n * faithful slider is the drift class this ecosystem keeps paying for. It is\n * bound to whatever axis the host gave us — the lens's own step axis when\n * there is one, the routing-stop projection when this view stands alone.\n *\n * THE BEAT RAIL is SkillGraph-specific: one card per routing stop, with the\n * cause that moved the cursor and the skill it landed in. It is a PROJECTION\n * of the same cursor (which card is lit is derived from it every render), and\n * clicking one drives the same transport state as the slider above it.\n *\n * A beat whose recording carried no stage id cannot be jumped to; it renders\n * disabled rather than silently doing nothing.\n */\n\nimport React from 'react';\n\nimport type { SkillBeat } from '../../core/selectors/selectSkillBeats.js';\nimport { T } from '../theme/index.js';\nimport { TimeTravel } from '../TimeTravel.js';\nimport type { SkillLens } from './lens.js';\n\n/** The dot colour per cause — the same vocabulary the route card names. */\nfunction causeColor(beat: SkillBeat): string {\n if (beat.refusedIds.length > 0) return T.error;\n switch (beat.cause) {\n case 'model-pick':\n case 'tool-proposal':\n return T.srcSkill;\n case 'route':\n case 'entry':\n return T.primary;\n case 'stay':\n case 'none':\n return T.textMuted;\n default:\n return T.textSecondary;\n }\n}\n\n/**\n * What the shared transport scrubs. `total`/`focus` are the host's axis when\n * it has one (identical numbers to the lens's own transport) and the routing\n * projection otherwise — either way the position is DERIVED, never stored.\n */\nexport interface BeatTransport {\n readonly total: number;\n readonly focus: number;\n readonly onFocusChange: (position: number) => void;\n /** Whether this transport owns ← → Home End. Off when the page has another. */\n readonly keyboard: boolean;\n /** What the axis is, said in the readout above the rail. */\n readonly axisLabel: string;\n /** The stops ◀ ▶ may land on, when the host narrowed them — positions on\n * `total`'s axis, handed straight to the shipped transport. Absent ⇒ the\n * step buttons walk every position, exactly as before. */\n readonly snapSteps?: readonly number[];\n}\n\nexport interface BeatStripProps {\n readonly beats: readonly SkillBeat[];\n readonly activeIndex?: number;\n readonly lens: SkillLens;\n readonly transport: BeatTransport;\n /** Move THE cursor. The only way this component changes anything. */\n readonly onJumpTo?: (runtimeStageId: string) => void;\n}\n\nexport function BeatStrip({\n beats,\n activeIndex,\n lens,\n transport,\n onJumpTo,\n}: BeatStripProps): React.ReactElement {\n const at = activeIndex ?? -1;\n\n return (\n <footer\n data-testid=\"beat-strip\"\n style={{\n borderTop: `1px solid ${T.border}`,\n background: T.bgPrimary,\n padding: '4px 12px 8px',\n fontFamily: T.fontSans,\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>\n <div style={{ flex: 1, minWidth: 220 }}>\n <TimeTravel\n total={transport.total}\n focusSeq={Math.max(0, transport.focus)}\n onFocusChange={transport.onFocusChange}\n isLive={transport.total > 0 && transport.focus >= transport.total - 1}\n keyboard={transport.keyboard}\n {...(transport.snapSteps !== undefined ? { snapSteps: transport.snapSteps } : {})}\n />\n </div>\n <span style={{ fontSize: 11, color: T.textMuted, whiteSpace: 'nowrap' }}>\n {transport.axisLabel}\n </span>\n </div>\n\n <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 2 }}>\n <span style={{ fontSize: 11, color: T.textMuted, whiteSpace: 'nowrap' }}>\n {beats.length === 0\n ? 'no routing stops in this run'\n : at < 0\n ? `${beats.length} routing stop${beats.length === 1 ? '' : 's'} — the cursor is before the first`\n : `${lens === 'product' ? 'step' : 'stop'} ${at + 1} of ${beats.length}`}\n </span>\n </div>\n\n <div\n style={{\n marginTop: 6,\n display: 'flex',\n gap: 6,\n overflowX: 'auto',\n paddingBottom: 2,\n }}\n >\n {beats.map((b, i) => {\n const active = i === at;\n const reachableStop = b.runtimeStageId !== undefined;\n return (\n <button\n key={`${b.turnIndex}:${b.iteration}`}\n type=\"button\"\n data-testid={`beat-${i}`}\n data-active={active ? 'true' : 'false'}\n disabled={!reachableStop}\n onClick={() => {\n if (b.runtimeStageId !== undefined) onJumpTo?.(b.runtimeStageId);\n }}\n title={b.headline}\n style={{\n flex: '0 0 auto',\n minWidth: 132,\n maxWidth: 210,\n textAlign: 'left',\n padding: '6px 8px',\n borderRadius: 8,\n border: `1px solid ${active ? T.primary : T.border}`,\n background: active ? T.bgTertiary : T.bgSecondary,\n color: T.textPrimary,\n cursor: reachableStop ? 'pointer' : 'default',\n opacity: reachableStop ? 1 : 0.55,\n }}\n >\n <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>\n <span\n aria-hidden\n style={{\n width: 7,\n height: 7,\n borderRadius: '50%',\n background: causeColor(b),\n }}\n />\n <span style={{ fontSize: 11, fontWeight: 600 }}>{b.label}</span>\n </span>\n <span\n style={{\n display: 'block',\n marginTop: 3,\n fontSize: 10,\n color: T.textMuted,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {lens === 'developer'\n ? `${b.cause ?? 'no cause'} · ${b.cursorSkillId ?? '—'}`\n : (b.cursorSkillId ?? 'nothing open yet')}\n </span>\n </button>\n );\n })}\n </div>\n </footer>\n );\n}\n","/**\n * <FrameFactsPanel> — what the model was looking at on THIS beat.\n *\n * Everything on this panel is verbatim from the recording, and everything the\n * recording does not carry is stated as ABSENT rather than filled in. That\n * split is the panel's whole job, so it is worth naming what falls on each\n * side of it:\n *\n * ON THE RECORD `read_skill`'s description as sent (the menu the model was\n * reading — the gate rewrites it every iteration), the tool\n * catalog as sent, every injection the skills contributed,\n * the engineered context the paired LLM call carried, and\n * the evidence gate's verdict. Since agentfootprint 9.50.0,\n * possibly two more: the ASSEMBLED system prompt verbatim\n * (`llm_start.systemPromptText` — opt-in, rendered here \"as\n * sent\" when present) and the reachable set as data\n * (`cursorMove.reachable`).\n * NOT ON IT whichever of those two this recording's era or dials left\n * out: the assembled prompt (recording it is an explicit\n * opt-in, `recordSystemPrompt: true` — the privacy default\n * keeps it off the record) and/or the reachable set as data\n * (older eras carry it only as prose inside `read_skill`'s\n * description, plus the typed list a refusal happens to\n * carry).\n *\n * The absence card names exactly what is absent from THIS beat's record —\n * and disappears when nothing is — rather than leaving a reader to assume\n * the panel is showing everything there was.\n */\n\nimport React from 'react';\n\nimport type { SkillBeat } from '../../core/selectors/selectSkillBeats.js';\nimport type { SkillFrameContext } from '../../core/selectors/selectSkillFrameContext.js';\nimport { T } from '../theme/index.js';\n\nexport interface FrameFactsPanelProps {\n readonly beat?: SkillBeat;\n /** The paired LLM call's engineered context. Omitted when the host has no\n * step graph to pair against — the panel then says the pairing is absent,\n * which is different from a call that carried nothing. */\n readonly frameContext?: SkillFrameContext;\n}\n\nexport function FrameFactsPanel({\n beat,\n frameContext,\n}: FrameFactsPanelProps): React.ReactElement {\n if (beat === undefined) {\n return (\n <div style={panelStyle} data-testid=\"frame-facts\">\n <p style={{ margin: 0, fontSize: 12, color: T.textMuted }}>\n Nothing has been sent to the model yet at this cursor position.\n </p>\n </div>\n );\n }\n\n const hop = beat.hop;\n const promptOnRecord = hop.systemPromptText !== undefined;\n const reachableAsData = beat.reachable?.source === 'cursor-move';\n return (\n <div style={panelStyle} data-testid=\"frame-facts\">\n <Header\n title=\"What the model saw\"\n subtitle={`${beat.label} · the call this stop prepared`}\n />\n\n {hop.systemPromptText !== undefined && (\n <Section title=\"system prompt, as sent\" count={1}>\n <div style={{ fontSize: 10, color: T.textMuted, marginBottom: 4 }}>\n the assembled prompt, byte-for-byte as the provider received it (the producer opted\n in with <code>recordSystemPrompt: true</code>)\n </div>\n <Mono testId=\"system-prompt-text\">{hop.systemPromptText}</Mono>\n </Section>\n )}\n\n <Section title=\"read_skill, as sent\" count={hop.readSkillDescription !== undefined ? 1 : 0}>\n {hop.readSkillDescription !== undefined ? (\n <Mono testId=\"read-skill-description\">{hop.readSkillDescription}</Mono>\n ) : (\n <Absent>\n This iteration's recording carries no <code>read_skill</code> description — either\n the run had no gate tool on this call, or the tool catalog was not captured.\n </Absent>\n )}\n </Section>\n\n <Section title=\"tools, as sent\" count={hop.toolsAsSent.length}>\n {hop.toolsAsSent.length === 0 ? (\n <Absent>No tool catalog was recorded for this call.</Absent>\n ) : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>\n {hop.toolsAsSent.map((t) => (\n <div key={t.name} style={{ fontSize: 11.5 }}>\n <span style={{ fontFamily: T.fontMono, color: T.textPrimary }}>{t.name}</span>\n {t.description !== undefined && (\n <span style={{ color: T.textMuted }}> — {t.description}</span>\n )}\n </div>\n ))}\n </div>\n )}\n </Section>\n\n <Section title=\"what the skills injected\" count={hop.skillInjections.length}>\n {hop.skillInjections.length === 0 ? (\n <Absent>No skill contributed to this call's prompt.</Absent>\n ) : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>\n {hop.skillInjections.map((inj, i) => (\n <div key={`${inj.slot}-${inj.skillId ?? i}`}>\n <div style={{ fontSize: 10, color: T.textMuted, fontFamily: T.fontMono }}>\n {inj.slot}\n {inj.skillId !== undefined ? ` · ${inj.skillId}` : ''}\n </div>\n <div style={{ fontSize: 11.5, color: T.textSecondary }}>\n {inj.text ?? inj.summary}\n </div>\n {inj.text === undefined && inj.summary !== '' && (\n <div style={{ fontSize: 10, color: T.textMuted }}>\n (summary only — this recording did not capture the full text)\n </div>\n )}\n </div>\n ))}\n </div>\n )}\n </Section>\n\n <Section\n title=\"engineered context on the call\"\n count={frameContext?.injections.length ?? 0}\n >\n {frameContext === undefined ? (\n <Absent>\n No step graph was supplied, so this beat could not be paired with the call it\n prepared. The skill-sourced injections above come from the routing events themselves.\n </Absent>\n ) : !frameContext.paired ? (\n <Absent>\n No LLM call was recorded after this stop — the run ended here, or the call was not\n captured.\n </Absent>\n ) : frameContext.injections.length === 0 ? (\n <Absent>\n The call carried {frameContext.totalInjections} injection\n {frameContext.totalInjections === 1 ? '' : 's'}, all of them baseline (the user\n message, tool results, the static prompt and tool registry) — none engineered.\n </Absent>\n ) : (\n <>\n <div style={{ fontSize: 10, color: T.textMuted, marginBottom: 4 }}>\n {frameContext.injections.length} of {frameContext.totalInjections} injections were\n engineered\n {frameContext.stepRuntimeStageId !== undefined\n ? ` · ${frameContext.stepRuntimeStageId}`\n : ''}\n </div>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>\n {frameContext.injections.map((inj, i) => (\n <span\n key={`${inj.source}-${inj.slot}-${i}`}\n title={inj.contentSummary}\n style={{\n padding: '2px 6px',\n borderRadius: 6,\n border: `1px solid ${T.border}`,\n background: T.bgSecondary,\n fontFamily: T.fontMono,\n fontSize: 10,\n color: T.textSecondary,\n }}\n >\n {inj.source} · {inj.slot}\n </span>\n ))}\n </div>\n </>\n )}\n </Section>\n\n {hop.evidence !== undefined && (\n <Section title=\"evidence gate\" count={hop.evidence.unsupported.length}>\n <div style={{ fontSize: 11.5, color: T.textSecondary }}>\n verdict {hop.evidence.action ?? '—'}\n {hop.evidence.posture !== undefined ? ` · posture ${hop.evidence.posture}` : ''}\n {hop.evidence.evidenceTruncated === true\n ? ' · the evidence index hit its ceiling, so this verdict judged a partial corpus'\n : ''}\n </div>\n {hop.evidence.unsupported.map((u, i) => (\n <div key={i} style={{ fontSize: 11, color: T.warning }}>\n unsupported: {u.value}\n {u.shape !== undefined ? ` (${u.shape})` : ''}\n </div>\n ))}\n </Section>\n )}\n\n {(!promptOnRecord || !reachableAsData) && (\n <div\n data-testid=\"frame-absence\"\n style={{\n marginTop: 12,\n padding: '8px 10px',\n borderRadius: 8,\n border: `1px dashed ${T.border}`,\n background: T.bgSecondary,\n fontSize: 11,\n lineHeight: 1.45,\n color: T.textMuted,\n }}\n >\n <strong style={{ color: T.textSecondary }}>Not in this recording.</strong>\n {!promptOnRecord && (\n <>\n {' '}\n The system prompt as one assembled string is not recorded — the injections above\n are the pieces it was composed from. Recording the assembled prompt is an explicit\n opt-in (<code>recordSystemPrompt: true</code>); the default keeps it out of every\n recording, because it carries everything injected into it.\n </>\n )}\n {!reachableAsData && (\n <>\n {' '}\n The reachable set is not recorded as data in this era's recording: it appears\n as prose inside <code>read_skill</code>'s description, and as a typed list\n only when the gate refused a pick.\n </>\n )}{' '}\n Nothing absent is reconstructed here.\n </div>\n )}\n </div>\n );\n}\n\nconst panelStyle: React.CSSProperties = {\n height: '100%',\n overflow: 'auto',\n padding: 12,\n boxSizing: 'border-box',\n background: T.bgPrimary,\n color: T.textPrimary,\n fontFamily: T.fontSans,\n};\n\nfunction Header({ title, subtitle }: { title: string; subtitle: string }): React.ReactElement {\n return (\n <div style={{ marginBottom: 10 }}>\n <div style={{ fontSize: 13, fontWeight: 650 }}>{title}</div>\n <div style={{ fontSize: 11, color: T.textMuted }}>{subtitle}</div>\n </div>\n );\n}\n\nfunction Section({\n title,\n count,\n children,\n}: {\n title: string;\n count: number;\n children: React.ReactNode;\n}): React.ReactElement {\n return (\n <section style={{ marginTop: 10, borderTop: `1px solid ${T.border}`, paddingTop: 8 }}>\n <div\n style={{\n display: 'flex',\n alignItems: 'baseline',\n justifyContent: 'space-between',\n marginBottom: 5,\n }}\n >\n <span\n style={{\n fontSize: 10,\n letterSpacing: '0.08em',\n textTransform: 'uppercase',\n color: T.textMuted,\n }}\n >\n {title}\n </span>\n <span style={{ fontSize: 10, color: T.textMuted, fontFamily: T.fontMono }}>{count}</span>\n </div>\n {children}\n </section>\n );\n}\n\nfunction Mono({ children, testId }: { children: string; testId?: string }): React.ReactElement {\n return (\n <pre\n data-testid={testId}\n style={{\n margin: 0,\n padding: 8,\n borderRadius: 6,\n background: T.bgSecondary,\n color: T.textSecondary,\n fontFamily: T.fontMono,\n fontSize: 11,\n lineHeight: 1.45,\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n maxHeight: 220,\n overflow: 'auto',\n }}\n >\n {children}\n </pre>\n );\n}\n\nfunction Absent({ children }: { children: React.ReactNode }): React.ReactElement {\n return <p style={{ margin: 0, fontSize: 11.5, color: T.textMuted }}>{children}</p>;\n}\n","/**\n * <NarrativeRail> — the product lens: the run's story, revealed with time.\n *\n * Every sentence here is the LIBRARY'S — `humanizeCursorMove`,\n * `humanizeSkillRejected`, `humanizeRouteConflict`, `humanizeTurnRouted`, the\n * same builders `defaultHumanizer` composes for the Commentary panel — carried\n * onto the beats by `selectSkillBeats`. This component chooses which of them\n * are visible and which one is emphasized; it writes none of them. That rule\n * is what keeps the product lens honest: a reader who switches to the\n * developer lens sees the same facts, not a different story.\n *\n * ACCUMULATION is the whole design. Beats up to the cursor stay on screen, in\n * order, dimmed; the beat at the cursor is emphasized; beats after it are\n * hidden, because a story that shows its ending has stopped being a replay.\n * Scrub back and the later paragraphs disappear again — the rail is a pure\n * function of the ONE cursor, and holds no position of its own.\n */\n\nimport React, { useEffect, useRef } from 'react';\n\nimport type { SkillBeat } from '../../core/selectors/selectSkillBeats.js';\nimport { T } from '../theme/index.js';\n\nexport interface NarrativeRailProps {\n readonly beats: readonly SkillBeat[];\n /** Index of the beat the cursor resolves to; `undefined` = before the first. */\n readonly activeIndex?: number;\n /** Move THE cursor — clicking a paragraph returns to that moment. */\n readonly onJumpTo?: (runtimeStageId: string) => void;\n}\n\nexport function NarrativeRail({\n beats,\n activeIndex,\n onJumpTo,\n}: NarrativeRailProps): React.ReactElement {\n const activeRef = useRef<HTMLLIElement>(null);\n useEffect(() => {\n // Feature-detected, not assumed: jsdom (and any non-browser renderer)\n // ships elements without it, and a rail that throws while scrolling has\n // taken the whole view down over a nicety.\n const el = activeRef.current;\n if (el !== null && typeof el.scrollIntoView === 'function') {\n el.scrollIntoView({ block: 'nearest' });\n }\n }, [activeIndex]);\n\n const shown = activeIndex === undefined ? [] : beats.slice(0, activeIndex + 1);\n\n return (\n <div\n data-testid=\"narrative-rail\"\n style={{\n height: '100%',\n overflow: 'auto',\n padding: 14,\n boxSizing: 'border-box',\n background: T.bgPrimary,\n color: T.textPrimary,\n fontFamily: T.fontSans,\n }}\n >\n <div style={{ fontSize: 13, fontWeight: 650 }}>What the assistant did, so far</div>\n <div style={{ fontSize: 11, color: T.textMuted, marginTop: 2 }}>\n {shown.length === 0\n ? 'The story starts at the first stop — move the cursor forward.'\n : `${shown.length} of ${beats.length} step${beats.length === 1 ? '' : 's'} so far`}\n </div>\n\n <ol style={{ listStyle: 'none', margin: '12px 0 0', padding: 0 }}>\n {shown.map((b, i) => {\n const isNewest = i === shown.length - 1;\n return (\n <li\n key={`${b.turnIndex}:${b.iteration}`}\n ref={isNewest ? activeRef : undefined}\n data-testid={`narrative-beat-${i}`}\n data-newest={isNewest ? 'true' : 'false'}\n style={{\n position: 'relative',\n paddingLeft: 16,\n paddingBottom: 12,\n opacity: isNewest ? 1 : 0.62,\n transition: 'opacity 160ms',\n }}\n >\n <span\n aria-hidden\n style={{\n position: 'absolute',\n left: 0,\n top: 5,\n width: 8,\n height: 8,\n borderRadius: '50%',\n background: isNewest ? T.primary : T.textMuted,\n }}\n />\n {i < shown.length - 1 && (\n <span\n aria-hidden\n style={{\n position: 'absolute',\n left: 3.5,\n top: 15,\n bottom: 0,\n width: 1,\n background: T.border,\n }}\n />\n )}\n <button\n type=\"button\"\n onClick={() => {\n if (b.runtimeStageId !== undefined) onJumpTo?.(b.runtimeStageId);\n }}\n disabled={b.runtimeStageId === undefined}\n style={{\n display: 'block',\n width: '100%',\n textAlign: 'left',\n border: 'none',\n background: 'transparent',\n padding: 0,\n color: 'inherit',\n cursor: b.runtimeStageId !== undefined ? 'pointer' : 'default',\n font: 'inherit',\n }}\n >\n <div\n style={{\n fontSize: 10,\n letterSpacing: '0.06em',\n textTransform: 'uppercase',\n color: T.textMuted,\n }}\n >\n {b.label}\n {b.cursorSkillId !== undefined ? ` · ${b.cursorSkillId}` : ''}\n </div>\n <div\n style={{\n marginTop: 3,\n fontSize: isNewest ? 13.5 : 12.5,\n lineHeight: 1.5,\n fontWeight: isNewest ? 600 : 400,\n color: isNewest ? T.textPrimary : T.textSecondary,\n }}\n >\n {b.headline}\n </div>\n {b.notes.map((n, ni) => (\n <div\n key={ni}\n style={{\n marginTop: 4,\n fontSize: 12,\n lineHeight: 1.45,\n color: b.refusedIds.length > 0 && ni === 0 ? T.error : T.textSecondary,\n }}\n >\n {n}\n </div>\n ))}\n </button>\n </li>\n );\n })}\n </ol>\n </div>\n );\n}\n","/**\n * <RouteDecisionCard> — why the cursor is where it is, on the beat being shown.\n *\n * The card is the answer to one question (\"what moved it, and on what\n * evidence\") and it is built only from the hop's own fields: the cause, the\n * library's sentence for it, the witness the rule matched on, and every\n * refusal / conflict / superseded pick stamped on the same iteration. Nothing\n * here is inferred from neighbouring beats — the one exception is a refusal's\n * `cursorAfter`, which the FOLD correlated (the refusal and its consequence\n * are stamped an iteration apart) and which is rendered as what it is: the\n * next iteration's cursor row.\n */\n\nimport React from 'react';\n\nimport type { SkillBeat } from '../../core/selectors/selectSkillBeats.js';\nimport type { SkillTurnStart } from '../../core/selectors/selectSkillRoute.js';\nimport { T } from '../theme/index.js';\nimport type { SkillLens } from './lens.js';\n\n/** What each cause is called for a reader who does not know the vocabulary. */\nconst CAUSE_LABEL: Record<string, string> = {\n entry: 'a start rule matched',\n route: \"the author's edge fired\",\n 'model-pick': 'the model picked it',\n 'tool-proposal': 'a tool proposed it',\n intent: 'the message was scored',\n continuity: 'the conversation carried on',\n decider: 'a separate chooser settled it',\n stay: 'nothing moved it',\n none: 'no skill was in play',\n};\n\nexport interface RouteDecisionCardProps {\n readonly beat?: SkillBeat;\n /**\n * The routing verdict for THIS beat's turn, joined by `turnIndex` — the one\n * field both types carry, so the correlation is a real key rather than a\n * guess about adjacency.\n *\n * Present only to show the SCORES. Tier 1 renders its witness (the substring\n * a rule matched); tier 2 had no equivalent, so a scored route announced that\n * it happened and never said with what numbers — the one kind of routing a\n * reader cannot work out for themselves.\n */\n readonly turnStart?: SkillTurnStart;\n readonly lens: SkillLens;\n}\n\nexport function RouteDecisionCard({ beat, turnStart, lens }: RouteDecisionCardProps): React.ReactElement {\n return (\n <aside\n data-testid=\"route-decision-card\"\n aria-live=\"polite\"\n style={{\n padding: '10px 12px',\n borderTop: `1px solid ${T.border}`,\n background: T.bgPrimary,\n fontFamily: T.fontSans,\n color: T.textPrimary,\n maxHeight: 210,\n overflow: 'auto',\n }}\n >\n {beat === undefined ? (\n <p style={{ margin: 0, fontSize: 12, color: T.textMuted }}>\n The cursor is before this run's first routing stop — nothing has been decided yet.\n </p>\n ) : (\n <>\n <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, flexWrap: 'wrap' }}>\n <span\n style={{\n fontSize: 10,\n letterSpacing: '0.08em',\n textTransform: 'uppercase',\n color: T.textMuted,\n }}\n >\n {beat.moved ? 'Why it moved' : 'Why it stayed'}\n </span>\n <strong style={{ fontSize: 13 }}>\n {beat.hop.from !== undefined ? `${beat.hop.from} → ` : ''}\n {beat.hop.to ?? '—'}\n </strong>\n {beat.cause !== undefined && (\n <span\n data-testid=\"route-cause\"\n style={{\n padding: '2px 6px',\n borderRadius: 6,\n border: `1px solid ${T.border}`,\n background: T.bgSecondary,\n fontFamily: lens === 'developer' ? T.fontMono : T.fontSans,\n fontSize: 10,\n color: T.textSecondary,\n }}\n >\n {lens === 'developer' ? beat.cause : (CAUSE_LABEL[beat.cause] ?? beat.cause)}\n </span>\n )}\n </div>\n\n <p style={{ margin: '6px 0 0', fontSize: 12.5, lineHeight: 1.45, color: T.textSecondary }}>\n {beat.headline}\n </p>\n\n {beat.hop.witness !== undefined && (\n <Evidence label=\"the message said\">\n “{beat.hop.witness.text}”\n {beat.hop.witness.keyword !== undefined && (\n <span style={{ color: T.textMuted }}> — matched on “{beat.hop.witness.keyword}”</span>\n )}\n </Evidence>\n )}\n\n {beat.reachable !== undefined && (\n <Evidence label={`reachable (${beat.reachable.source})`}>\n {beat.reachable.ids.length > 0\n ? beat.reachable.ids.join(', ')\n : 'none — a dead end: no skill was admissible from this cursor'}\n </Evidence>\n )}\n\n {beat.hop.offered !== undefined && (\n <Evidence label=\"menu offered\">{beat.hop.offered.join(', ')}</Evidence>\n )}\n\n {beat.hop.refusals.map((r, i) => (\n <div\n key={`${r.requestedId}-${i}`}\n data-testid=\"route-refusal\"\n style={{\n marginTop: 8,\n padding: '8px 10px',\n borderRadius: 8,\n border: `1px solid ${T.error}`,\n background: T.bgSecondary,\n }}\n >\n <div style={{ fontSize: 11.5, color: T.error, fontWeight: 600 }}>\n refused: read_skill(“{r.requestedId}”)\n {r.posture !== undefined && (\n <span style={{ color: T.textMuted, fontWeight: 400 }}> · posture {r.posture}</span>\n )}\n </div>\n {r.allowed.length > 0 && (\n <Evidence label=\"reachable instead\">{r.allowed.join(', ')}</Evidence>\n )}\n {r.refusalText !== undefined ? (\n <pre\n style={{\n margin: '6px 0 0',\n padding: 8,\n borderRadius: 6,\n background: T.bgPrimary,\n color: T.textSecondary,\n fontFamily: T.fontMono,\n fontSize: 11,\n lineHeight: 1.4,\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n }}\n >\n {r.refusalText}\n </pre>\n ) : (\n <p style={{ margin: '6px 0 0', fontSize: 11, color: T.textMuted }}>\n The sentence the model read back is not in this recording (no tool result was\n paired with the refused call).\n </p>\n )}\n {r.cursorAfter !== undefined ? (\n <p style={{ margin: '6px 0 0', fontSize: 11, color: T.textSecondary }}>\n Next iteration ({r.cursorAfter.iteration}):{' '}\n {r.cursorAfter.moved\n ? `the cursor moved to \"${r.cursorAfter.to ?? '—'}\" (${r.cursorAfter.by ?? '—'}).`\n : `the cursor did not move (${r.cursorAfter.by ?? '—'}).`}\n </p>\n ) : (\n <p style={{ margin: '6px 0 0', fontSize: 11, color: T.textMuted }}>\n The run ended on this iteration — no later cursor row exists to say what the\n refusal led to.\n </p>\n )}\n </div>\n ))}\n\n {beat.notes.length > 0 && (\n <ul\n data-testid=\"route-notes\"\n style={{\n margin: '8px 0 0',\n paddingLeft: 16,\n fontSize: 11.5,\n lineHeight: 1.45,\n color: T.textSecondary,\n }}\n >\n {beat.notes.map((n, i) => (\n <li key={i}>{n}</li>\n ))}\n </ul>\n )}\n\n {/* Scores, for the tiers that HAVE numbers. `intent` is a scorer win;\n `continuity` carries the losing numbers when it stayed on a\n near-tie. Every other verdict has nothing to show, and shows\n nothing — the house law: render only what the event carries. */}\n {turnStart !== undefined &&\n (turnStart.by === 'intent' || turnStart.by === 'continuity') && (\n <ScoreTable start={turnStart} />\n )}\n\n {lens === 'developer' && beat.runtimeStageId !== undefined && (\n <div style={{ marginTop: 8, fontFamily: T.fontMono, fontSize: 10, color: T.textMuted }}>\n {beat.runtimeStageId}\n </div>\n )}\n </>\n )}\n </aside>\n );\n}\n\nfunction Evidence({\n label,\n children,\n}: {\n label: string;\n children: React.ReactNode;\n}): React.ReactElement {\n return (\n <div style={{ marginTop: 6, fontSize: 11.5, color: T.textSecondary }}>\n <span\n style={{\n marginRight: 6,\n fontFamily: T.fontMono,\n fontSize: 10,\n color: T.textMuted,\n }}\n >\n {label}\n </span>\n {children}\n </div>\n );\n}\n\n/**\n * The scores a tier-2 route was decided by — every candidate, losers included.\n *\n * Why the losers are the point: a floor is a number you set by looking at what\n * real messages score, and a near-tie is only visible next to what it nearly\n * tied with. A winner alone tells a reader nothing they can act on.\n *\n * ONE LIMIT, and it is not recoverable from this data: a candidate scored 0\n * because a scorer gated it out (wrong product, say) and one scored 0 because\n * its overlap was genuinely low are the same number here. If a scorer ever\n * carries its own reason on `witness`, that is where the distinction would come\n * from — until then this renders the number and declines to interpret it.\n */\nfunction ScoreTable({ start }: { readonly start: SkillTurnStart }): React.ReactElement | null {\n if (start.scores.length === 0) return null;\n const floor = start.policy?.floor;\n const margin = start.policy?.nearTieMargin;\n\n return (\n <div style={{ marginTop: 8 }}>\n <div\n style={{\n fontSize: 10,\n letterSpacing: '0.08em',\n textTransform: 'uppercase',\n color: T.textMuted,\n marginBottom: 4,\n }}\n >\n Scored{start.scorer ? ` by ${start.scorer}` : ''}\n {floor !== undefined ? ` · floor ${floor}` : ''}\n {start.runnerUp !== undefined && margin !== undefined\n ? ` · gap ${fmt(start.runnerUp.gap)} of ${margin} needed`\n : ''}\n </div>\n <table\n style={{ borderCollapse: 'collapse', width: '100%', fontSize: 12 }}\n >\n <caption\n style={{\n captionSide: 'top',\n textAlign: 'left',\n fontSize: 11,\n color: T.textMuted,\n paddingBottom: 3,\n }}\n >\n Every candidate this turn was scored against, best first.\n </caption>\n <tbody>\n {start.scores.map((row) => {\n const belowFloor = floor !== undefined && row.score <= floor;\n const won = row.id === start.to;\n return (\n <tr key={row.id}>\n <td\n style={{\n padding: '2px 6px 2px 0',\n color: belowFloor ? T.textMuted : T.textPrimary,\n fontWeight: won ? 700 : 400,\n fontFamily: T.fontMono,\n }}\n >\n {won ? '→ ' : ' '}\n {row.id}\n </td>\n <td\n style={{\n padding: '2px 6px',\n textAlign: 'right',\n fontFamily: T.fontMono,\n color: belowFloor ? T.textMuted : T.textPrimary,\n }}\n >\n {fmt(row.score)}\n </td>\n <td\n style={{\n padding: '2px 6px',\n textAlign: 'right',\n fontFamily: T.fontMono,\n color: T.textMuted,\n }}\n >\n {Math.round(row.relevance * 100)}%\n </td>\n <td style={{ padding: '2px 0 2px 6px', color: T.textMuted, fontSize: 11 }}>\n {/* \"did not match at all\" and \"was beaten\" are different facts.\n Stated in words, not by colour alone. */}\n {belowFloor ? 'below floor' : won ? '' : 'beaten'}\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n );\n}\n\n/** Three decimals, trailing zeros trimmed — a raw score, not a percentage. */\nfunction fmt(n: number): string {\n return String(Math.round(n * 1000) / 1000);\n}\n","/**\n * skillTopologyPositions — where each skill sits on the debugger's canvas.\n *\n * Pure + framework-free, and deliberately NOT a second layout engine: it feeds\n * the ids and endpoints to `layoutSkillGraph` (the dagre pass `<SkillGraphFlow>`\n * already ships) and keeps only the node positions. The debugger draws its own\n * edges — declared and observed are different lines with different meanings,\n * and that distinction does not survive a generic edge list.\n *\n * Stability matters more than beauty here: the canvas re-renders on every\n * cursor move, so the layout must depend ONLY on the graph's shape (ids +\n * endpoints), never on which node is current. A layout that shifts when the\n * reader scrubs is a layout that cannot be read.\n */\n\nimport { layoutSkillGraph, sizeFor } from '../skillGraphFlowLayout.js';\n\n/** The endpoints a layout needs — a structural subset of `SkillTopologyEdge`. */\nexport interface TopologyEdgeEndpoints {\n readonly from: string;\n readonly to: string;\n}\n\nexport interface SkillNodePosition {\n readonly id: string;\n /** Top-left, in xyflow's coordinate space. */\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n}\n\n/**\n * Lay the skills out top-to-bottom by routing depth — the same direction\n * `<SkillGraphFlow>` draws a declared graph in, so the two views of one graph\n * do not read as two different graphs.\n *\n * `nodeIds` is the authority on WHICH nodes exist — an edge naming an unknown\n * endpoint is skipped rather than conjuring a node, and a node with no edges\n * still gets a position (an unreached skill is part of the graph).\n *\n * @example\n * ```ts\n * const pos = skillTopologyPositions(['a', 'b'], [{ from: 'a', to: 'b' }]);\n * pos.get('b')!.y > pos.get('a')!.y; // laid out in flow order\n * ```\n */\nexport function skillTopologyPositions(\n nodeIds: readonly string[],\n edges: readonly TopologyEdgeEndpoints[],\n): ReadonlyMap<string, SkillNodePosition> {\n const known = new Set(nodeIds);\n const laid = layoutSkillGraph(\n {\n nodes: nodeIds.map((id) => ({ id, kind: 'skill' as const })),\n edges: edges\n .filter((e) => known.has(e.from) && known.has(e.to) && e.from !== e.to)\n .map((e) => ({ from: e.from, to: e.to })),\n },\n { showStart: false, rankSep: 96, nodeSep: 28 },\n );\n\n const out = new Map<string, SkillNodePosition>();\n for (const n of laid.nodes) {\n out.set(n.id, { id: n.id, x: n.x, y: n.y, width: n.width, height: n.height });\n }\n // A node dagre never placed (it appeared only after the graph was built)\n // still needs a spot rather than stacking at the origin.\n let spare = 0;\n for (const id of nodeIds) {\n if (out.has(id)) continue;\n const { width, height } = sizeFor('skill');\n out.set(id, { id, x: -(width + 40), y: spare * (height + 24), width, height });\n spare += 1;\n }\n return out;\n}\n","/**\n * <SkillTopologyCanvas> — the skill graph with the run's cursor on it.\n *\n * Draws what {@link selectSkillTopology} resolved and decides nothing itself:\n * node states, edge origins and the active hop all arrive computed. Two things\n * it is careful about, because both are places a debugger can lie:\n *\n * DECLARED vs OBSERVED — an author's edge and a hop the model took are\n * drawn differently and named in the legend. An observed edge with no\n * declared twin is the finding, not a rendering detail.\n *\n * PARTIAL DECLARATIONS — when the declared set is only `routing[]`'s fired\n * edges, it is a lower bound, and the canvas says so under the legend\n * rather than implying the author drew only what ran. When the recording\n * carries the author's whole map (`skill.graph_declared`, 9.50.0) — or the\n * caller passed the built graph — the warning does NOT show, because it\n * would then be the lie.\n *\n * Clicking a node FILTERS THE ONE CURSOR to that skill's next span. It never\n * holds a selection of its own — what is highlighted is a function of the\n * cursor, so the canvas and the strip cannot disagree.\n */\n\nimport React, { useMemo } from 'react';\nimport {\n ReactFlow,\n ReactFlowProvider,\n Background,\n Handle,\n Position,\n MarkerType,\n type Edge,\n type Node,\n type NodeProps,\n type NodeTypes,\n} from '@xyflow/react';\nimport '@xyflow/react/dist/style.css';\n\nimport type { SkillNodeState, SkillTopology } from '../../core/selectors/selectSkillTopology.js';\nimport { T } from '../theme/index.js';\nimport { skillTopologyPositions } from './skillTopologyPositions.js';\nimport type { SkillLens } from './lens.js';\n\n/** Per-state paint + the two legends. Product wording is the SAME state, said\n * for a reader who has never seen a cursor — never a different state. */\nconst STATE_STYLE: Record<\n SkillNodeState,\n { color: string; developer: string; product: string; dim: number }\n> = {\n current: { color: T.primary, developer: 'current', product: 'reading now', dim: 1 },\n refused: { color: T.error, developer: 'refused here', product: 'asked for, not allowed', dim: 1 },\n reachable: { color: T.srcSkill, developer: 'reachable', product: 'can open next', dim: 1 },\n visited: { color: T.textSecondary, developer: 'visited', product: 'already read', dim: 0.92 },\n idle: { color: T.textMuted, developer: 'not entered', product: 'not opened', dim: 0.55 },\n};\n\nconst HANDLE: React.CSSProperties = {\n opacity: 0,\n width: 1,\n height: 1,\n border: 'none',\n background: 'transparent',\n pointerEvents: 'none',\n};\n\ninterface SkillNodeData extends Record<string, unknown> {\n readonly label: string;\n readonly state: SkillNodeState;\n readonly stateLabel: string;\n readonly pickedByModel: boolean;\n readonly jumpable: boolean;\n /** The catalog description, verbatim — shown as the node's tooltip. */\n readonly description?: string;\n /** The declared map's synthetic START points here. */\n readonly isEntry: boolean;\n}\n\nconst SkillStateNode: React.FC<NodeProps> = ({ data }) => {\n const d = data as SkillNodeData;\n const paint = STATE_STYLE[d.state];\n const isCurrent = d.state === 'current';\n return (\n <div\n data-testid={`skill-node-${d.label}`}\n data-state={d.state}\n title={[\n d.description,\n d.jumpable ? `Jump the cursor to \"${d.label}\"` : `The cursor never stood in \"${d.label}\"`,\n ]\n .filter((line) => line !== undefined)\n .join('\\n\\n')}\n style={{\n width: 192,\n minHeight: 56,\n padding: '8px 10px',\n borderRadius: 10,\n boxSizing: 'border-box',\n background: isCurrent ? T.bgTertiary : T.bgSecondary,\n // Longhand, never the `border` shorthand: React warns (and browsers\n // disagree) when a shorthand and one of its longhands are both set,\n // and this node sets `borderStyle` on its own for the reachable state.\n borderWidth: isCurrent ? 2 : 1,\n borderStyle: d.state === 'reachable' ? 'dashed' : 'solid',\n borderColor: paint.color,\n boxShadow: isCurrent ? `0 0 0 3px ${T.primary}33` : 'none',\n opacity: paint.dim,\n color: T.textPrimary,\n fontFamily: T.fontSans,\n cursor: d.jumpable ? 'pointer' : 'default',\n }}\n >\n <Handle type=\"target\" position={Position.Top} style={HANDLE} isConnectable={false} />\n <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>\n <span\n aria-hidden\n style={{ flex: '0 0 auto', width: 8, height: 8, borderRadius: 2, background: paint.color }}\n />\n <span\n style={{\n fontSize: 13,\n fontWeight: 600,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {d.label}\n </span>\n </div>\n <div\n style={{\n marginTop: 4,\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n fontSize: 10,\n color: paint.color,\n letterSpacing: '0.04em',\n textTransform: 'uppercase',\n }}\n >\n <span>{d.stateLabel}</span>\n {d.isEntry && (\n <span\n style={{\n padding: '1px 5px',\n borderRadius: 5,\n background: `${T.bgPrimary}`,\n border: `1px solid ${T.textMuted}`,\n color: T.textMuted,\n textTransform: 'none',\n letterSpacing: 0,\n }}\n >\n entry\n </span>\n )}\n {d.pickedByModel && (\n <span\n style={{\n padding: '1px 5px',\n borderRadius: 5,\n background: `${T.bgPrimary}`,\n border: `1px solid ${T.srcSkill}`,\n color: T.srcSkill,\n textTransform: 'none',\n letterSpacing: 0,\n }}\n >\n model's pick\n </span>\n )}\n </div>\n <Handle type=\"source\" position={Position.Bottom} style={HANDLE} isConnectable={false} />\n </div>\n );\n};\n\nconst NODE_TYPES: NodeTypes = { sgdSkill: SkillStateNode };\n\nexport interface SkillTopologyCanvasProps {\n readonly topology: SkillTopology;\n readonly lens: SkillLens;\n /** Fired when a node is clicked and the cursor CAN go there. */\n readonly onPickSkill?: (skillId: string) => void;\n /** Skills the cursor stood in at some beat — the only clickable ones. */\n readonly jumpable: ReadonlySet<string>;\n}\n\nexport function SkillTopologyCanvas({\n topology,\n lens,\n onPickSkill,\n jumpable,\n}: SkillTopologyCanvasProps): React.ReactElement {\n // Positions depend on the graph's SHAPE only, so scrubbing never re-lays it out.\n const positions = useMemo(\n () =>\n skillTopologyPositions(\n topology.nodes.map((n) => n.id),\n topology.edges,\n ),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n topology.nodes.map((n) => n.id).join('|'),\n topology.edges.map((e) => e.id).join('|'),\n ],\n );\n\n const rfNodes = useMemo<Node[]>(\n () =>\n topology.nodes.map((n) => {\n const p = positions.get(n.id);\n return {\n id: n.id,\n type: 'sgdSkill',\n position: { x: p?.x ?? 0, y: p?.y ?? 0 },\n draggable: false,\n selectable: true,\n data: {\n label: n.label ?? n.id,\n state: n.state,\n stateLabel: lens === 'product' ? STATE_STYLE[n.state].product : STATE_STYLE[n.state].developer,\n pickedByModel: n.pickedByModel,\n jumpable: jumpable.has(n.id),\n ...(n.description !== undefined ? { description: n.description } : {}),\n isEntry: n.isEntry,\n } satisfies SkillNodeData,\n };\n }),\n [topology.nodes, positions, lens, jumpable],\n );\n\n const rfEdges = useMemo<Edge[]>(\n () =>\n topology.edges.map((e) => {\n const color = e.active ? T.primary : e.observed ? T.srcSkill : T.edgeDefault;\n return {\n id: e.id,\n source: e.from,\n target: e.to,\n // NOT `animated`: xyflow animates an edge by MARCHING DASHES, which\n // is the exact stroke this canvas reserves for \"the run took it, the\n // record never declared it\". The active hop is said with weight and\n // colour instead, so one visual means one thing.\n animated: false,\n label: e.label ?? (lens === 'developer' ? e.triggerKind : undefined),\n style: {\n stroke: color,\n strokeWidth: e.active ? 3 : 1.5,\n // An edge the run took but the record never declared is the one a\n // reader must not mistake for the author's own line.\n strokeDasharray: e.observed && !e.declared ? '5 4' : undefined,\n },\n labelStyle: { fill: T.textMuted, fontFamily: T.fontSans, fontSize: 10 },\n labelBgStyle: { fill: T.bgPrimary, fillOpacity: 0.85 },\n markerEnd: { type: MarkerType.ArrowClosed, color, width: 14, height: 14 },\n };\n }),\n [topology.edges, lens],\n );\n\n return (\n <div\n style={{ display: 'flex', flexDirection: 'column', height: '100%', minHeight: 0 }}\n data-testid=\"skill-topology\"\n >\n <div style={{ flex: 1, minHeight: 0, position: 'relative' }}>\n <ReactFlowProvider>\n <ReactFlow\n nodes={rfNodes}\n edges={rfEdges}\n nodeTypes={NODE_TYPES}\n onNodeClick={(_, node) => {\n if (jumpable.has(node.id)) onPickSkill?.(node.id);\n }}\n nodesDraggable={false}\n nodesConnectable={false}\n fitView\n fitViewOptions={{ padding: 0.18 }}\n minZoom={0.1}\n maxZoom={1.5}\n proOptions={{ hideAttribution: true }}\n >\n <Background color={T.border} gap={20} />\n </ReactFlow>\n </ReactFlowProvider>\n </div>\n <Legend topology={topology} lens={lens} />\n </div>\n );\n}\n\nfunction Legend({\n topology,\n lens,\n}: {\n topology: SkillTopology;\n lens: SkillLens;\n}): React.ReactElement {\n const states: SkillNodeState[] = ['current', 'reachable', 'visited', 'refused', 'idle'];\n return (\n <div\n data-testid=\"skill-topology-legend\"\n style={{\n flex: '0 0 auto',\n display: 'flex',\n alignItems: 'flex-start',\n gap: 14,\n flexWrap: 'wrap',\n padding: '6px 10px',\n borderTop: `1px solid ${T.border}`,\n background: T.bgPrimary,\n fontFamily: T.fontSans,\n fontSize: 10,\n color: T.textSecondary,\n }}\n >\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '4px 10px' }}>\n {states.map((s) => (\n <span key={s} style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>\n <span\n aria-hidden\n style={{\n width: 8,\n height: 8,\n borderRadius: 2,\n background: STATE_STYLE[s].color,\n }}\n />\n {lens === 'product' ? STATE_STYLE[s].product : STATE_STYLE[s].developer}\n </span>\n ))}\n </div>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '4px 10px' }}>\n <span>— solid: an edge the author declared</span>\n <span>┄ dashed: a hop the run took, never declared on the record</span>\n </div>\n {topology.declaredSource === 'recording-declared' && (\n <div\n data-testid=\"declared-complete-note\"\n style={{ flex: '1 1 100%', color: T.textMuted, lineHeight: 1.35 }}\n >\n The author's complete declared map — this recording carries it\n (skill.graph_declared).\n </div>\n )}\n {!topology.declaredComplete && (\n <div style={{ flex: '1 1 100%', color: T.warning, lineHeight: 1.35 }}>\n {topology.declaredSource === 'recording'\n ? 'Declared edges shown are only the ones this recording named — a recording names an edge once it fires, so the author may have drawn more.'\n : 'This recording named no declared edges; every line here is a hop that was observed.'}\n </div>\n )}\n </div>\n );\n}\n","/**\n * <SkillGraphDebugger> — the skill graph, with the run replayed across it.\n *\n * <SkillGraphDebugger\n * recorder={recorder}\n * cursorRuntimeStageId={cursor}\n * onJumpTo={(id) => moveTheLensCursorTo(id)}\n * />\n *\n * `<SkillGraphFlow>` draws the graph an author BUILT. This draws the graph a\n * run WALKED: the declared topology with the run's cursor on it, why the\n * cursor moved at each stop, what the model was looking at when it decided,\n * and the same run told as a story that reveals with time.\n *\n * ONE CURSOR, ONE TRANSPORT — the transport under the beat rail is\n * `<TimeTravel>`, the component `<Lens>` itself mounts, not a lookalike. Pass\n * `step` / `totalSteps` / `onStepChange` (the `<Lens>` grammar) and it scrubs\n * the host's own axis with the host's own numbers; omit them and it scrubs\n * this view's routing stops. Either way it is the shipped slider.\n *\n * SHARING AN AXIS IS NOT SHARING A STRIDE. The host's axis is the RUN's: a\n * four-tool turn puts 73 stops on it, and this view changes at eight. Pass\n * `snapSteps` — the steps this view's picture changes at, in the host's own\n * numbers — and ◀ ▶ walk those instead of walking framework stages that change\n * nothing here. The cursor, the axis and the numbers all stay the host's; the\n * slider still reaches every position; only the step buttons' landing set\n * narrows, and the readout says when the cursor is standing between two stops.\n *\n * THE ONE-CURSOR LAW — the rule this component is shaped by. The lens has one\n * time cursor (`memory/lens_v0_1_one_cursor_architecture.md`), and this view\n * SCRUBS AND FILTERS it. It holds no position: the beat being shown is\n * resolved from `cursorRuntimeStageId` on every render by `selectSkillBeatAt`,\n * and every mover here — the transport, a beat, a narrative paragraph, a click\n * on a skill node — reports a `runtimeStageId` through `onJumpTo` and waits to\n * be told where the cursor went. Give it a cursor that never moves and the\n * view never moves, which is the correct behaviour for a controlled component\n * whose owner ignored it.\n *\n * WIRED INTO `<Lens>`: mount it in the detail slot and forward the props the\n * slot already hands you — that is the whole integration.\n *\n * // The host holds ONE navigator, on <Lens> — this view owns no axis, so it\n * // reports an ADDRESS and lets the cursor's owner resolve it.\n * const nav = useRef<LensNavigator>(null);\n *\n * const detail = (p: LensDetailSlotProps) => (\n * <SkillGraphDebugger\n * recorder={p.recorder}\n * cursorRuntimeStageId={p.cursorRuntimeStageId}\n * cursorKind={p.kind}\n * step={p.step}\n * totalSteps={p.totalSteps}\n * onStepChange={p.onNavigate}\n * onJumpTo={(id) => nav.current?.navigateTo(id)}\n * />\n * );\n * <Lens recorder={recorder} navigatorRef={nav} slots={{ detail }} />\n *\n * `navigateTo` hands back `{ ok: false, nearest }` when the host's ruler has\n * no stop for that beat, so the host can OFFER the nearest earlier stop\n * instead of jumping somewhere the person did not ask for. (The older\n * `stepForRuntimeStageId(positions, id)` + `p.onNavigate(step)` wiring still\n * works and is still supported — it simply takes that offer silently.)\n *\n * The two lenses are one data path (see `./lens.ts`): the developer lens shows\n * the record, the product lens shows the library's sentences for the same\n * record, accumulated to the cursor. Neither can show a fact the other cannot.\n */\n\nimport React, { useMemo, useRef, useState } from 'react';\n\nimport type { LensRecorder } from '../../core/LensRecorder.js';\nimport {\n selectSkillBeatAt,\n selectSkillBeats,\n type SkillBeat,\n} from '../../core/selectors/selectSkillBeats.js';\nimport { selectSkillFrameContext } from '../../core/selectors/selectSkillFrameContext.js';\nimport { selectSkillRoute, type SkillRoute } from '../../core/selectors/selectSkillRoute.js';\nimport {\n selectSkillTopology,\n type DeclaredEdgeInput,\n} from '../../core/selectors/selectSkillTopology.js';\nimport { DoorRefusalCard } from '../../doors/DoorRefusalCard.js';\nimport {\n REFUSAL_GO_TO,\n describeReceived,\n refusalDestinationFor,\n} from '../../doors/recordingInput.js';\nimport { useNarrowRow } from '../narrowLayout.js';\nimport { T } from '../theme/index.js';\nimport { BeatStrip, type BeatTransport } from './BeatStrip.js';\nimport { FrameFactsPanel } from './FrameFactsPanel.js';\nimport { NarrativeRail } from './NarrativeRail.js';\nimport { RouteDecisionCard } from './RouteDecisionCard.js';\nimport { SkillTopologyCanvas } from './SkillTopologyCanvas.js';\nimport type { SkillLens } from './lens.js';\n\n/** Sentence 1 of the door's refusal — what the Skill Graph debugger reads. */\nexport const SKILL_GRAPH_READS =\n 'a replayed recording — the recorder that observeRecording(recording) returns, or a live lensRecorder()';\n\nexport interface SkillGraphDebuggerProps {\n /** The recording. Everything is folded from its event log + step graph. */\n readonly recorder?: LensRecorder;\n /** A pre-folded routing record, for a host that already computed one.\n * Wins over `recorder` for the routing facts; `recorder` is still read for\n * the step graph that pairs a beat with the call it prepared. */\n readonly route?: SkillRoute;\n /** THE cursor — a `runtimeStageId`, the lens's own address space. */\n readonly cursorRuntimeStageId: string;\n /** The kind of stop the cursor is on, when the host knows it (`'group-start'`\n * / `'group-end'` / `'user-in'` / `'user-out'`). Resolves the run's bookends. */\n readonly cursorKind?: string;\n /** Move THE cursor. Without it the view is read-only — every mover still\n * renders, and none of them changes anything. */\n readonly onJumpTo?: (runtimeStageId: string) => void;\n /**\n * The host's cursor on its own step axis — `<Lens step onStepChange>`'s\n * grammar, and the same two numbers. Pass them and the shipped transport\n * (`<TimeTravel>`) scrubs the SAME axis the lens's own transport does, with\n * the same numbers; omit them and it scrubs this view's routing stops.\n *\n * Either way there is one cursor and one transport COMPONENT: this view\n * never re-implements the slider, it mounts the shipped one.\n */\n readonly step?: number;\n readonly totalSteps?: number;\n readonly onStepChange?: (step: number) => void;\n /**\n * SNAP STOPS — the positions on the HOST's axis that ◀ ▶ and ← → may land\n * on. Ascending, in the same units as `step` / `totalSteps`.\n *\n * Why a host needs this: sharing the host's axis is the one-cursor law\n * working correctly, but the host's axis is the RUN's, not this view's. A\n * four-tool turn can put 73 stops on it while the routing picture changes at\n * eight — so scrubbing spends 65 presses walking framework stages that\n * change nothing here. Hand the steps this view actually changes at and the\n * transport walks those; everything else about it is unchanged.\n *\n * The host builds the list, because the host owns the axis — the mapping is\n * `stepForRuntimeStageId(positions, beat.runtimeStageId)` over\n * `selectSkillBeats`, both already exported from this door.\n *\n * IGNORED when this view scrubs its OWN routing stops (no `step` /\n * `totalSteps`): every routing stop already changes the picture, so there is\n * nothing to narrow. Absent ⇒ byte-identical to today.\n *\n * @example\n * ```tsx\n * const beats = selectSkillBeats({ route: selectSkillRoute({ log }) });\n * const snapSteps = [...new Set(beats\n * .map((b) => (b.runtimeStageId !== undefined\n * ? stepForRuntimeStageId(positions, b.runtimeStageId) : -1))\n * .filter((s) => s >= 0))].sort((a, b) => a - b);\n * ```\n */\n readonly snapSteps?: readonly number[];\n /**\n * Whether this view's transport owns ← → Home End. Defaults to `true` when\n * it is the page's only transport and `false` when the host passed its own\n * axis (a hosted view sits beside the host's transport, and two bound\n * transports move the one cursor twice per press).\n */\n readonly transportKeyboard?: boolean;\n /**\n * The author's declared edges, from the BUILT graph\n * (`graph.edges.filter((e) => e.from !== null)`). A recording names an edge\n * only once it fires, so without this the declared topology is a lower\n * bound — and the canvas says so rather than implying otherwise.\n */\n readonly declaredEdges?: readonly DeclaredEdgeInput[];\n /** Controlled lens. */\n readonly lens?: SkillLens;\n /** Uncontrolled initial lens. Ignored when `lens` is set. */\n readonly defaultLens?: SkillLens;\n readonly onLensChange?: (lens: SkillLens) => void;\n readonly height?: number | string;\n readonly className?: string;\n readonly style?: React.CSSProperties;\n}\n\nexport function SkillGraphDebugger({\n recorder,\n route: routeProp,\n cursorRuntimeStageId,\n cursorKind,\n onJumpTo,\n step,\n totalSteps,\n onStepChange,\n snapSteps,\n transportKeyboard,\n declaredEdges,\n lens: lensProp,\n defaultLens = 'developer',\n onLensChange,\n height = '100%',\n className,\n style,\n}: SkillGraphDebuggerProps): React.ReactElement {\n const [internalLens, setInternalLens] = useState<SkillLens>(defaultLens);\n const lens = lensProp ?? internalLens;\n const pickLens = (next: SkillLens): void => {\n if (lensProp === undefined) setInternalLens(next);\n onLensChange?.(next);\n };\n\n const rowRef = useRef<HTMLDivElement>(null);\n const narrow = useNarrowRow(rowRef);\n\n // THE DOOR'S GATE (`agentfootprint-lens/skillgraph`): `recorder` is TYPED\n // LensRecorder — TypeScript consumers fail at build time — but a JS consumer\n // can hand this prop anything. A wrong shape renders the teaching refusal\n // card below (never a crash on `.getVersion()`), and every hook after this\n // line reads the vetted handle so the hook order never changes.\n const recorderRefused =\n recorder !== undefined &&\n (typeof (recorder as { getVersion?: unknown }).getVersion !== 'function' ||\n typeof (recorder as { selectEventLog?: unknown }).selectEventLog !== 'function');\n const vettedRecorder = recorderRefused ? undefined : recorder;\n\n // `getVersion()` is the recorder's monotonic change stamp — the fold reruns\n // when the run advances, and not on every render of a finished one.\n const version = vettedRecorder?.getVersion() ?? 0;\n const route = useMemo(\n () =>\n routeProp ??\n (vettedRecorder !== undefined\n ? selectSkillRoute({ log: vettedRecorder.selectEventLog() })\n : undefined),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [routeProp, vettedRecorder, version],\n );\n\n const beats = useMemo(\n () => (route !== undefined ? selectSkillBeats({ route }) : []),\n [route],\n );\n const activeBeat = useMemo(\n () => selectSkillBeatAt(beats, cursorRuntimeStageId, cursorKind),\n [beats, cursorRuntimeStageId, cursorKind],\n );\n const activeIndex = activeBeat?.index;\n // The turn's routing verdict for the beat in view, joined on `turnIndex` —\n // the one field SkillBeat and SkillTurnStart both carry. A join on a shared\n // key, never an assumption about which turn a beat sits next to.\n const activeTurnStart = useMemo(\n () =>\n activeBeat === undefined || route === undefined\n ? undefined\n : route.turns.find((t) => t.turnIndex === activeBeat.turnIndex),\n [route, activeBeat],\n );\n\n const topology = useMemo(\n () =>\n route !== undefined\n ? selectSkillTopology({\n route,\n ...(activeBeat !== undefined ? { beat: activeBeat } : {}),\n ...(declaredEdges !== undefined ? { declaredEdges } : {}),\n })\n : undefined,\n [route, activeBeat, declaredEdges],\n );\n\n // Pairing a beat with the call it prepared needs the step graph; a host that\n // passed only a pre-folded route has none, and the panel says so.\n const frameContext = useMemo(() => {\n if (vettedRecorder === undefined || activeBeat === undefined) return undefined;\n const next = beats[activeBeat.index + 1];\n return selectSkillFrameContext({\n graph: vettedRecorder.getStepGraph(),\n beat: activeBeat,\n ...(next !== undefined ? { nextBeat: next } : {}),\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [vettedRecorder, version, activeBeat, beats]);\n\n /** Skills the cursor stood in at some beat — the clickable ones. */\n const jumpable = useMemo(() => {\n const ids = new Set<string>();\n for (const b of beats) {\n if (b.cursorSkillId !== undefined && b.runtimeStageId !== undefined) ids.add(b.cursorSkillId);\n }\n return ids;\n }, [beats]);\n\n /**\n * What the shipped transport scrubs. The host's axis when it gave us one —\n * the same numbers its own `<TimeTravel>` shows — otherwise this view's\n * routing stops. In BOTH cases the position is DERIVED (from the host's\n * `step`, or from where the cursor resolved) and a scrub reports a move\n * back out; nothing is stored here.\n */\n const hostAxis = step !== undefined && totalSteps !== undefined && totalSteps > 0;\n const transport: BeatTransport = {\n total: hostAxis ? totalSteps : beats.length,\n focus: hostAxis ? step : (activeIndex ?? 0),\n onFocusChange: (position: number): void => {\n if (hostAxis) {\n onStepChange?.(position);\n return;\n }\n const id = beats[position]?.runtimeStageId;\n if (id !== undefined) onJumpTo?.(id);\n },\n keyboard: transportKeyboard ?? !hostAxis,\n axisLabel: hostAxis ? 'the run' : 'routing stops',\n // Snap stops are a HOST-AXIS notion: they are steps on the axis the host\n // handed us. Without one the transport is already scrubbing this view's\n // routing stops — every one of which changes the picture — so there is\n // nothing to narrow and the list is not forwarded.\n ...(hostAxis && snapSteps !== undefined ? { snapSteps } : {}),\n };\n\n /** Filter the ONE cursor to a skill's next span, wrapping to its first. */\n const jumpToSkill = (skillId: string): void => {\n const spans = beats.filter(\n (b) => b.cursorSkillId === skillId && b.runtimeStageId !== undefined,\n );\n if (spans.length === 0) return;\n const from = activeIndex ?? -1;\n const next = spans.find((b) => b.index > from) ?? spans[0];\n if (next?.runtimeStageId !== undefined) onJumpTo?.(next.runtimeStageId);\n };\n\n const shell: React.CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n height,\n width: '100%',\n minHeight: 0,\n background: T.bgPrimary,\n color: T.textPrimary,\n fontFamily: T.fontSans,\n ...style,\n };\n\n if (recorderRefused) {\n return (\n <div className={className} style={shell} data-testid=\"skill-graph-debugger\">\n <Header lens={lens} onPick={pickLens} subtitle=\"the recorder prop is not a recorder\" />\n <DoorRefusalCard\n door=\"Skill Graph\"\n reads={SKILL_GRAPH_READS}\n received={describeReceived(recorder)}\n goTo={\n refusalDestinationFor(recorder) === 'commit-trace-lens'\n ? REFUSAL_GO_TO['commit-trace-lens']\n : 'Replay the recording first — observeRecording(recording).recorder (or a live lensRecorder()) is what this prop wants.'\n }\n />\n </div>\n );\n }\n\n if (route === undefined) {\n return (\n <div className={className} style={shell} data-testid=\"skill-graph-debugger\">\n <Header lens={lens} onPick={pickLens} subtitle=\"no recording was supplied\" />\n <Empty>\n Pass a <code>recorder</code> (or a pre-folded <code>route</code>) — this view renders a\n recording, it does not run anything.\n </Empty>\n </div>\n );\n }\n\n if (!route.hasRouting) {\n return (\n <div className={className} style={shell} data-testid=\"skill-graph-debugger\">\n <Header lens={lens} onPick={pickLens} subtitle=\"this run did not route through skills\" />\n <Empty>\n No skill graph ran here: the recording carries no skill catalog, no cursor move and no\n refusal. Nothing is hidden — there is nothing to draw. The run itself is still fully\n readable — the Why Lens (<code>agentfootprint-lens/why</code>) replays every recording,\n skills or not.\n </Empty>\n </div>\n );\n }\n\n return (\n <div className={className} style={shell} data-testid=\"skill-graph-debugger\">\n <Header\n lens={lens}\n onPick={pickLens}\n subtitle={\n lens === 'product'\n ? 'How the assistant found its way through the playbook'\n : `${route.nodes.length} skills · ${beats.length} routing stops · ${route.observedEdges.length} hops taken`\n }\n />\n\n <div\n ref={rowRef}\n style={{\n flex: 1,\n minHeight: 0,\n display: 'grid',\n gridTemplateColumns: narrow ? '1fr' : 'minmax(0, 1.15fr) minmax(300px, 0.85fr)',\n gridTemplateRows: narrow ? 'minmax(240px, 1fr) minmax(200px, 1fr)' : '1fr',\n }}\n >\n <section\n style={{\n minHeight: 0,\n display: 'flex',\n flexDirection: 'column',\n borderRight: narrow ? 'none' : `1px solid ${T.border}`,\n borderBottom: narrow ? `1px solid ${T.border}` : 'none',\n }}\n >\n <div style={{ flex: 1, minHeight: 0 }}>\n {topology !== undefined && (\n <SkillTopologyCanvas\n topology={topology}\n lens={lens}\n jumpable={jumpable}\n onPickSkill={jumpToSkill}\n />\n )}\n </div>\n <RouteDecisionCard\n {...(activeBeat !== undefined ? { beat: activeBeat } : {})}\n {...(activeTurnStart !== undefined ? { turnStart: activeTurnStart } : {})}\n lens={lens}\n />\n </section>\n\n <section style={{ minHeight: 0 }}>\n {lens === 'product' ? (\n <NarrativeRail\n beats={beats}\n {...(activeIndex !== undefined ? { activeIndex } : {})}\n {...(onJumpTo !== undefined ? { onJumpTo } : {})}\n />\n ) : (\n <FrameFactsPanel\n {...(activeBeat !== undefined ? { beat: activeBeat } : {})}\n {...(frameContext !== undefined ? { frameContext } : {})}\n />\n )}\n </section>\n </div>\n\n <BeatStrip\n beats={beats}\n {...(activeIndex !== undefined ? { activeIndex } : {})}\n lens={lens}\n transport={transport}\n {...(onJumpTo !== undefined ? { onJumpTo } : {})}\n />\n </div>\n );\n}\n\nfunction Header({\n lens,\n onPick,\n subtitle,\n}: {\n lens: SkillLens;\n onPick: (lens: SkillLens) => void;\n subtitle: string;\n}): React.ReactElement {\n const tab = (value: SkillLens, label: string): React.ReactElement => (\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={lens === value}\n data-testid={`lens-tab-${value}`}\n onClick={() => onPick(value)}\n style={{\n minWidth: 84,\n padding: '5px 10px',\n borderRadius: 6,\n border: 'none',\n background: lens === value ? T.bgTertiary : 'transparent',\n boxShadow: lens === value ? `inset 0 0 0 1px ${T.primary}` : 'none',\n color: lens === value ? T.textPrimary : T.textSecondary,\n fontSize: 11,\n cursor: 'pointer',\n }}\n >\n {label}\n </button>\n );\n\n return (\n <header\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 12,\n padding: '8px 12px',\n borderBottom: `1px solid ${T.border}`,\n background: T.bgPrimary,\n }}\n >\n <div style={{ minWidth: 0 }}>\n <div style={{ fontSize: 13, fontWeight: 650 }}>Skill routing</div>\n <div style={{ fontSize: 11, color: T.textMuted }}>{subtitle}</div>\n </div>\n <div style={{ flex: 1 }} />\n <div\n role=\"tablist\"\n aria-label=\"Explanation lens\"\n style={{\n display: 'inline-flex',\n gap: 3,\n padding: 3,\n borderRadius: 9,\n border: `1px solid ${T.border}`,\n background: T.bgSecondary,\n }}\n >\n {tab('product', 'Product lens')}\n {tab('developer', 'Developer lens')}\n </div>\n </header>\n );\n}\n\nfunction Empty({ children }: { children: React.ReactNode }): React.ReactElement {\n return (\n <div style={{ padding: 16 }}>\n <p style={{ margin: 0, fontSize: 12.5, lineHeight: 1.5, color: T.textMuted }}>{children}</p>\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","jsxs","jsx","jsxs","Fragment","jsx","jsxs","jsx","jsxs","useMemo","useRef","jsx","jsxs","useRef","useMemo","Header"]}
|
package/dist/core.d.cts
CHANGED
|
@@ -3,7 +3,7 @@ export { i as CommitSyncEntry, j as CompositionDetails, D as DEFAULT_MAX_EVENTS,
|
|
|
3
3
|
import { H as Humanizer } from './scrubAxisFor-CNceBlz-.cjs';
|
|
4
4
|
export { A as ActiveChartGroupArgs, C as ChartGroupHighlight, f as CommitWithStage, O as ObservedRecording, a as RecordedSnapshot, R as Recording, S as ScrubAxis, b as StepBand, g as activeChartGroup, h as bandChartGroup, c as bandIndexOf, i as chartNodeIdOf, j as defaultHumanizer, k as humanizeWith, o as observeRecording, s as scrubAxisFor, d as stepBands, e as stepForCommitIdx, t as teachingHumanizer } from './scrubAxisFor-CNceBlz-.cjs';
|
|
5
5
|
import { StepGraph, BoundaryRecorder, StepNode, ContextInjection, BoundaryRangeLabel, ToolChoiceCall, BoundaryAggregate } from 'agentfootprint/observe';
|
|
6
|
-
export { D as DeclaredEdgeInput,
|
|
6
|
+
export { D as DeclaredEdgeInput, d as SelectSkillBeatsArgs, e as SelectSkillFrameContextArgs, f as SelectSkillRouteArgs, g as SelectSkillTopologyArgs, a as SkillBeat, h as SkillCursorAfter, i as SkillCursorCause, j as SkillDeclaredEdge, k as SkillEvidenceCheck, c as SkillFrameContext, l as SkillHop, m as SkillHopRef, n as SkillInjectionSeen, o as SkillNodeState, p as SkillObservedEdge, q as SkillReachableSet, r as SkillRefusal, s as SkillRoute, t as SkillRouteConflict, u as SkillRouteNode, v as SkillRouteWitness, w as SkillSuperseded, x as SkillToolAsSent, S as SkillTopology, y as SkillTopologyEdge, z as SkillTopologyNode, b as SkillTurnStart, A as SkillTurnVerdict, B as selectSkillBeatAt, C as selectSkillBeats, E as selectSkillFrameContext, F as selectSkillRoute, G as selectSkillTopology } from './selectSkillFrameContext-DJkvrggG.cjs';
|
|
7
7
|
import { CommitRangeIndex, MissingSliceReason } from 'footprintjs/trace';
|
|
8
8
|
import { GroupKind, GroupTranslator, GroupMetadata, GroupMember, Agent } from 'agentfootprint';
|
|
9
9
|
import { TraceGraph } from 'footprint-explainable-ui/flowchart';
|
package/dist/core.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { i as CommitSyncEntry, j as CompositionDetails, D as DEFAULT_MAX_EVENTS,
|
|
|
3
3
|
import { H as Humanizer } from './scrubAxisFor-Cz214OHj.js';
|
|
4
4
|
export { A as ActiveChartGroupArgs, C as ChartGroupHighlight, f as CommitWithStage, O as ObservedRecording, a as RecordedSnapshot, R as Recording, S as ScrubAxis, b as StepBand, g as activeChartGroup, h as bandChartGroup, c as bandIndexOf, i as chartNodeIdOf, j as defaultHumanizer, k as humanizeWith, o as observeRecording, s as scrubAxisFor, d as stepBands, e as stepForCommitIdx, t as teachingHumanizer } from './scrubAxisFor-Cz214OHj.js';
|
|
5
5
|
import { StepGraph, BoundaryRecorder, StepNode, ContextInjection, BoundaryRangeLabel, ToolChoiceCall, BoundaryAggregate } from 'agentfootprint/observe';
|
|
6
|
-
export { D as DeclaredEdgeInput,
|
|
6
|
+
export { D as DeclaredEdgeInput, d as SelectSkillBeatsArgs, e as SelectSkillFrameContextArgs, f as SelectSkillRouteArgs, g as SelectSkillTopologyArgs, a as SkillBeat, h as SkillCursorAfter, i as SkillCursorCause, j as SkillDeclaredEdge, k as SkillEvidenceCheck, c as SkillFrameContext, l as SkillHop, m as SkillHopRef, n as SkillInjectionSeen, o as SkillNodeState, p as SkillObservedEdge, q as SkillReachableSet, r as SkillRefusal, s as SkillRoute, t as SkillRouteConflict, u as SkillRouteNode, v as SkillRouteWitness, w as SkillSuperseded, x as SkillToolAsSent, S as SkillTopology, y as SkillTopologyEdge, z as SkillTopologyNode, b as SkillTurnStart, A as SkillTurnVerdict, B as selectSkillBeatAt, C as selectSkillBeats, E as selectSkillFrameContext, F as selectSkillRoute, G as selectSkillTopology } from './selectSkillFrameContext-IPsw4Pbj.js';
|
|
7
7
|
import { CommitRangeIndex, MissingSliceReason } from 'footprintjs/trace';
|
|
8
8
|
import { GroupKind, GroupTranslator, GroupMetadata, GroupMember, Agent } from 'agentfootprint';
|
|
9
9
|
import { TraceGraph } from 'footprint-explainable-ui/flowchart';
|
package/dist/index.cjs
CHANGED
|
@@ -11587,7 +11587,7 @@ var CAUSE_LABEL = {
|
|
|
11587
11587
|
stay: "nothing moved it",
|
|
11588
11588
|
none: "no skill was in play"
|
|
11589
11589
|
};
|
|
11590
|
-
function RouteDecisionCard({ beat, lens }) {
|
|
11590
|
+
function RouteDecisionCard({ beat, turnStart, lens }) {
|
|
11591
11591
|
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
11592
11592
|
"aside",
|
|
11593
11593
|
{
|
|
@@ -11715,6 +11715,7 @@ function RouteDecisionCard({ beat, lens }) {
|
|
|
11715
11715
|
children: beat.notes.map((n, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("li", { children: n }, i))
|
|
11716
11716
|
}
|
|
11717
11717
|
),
|
|
11718
|
+
turnStart !== void 0 && (turnStart.by === "intent" || turnStart.by === "continuity") && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ScoreTable, { start: turnStart }),
|
|
11718
11719
|
lens === "developer" && beat.runtimeStageId !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { marginTop: 8, fontFamily: T.fontMono, fontSize: 10, color: T.textMuted }, children: beat.runtimeStageId })
|
|
11719
11720
|
] })
|
|
11720
11721
|
}
|
|
@@ -11740,6 +11741,104 @@ function Evidence({
|
|
|
11740
11741
|
children
|
|
11741
11742
|
] });
|
|
11742
11743
|
}
|
|
11744
|
+
function ScoreTable({ start }) {
|
|
11745
|
+
if (start.scores.length === 0) return null;
|
|
11746
|
+
const floor = start.policy?.floor;
|
|
11747
|
+
const margin = start.policy?.nearTieMargin;
|
|
11748
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { marginTop: 8 }, children: [
|
|
11749
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
11750
|
+
"div",
|
|
11751
|
+
{
|
|
11752
|
+
style: {
|
|
11753
|
+
fontSize: 10,
|
|
11754
|
+
letterSpacing: "0.08em",
|
|
11755
|
+
textTransform: "uppercase",
|
|
11756
|
+
color: T.textMuted,
|
|
11757
|
+
marginBottom: 4
|
|
11758
|
+
},
|
|
11759
|
+
children: [
|
|
11760
|
+
"Scored",
|
|
11761
|
+
start.scorer ? ` by ${start.scorer}` : "",
|
|
11762
|
+
floor !== void 0 ? ` \xB7 floor ${floor}` : "",
|
|
11763
|
+
start.runnerUp !== void 0 && margin !== void 0 ? ` \xB7 gap ${fmt(start.runnerUp.gap)} of ${margin} needed` : ""
|
|
11764
|
+
]
|
|
11765
|
+
}
|
|
11766
|
+
),
|
|
11767
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
11768
|
+
"table",
|
|
11769
|
+
{
|
|
11770
|
+
style: { borderCollapse: "collapse", width: "100%", fontSize: 12 },
|
|
11771
|
+
children: [
|
|
11772
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
11773
|
+
"caption",
|
|
11774
|
+
{
|
|
11775
|
+
style: {
|
|
11776
|
+
captionSide: "top",
|
|
11777
|
+
textAlign: "left",
|
|
11778
|
+
fontSize: 11,
|
|
11779
|
+
color: T.textMuted,
|
|
11780
|
+
paddingBottom: 3
|
|
11781
|
+
},
|
|
11782
|
+
children: "Every candidate this turn was scored against, best first."
|
|
11783
|
+
}
|
|
11784
|
+
),
|
|
11785
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("tbody", { children: start.scores.map((row) => {
|
|
11786
|
+
const belowFloor = floor !== void 0 && row.score <= floor;
|
|
11787
|
+
const won = row.id === start.to;
|
|
11788
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("tr", { children: [
|
|
11789
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
11790
|
+
"td",
|
|
11791
|
+
{
|
|
11792
|
+
style: {
|
|
11793
|
+
padding: "2px 6px 2px 0",
|
|
11794
|
+
color: belowFloor ? T.textMuted : T.textPrimary,
|
|
11795
|
+
fontWeight: won ? 700 : 400,
|
|
11796
|
+
fontFamily: T.fontMono
|
|
11797
|
+
},
|
|
11798
|
+
children: [
|
|
11799
|
+
won ? "\u2192 " : " ",
|
|
11800
|
+
row.id
|
|
11801
|
+
]
|
|
11802
|
+
}
|
|
11803
|
+
),
|
|
11804
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
11805
|
+
"td",
|
|
11806
|
+
{
|
|
11807
|
+
style: {
|
|
11808
|
+
padding: "2px 6px",
|
|
11809
|
+
textAlign: "right",
|
|
11810
|
+
fontFamily: T.fontMono,
|
|
11811
|
+
color: belowFloor ? T.textMuted : T.textPrimary
|
|
11812
|
+
},
|
|
11813
|
+
children: fmt(row.score)
|
|
11814
|
+
}
|
|
11815
|
+
),
|
|
11816
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
11817
|
+
"td",
|
|
11818
|
+
{
|
|
11819
|
+
style: {
|
|
11820
|
+
padding: "2px 6px",
|
|
11821
|
+
textAlign: "right",
|
|
11822
|
+
fontFamily: T.fontMono,
|
|
11823
|
+
color: T.textMuted
|
|
11824
|
+
},
|
|
11825
|
+
children: [
|
|
11826
|
+
Math.round(row.relevance * 100),
|
|
11827
|
+
"%"
|
|
11828
|
+
]
|
|
11829
|
+
}
|
|
11830
|
+
),
|
|
11831
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("td", { style: { padding: "2px 0 2px 6px", color: T.textMuted, fontSize: 11 }, children: belowFloor ? "below floor" : won ? "" : "beaten" })
|
|
11832
|
+
] }, row.id);
|
|
11833
|
+
}) })
|
|
11834
|
+
]
|
|
11835
|
+
}
|
|
11836
|
+
)
|
|
11837
|
+
] });
|
|
11838
|
+
}
|
|
11839
|
+
function fmt(n) {
|
|
11840
|
+
return String(Math.round(n * 1e3) / 1e3);
|
|
11841
|
+
}
|
|
11743
11842
|
|
|
11744
11843
|
// src/react/skillgraph/SkillTopologyCanvas.tsx
|
|
11745
11844
|
var import_react27 = require("react");
|
|
@@ -12096,6 +12195,10 @@ function SkillGraphDebugger({
|
|
|
12096
12195
|
[beats, cursorRuntimeStageId, cursorKind]
|
|
12097
12196
|
);
|
|
12098
12197
|
const activeIndex = activeBeat?.index;
|
|
12198
|
+
const activeTurnStart = (0, import_react29.useMemo)(
|
|
12199
|
+
() => activeBeat === void 0 || route === void 0 ? void 0 : route.turns.find((t) => t.turnIndex === activeBeat.turnIndex),
|
|
12200
|
+
[route, activeBeat]
|
|
12201
|
+
);
|
|
12099
12202
|
const topology = (0, import_react29.useMemo)(
|
|
12100
12203
|
() => route !== void 0 ? selectSkillTopology({
|
|
12101
12204
|
route,
|
|
@@ -12237,7 +12340,14 @@ function SkillGraphDebugger({
|
|
|
12237
12340
|
onPickSkill: jumpToSkill
|
|
12238
12341
|
}
|
|
12239
12342
|
) }),
|
|
12240
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
12343
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
12344
|
+
RouteDecisionCard,
|
|
12345
|
+
{
|
|
12346
|
+
...activeBeat !== void 0 ? { beat: activeBeat } : {},
|
|
12347
|
+
...activeTurnStart !== void 0 ? { turnStart: activeTurnStart } : {},
|
|
12348
|
+
lens
|
|
12349
|
+
}
|
|
12350
|
+
)
|
|
12241
12351
|
]
|
|
12242
12352
|
}
|
|
12243
12353
|
),
|