@opetope/devtools 0.1.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/CHANGELOG.md +5 -0
- package/LICENSE +21 -0
- package/README.md +105 -0
- package/README.ru.md +105 -0
- package/dist/activity-export.d.ts +4 -0
- package/dist/activity.d.ts +63 -0
- package/dist/conformance-activity.d.ts +8 -0
- package/dist/conformance.d.ts +37 -0
- package/dist/control-subject.d.ts +15 -0
- package/dist/control-ui-DMmVy9Ob.js +16 -0
- package/dist/control-ui-DMmVy9Ob.js.map +1 -0
- package/dist/control.d.ts +45 -0
- package/dist/corpus.d.ts +33 -0
- package/dist/decode-activity.d.ts +4 -0
- package/dist/decode-shapes.d.ts +32 -0
- package/dist/decode-values.d.ts +36 -0
- package/dist/decode.d.ts +41 -0
- package/dist/digest.d.ts +17 -0
- package/dist/export-run-DIQZax_d.js +2 -0
- package/dist/export-run-DIQZax_d.js.map +1 -0
- package/dist/export-snapshot-Buw-c6ZG.js +2 -0
- package/dist/export-snapshot-Buw-c6ZG.js.map +1 -0
- package/dist/export-snapshot.d.ts +34 -0
- package/dist/extension-points.d.ts +45 -0
- package/dist/fixture-plan.d.ts +62 -0
- package/dist/fixture-runtime.d.ts +37 -0
- package/dist/fixture.d.ts +23 -0
- package/dist/fold-snapshot-DjiURn8v.js +2 -0
- package/dist/fold-snapshot-DjiURn8v.js.map +1 -0
- package/dist/fold-snapshot.d.ts +15 -0
- package/dist/graph-index.d.ts +104 -0
- package/dist/graph-store.d.ts +77 -0
- package/dist/graph.d.ts +211 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/inspector.d.ts +70 -0
- package/dist/install.d.ts +44 -0
- package/dist/install.js +2 -0
- package/dist/install.js.map +1 -0
- package/dist/integration.d.ts +42 -0
- package/dist/integration.js +2 -0
- package/dist/integration.js.map +1 -0
- package/dist/legend-DT7j0_pD.js +2 -0
- package/dist/legend-DT7j0_pD.js.map +1 -0
- package/dist/node-facts.d.ts +20 -0
- package/dist/node-state.d.ts +152 -0
- package/dist/optional.d.ts +9 -0
- package/dist/panel-5jvisQBr.js +367 -0
- package/dist/panel-5jvisQBr.js.map +1 -0
- package/dist/producer-ids.d.ts +15 -0
- package/dist/protocol-joKTjlMj.js +2 -0
- package/dist/protocol-joKTjlMj.js.map +1 -0
- package/dist/protocol.d.ts +238 -0
- package/dist/react/activity-rows.d.ts +12 -0
- package/dist/react/activity-view.d.ts +9 -0
- package/dist/react/control-locale.d.ts +25 -0
- package/dist/react/control-styles.d.ts +7 -0
- package/dist/react/control-ui.d.ts +37 -0
- package/dist/react/edge-filter.d.ts +36 -0
- package/dist/react/edge-filters.d.ts +17 -0
- package/dist/react/export-delivery.d.ts +33 -0
- package/dist/react/export-run.d.ts +20 -0
- package/dist/react/format.d.ts +17 -0
- package/dist/react/glyph.d.ts +20 -0
- package/dist/react/graph-layout.d.ts +67 -0
- package/dist/react/graph-view.d.ts +30 -0
- package/dist/react/graph-viewport.d.ts +48 -0
- package/dist/react/icons.d.ts +12 -0
- package/dist/react/inspector-view.d.ts +29 -0
- package/dist/react/label.d.ts +28 -0
- package/dist/react/lazy-module.d.ts +38 -0
- package/dist/react/legend-locale.d.ts +23 -0
- package/dist/react/legend.d.ts +10 -0
- package/dist/react/locale-context.d.ts +17 -0
- package/dist/react/locale.d.ts +115 -0
- package/dist/react/main-column.d.ts +22 -0
- package/dist/react/panel-header.d.ts +20 -0
- package/dist/react/panel-mode.d.ts +3 -0
- package/dist/react/panel-status.d.ts +19 -0
- package/dist/react/panel.d.ts +41 -0
- package/dist/react/search-results.d.ts +18 -0
- package/dist/react/selection.d.ts +15 -0
- package/dist/react/styles.d.ts +13 -0
- package/dist/react/theme.d.ts +39 -0
- package/dist/react/timeline-locale.d.ts +20 -0
- package/dist/react/timeline-view.d.ts +14 -0
- package/dist/react/tree.d.ts +26 -0
- package/dist/react/use-store.d.ts +11 -0
- package/dist/react.d.ts +16 -0
- package/dist/react.js +2 -0
- package/dist/react.js.map +1 -0
- package/dist/search-CC7avy6I.js +2 -0
- package/dist/search-CC7avy6I.js.map +1 -0
- package/dist/search.d.ts +20 -0
- package/dist/session-qjKT0E69.js +2 -0
- package/dist/session-qjKT0E69.js.map +1 -0
- package/dist/session.d.ts +59 -0
- package/dist/testing.d.ts +10 -0
- package/dist/testing.js +4 -0
- package/dist/testing.js.map +1 -0
- package/dist/timeline-view-ByPB1a7-.js +2 -0
- package/dist/timeline-view-ByPB1a7-.js.map +1 -0
- package/dist/timeline.d.ts +57 -0
- package/dist/visual-axes.d.ts +35 -0
- package/package.json +107 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-CC7avy6I.js","sources":["../src/extension-points.ts","../src/node-facts.ts","../src/optional.ts","../src/inspector.ts","../src/search.ts"],"sourcesContent":["/**\n * The two-step projection behind the `Extension points` preset (`docs/devtools.md` §4.2).\n *\n * A contribution is a node _between_ a feature and its target, so a one-hop neighbourhood shows a feature's\n * contributions and stops exactly where the question starts: where do they go, and who else is there. This walks the\n * second step — feature → contributions → targets — and then back down from each target to every other contribution\n * aimed at it, because priority and competition are only legible side by side.\n *\n * Selecting a target inverts the walk: target → contributions → contributors. The rows are the same shape either\n * way, so the layout draws one picture and the panel keeps one selection.\n */\n\nimport type { DiagnosticGraphIndex } from './graph-index';\nimport type { DevtoolsGraphStore } from './graph-store';\nimport type { DiagnosticLabel, DiagnosticNodeId, DiagnosticNodeKind } from './protocol';\nimport type { NodeDisplayState } from './visual-axes';\n\n/** One contribution and the node at its far end: its target, or its contributor when the walk is inverted. */\ntype ExtensionRow = Readonly<{\n contribution: DiagnosticNodeId;\n contributionDisplay: NodeDisplayState;\n contributionLabel: DiagnosticLabel;\n /** Whose contribution it is. On a sibling row this is the competitor's name, which is why the row is drawn. */\n contributorLabel: DiagnosticLabel;\n endpoint: DiagnosticNodeId;\n endpointDisplay: NodeDisplayState;\n endpointLabel: DiagnosticLabel;\n /** Whether the selected node is at this contribution's near end. A sibling contribution is somebody else's. */\n own: boolean;\n /** The contribution's own state, as the protocol names it. */\n state: string;\n}>;\n\ntype ExtensionPointsProjection = Readonly<{\n display: NodeDisplayState;\n id: DiagnosticNodeId;\n /** True when the selection is a target and the walk runs from it back to its contributors. */\n inverted: boolean;\n kind: DiagnosticNodeKind;\n label: DiagnosticLabel;\n rows: readonly ExtensionRow[];\n}>;\n\nfunction labelOf(index: DiagnosticGraphIndex, id: DiagnosticNodeId): DiagnosticLabel {\n return index.node(id)?.label ?? id;\n}\n\nfunction contributionState(index: DiagnosticGraphIndex, id: DiagnosticNodeId): string {\n const node = index.runtimeNode(id);\n\n return node?.kind === 'contribution' ? node.state.kind : 'declared';\n}\n\n/** Contributions this node publishes: the `owns` edges that land on a contribution. */\nfunction contributionsOf(index: DiagnosticGraphIndex, id: DiagnosticNodeId): readonly DiagnosticNodeId[] {\n const found: DiagnosticNodeId[] = [];\n\n for (const edge of index.outgoing(id)) {\n if (edge.kind === 'owns' && index.node(edge.to)?.kind === 'contribution') found.push(edge.to);\n }\n\n return found;\n}\n\n/** Every contribution aimed at this target, in the order the graph holds them. */\nfunction contributionsInto(index: DiagnosticGraphIndex, target: DiagnosticNodeId): readonly DiagnosticNodeId[] {\n const found: DiagnosticNodeId[] = [];\n\n for (const edge of index.incoming(target)) {\n if (edge.kind === 'contributes-to') found.push(edge.from);\n }\n\n return found;\n}\n\nfunction targetOf(index: DiagnosticGraphIndex, contribution: DiagnosticNodeId): DiagnosticNodeId | undefined {\n return index.outgoing(contribution).find(edge => edge.kind === 'contributes-to')?.to;\n}\n\nfunction contributorOf(index: DiagnosticGraphIndex, contribution: DiagnosticNodeId): DiagnosticNodeId | undefined {\n return index.incoming(contribution).find(edge => edge.kind === 'owns')?.from;\n}\n\nfunction rowFor(\n index: DiagnosticGraphIndex,\n contribution: DiagnosticNodeId,\n endpoint: DiagnosticNodeId,\n own: boolean,\n): ExtensionRow {\n const contributor = contributorOf(index, contribution);\n\n return {\n contribution,\n contributionDisplay: index.displayOf(contribution),\n contributionLabel: labelOf(index, contribution),\n contributorLabel: contributor === undefined ? labelOf(index, contribution) : labelOf(index, contributor),\n endpoint,\n endpointDisplay: index.displayOf(endpoint),\n endpointLabel: labelOf(index, endpoint),\n own,\n state: contributionState(index, contribution),\n };\n}\n\n/** Feature → its contributions → their targets, and back down to whoever else contributes to those targets. */\nfunction rowsFromContributor(index: DiagnosticGraphIndex, id: DiagnosticNodeId): readonly ExtensionRow[] {\n const own = new Set(contributionsOf(index, id));\n const rows: ExtensionRow[] = [];\n const seen = new Set<DiagnosticNodeId>();\n\n for (const contribution of own) {\n const target = targetOf(index, contribution);\n\n if (target === undefined || seen.has(target)) continue;\n\n seen.add(target);\n\n for (const sibling of contributionsInto(index, target)) {\n rows.push(rowFor(index, sibling, target, own.has(sibling)));\n }\n }\n\n return rows;\n}\n\n/** Target → its contributions → their contributors. Every row is `own`: they all reach the selected target. */\nfunction rowsFromTarget(index: DiagnosticGraphIndex, id: DiagnosticNodeId): readonly ExtensionRow[] {\n const rows: ExtensionRow[] = [];\n\n for (const contribution of contributionsInto(index, id)) {\n const contributor = contributorOf(index, contribution);\n\n if (contributor !== undefined) rows.push(rowFor(index, contribution, contributor, true));\n }\n\n return rows;\n}\n\n/**\n * The projection for the selected node, or `undefined` when it takes no part in any extension point — a feature\n * that contributes nothing has nothing to draw here, and saying so is the layout's job, not this one's.\n */\nfunction projectExtensionPoints(\n store: DevtoolsGraphStore,\n id: DiagnosticNodeId,\n): ExtensionPointsProjection | undefined {\n const index = store.graph;\n const node = index.node(id);\n\n if (node === undefined) return undefined;\n\n const inverted = node.kind === 'contribution-target';\n\n return {\n display: index.displayOf(id),\n id,\n inverted,\n kind: node.kind,\n label: node.label,\n rows: inverted ? rowsFromTarget(index, id) : rowsFromContributor(index, id),\n };\n}\n\nexport { projectExtensionPoints };\nexport type { ExtensionPointsProjection, ExtensionRow };\n","/**\n * Small readers over the kind-specific state unions. They exist so the panel and the search index ask \"does this node\n * carry a failure\" once, in one place, instead of every view re-implementing a `state.kind` switch and drifting.\n */\n\nimport type { DiagnosticRuntimeNode } from './graph';\nimport type { DiagnosticFailure } from './protocol';\n\n/** §2.6: a failure is the runtime's own subject and code plus a phase. There is no message, stack or cause to read. */\nfunction failureOf(node: DiagnosticRuntimeNode): DiagnosticFailure | undefined {\n return 'failure' in node.state ? node.state.failure : undefined;\n}\n\nfunction generationOf(node: DiagnosticRuntimeNode): number | undefined {\n return node.kind === 'feature-instance' ? node.generation : undefined;\n}\n\n/**\n * How far a group has walked its canonical order, in either direction. A count, never a duration.\n *\n * The counts are written in the protocol's own words — the state kind and the numbers it carries — and not as a\n * sentence. A projection that composes prose would be prose no dictionary could reach: this string is built below\n * the view, so an English sentence here would print English in a Russian panel (U21).\n */\nfunction progressOf(node: DiagnosticRuntimeNode): string | undefined {\n const { state } = node;\n\n if (state.kind === 'opening' && 'total' in state) return `${state.kind} · ${state.opened}/${state.total}`;\n\n if (state.kind === 'retiring' && 'remaining' in state) return `${state.kind} · ${state.remaining}`;\n\n return undefined;\n}\n\n/** Whether this node currently satisfies whoever depends on it. */\nfunction isReadyDisplay(node: DiagnosticRuntimeNode): boolean {\n const { kind } = node.state;\n\n return kind === 'ready' || kind === 'active' || kind === 'available' || kind === 'bound' || kind === 'true';\n}\n\nexport { failureOf, generationOf, isReadyDisplay, progressOf };\n","/**\n * `exactOptionalPropertyTypes` forbids writing `undefined` into an optional property, which otherwise turns every\n * optional field into its own conditional spread. This drops absent keys instead, so a projection can be assembled\n * from possibly-absent values in one place.\n */\nfunction defined<Fields extends object>(fields: { [Key in keyof Fields]?: Fields[Key] | undefined }): Fields {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(fields)) {\n if (value !== undefined) result[key] = value;\n }\n\n return result as Fields;\n}\n\nexport { defined };\n","/**\n * What the inspector — and the graph canvas next to it — is allowed to know about the selected node.\n *\n * §2 is explicit that the UI neither computes state nor parses error text, so this projection resolves refs into\n * typed facts and stops there. It counts blockers, it does not phrase \"all three hard imports were already ready\";\n * the panel composes that sentence from the counts. §4.3 fixes the contents: id, kind, provenance, current state and\n * instance, the immediate cause, incoming dependencies, what the instance owns, and the last causal chain.\n */\n\nimport type { RuntimeActivitySnapshot } from './activity';\nimport type { ConditionGroupRuntimeNode, DiagnosticNode, DiagnosticRuntimeNode } from './graph';\nimport type { DiagnosticGraphIndex } from './graph-index';\nimport type { DevtoolsGraphStore } from './graph-store';\nimport { failureOf, generationOf, isReadyDisplay, progressOf } from './node-facts';\nimport type { DiagnosticCausalStep } from './node-state';\nimport { defined } from './optional';\nimport type {\n DesiredAxis,\n DiagnosticCauseRef,\n DiagnosticEdge,\n DiagnosticEdgeKind,\n DiagnosticFailure,\n DiagnosticLabel,\n DiagnosticNodeId,\n DiagnosticNodeKind,\n DiagnosticOverride,\n DiagnosticProvenance,\n WeakEdgeState,\n} from './protocol';\nimport { isDependencyEdge, isHardEdge, isWeakEdge } from './protocol';\nimport type { DiagnosticAxes, NodeDisplayState } from './visual-axes';\n\n/**\n * One incoming dependency. A hard edge is satisfied when it is no longer pending; a weak edge is never pending and\n * reports the `Lookup` its consumer reads instead, so `missing` shows as unsatisfied without claiming a wait (D105).\n */\ntype InspectorBlocker = Readonly<{\n display: NodeDisplayState;\n kind: DiagnosticEdgeKind;\n label: DiagnosticLabel;\n lookup?: WeakEdgeState;\n node: DiagnosticNodeId;\n /** Whether this dependency is satisfied. A satisfied edge stays visible: \"0 of 3\" is the useful answer. */\n ready: boolean;\n weak: boolean;\n}>;\n\ntype InspectorOwned = Readonly<{\n /** 0 for what the node owns directly, 1 for what its own children own in turn. */\n depth: number;\n display: NodeDisplayState;\n edge: DiagnosticEdge;\n node: DiagnosticRuntimeNode;\n}>;\n\ntype InspectorWhy = Readonly<{\n cause?: DiagnosticCauseRef;\n failure?: DiagnosticFailure;\n /** How far a condition group has walked its canonical order, when it is walking it. */\n progress?: string;\n readyBlockers: number;\n totalBlockers: number;\n}>;\n\ntype InspectorBreadcrumb = Readonly<{\n id?: DiagnosticNodeId;\n label: DiagnosticLabel;\n}>;\n\ntype InspectorProjection = Readonly<{\n applicationActivity: RuntimeActivitySnapshot | undefined;\n axes: DiagnosticAxes;\n blockers: readonly InspectorBlocker[];\n breadcrumbs: readonly InspectorBreadcrumb[];\n chain: readonly DiagnosticCausalStep[];\n display: NodeDisplayState;\n /** The kernel's instance counter, a number and not a concept (D110). */\n generation?: number;\n groupLabel?: DiagnosticLabel;\n id: DiagnosticNodeId;\n kind: DiagnosticNodeKind;\n label: DiagnosticLabel;\n node?: DiagnosticRuntimeNode;\n override: DiagnosticOverride;\n owned: readonly InspectorOwned[];\n provenance?: DiagnosticProvenance;\n why: InspectorWhy;\n}>;\n\n/** A hard edge is satisfied once it stops pending and its provider reports ready; a weak one, once it reads found. */\nfunction isSatisfied(index: DiagnosticGraphIndex, edge: DiagnosticEdge): boolean {\n if (isWeakEdge(edge)) return edge.lookup === 'found';\n\n if (!isHardEdge(edge)) return true;\n\n const provider = index.runtimeNode(edge.from);\n\n return !edge.pending && (provider === undefined || isReadyDisplay(provider));\n}\n\nfunction blockerRow(index: DiagnosticGraphIndex, edge: DiagnosticEdge): InspectorBlocker {\n const weak = isWeakEdge(edge);\n\n return {\n display: index.displayOf(edge.from),\n kind: edge.kind,\n label: index.node(edge.from)?.label ?? edge.from,\n ...(weak ? { lookup: edge.lookup } : {}),\n node: edge.from,\n ready: isSatisfied(index, edge),\n weak,\n };\n}\n\nfunction blockerRows(index: DiagnosticGraphIndex, id: DiagnosticNodeId): readonly InspectorBlocker[] {\n const rows: InspectorBlocker[] = [];\n\n for (const edge of index.incoming(id)) {\n if (isDependencyEdge(edge)) rows.push(blockerRow(index, edge));\n }\n\n return rows;\n}\n\nfunction nestedOwned(index: DiagnosticGraphIndex, owner: DiagnosticRuntimeNode, rows: InspectorOwned[]): void {\n for (const edge of index.outgoing(owner.id)) {\n if (isDependencyEdge(edge)) continue;\n\n const child = index.runtimeNode(edge.to);\n\n if (child === undefined) continue;\n\n rows.push({ depth: 1, display: index.displayOf(child.id), edge, node: child });\n }\n}\n\n/**\n * What the node owns. A condition group owns its feature instances and each instance owns its attachments and\n * contributions, so one nested level is enough to show a group's whole world without walking the graph.\n */\nfunction ownedRows(index: DiagnosticGraphIndex, id: DiagnosticNodeId): readonly InspectorOwned[] {\n const rows: InspectorOwned[] = [];\n\n for (const edge of index.outgoing(id)) {\n if (isDependencyEdge(edge)) continue;\n\n const node = index.runtimeNode(edge.to);\n\n if (node === undefined) continue;\n\n rows.push({ depth: 0, display: index.displayOf(node.id), edge, node });\n\n if (node.kind === 'feature-instance') nestedOwned(index, node, rows);\n }\n\n return rows;\n}\n\nfunction whyThisState(node: DiagnosticRuntimeNode | undefined, blockers: readonly InspectorBlocker[]): InspectorWhy {\n const failure = node === undefined ? undefined : failureOf(node);\n const progress = node === undefined ? undefined : progressOf(node);\n\n return {\n readyBlockers: blockers.reduce((total, blocker) => total + (blocker.ready ? 1 : 0), 0),\n totalBlockers: blockers.length,\n ...defined<Partial<Pick<InspectorWhy, 'cause' | 'failure' | 'progress'>>>({\n cause: node?.cause,\n failure,\n progress,\n }),\n };\n}\n\n/**\n * Provenance lives on the declaration, and the selected node is usually an instance. Falling back through\n * `declaration` is what makes the inspector able to answer \"which file is this\" for a live instance.\n */\nfunction provenanceOf(index: DiagnosticGraphIndex, node: DiagnosticNode): DiagnosticProvenance | undefined {\n if ('provenance' in node && node.provenance !== undefined) return node.provenance;\n\n if (!('declaration' in node) || node.declaration === undefined) return undefined;\n\n return index.planNode(node.declaration)?.provenance;\n}\n\nfunction fallbackAxes(desired: DesiredAxis): DiagnosticAxes {\n return { desired, health: 'healthy', lifecycle: 'declared' };\n}\n\nfunction breadcrumbsFor(\n index: DiagnosticGraphIndex,\n node: DiagnosticNode,\n groupLabel: DiagnosticLabel | undefined,\n groupId: DiagnosticNodeId | undefined,\n): readonly InspectorBreadcrumb[] {\n const application = { id: index.plan.application.id, label: index.plan.application.label };\n const trail: InspectorBreadcrumb[] = [application];\n\n if (groupLabel !== undefined && groupId !== node.id) {\n trail.push({ ...(groupId === undefined ? {} : { id: groupId }), label: groupLabel });\n }\n\n // The application is already the first crumb: selecting it must not put it in the path twice, once as the root of\n // the trail and once as its own destination.\n if (node.id !== application.id) trail.push({ id: node.id, label: node.label });\n\n return trail;\n}\n\ntype ProjectionOptionals = Partial<Pick<InspectorProjection, 'generation' | 'groupLabel' | 'node' | 'provenance'>>;\n\n/** What the owning condition group contributes: its identity for breadcrumbs and its debug override. */\ntype GroupFacts = Readonly<{\n id: DiagnosticNodeId | undefined;\n label: DiagnosticLabel | undefined;\n override: DiagnosticOverride;\n}>;\n\nfunction groupFacts(group: ConditionGroupRuntimeNode | undefined): GroupFacts {\n return { id: group?.id, label: group?.label, override: group?.desired.override ?? 'none' };\n}\n\nfunction optionalFields(\n index: DiagnosticGraphIndex,\n node: DiagnosticNode,\n runtime: DiagnosticRuntimeNode | undefined,\n group: ConditionGroupRuntimeNode | undefined,\n): ProjectionOptionals {\n return defined<ProjectionOptionals>({\n generation: runtime === undefined ? undefined : generationOf(runtime),\n groupLabel: group?.label,\n node: runtime,\n provenance: provenanceOf(index, node),\n });\n}\n\n/** Everything the selected-node views read. `undefined` means the selection no longer exists in this session. */\nfunction projectInspector(store: DevtoolsGraphStore, id: DiagnosticNodeId): InspectorProjection | undefined {\n const index = store.graph;\n const node = index.node(id);\n\n if (node === undefined) return undefined;\n\n const runtime = index.runtimeNode(id);\n const group = index.groupOf(id);\n const facts = groupFacts(group);\n const blockers = blockerRows(index, id);\n\n return {\n applicationActivity: store.activity,\n axes: index.axesOf(id) ?? fallbackAxes(index.desiredOf(id)),\n blockers,\n breadcrumbs: breadcrumbsFor(index, node, facts.label, facts.id),\n chain: store.chainFor(id),\n display: index.displayOf(id),\n id,\n kind: node.kind,\n label: node.label,\n override: facts.override,\n owned: ownedRows(index, id),\n why: whyThisState(runtime, blockers),\n ...optionalFields(index, node, runtime, group),\n };\n}\n\nexport { projectInspector };\nexport type { InspectorBlocker, InspectorBreadcrumb, InspectorOwned, InspectorProjection, InspectorWhy };\n","/**\n * Search over the fields §2 puts in the protocol: id, label, kind, origin and failure. A failure is indexed by the\n * two words that make it up — the subject of the runtime's error class and its code (D69) — so `quarantined` and\n * `feature` both find the same node. Arbitrary error text is not in the protocol and is therefore not indexable:\n * there is nothing here to grep for a stack trace.\n */\n\nimport type { DiagnosticNode } from './graph';\nimport type { DiagnosticGraphIndex } from './graph-index';\nimport { failureOf } from './node-facts';\nimport type { DiagnosticLabel, DiagnosticNodeId, DiagnosticNodeKind } from './protocol';\nimport type { NodeDisplayState } from './visual-axes';\n\ntype SearchField = 'failure-code' | 'failure-subject' | 'id' | 'kind' | 'label' | 'provenance';\n\ntype SearchHit = Readonly<{\n display: NodeDisplayState;\n field: SearchField;\n id: DiagnosticNodeId;\n kind: DiagnosticNodeKind;\n label: DiagnosticLabel;\n}>;\n\nconst defaultLimit = 40;\n\n/** Order matters: the first match becomes the hit's `field`, and a label match is the one worth reporting. */\nconst readers: readonly (readonly [SearchField, (node: DiagnosticNode) => string | undefined])[] = [\n ['label', node => node.label],\n ['id', node => node.id],\n ['kind', node => node.kind],\n ['provenance', node => ('provenance' in node ? node.provenance : undefined)],\n ['failure-code', node => ('state' in node ? failureOf(node)?.code : undefined)],\n ['failure-subject', node => ('state' in node ? failureOf(node)?.subject : undefined)],\n];\n\nfunction matchField(node: DiagnosticNode, needle: string): SearchField | undefined {\n for (const [field, read] of readers) {\n if (read(node)?.toLowerCase().includes(needle) === true) return field;\n }\n\n return undefined;\n}\n\nfunction searchGraph(index: DiagnosticGraphIndex, query: string, limit: number = defaultLimit): readonly SearchHit[] {\n const needle = query.trim().toLowerCase();\n\n if (needle.length === 0) return [];\n\n const hits: SearchHit[] = [];\n\n for (const node of index.nodes()) {\n if (hits.length >= limit) break;\n\n const field = matchField(node, needle);\n\n if (field === undefined) continue;\n\n hits.push({ display: index.displayOf(node.id), field, id: node.id, kind: node.kind, label: node.label });\n }\n\n return hits;\n}\n\nexport { searchGraph };\nexport type { SearchField, SearchHit };\n"],"names":["labelOf","index","id","_a","contributionState","node","contributionsOf","found","edge","contributionsInto","target","targetOf","contribution","contributorOf","rowFor","endpoint","own","contributor","rowsFromContributor","rows","seen","sibling","rowsFromTarget","projectExtensionPoints","store","inverted","failureOf","generationOf","progressOf","state","isReadyDisplay","kind","defined","fields","result","key","value","isSatisfied","isWeakEdge","isHardEdge","provider","blockerRow","weak","blockerRows","isDependencyEdge","nestedOwned","owner","child","ownedRows","whyThisState","blockers","failure","progress","total","blocker","provenanceOf","fallbackAxes","desired","breadcrumbsFor","groupLabel","groupId","application","trail","groupFacts","group","optionalFields","runtime","projectInspector","facts","defaultLimit","readers","matchField","needle","field","read","searchGraph","query","limit","hits"],"mappings":"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"}
|
package/dist/search.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search over the fields §2 puts in the protocol: id, label, kind, origin and failure. A failure is indexed by the
|
|
3
|
+
* two words that make it up — the subject of the runtime's error class and its code (D69) — so `quarantined` and
|
|
4
|
+
* `feature` both find the same node. Arbitrary error text is not in the protocol and is therefore not indexable:
|
|
5
|
+
* there is nothing here to grep for a stack trace.
|
|
6
|
+
*/
|
|
7
|
+
import type { DiagnosticGraphIndex } from './graph-index.js';
|
|
8
|
+
import type { DiagnosticLabel, DiagnosticNodeId, DiagnosticNodeKind } from './protocol.js';
|
|
9
|
+
import type { NodeDisplayState } from './visual-axes.js';
|
|
10
|
+
type SearchField = 'failure-code' | 'failure-subject' | 'id' | 'kind' | 'label' | 'provenance';
|
|
11
|
+
type SearchHit = Readonly<{
|
|
12
|
+
display: NodeDisplayState;
|
|
13
|
+
field: SearchField;
|
|
14
|
+
id: DiagnosticNodeId;
|
|
15
|
+
kind: DiagnosticNodeKind;
|
|
16
|
+
label: DiagnosticLabel;
|
|
17
|
+
}>;
|
|
18
|
+
declare function searchGraph(index: DiagnosticGraphIndex, query: string, limit?: number): readonly SearchHit[];
|
|
19
|
+
export { searchGraph };
|
|
20
|
+
export type { SearchField, SearchHit };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const T="opetope.devtools-graph/3",S="opetope.devtools-frame/3",L={false:["closed","healthy"],"source-closed":["closed","stale"],true:["ready","healthy"]},D={active:["ready","healthy"],closed:["closed","healthy"],failed:["closed","failed"],inactive:["closed","healthy"],opening:["opening","healthy"],retiring:["retiring","healthy"]},G={"cleanup-failed":["closed","failed"],draining:["retiring","healthy"],fencing:["fencing","healthy"],"not-ready":["closed","failed"],opening:["opening","healthy"],quarantined:["retiring","quarantined"],ready:["ready","healthy"],retired:["closed","healthy"],waiting:["waiting","blocked"]},j={closed:["closed","healthy"],closing:["retiring","healthy"],"failed-close":["retiring","failed"],opening:["opening","healthy"],ready:["ready","healthy"]},z={pending:["waiting","blocked"],published:["ready","healthy"],rejected:["closed","failed"],withdrawn:["closed","healthy"],withheld:["ready","blocked"]},H={absent:["declared","blocked"],available:["ready","healthy"],unavailable:["waiting","blocked"]},K={bound:["ready","healthy"],deferred:["declared","healthy"],unbound:["declared","blocked"]},V={attachment:j,condition:L,"condition-group":D,contribution:z,"feature-instance":G,"host-contract":K,port:H},_=["declared","healthy"];function w(i){return V[i.kind][i.state.kind]??_}function k(i,e){const[t,s]=w(i);return{desired:e,health:s,lifecycle:t}}const $={cancelled:"failed",failed:"failed",quarantined:"quarantined",stale:"retiring"},J={closed:"retiring",declared:"declared",fencing:"retiring",opening:"opening",ready:"ready",retiring:"retiring",waiting:"waiting"};function q(i){return $[i.health]??J[i.lifecycle]}function B(i){if(i.kind==="feature-instance")return i.group;if(i.kind==="attachment")return i.owner;if(i.kind==="contribution")return i.contributor}const I=4,Q=[];function E(i,e){let t=i.get(e);return t===void 0&&(t=new Set,i.set(e,t)),t}class N{plan;conditionsById=new Map;edgesById=new Map;edgesFrom=new Map;edgesTo=new Map;instanceByFeature=new Map;planNodes=new Map;runtimeNodes=new Map;treeCache;constructor(e){this.plan=e.plan;const{plan:t,runtime:s}=e;this.addPlanNodes([t.application]),this.addPlanNodes(t.absentProviders),this.addPlanNodes(t.conditions);for(const n of t.conditions)this.conditionsById.set(n.conditionId,n);this.addPlanNodes(t.groups),this.addPlanNodes(t.features),this.addPlanNodes(t.ports),this.addPlanNodes(t.hostContracts),this.addPlanNodes(t.targets),this.addPlanNodes(t.contributions);for(const n of t.edges)this.upsertEdge(n);this.addRuntimeNodes(s.conditions),this.addRuntimeNodes(s.groups),this.addRuntimeNodes(s.instances),this.addRuntimeNodes(s.attachments),this.addRuntimeNodes(s.contributions),this.addRuntimeNodes(s.ports),this.addRuntimeNodes(s.hostContracts);for(const n of s.edges)this.upsertEdge(n)}axesOf(e){const t=this.runtimeNodes.get(e);if(t!==void 0)return k(t,this.desiredOf(e))}condition(e){return this.conditionsById.get(e)}currentNodeId(e){var t;return((t=this.instanceByFeature.get(e))==null?void 0:t.id)??e}desiredOf(e){const t=this.groupOf(e);return t!==void 0?t.desired.effective:this.ownedByApplication(e)?"active":"inactive"}displayOf(e){const t=this.axesOf(e);return t===void 0?"declared":q(t)}edge(e){return this.edgesById.get(e)}edges(){return this.edgesById.values()}groupOf(e){let t=this.runtimeNodes.get(e)??this.declarationGroup(e);for(let s=0;s<I;s+=1){if(t===void 0)return;if(t.kind==="condition-group")return t;const n=B(t);if(n===void 0)return;t=this.runtimeNodes.get(n)}}incoming(e){return this.collect(this.edgesTo.get(e))}instanceOf(e){return this.instanceByFeature.get(e)}node(e){return this.runtimeNodes.get(e)??this.planNodes.get(e)}*nodes(){yield*this.runtimeNodes.values();for(const e of this.planNodes.values())this.runtimeNodes.has(e.id)||(yield e)}outgoing(e){return this.collect(this.edgesFrom.get(e))}planNode(e){return this.planNodes.get(e)}removeEdge(e){const t=this.edgesById.get(e);t!==void 0&&(this.detachEdge(t),this.edgesById.delete(e))}removeNode(e){var s;const t=this.runtimeNodes.get(e);(t==null?void 0:t.kind)==="feature-instance"&&t.declaration!==void 0&&((s=this.instanceByFeature.get(t.declaration))==null?void 0:s.id)===e&&this.instanceByFeature.delete(t.declaration),this.runtimeNodes.delete(e)}runtimeNode(e){return this.runtimeNodes.get(e)}tree(){return this.treeCache??(this.treeCache=this.buildTree()),this.treeCache}upsertEdge(e){const t=this.edgesById.get(e.id);t!==void 0&&this.detachEdge(t),this.edgesById.set(e.id,e),E(this.edgesFrom,e.from).add(e.id),E(this.edgesTo,e.to).add(e.id)}upsertNode(e){this.runtimeNodes.set(e.id,e),e.kind==="feature-instance"&&e.declaration!==void 0&&this.instanceByFeature.set(e.declaration,e)}addPlanNodes(e){for(const t of e)this.planNodes.set(t.id,t)}addRuntimeNodes(e){for(const t of e)this.upsertNode(t)}buildTree(){const e=this.plan.application.id,t=[],s=this.plan.features.filter(n=>n.owner===e);s.length>0&&t.push({conditions:[],features:s.map(n=>this.featureRow(n)),id:e,label:this.plan.application.label});for(const n of this.plan.groups)t.push(this.groupRow(n));return t}collect(e){if(e===void 0||e.size===0)return Q;const t=[];for(const s of e){const n=this.edgesById.get(s);n!==void 0&&t.push(n)}return t}conditionNodes(e){const t=[];for(const s of e){const n=this.conditionsById.get(s);n!==void 0&&t.push(n)}return t}declarationGroup(e){const t=this.planNodes.get(e);if((t==null?void 0:t.kind)==="feature")return this.runtimeNodes.get(t.owner)}detachEdge(e){var t,s;(t=this.edgesFrom.get(e.from))==null||t.delete(e.id),(s=this.edgesTo.get(e.to))==null||s.delete(e.id)}featureDeclaration(e){const t=this.runtimeNodes.get(e),s=(t==null?void 0:t.kind)==="feature-instance"?t.declaration:e,n=s===void 0?void 0:this.planNodes.get(s);return(n==null?void 0:n.kind)==="feature"?n:void 0}featureRow(e){return{declaration:e,id:e.id,label:e.label}}groupRow(e){const t=[];for(const s of e.order){const n=this.planNodes.get(s);(n==null?void 0:n.kind)==="feature"&&t.push(this.featureRow(n))}return{conditions:this.conditionNodes(e.conditions),features:t,group:e,id:e.id,label:e.label}}ownedByApplication(e){let t=e;for(let s=0;s<I;s+=1){const n=this.featureDeclaration(t);if(n!==void 0)return n.owner===this.plan.application.id;const o=this.runtimeNodes.get(t),d=o===void 0?void 0:B(o);if(d===void 0)return!1;t=d}return!1}}const F={maxBytes:8*1024*1024,maxEntries:1e4},f=192,U=96;class P{get droppedCount(){return this.dropped}bytes=0;dropped=0;entries=new Map;limits;nextEntry=0;overflow;snapshot;constructor(e=F){if(!Number.isSafeInteger(e.maxEntries)||e.maxEntries<1)throw new RangeError("Timeline maxEntries must be a positive safe integer.");if(!Number.isSafeInteger(e.maxBytes)||e.maxBytes<f)throw new RangeError(`Timeline maxBytes must be a safe integer of at least ${f}.`);this.limits={maxBytes:e.maxBytes,maxEntries:e.maxEntries}}clear(){this.entries.clear(),this.bytes=0,this.dropped=0,this.nextEntry=0,this.overflow=void 0,this.snapshot=void 0}list(){return this.snapshot??(this.snapshot=[...this.overflow===void 0?[]:[this.overflow],...Array.from(this.entries.values(),({entry:e})=>e)]),this.snapshot}recordFrame(e){this.push({...e.cause===void 0?{}:{cause:e.cause},changed:e.operations.length,kind:"frame",sequence:e.lastSequence,stateRevision:e.nextRevision},f+e.operations.length*U)}recordGap(e,t){this.dropped+=t,this.push({dropped:t,kind:"gap",reason:e},f)}evict(){var t;let e=((t=this.overflow)==null?void 0:t.dropped)??0;for(;this.overflows(e);){const s=this.entries.entries().next().value;if(s===void 0)break;const[n,{cost:o,entry:d}]=s;this.entries.delete(n),this.bytes-=o,d.kind==="frame"?(e+=1,this.dropped+=1):e+=d.dropped}this.overflow=e===0?void 0:{dropped:e,kind:"gap",reason:"overflow"}}overflows(e){return this.entries.size+(e>0?1:0)>this.limits.maxEntries||this.bytes+(e>0?f:0)>this.limits.maxBytes}push(e,t){this.entries.set(this.nextEntry++,{cost:t,entry:e}),this.bytes+=t,this.snapshot=void 0,this.evict()}}const O=256,W=6;function X(i,e){var s;let t;for(const n of i.operations)n.op==="upsert-node"&&(e.push(n.node.id),(t===void 0||n.node.id===((s=i.cause)==null?void 0:s.node))&&(t=n.node));return t}function M(){return typeof performance=="object"?performance.now():0}class A{get activity(){return this.currentActivity}get graph(){return this.index}get status(){return{droppedFrames:this.timelineLog.droppedCount,frames:this.frames,lastSequence:this.lastSequence,planFingerprint:this.snapshot.planFingerprint,reducerMs:this.reducerMs,schemaRevision:this.snapshot.schemaRevision,sessionId:this.snapshot.sessionId,stateRevision:this.stateRevision,topologyRevision:this.snapshot.topologyRevision}}get timeline(){return this.timelineLog}currentActivity;frames=0;index;lastSequence;listeners=new Set;reducerMs=0;snapshot;stateRevision;steps=[];timelineLog;version=0;constructor(e,t){this.snapshot=e,this.currentActivity=e.activity,this.index=new N(e),this.lastSequence=e.lastSequence,this.stateRevision=e.stateRevision,this.timelineLog=new P(t)}applyFrame(e){const t=this.validateIdentity(e)??this.validateContinuity(e);if(t==="stale-session")return{kind:"ignored",reason:"stale-session"};if(t!==void 0)return{kind:"resync-required",reason:t};const s=M();return this.applyOperations(e.operations),e.activity!==void 0&&(this.currentActivity=e.activity),this.recordSteps(e),this.stateRevision=e.nextRevision,this.lastSequence=e.lastSequence,this.frames+=1,this.timelineLog.recordFrame(e),this.reducerMs=this.reducerMs*.8+(M()-s)*.2,this.notify(),{kind:"applied"}}chainFor(e,t=W){const s=this.relatedNodes(e),n=[];for(let o=this.steps.length-1;o>=0&&n.length<t;o-=1){const d=this.steps[o];(d==null?void 0:d.touched.some(u=>s.has(u)))===!0&&n.push(d.step)}return n.reverse()}getVersion(){return this.version}reset(e,t){const s=e.sessionId!==this.snapshot.sessionId;this.snapshot=e,this.currentActivity=e.activity,this.index=new N(e),this.lastSequence=e.lastSequence,this.stateRevision=e.stateRevision,this.steps.length=0,s&&this.timelineLog.clear(),this.timelineLog.recordGap(t,0),this.notify()}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}applyOperations(e){for(const t of e)t.op==="upsert-node"?this.index.upsertNode(t.node):t.op==="upsert-edge"?this.index.upsertEdge(t.edge):t.op==="remove-node"?this.index.removeNode(t.id):this.index.removeEdge(t.id)}notify(){this.version+=1;for(const e of this.listeners)e()}recordSteps(e){const{cause:t}=e;if(t===void 0)return;const s=[],n=X(e,s);if(n===void 0)return;const[o]=w(n);this.steps.push({step:{cause:t,lifecycle:o,node:n.id,sequence:e.lastSequence},touched:s}),this.steps.length>O&&this.steps.splice(0,this.steps.length-O)}relatedNodes(e){const t=new Set([e]),s=this.index.groupOf(e);s!==void 0&&t.add(s.id);for(const n of this.index.incoming(e))t.add(n.from);for(const n of this.index.outgoing(e))t.add(n.to);return t}validateContinuity(e){if(e.nextRevision<=this.stateRevision)return"duplicate";if(e.baseRevision!==this.stateRevision)return"revision-gap";if(e.firstSequence!==this.lastSequence+1)return"sequence-gap"}validateIdentity(e){if(e.schemaRevision!==S)return"schema-mismatch";if(e.sessionId!==this.snapshot.sessionId)return"stale-session";if(e.lastSequence<e.firstSequence||e.nextRevision<=e.baseRevision)return"malformed"}}const Y={maxBytes:512*1024,maxFrames:64},Z=8;function ee(i){if(typeof requestAnimationFrame!="function"){const t=setTimeout(i,0);return()=>clearTimeout(t)}const e=requestAnimationFrame(()=>i());return()=>cancelAnimationFrame(e)}function te(i,e={}){const t=e.limits??Y,s=e.schedule??ee;let n=i,o,d,u=!1,h=!1,v=!1;const b=()=>{if(u)return;u=!0,h=!1;const r=o,a=d,c=n;n=void 0,o=void 0,d=void 0;try{r==null||r()}finally{try{a==null||a()}finally{c==null||c.close()}}},p=(r,a)=>{var y;const c=[{kind:r,reason:a}];try{b()}catch(m){c.push({kind:"producer-threw",reason:m})}for(const m of c)(y=e.onFailure)==null||y.call(e,m)};let l;try{l=new A(i.getSnapshot(),e.timeline)}catch(r){throw p("snapshot-failed",r),r}const x=(r,a)=>{l.reset(a,r)},C=()=>{const r=n;if(r===void 0)return!1;const a=l.status.lastSequence,c=r.readSince(a,t);if(c.kind==="resync-required")return x(c.snapshot.sessionId===l.status.sessionId?"resync":"session-reset",c.snapshot),!1;for(const y of c.frames)if(l.applyFrame(y).kind==="resync-required")return x("resync",r.getSnapshot()),!1;return l.status.lastSequence>a},R={run:()=>{}},g=()=>{if(u||h)return;if(h=!0,v){queueMicrotask(()=>{h=!1,g()});return}let r=!1;v=!0;try{const a=s(()=>{r=!0,R.run()});!r&&h&&(o=a)}catch(a){p("producer-threw",a)}finally{v=!1}};R.run=()=>{if(o=void 0,h=!1,!u){try{for(let r=0;r<Z;r+=1)if(!C())return}catch(r){p("producer-threw",r);return}g()}};try{const r=i.subscribe(g);u?r():d=r,g()}catch(r){throw p("producer-threw",r),r}return{close:b,store:l}}export{A as D,P as a,N as b,te as c,F as d,q as e,S as f,T as g,w as h,k as n};
|
|
2
|
+
//# sourceMappingURL=session-qjKT0E69.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-qjKT0E69.js","sources":["../src/graph.ts","../src/visual-axes.ts","../src/graph-index.ts","../src/timeline.ts","../src/graph-store.ts","../src/session.ts"],"sourcesContent":["/**\n * The two projections of the diagnostic protocol: the immutable `plan` the application compiler produced and the\n * `runtime` state of the world it opened. They are not one mutable graph object — a feature keeps its declaration\n * while instances of it come and go — and merging them is exactly the mistake this protocol exists to prevent.\n *\n * `docs/devtools.md` §2 had a third, `resolutions`, holding frozen selection and admission\n * reasons for capability resolution. The current compiler has no such history: a port has exactly one provider,\n * chosen when `defineApplication` compiles the topology, and two providers are a compile error. The projection is\n * gone rather than kept empty.\n *\n * The plan mirrors `runtime/src/application-compiler.ts` one node kind at a time: `CompiledApplicationFeatureIR`,\n * `CompiledConditionGroupIR`, `ApplicationPortProviderIR`, `CompiledApplicationRequirementIR`,\n * `ApplicationImportProviderIR` and `CompiledApplicationContributionIR`.\n */\n\nimport type { RuntimeActivitySnapshot } from './activity';\nimport type {\n AttachmentState,\n ConditionGroupState,\n ConditionState,\n ContributionState,\n FeatureInstanceState,\n HostContractState,\n PortState,\n} from './node-state';\nimport type {\n DiagnosticCauseRef,\n DiagnosticConditionId,\n DiagnosticDesiredState,\n DiagnosticEdge,\n DiagnosticEdgeId,\n DiagnosticLabel,\n DiagnosticNodeId,\n DiagnosticPlanFingerprint,\n DiagnosticProvenance,\n DiagnosticSequence,\n DiagnosticSessionId,\n DiagnosticStateRevision,\n DiagnosticTopologyRevision,\n HostContractDemand,\n} from './protocol';\n\nconst graphSchemaRevision = 'opetope.devtools-graph/3';\nconst frameSchemaRevision = 'opetope.devtools-frame/3';\n\ntype GraphSchemaRevision = typeof graphSchemaRevision;\ntype FrameSchemaRevision = typeof frameSchemaRevision;\n\ntype PlanNodeBase = Readonly<{\n id: DiagnosticNodeId;\n label: DiagnosticLabel;\n provenance?: DiagnosticProvenance;\n}>;\n\ntype ApplicationPlanNode = PlanNodeBase &\n Readonly<{\n features: number;\n groups: number;\n kind: 'application';\n }>;\n\n/**\n * A condition declaration. `defineCondition({ id })` is bound by the host at `openApplication`; `source` names the\n * feature instead when `defineCondition({ from, id, select })` computes the fact from that feature's exports, and\n * the host is then not allowed to bind the id at all (D102).\n */\ntype ConditionPlanNode = PlanNodeBase &\n Readonly<{\n conditionId: DiagnosticConditionId;\n kind: 'condition';\n source: DiagnosticNodeId | 'host';\n }>;\n\n/**\n * The inferred owner of activation: features whose `when` names the same set of conditions form one group (D93). The\n * set decides membership, not the order; `order` is the canonical opening order the compiler derived from the hard\n * edges, and closing runs it in reverse.\n */\ntype ConditionGroupPlanNode = PlanNodeBase &\n Readonly<{\n conditions: readonly DiagnosticConditionId[];\n kind: 'condition-group';\n order: readonly DiagnosticNodeId[];\n }>;\n\n/** One `defineFeature`. `owner` is the application node for an empty `when`, otherwise its condition group. */\ntype FeaturePlanNode = PlanNodeBase &\n Readonly<{\n kind: 'feature';\n owner: DiagnosticNodeId;\n }>;\n\n/** One `definePort`. `provider` is absent when only `optional(port)` requires it and nothing provides it (D101). */\ntype PortPlanNode = PlanNodeBase &\n Readonly<{\n kind: 'port';\n provider?: DiagnosticNodeId;\n }>;\n\n/** One `defineHostContract`, seen as the `application-input` provider of the plan (D68, D83). */\ntype HostContractPlanNode = PlanNodeBase &\n Readonly<{\n demand: HostContractDemand;\n kind: 'host-contract';\n optional: boolean;\n }>;\n\n/**\n * A feature export contract the plan names with nothing behind it: `ApplicationImportProviderIR` of kind `absent`,\n * produced by `optional(featureDefinition)` when the application never enabled that feature. It is a node so an\n * `absent-import` edge has an origin to point at; it never opens, and it has no owner (D105).\n */\ntype AbsentProviderPlanNode = PlanNodeBase &\n Readonly<{\n kind: 'absent-provider';\n }>;\n\n/** A `defineSlot`, `definePipe` or `defineRegistry` target. Targets are declared standalone and own nothing. */\ntype ContributionTargetPlanNode = PlanNodeBase &\n Readonly<{\n kind: 'contribution-target';\n }>;\n\ntype ContributionPlanNode = PlanNodeBase &\n Readonly<{\n contributor: DiagnosticNodeId;\n kind: 'contribution';\n priority: number;\n target: DiagnosticNodeId;\n }>;\n\ntype DiagnosticPlanNode =\n | AbsentProviderPlanNode\n | ApplicationPlanNode\n | ConditionGroupPlanNode\n | ConditionPlanNode\n | ContributionPlanNode\n | ContributionTargetPlanNode\n | FeaturePlanNode\n | HostContractPlanNode\n | PortPlanNode;\n\n/** Immutable inside one diagnostic session; a plan replacement opens a new `sessionId` instead of mutating (§2.1). */\ntype ApplicationPlanSnapshot = Readonly<{\n absentProviders: readonly AbsentProviderPlanNode[];\n application: ApplicationPlanNode;\n conditions: readonly ConditionPlanNode[];\n contributions: readonly ContributionPlanNode[];\n /** Declaration-level edges. Instance-level ones live in `RuntimeStateSnapshot.edges`. */\n edges: readonly DiagnosticEdge[];\n features: readonly FeaturePlanNode[];\n groups: readonly ConditionGroupPlanNode[];\n hostContracts: readonly HostContractPlanNode[];\n ports: readonly PortPlanNode[];\n targets: readonly ContributionTargetPlanNode[];\n}>;\n\ntype RuntimeNodeBase = Readonly<{\n /** Immediate reason for the current state. Required for every state that is not healthy (§2.4). */\n cause?: DiagnosticCauseRef;\n /** The plan node this runtime record belongs to, when it is not itself a declaration. */\n declaration?: DiagnosticNodeId;\n id: DiagnosticNodeId;\n label: DiagnosticLabel;\n}>;\n\ntype ConditionRuntimeNode = Readonly<{\n kind: 'condition';\n state: ConditionState;\n}> &\n RuntimeNodeBase;\n\ntype ConditionGroupRuntimeNode = Readonly<{\n desired: DiagnosticDesiredState;\n kind: 'condition-group';\n state: ConditionGroupState;\n}> &\n RuntimeNodeBase;\n\n/**\n * One open of one feature. `generation` is the kernel's counter, kept as a number and not as a concept (D110); it\n * makes a restart visible without pretending the panel can address a past life.\n */\ntype FeatureInstanceNode = Readonly<{\n generation: number;\n /** The condition group that owns the desired axis, absent for a feature the application itself owns. */\n group?: DiagnosticNodeId;\n kind: 'feature-instance';\n previous?: number;\n state: FeatureInstanceState;\n}> &\n RuntimeNodeBase;\n\ntype AttachmentNode = Readonly<{\n kind: 'attachment';\n owner: DiagnosticNodeId;\n state: AttachmentState;\n}> &\n RuntimeNodeBase;\n\ntype ContributionRuntimeNode = Readonly<{\n contributor: DiagnosticNodeId;\n kind: 'contribution';\n state: ContributionState;\n target: DiagnosticNodeId;\n}> &\n RuntimeNodeBase;\n\ntype PortRuntimeNode = Readonly<{\n kind: 'port';\n state: PortState;\n}> &\n RuntimeNodeBase;\n\ntype HostContractRuntimeNode = Readonly<{\n kind: 'host-contract';\n state: HostContractState;\n}> &\n RuntimeNodeBase;\n\ntype DiagnosticRuntimeNode =\n | AttachmentNode\n | ConditionGroupRuntimeNode\n | ConditionRuntimeNode\n | ContributionRuntimeNode\n | FeatureInstanceNode\n | HostContractRuntimeNode\n | PortRuntimeNode;\n\ntype DiagnosticNode = DiagnosticPlanNode | DiagnosticRuntimeNode;\n\n/** Only the live world: current instances, their attachments, and the facts that decide what opens next. */\ntype RuntimeStateSnapshot = Readonly<{\n attachments: readonly AttachmentNode[];\n conditions: readonly ConditionRuntimeNode[];\n contributions: readonly ContributionRuntimeNode[];\n /** Instance-level edges: `owns`, live hard waits and the `Lookup` of every weak edge. */\n edges: readonly DiagnosticEdge[];\n groups: readonly ConditionGroupRuntimeNode[];\n hostContracts: readonly HostContractRuntimeNode[];\n instances: readonly FeatureInstanceNode[];\n ports: readonly PortRuntimeNode[];\n}>;\n\ntype RuntimeGraphSnapshot = Readonly<{\n activity?: RuntimeActivitySnapshot;\n lastSequence: DiagnosticSequence;\n plan: ApplicationPlanSnapshot;\n planFingerprint: DiagnosticPlanFingerprint;\n runtime: RuntimeStateSnapshot;\n schemaRevision: GraphSchemaRevision;\n sessionId: DiagnosticSessionId;\n stateRevision: DiagnosticStateRevision;\n topologyRevision: DiagnosticTopologyRevision;\n}>;\n\n/**\n * §6: a frame costs `O(changed nodes + changed edges)`, so it carries whole changed records rather than a copy of\n * the graph. Plan nodes never appear here — topology is immutable within a session.\n */\ntype DiagnosticOperation =\n | Readonly<{ edge: DiagnosticEdge; op: 'upsert-edge' }>\n | Readonly<{ id: DiagnosticEdgeId; op: 'remove-edge' }>\n | Readonly<{ id: DiagnosticNodeId; op: 'remove-node' }>\n | Readonly<{ node: DiagnosticRuntimeNode; op: 'upsert-node' }>;\n\n/**\n * One visible scheduler transaction. The panel must never see a state where a contribution is published but its\n * owning instance is not yet committed, or where a contribution is still visible after a fence (§2).\n *\n * There is no commit timestamp. The only clock in the protocol is `cause.at`, which stamps the trigger; a frame with\n * no cause has no time, and the timeline renders that column empty instead of stamping the moment the panel happened\n * to reduce it.\n */\ntype RuntimeGraphFrame = Readonly<{\n activity?: RuntimeActivitySnapshot;\n baseRevision: DiagnosticStateRevision;\n cause?: DiagnosticCauseRef;\n firstSequence: DiagnosticSequence;\n lastSequence: DiagnosticSequence;\n nextRevision: DiagnosticStateRevision;\n operations: readonly DiagnosticOperation[];\n schemaRevision: FrameSchemaRevision;\n sessionId: DiagnosticSessionId;\n}>;\n\nexport { frameSchemaRevision, graphSchemaRevision };\nexport type {\n AbsentProviderPlanNode,\n ApplicationPlanNode,\n ApplicationPlanSnapshot,\n AttachmentNode,\n ConditionGroupPlanNode,\n ConditionGroupRuntimeNode,\n ConditionPlanNode,\n ConditionRuntimeNode,\n ContributionPlanNode,\n ContributionRuntimeNode,\n ContributionTargetPlanNode,\n DiagnosticNode,\n DiagnosticOperation,\n DiagnosticPlanNode,\n DiagnosticRuntimeNode,\n FeatureInstanceNode,\n FeaturePlanNode,\n GraphSchemaRevision,\n HostContractPlanNode,\n HostContractRuntimeNode,\n PortPlanNode,\n PortRuntimeNode,\n RuntimeGraphFrame,\n RuntimeGraphSnapshot,\n RuntimeStateSnapshot,\n};\n","/**\n * The three orthogonal axes of `docs/devtools.md` §2.4, derived from the kind-specific state\n * unions. Only this module knows how a state maps onto `desired / lifecycle / health`; the panel styles nodes from\n * the axes and never re-reads a state union, and nothing derives a state from a neighbour's colour.\n *\n * Every table below is a total record over its union, so adding a state to `node-state.ts` is a type error here\n * rather than a silently grey node in the tree.\n */\n\nimport type { DiagnosticRuntimeNode } from './graph';\nimport type {\n AttachmentState,\n ConditionGroupState,\n ConditionState,\n ContributionState,\n FeatureInstanceState,\n HostContractState,\n PortState,\n} from './node-state';\nimport type { DesiredAxis, HealthAxis, LifecycleAxis } from './protocol';\n\ntype DiagnosticAxes = Readonly<{\n desired: DesiredAxis;\n health: HealthAxis;\n lifecycle: LifecycleAxis;\n}>;\n\n/**\n * The shapes of `docs/devtools.md` §4.6. State is never carried by colour alone.\n *\n * `declared` extends that table by owner decision: the design doc lists six states, all of which presuppose an open\n * instance, and a feature the plan declares while nothing has opened it is none of them. It renders as a muted ring\n * with its own tag rather than borrowing `waiting`, which would claim a blocker that does not exist.\n */\ntype NodeDisplayState = 'declared' | 'failed' | 'opening' | 'quarantined' | 'ready' | 'retiring' | 'waiting';\n\ntype Position = readonly [LifecycleAxis, HealthAxis];\ntype StateTable<State extends { readonly kind: string }> = Readonly<Record<State['kind'], Position>>;\n\n/** A condition is a fact, not a lifetime: it is either true, false, or unreadable because its source is gone. */\nconst conditionPositions: StateTable<ConditionState> = {\n false: ['closed', 'healthy'],\n 'source-closed': ['closed', 'stale'],\n true: ['ready', 'healthy'],\n};\n\nconst groupPositions: StateTable<ConditionGroupState> = {\n active: ['ready', 'healthy'],\n closed: ['closed', 'healthy'],\n failed: ['closed', 'failed'],\n inactive: ['closed', 'healthy'],\n opening: ['opening', 'healthy'],\n retiring: ['retiring', 'healthy'],\n};\n\nconst instancePositions: StateTable<FeatureInstanceState> = {\n 'cleanup-failed': ['closed', 'failed'],\n draining: ['retiring', 'healthy'],\n fencing: ['fencing', 'healthy'],\n 'not-ready': ['closed', 'failed'],\n opening: ['opening', 'healthy'],\n quarantined: ['retiring', 'quarantined'],\n ready: ['ready', 'healthy'],\n retired: ['closed', 'healthy'],\n waiting: ['waiting', 'blocked'],\n};\n\nconst attachmentPositions: StateTable<AttachmentState> = {\n closed: ['closed', 'healthy'],\n closing: ['retiring', 'healthy'],\n 'failed-close': ['retiring', 'failed'],\n opening: ['opening', 'healthy'],\n ready: ['ready', 'healthy'],\n};\n\nconst contributionPositions: StateTable<ContributionState> = {\n pending: ['waiting', 'blocked'],\n published: ['ready', 'healthy'],\n rejected: ['closed', 'failed'],\n withdrawn: ['closed', 'healthy'],\n /** Published and valid, but its `when` reads false, so the target does not list it (D79). */\n withheld: ['ready', 'blocked'],\n};\n\n/** A port with no provider is not broken: `optional(port)` is a legal hole in the plan, and calls settle (D105). */\nconst portPositions: StateTable<PortState> = {\n absent: ['declared', 'blocked'],\n available: ['ready', 'healthy'],\n unavailable: ['waiting', 'blocked'],\n};\n\nconst hostContractPositions: StateTable<HostContractState> = {\n bound: ['ready', 'healthy'],\n deferred: ['declared', 'healthy'],\n unbound: ['declared', 'blocked'],\n};\n\nconst positionsByNodeKind: Readonly<Record<DiagnosticRuntimeNode['kind'], Readonly<Record<string, Position>>>> = {\n attachment: attachmentPositions,\n condition: conditionPositions,\n 'condition-group': groupPositions,\n contribution: contributionPositions,\n 'feature-instance': instancePositions,\n 'host-contract': hostContractPositions,\n port: portPositions,\n};\n\nconst unknownPosition: Position = ['declared', 'healthy'];\n\n/** Where the node sits in its own automaton, without the desired axis its owning condition group contributes. */\nfunction nodePosition(node: DiagnosticRuntimeNode): Position {\n return positionsByNodeKind[node.kind][node.state.kind] ?? unknownPosition;\n}\n\n/**\n * The full style input for one node. `desired` is resolved by the caller from the owning condition group: a feature\n * instance has no desired state of its own, and a debug override would live on the group (§5.4).\n */\nfunction nodeAxes(node: DiagnosticRuntimeNode, desired: DesiredAxis): DiagnosticAxes {\n const [lifecycle, health] = nodePosition(node);\n\n return { desired, health, lifecycle };\n}\n\nconst displayByHealth: Readonly<Partial<Record<HealthAxis, NodeDisplayState>>> = {\n cancelled: 'failed',\n failed: 'failed',\n quarantined: 'quarantined',\n stale: 'retiring',\n};\n\nconst displayByLifecycle: Readonly<Record<LifecycleAxis, NodeDisplayState>> = {\n closed: 'retiring',\n declared: 'declared',\n fencing: 'retiring',\n opening: 'opening',\n ready: 'ready',\n retiring: 'retiring',\n waiting: 'waiting',\n};\n\n/** Health wins over lifecycle: a quarantined node that is technically retiring must read as quarantined. */\nfunction nodeDisplayState(axes: DiagnosticAxes): NodeDisplayState {\n return displayByHealth[axes.health] ?? displayByLifecycle[axes.lifecycle];\n}\n\nexport { nodeAxes, nodeDisplayState, nodePosition };\nexport type { DiagnosticAxes, NodeDisplayState };\n","/**\n * Incremental indexes over the two projections, per `docs/devtools.md` §6: built `O(N + E)`\n * from a snapshot, then updated per changed record. No recursive walk anywhere on the ingest path — owner chains are\n * followed with a bounded loop so a 20k-node corpus cannot overflow the stack.\n *\n * Condition groups, ports, host contracts, conditions and contributions each hold a plan record and a runtime record\n * under the same id: the plan declares them once, and a restart replaces the runtime record instead of minting a new\n * node. Only a feature is split in two — a `feature` declaration and a `feature-instance` per life — because one\n * declaration outlives many instances (§2.1).\n */\n\nimport type {\n ApplicationPlanSnapshot,\n ConditionGroupPlanNode,\n ConditionGroupRuntimeNode,\n ConditionPlanNode,\n DiagnosticNode,\n DiagnosticPlanNode,\n DiagnosticRuntimeNode,\n FeatureInstanceNode,\n FeaturePlanNode,\n RuntimeGraphSnapshot,\n} from './graph';\nimport type {\n DesiredAxis,\n DiagnosticConditionId,\n DiagnosticEdge,\n DiagnosticEdgeId,\n DiagnosticLabel,\n DiagnosticNodeId,\n} from './protocol';\nimport type { DiagnosticAxes, NodeDisplayState } from './visual-axes';\nimport { nodeAxes, nodeDisplayState } from './visual-axes';\n\n/**\n * A row of the tree carries structure only. Display is resolved per rendered row through `displayOf`, because\n * structure is immutable inside a session while display changes on every commit: baking it in here would make one\n * state-only frame cost `O(features)` instead of `O(rows actually drawn)` (§6).\n */\ntype TreeFeatureRow = Readonly<{\n declaration: FeaturePlanNode;\n /** Stable declaration identity. Resolve its current instance only when reading state or inspecting the row. */\n id: DiagnosticNodeId;\n label: DiagnosticLabel;\n}>;\n\n/**\n * One lifetime owner and its features. The application itself is an owner — a feature with an empty `when` lives as\n * long as the application (D93) — so it takes the first row and carries no conditions.\n */\ntype TreeGroupRow = Readonly<{\n conditions: readonly ConditionPlanNode[];\n features: readonly TreeFeatureRow[];\n group?: ConditionGroupPlanNode;\n id: DiagnosticNodeId;\n label: DiagnosticLabel;\n}>;\n\n/** Which node the desired axis of a dependent node comes from. A condition group owns the axis; nothing below does. */\nfunction ownerRefOf(node: DiagnosticRuntimeNode): DiagnosticNodeId | undefined {\n if (node.kind === 'feature-instance') return node.group;\n\n if (node.kind === 'attachment') return node.owner;\n\n if (node.kind === 'contribution') return node.contributor;\n\n return undefined;\n}\n\nconst maxOwnerHops = 4;\nconst emptyEdges: readonly DiagnosticEdge[] = [];\n\nfunction endpoint(index: Map<DiagnosticNodeId, Set<DiagnosticEdgeId>>, id: DiagnosticNodeId): Set<DiagnosticEdgeId> {\n let bucket = index.get(id);\n\n if (bucket === undefined) {\n bucket = new Set<DiagnosticEdgeId>();\n index.set(id, bucket);\n }\n\n return bucket;\n}\n\nclass DiagnosticGraphIndex {\n public readonly plan: ApplicationPlanSnapshot;\n\n private readonly conditionsById = new Map<DiagnosticConditionId, ConditionPlanNode>();\n private readonly edgesById = new Map<DiagnosticEdgeId, DiagnosticEdge>();\n private readonly edgesFrom = new Map<DiagnosticNodeId, Set<DiagnosticEdgeId>>();\n private readonly edgesTo = new Map<DiagnosticNodeId, Set<DiagnosticEdgeId>>();\n private readonly instanceByFeature = new Map<DiagnosticNodeId, FeatureInstanceNode>();\n private readonly planNodes = new Map<DiagnosticNodeId, DiagnosticPlanNode>();\n private readonly runtimeNodes = new Map<DiagnosticNodeId, DiagnosticRuntimeNode>();\n\n private treeCache: readonly TreeGroupRow[] | undefined;\n\n public constructor(snapshot: RuntimeGraphSnapshot) {\n this.plan = snapshot.plan;\n\n const { plan, runtime } = snapshot;\n\n this.addPlanNodes([plan.application]);\n this.addPlanNodes(plan.absentProviders);\n this.addPlanNodes(plan.conditions);\n\n for (const condition of plan.conditions) this.conditionsById.set(condition.conditionId, condition);\n\n this.addPlanNodes(plan.groups);\n this.addPlanNodes(plan.features);\n this.addPlanNodes(plan.ports);\n this.addPlanNodes(plan.hostContracts);\n this.addPlanNodes(plan.targets);\n this.addPlanNodes(plan.contributions);\n\n for (const edge of plan.edges) this.upsertEdge(edge);\n\n this.addRuntimeNodes(runtime.conditions);\n this.addRuntimeNodes(runtime.groups);\n this.addRuntimeNodes(runtime.instances);\n this.addRuntimeNodes(runtime.attachments);\n this.addRuntimeNodes(runtime.contributions);\n this.addRuntimeNodes(runtime.ports);\n this.addRuntimeNodes(runtime.hostContracts);\n\n for (const edge of runtime.edges) this.upsertEdge(edge);\n }\n\n public axesOf(id: DiagnosticNodeId): DiagnosticAxes | undefined {\n const node = this.runtimeNodes.get(id);\n\n if (node === undefined) return undefined;\n\n return nodeAxes(node, this.desiredOf(id));\n }\n\n /** Edges whose `to` is this node: its blockers, owners and providers (§2.3 orientation). */\n /**\n * The condition a control command addresses, found by the atom the producer publishes. The readable declaration id\n * is its label: a panel that printed the atom would show `a_sb` where the author wrote `a/b` (D200).\n */\n public condition(id: DiagnosticConditionId): ConditionPlanNode | undefined {\n return this.conditionsById.get(id);\n }\n\n /** Topology and selection keep declaration ids; the current runtime instance is a separate projection. */\n public currentNodeId(id: DiagnosticNodeId): DiagnosticNodeId {\n return this.instanceByFeature.get(id)?.id ?? id;\n }\n\n /**\n * What the activation machine wants for this node. It comes from the condition group that owns it, or from the\n * application itself for a feature with an empty `when`, which lives as long as the application does.\n */\n public desiredOf(id: DiagnosticNodeId): DesiredAxis {\n const group = this.groupOf(id);\n\n if (group !== undefined) return group.desired.effective;\n\n return this.ownedByApplication(id) ? 'active' : 'inactive';\n }\n\n public displayOf(id: DiagnosticNodeId): NodeDisplayState {\n const axes = this.axesOf(id);\n\n if (axes === undefined) return 'declared';\n\n return nodeDisplayState(axes);\n }\n\n public edge(id: DiagnosticEdgeId): DiagnosticEdge | undefined {\n return this.edgesById.get(id);\n }\n\n public edges(): IterableIterator<DiagnosticEdge> {\n return this.edgesById.values();\n }\n\n /** The condition group that owns this node's desired axis, found by a bounded owner walk. */\n public groupOf(id: DiagnosticNodeId): ConditionGroupRuntimeNode | undefined {\n let current = this.runtimeNodes.get(id) ?? this.declarationGroup(id);\n\n for (let hop = 0; hop < maxOwnerHops; hop += 1) {\n if (current === undefined) return undefined;\n\n if (current.kind === 'condition-group') return current;\n\n const owner = ownerRefOf(current);\n\n if (owner === undefined) return undefined;\n\n current = this.runtimeNodes.get(owner);\n }\n\n return undefined;\n }\n\n public incoming(id: DiagnosticNodeId): readonly DiagnosticEdge[] {\n return this.collect(this.edgesTo.get(id));\n }\n\n public instanceOf(feature: DiagnosticNodeId): FeatureInstanceNode | undefined {\n return this.instanceByFeature.get(feature);\n }\n\n public node(id: DiagnosticNodeId): DiagnosticNode | undefined {\n return this.runtimeNodes.get(id) ?? this.planNodes.get(id);\n }\n\n /**\n * Every node exactly once, runtime record first. A group, port, host contract, condition or contribution holds a\n * plan and a runtime record under the same id, so the plan pass skips whatever the runtime pass already yielded.\n */\n public *nodes(): Generator<DiagnosticNode> {\n yield* this.runtimeNodes.values();\n\n for (const node of this.planNodes.values()) {\n if (!this.runtimeNodes.has(node.id)) yield node;\n }\n }\n\n /** Edges whose `from` is this node: what it owns, provides and unblocks. */\n public outgoing(id: DiagnosticNodeId): readonly DiagnosticEdge[] {\n return this.collect(this.edgesFrom.get(id));\n }\n\n public planNode(id: DiagnosticNodeId): DiagnosticPlanNode | undefined {\n return this.planNodes.get(id);\n }\n\n public removeEdge(id: DiagnosticEdgeId): void {\n const edge = this.edgesById.get(id);\n\n if (edge === undefined) return;\n\n this.detachEdge(edge);\n this.edgesById.delete(id);\n }\n\n public removeNode(id: DiagnosticNodeId): void {\n const node = this.runtimeNodes.get(id);\n\n if (\n node?.kind === 'feature-instance' &&\n node.declaration !== undefined &&\n this.instanceByFeature.get(node.declaration)?.id === id\n ) {\n this.instanceByFeature.delete(node.declaration);\n }\n\n this.runtimeNodes.delete(id);\n }\n\n public runtimeNode(id: DiagnosticNodeId): DiagnosticRuntimeNode | undefined {\n return this.runtimeNodes.get(id);\n }\n\n /**\n * Features grouped by the lifetime owner the compiler inferred. Built once and kept: the plan is immutable inside a\n * session (§2.1), so no commit can change which feature belongs to which owner. Only display changes, and display\n * is not in these rows.\n */\n public tree(): readonly TreeGroupRow[] {\n this.treeCache ??= this.buildTree();\n\n return this.treeCache;\n }\n\n public upsertEdge(edge: DiagnosticEdge): void {\n const previous = this.edgesById.get(edge.id);\n\n if (previous !== undefined) this.detachEdge(previous);\n\n this.edgesById.set(edge.id, edge);\n endpoint(this.edgesFrom, edge.from).add(edge.id);\n endpoint(this.edgesTo, edge.to).add(edge.id);\n }\n\n public upsertNode(node: DiagnosticRuntimeNode): void {\n this.runtimeNodes.set(node.id, node);\n\n if (node.kind === 'feature-instance' && node.declaration !== undefined) {\n this.instanceByFeature.set(node.declaration, node);\n }\n }\n\n private addPlanNodes(nodes: readonly DiagnosticPlanNode[]): void {\n for (const node of nodes) this.planNodes.set(node.id, node);\n }\n\n private addRuntimeNodes(nodes: readonly DiagnosticRuntimeNode[]): void {\n for (const node of nodes) this.upsertNode(node);\n }\n\n private buildTree(): readonly TreeGroupRow[] {\n const application = this.plan.application.id;\n const rows: TreeGroupRow[] = [];\n const owned = this.plan.features.filter(feature => feature.owner === application);\n\n if (owned.length > 0) {\n rows.push({\n conditions: [],\n features: owned.map(feature => this.featureRow(feature)),\n id: application,\n label: this.plan.application.label,\n });\n }\n\n for (const group of this.plan.groups) rows.push(this.groupRow(group));\n\n return rows;\n }\n\n private collect(ids: ReadonlySet<DiagnosticEdgeId> | undefined): readonly DiagnosticEdge[] {\n if (ids === undefined || ids.size === 0) return emptyEdges;\n\n const edges: DiagnosticEdge[] = [];\n\n for (const id of ids) {\n const edge = this.edgesById.get(id);\n\n if (edge !== undefined) edges.push(edge);\n }\n\n return edges;\n }\n\n private conditionNodes(ids: readonly DiagnosticConditionId[]): readonly ConditionPlanNode[] {\n const nodes: ConditionPlanNode[] = [];\n\n for (const id of ids) {\n const node = this.conditionsById.get(id);\n\n if (node !== undefined) nodes.push(node);\n }\n\n return nodes;\n }\n\n /** A declaration has no runtime record, so its owner is read from the plan instead of walked. */\n private declarationGroup(id: DiagnosticNodeId): DiagnosticRuntimeNode | undefined {\n const declaration = this.planNodes.get(id);\n\n if (declaration?.kind !== 'feature') return undefined;\n\n return this.runtimeNodes.get(declaration.owner);\n }\n\n private detachEdge(edge: DiagnosticEdge): void {\n this.edgesFrom.get(edge.from)?.delete(edge.id);\n this.edgesTo.get(edge.to)?.delete(edge.id);\n }\n\n private featureDeclaration(id: DiagnosticNodeId): FeaturePlanNode | undefined {\n const node = this.runtimeNodes.get(id);\n const declaration = node?.kind === 'feature-instance' ? node.declaration : id;\n const plan = declaration === undefined ? undefined : this.planNodes.get(declaration);\n\n return plan?.kind === 'feature' ? plan : undefined;\n }\n\n /** Only immutable plan structure enters the cache. Instance arrival/replacement cannot stale this row. */\n private featureRow(declaration: FeaturePlanNode): TreeFeatureRow {\n return {\n declaration,\n id: declaration.id,\n label: declaration.label,\n };\n }\n\n private groupRow(group: ConditionGroupPlanNode): TreeGroupRow {\n const features: TreeFeatureRow[] = [];\n\n for (const featureId of group.order) {\n const declaration = this.planNodes.get(featureId);\n\n if (declaration?.kind === 'feature') features.push(this.featureRow(declaration));\n }\n\n return { conditions: this.conditionNodes(group.conditions), features, group, id: group.id, label: group.label };\n }\n\n /** A feature with an empty `when` owns the desired axis of its descendants through the application (D93). */\n private ownedByApplication(id: DiagnosticNodeId): boolean {\n let current = id;\n\n for (let hop = 0; hop < maxOwnerHops; hop += 1) {\n const feature = this.featureDeclaration(current);\n\n if (feature !== undefined) return feature.owner === this.plan.application.id;\n\n const node = this.runtimeNodes.get(current);\n const owner = node === undefined ? undefined : ownerRefOf(node);\n\n if (owner === undefined) return false;\n\n current = owner;\n }\n\n return false;\n }\n}\n\nexport { DiagnosticGraphIndex };\nexport type { TreeFeatureRow, TreeGroupRow };\n","/**\n * Bounded history, per `docs/devtools.md` §6: capped by both frame count and approximate\n * payload bytes, whichever comes first. Overflow drops the oldest history and inserts a gap marker — current state\n * is never part of what gets dropped, because it lives in the index, not here.\n *\n * The recorder cap on the runtime side and this UI cap are independent by design: one protects the producer, this one\n * protects the panel's store and the developer's readable history.\n */\n\nimport type { RuntimeGraphFrame } from './graph';\nimport type { DiagnosticCauseRef, DiagnosticSequence, DiagnosticStateRevision } from './protocol';\n\n/**\n * A committed transaction. It has no clock of its own: the only timestamp in the protocol is `cause.at`, which\n * stamps the trigger, so a commit with no cause shows an empty time column rather than the moment the panel reduced\n * it. Ordering is carried by `sequence`, which is what ordering actually depends on.\n */\ntype TimelineFrameEntry = Readonly<{\n cause?: DiagnosticCauseRef;\n /** Changed records in the commit: the `O(delta)` size of the frame, not of the graph. */\n changed: number;\n kind: 'frame';\n sequence: DiagnosticSequence;\n stateRevision: DiagnosticStateRevision;\n}>;\n\ntype TimelineGapReason = 'overflow' | 'resync' | 'session-reset';\n\ntype TimelineGapEntry = Readonly<{\n /** Frames known to be missing, or 0 when the count itself was lost. */\n dropped: number;\n kind: 'gap';\n reason: TimelineGapReason;\n}>;\n\ntype TimelineEntry = TimelineFrameEntry | TimelineGapEntry;\n\ntype TimelineLimits = Readonly<{\n maxBytes: number;\n maxEntries: number;\n}>;\n\nconst defaultTimelineLimits: TimelineLimits = {\n maxBytes: 8 * 1024 * 1024,\n maxEntries: 10_000,\n};\n\n/** Rough per-entry cost. Exact byte accounting would need serialization on the ingest path, which §6 forbids. */\nconst bytesPerEntry = 192;\nconst bytesPerOperation = 96;\n\nclass DevtoolsTimeline {\n public get droppedCount(): number {\n return this.dropped;\n }\n private bytes = 0;\n private dropped = 0;\n private readonly entries = new Map<number, { readonly cost: number; readonly entry: TimelineEntry }>();\n private readonly limits: TimelineLimits;\n private nextEntry = 0;\n private overflow: TimelineGapEntry | undefined;\n private snapshot: readonly TimelineEntry[] | undefined;\n\n public constructor(limits: TimelineLimits = defaultTimelineLimits) {\n if (!Number.isSafeInteger(limits.maxEntries) || limits.maxEntries < 1) {\n throw new RangeError('Timeline maxEntries must be a positive safe integer.');\n }\n\n if (!Number.isSafeInteger(limits.maxBytes) || limits.maxBytes < bytesPerEntry) {\n throw new RangeError(`Timeline maxBytes must be a safe integer of at least ${bytesPerEntry}.`);\n }\n\n this.limits = { maxBytes: limits.maxBytes, maxEntries: limits.maxEntries };\n }\n\n public clear(): void {\n this.entries.clear();\n this.bytes = 0;\n this.dropped = 0;\n this.nextEntry = 0;\n this.overflow = undefined;\n this.snapshot = undefined;\n }\n\n public list(): readonly TimelineEntry[] {\n this.snapshot ??= [\n ...(this.overflow === undefined ? [] : [this.overflow]),\n ...Array.from(this.entries.values(), ({ entry }) => entry),\n ];\n\n return this.snapshot;\n }\n\n public recordFrame(frame: RuntimeGraphFrame): void {\n this.push(\n {\n ...(frame.cause === undefined ? {} : { cause: frame.cause }),\n changed: frame.operations.length,\n kind: 'frame',\n sequence: frame.lastSequence,\n stateRevision: frame.nextRevision,\n },\n bytesPerEntry + frame.operations.length * bytesPerOperation,\n );\n }\n\n public recordGap(reason: TimelineGapReason, dropped: number): void {\n this.dropped += dropped;\n this.push({ dropped, kind: 'gap', reason }, bytesPerEntry);\n }\n\n /** The gap is part of both caps. A frame too large for the history becomes an explicit loss marker. */\n private evict(): void {\n let missing = this.overflow?.dropped ?? 0;\n\n while (this.overflows(missing)) {\n const oldest = this.entries.entries().next().value;\n\n if (oldest === undefined) break;\n\n const [id, { cost, entry }] = oldest;\n this.entries.delete(id);\n this.bytes -= cost;\n\n if (entry.kind === 'frame') {\n missing += 1;\n this.dropped += 1;\n } else {\n // Producer losses already entered droppedCount at recordGap; retain their count without counting twice.\n missing += entry.dropped;\n }\n }\n\n this.overflow = missing === 0 ? undefined : { dropped: missing, kind: 'gap', reason: 'overflow' };\n }\n\n private overflows(missing: number): boolean {\n return (\n this.entries.size + (missing > 0 ? 1 : 0) > this.limits.maxEntries ||\n this.bytes + (missing > 0 ? bytesPerEntry : 0) > this.limits.maxBytes\n );\n }\n\n private push(entry: TimelineEntry, cost: number): void {\n this.entries.set(this.nextEntry++, { cost, entry });\n this.bytes += cost;\n this.snapshot = undefined;\n this.evict();\n }\n}\n\nexport { defaultTimelineLimits, DevtoolsTimeline };\nexport type { TimelineEntry, TimelineFrameEntry, TimelineGapEntry, TimelineGapReason, TimelineLimits };\n","/**\n * The reducer of `docs/devtools.md` §3.3 and §7: a snapshot is the source of truth, contiguous\n * frames advance it, and anything that breaks continuity is rejected in favour of a fresh snapshot rather than\n * quietly applied.\n *\n * A frame is only accepted when it continues exactly this session and exactly this revision. A frame from an older\n * HMR session is ignored (its own store is gone); a duplicate, a revision jump or a sequence hole asks the caller to\n * resync, because a partially applied delta is a debugger that lies.\n */\n\nimport type { RuntimeActivitySnapshot } from './activity';\nimport type {\n DiagnosticOperation,\n DiagnosticRuntimeNode,\n GraphSchemaRevision,\n RuntimeGraphFrame,\n RuntimeGraphSnapshot,\n} from './graph';\nimport { frameSchemaRevision } from './graph';\nimport { DiagnosticGraphIndex } from './graph-index';\nimport type { DiagnosticCausalStep } from './node-state';\nimport type {\n DiagnosticNodeId,\n DiagnosticPlanFingerprint,\n DiagnosticSequence,\n DiagnosticSessionId,\n DiagnosticStateRevision,\n DiagnosticTopologyRevision,\n} from './protocol';\nimport type { TimelineGapReason, TimelineLimits } from './timeline';\nimport { DevtoolsTimeline } from './timeline';\nimport { nodePosition } from './visual-axes';\n\ntype FrameRejection = 'duplicate' | 'malformed' | 'revision-gap' | 'schema-mismatch' | 'sequence-gap';\n\ntype FrameOutcome =\n | Readonly<{ kind: 'applied' }>\n | Readonly<{ kind: 'ignored'; reason: 'stale-session' }>\n | Readonly<{ kind: 'resync-required'; reason: FrameRejection }>;\n\ntype DevtoolsStoreStatus = Readonly<{\n droppedFrames: number;\n frames: number;\n lastSequence: DiagnosticSequence;\n planFingerprint: DiagnosticPlanFingerprint;\n /** Rolling average of the reducer cost, against the §6 budget of 4 ms p95 for ≤100 changed records. */\n reducerMs: number;\n schemaRevision: GraphSchemaRevision;\n sessionId: DiagnosticSessionId;\n stateRevision: DiagnosticStateRevision;\n topologyRevision: DiagnosticTopologyRevision;\n}>;\n\n/** Commits kept for causal-path queries. Bounded like every other history in the panel (§6). */\nconst maxSteps = 256;\nconst defaultChainLimit = 6;\n\n/**\n * One recorded commit: the step the inspector renders, plus every node the commit touched. Relevance is decided by\n * the touched set, so a commit still counts as part of a node's cascade when it changed that node's condition group\n * or one of its blockers rather than the node itself.\n */\ntype RecordedStep = Readonly<{\n step: DiagnosticCausalStep;\n touched: readonly DiagnosticNodeId[];\n}>;\n\n/**\n * The node that best stands for a commit: the one its cause names, else the first node it changed. A commit that\n * opens a feature instance touches its attachments and contributions too, and listing all of them would bury the\n * transition the developer is actually reading.\n */\nfunction representativeOf(frame: RuntimeGraphFrame, touched: DiagnosticNodeId[]): DiagnosticRuntimeNode | undefined {\n let representative: DiagnosticRuntimeNode | undefined;\n\n for (const operation of frame.operations) {\n if (operation.op !== 'upsert-node') continue;\n\n touched.push(operation.node.id);\n\n if (representative === undefined || operation.node.id === frame.cause?.node) representative = operation.node;\n }\n\n return representative;\n}\n\nfunction now(): number {\n return typeof performance === 'object' ? performance.now() : 0;\n}\n\nclass DevtoolsGraphStore {\n public get activity(): RuntimeActivitySnapshot | undefined {\n return this.currentActivity;\n }\n public get graph(): DiagnosticGraphIndex {\n return this.index;\n }\n public get status(): DevtoolsStoreStatus {\n return {\n droppedFrames: this.timelineLog.droppedCount,\n frames: this.frames,\n lastSequence: this.lastSequence,\n planFingerprint: this.snapshot.planFingerprint,\n reducerMs: this.reducerMs,\n schemaRevision: this.snapshot.schemaRevision,\n sessionId: this.snapshot.sessionId,\n stateRevision: this.stateRevision,\n topologyRevision: this.snapshot.topologyRevision,\n };\n }\n public get timeline(): DevtoolsTimeline {\n return this.timelineLog;\n }\n\n private currentActivity: RuntimeActivitySnapshot | undefined;\n private frames = 0;\n private index: DiagnosticGraphIndex;\n private lastSequence: DiagnosticSequence;\n private readonly listeners = new Set<() => void>();\n private reducerMs = 0;\n private snapshot: RuntimeGraphSnapshot;\n private stateRevision: DiagnosticStateRevision;\n\n private readonly steps: RecordedStep[] = [];\n\n private readonly timelineLog: DevtoolsTimeline;\n\n private version = 0;\n\n public constructor(snapshot: RuntimeGraphSnapshot, limits?: TimelineLimits) {\n this.snapshot = snapshot;\n this.currentActivity = snapshot.activity;\n this.index = new DiagnosticGraphIndex(snapshot);\n this.lastSequence = snapshot.lastSequence;\n this.stateRevision = snapshot.stateRevision;\n this.timelineLog = new DevtoolsTimeline(limits);\n }\n\n public applyFrame(frame: RuntimeGraphFrame): FrameOutcome {\n const rejection = this.validateIdentity(frame) ?? this.validateContinuity(frame);\n\n if (rejection === 'stale-session') return { kind: 'ignored', reason: 'stale-session' };\n\n if (rejection !== undefined) return { kind: 'resync-required', reason: rejection };\n\n const started = now();\n\n this.applyOperations(frame.operations);\n\n if (frame.activity !== undefined) this.currentActivity = frame.activity;\n\n this.recordSteps(frame);\n this.stateRevision = frame.nextRevision;\n this.lastSequence = frame.lastSequence;\n this.frames += 1;\n this.timelineLog.recordFrame(frame);\n this.reducerMs = this.reducerMs * 0.8 + (now() - started) * 0.2;\n this.notify();\n\n return { kind: 'applied' };\n }\n\n /**\n * The causal path behind one node: the newest commits that touched it, the condition group that owns its desired\n * axis, or a node directly adjacent to it, one step per commit. That is what makes the chain read as a cascade — a\n * condition flipping, its group turning active, a feature instance opening, its contribution publishing — rather\n * than a burst of same-commit records that pushes the actual trigger out of the window.\n */\n public chainFor(id: DiagnosticNodeId, limit: number = defaultChainLimit): readonly DiagnosticCausalStep[] {\n const related = this.relatedNodes(id);\n const picked: DiagnosticCausalStep[] = [];\n\n for (let cursor = this.steps.length - 1; cursor >= 0 && picked.length < limit; cursor -= 1) {\n const recorded = this.steps[cursor];\n\n if (recorded?.touched.some(node => related.has(node)) === true) picked.push(recorded.step);\n }\n\n return picked.reverse();\n }\n\n /** The value `useSyncExternalStore` compares: it changes exactly when the graph, timeline or status changed. */\n public getVersion(): number {\n return this.version;\n }\n\n /** A new snapshot after a gap, a session reset or an HMR plan replacement (§3.3). */\n public reset(snapshot: RuntimeGraphSnapshot, reason: TimelineGapReason): void {\n const sessionChanged = snapshot.sessionId !== this.snapshot.sessionId;\n\n this.snapshot = snapshot;\n this.currentActivity = snapshot.activity;\n this.index = new DiagnosticGraphIndex(snapshot);\n this.lastSequence = snapshot.lastSequence;\n this.stateRevision = snapshot.stateRevision;\n this.steps.length = 0;\n\n if (sessionChanged) this.timelineLog.clear();\n\n this.timelineLog.recordGap(reason, 0);\n this.notify();\n }\n\n public subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n private applyOperations(operations: readonly DiagnosticOperation[]): void {\n for (const operation of operations) {\n if (operation.op === 'upsert-node') this.index.upsertNode(operation.node);\n else if (operation.op === 'upsert-edge') this.index.upsertEdge(operation.edge);\n else if (operation.op === 'remove-node') this.index.removeNode(operation.id);\n else this.index.removeEdge(operation.id);\n }\n }\n\n private notify(): void {\n this.version += 1;\n\n for (const listener of this.listeners) listener();\n }\n\n private recordSteps(frame: RuntimeGraphFrame): void {\n const { cause } = frame;\n\n if (cause === undefined) return;\n\n const touched: DiagnosticNodeId[] = [];\n const representative = representativeOf(frame, touched);\n\n if (representative === undefined) return;\n\n const [lifecycle] = nodePosition(representative);\n\n this.steps.push({\n step: { cause, lifecycle, node: representative.id, sequence: frame.lastSequence },\n touched,\n });\n\n if (this.steps.length > maxSteps) this.steps.splice(0, this.steps.length - maxSteps);\n }\n\n private relatedNodes(id: DiagnosticNodeId): ReadonlySet<DiagnosticNodeId> {\n const related = new Set<DiagnosticNodeId>([id]);\n const group = this.index.groupOf(id);\n\n if (group !== undefined) related.add(group.id);\n\n for (const edge of this.index.incoming(id)) related.add(edge.from);\n\n for (const edge of this.index.outgoing(id)) related.add(edge.to);\n\n return related;\n }\n\n private validateContinuity(frame: RuntimeGraphFrame): FrameRejection | undefined {\n if (frame.nextRevision <= this.stateRevision) return 'duplicate';\n\n if (frame.baseRevision !== this.stateRevision) return 'revision-gap';\n\n if (frame.firstSequence !== this.lastSequence + 1) return 'sequence-gap';\n\n return undefined;\n }\n\n private validateIdentity(frame: RuntimeGraphFrame): FrameRejection | 'stale-session' | undefined {\n if (frame.schemaRevision !== frameSchemaRevision) return 'schema-mismatch';\n\n if (frame.sessionId !== this.snapshot.sessionId) return 'stale-session';\n\n if (frame.lastSequence < frame.firstSequence) return 'malformed';\n\n if (frame.nextRevision <= frame.baseRevision) return 'malformed';\n\n return undefined;\n }\n}\n\nexport { DevtoolsGraphStore };\nexport type { DevtoolsStoreStatus, FrameOutcome, FrameRejection };\n","/**\n * The observation contract of `docs/devtools.md` §3.3 and the client that drives it.\n *\n * `RuntimeInspectionSession` is a *consumed* interface: the application-level Opetope runtime owns the semantics and\n * implements it behind its own trusted seam, and this package deliberately does not import `@opetope/runtime`.\n * Structural typing is the whole boundary — runtime never learns about devtools (§3.1), and devtools never reaches into\n * runtime internals, scans private WeakMaps or reconstructs the graph from logs (§3.1).\n *\n * Delivery is pull by cursor: the runtime commits a frame and only notifies, the client reads the batch itself. A\n * closed or slow panel therefore cannot create backpressure on the application (§3.3).\n */\n\nimport type { RuntimeGraphFrame, RuntimeGraphSnapshot } from './graph';\nimport { DevtoolsGraphStore } from './graph-store';\nimport type { DiagnosticSequence } from './protocol';\nimport type { TimelineLimits } from './timeline';\n\ntype ReadLimits = Readonly<{\n maxBytes: number;\n maxFrames: number;\n}>;\n\ntype ReadResult =\n | Readonly<{ frames: readonly RuntimeGraphFrame[]; kind: 'changes' }>\n | Readonly<{ kind: 'resync-required'; snapshot: RuntimeGraphSnapshot }>;\n\ninterface RuntimeInspectionSession {\n close(): void;\n getSnapshot(): RuntimeGraphSnapshot;\n readSince(cursor: DiagnosticSequence, limits: ReadLimits): ReadResult;\n subscribe(listener: () => void): () => void;\n}\n\ntype DevtoolsSessionFailure = Readonly<{\n kind: 'producer-threw' | 'snapshot-failed';\n reason: unknown;\n}>;\n\ntype DevtoolsSessionOptions = Readonly<{\n limits?: ReadLimits;\n /**\n * Where a diagnostics failure goes. §3.3: it is reported out of band to the host, never published back into the\n * same feed, so a failure path cannot recurse.\n */\n onFailure?: (failure: DevtoolsSessionFailure) => void;\n /** Coalescing hook. Defaults to one drain per animation frame (§6); tests pass a synchronous scheduler. */\n schedule?: (task: () => void) => () => void;\n timeline?: TimelineLimits;\n}>;\n\ntype DevtoolsSession = Readonly<{\n close: () => void;\n store: DevtoolsGraphStore;\n}>;\n\nconst defaultReadLimits: ReadLimits = { maxBytes: 512 * 1024, maxFrames: 64 };\n\n/** Pulls per drain. A burst is spread over frames instead of blocking the panel in one long task (§6). */\nconst maxPullsPerDrain = 8;\n\nfunction animationFrameScheduler(task: () => void): () => void {\n if (typeof requestAnimationFrame !== 'function') {\n const timer = setTimeout(task, 0);\n\n return () => clearTimeout(timer);\n }\n\n const handle = requestAnimationFrame(() => task());\n\n return () => cancelAnimationFrame(handle);\n}\n\n/**\n * Attaches to a runtime inspection session and keeps a `DevtoolsGraphStore` in step with it. Zero, one or many\n * attached clients must leave the application's demand store identical (§3.4): this reads and never asks for\n * anything to stay alive.\n */\nfunction connectDevtoolsSession(\n session: RuntimeInspectionSession,\n options: DevtoolsSessionOptions = {},\n): DevtoolsSession {\n const limits = options.limits ?? defaultReadLimits;\n const schedule = options.schedule ?? animationFrameScheduler;\n let producer: RuntimeInspectionSession | undefined = session;\n let cancelScheduled: (() => void) | undefined;\n let release: (() => void) | undefined;\n let closed = false;\n let scheduled = false;\n let scheduling = false;\n\n const close = (): void => {\n if (closed) return;\n\n closed = true;\n scheduled = false;\n const cancel = cancelScheduled;\n const unsubscribe = release;\n const retiring = producer;\n producer = undefined;\n cancelScheduled = undefined;\n release = undefined;\n\n try {\n cancel?.();\n } finally {\n try {\n unsubscribe?.();\n } finally {\n retiring?.close();\n }\n }\n };\n\n const fail = (kind: DevtoolsSessionFailure['kind'], reason: unknown): void => {\n const failures: DevtoolsSessionFailure[] = [{ kind, reason }];\n\n try {\n close();\n } catch (cleanupError) {\n failures.push({ kind: 'producer-threw', reason: cleanupError });\n }\n\n for (const failure of failures) options.onFailure?.(failure);\n };\n\n let store: DevtoolsGraphStore;\n\n try {\n store = new DevtoolsGraphStore(session.getSnapshot(), options.timeline);\n } catch (reason) {\n fail('snapshot-failed', reason);\n\n throw reason;\n }\n\n const resync = (reason: 'resync' | 'session-reset', snapshot: RuntimeGraphSnapshot): void => {\n store.reset(snapshot, reason);\n };\n\n /** One pull. Returns whether another is worth attempting right away. */\n const pull = (): boolean => {\n const current = producer;\n\n if (current === undefined) return false;\n\n const cursor = store.status.lastSequence;\n const result = current.readSince(cursor, limits);\n\n if (result.kind === 'resync-required') {\n resync(result.snapshot.sessionId === store.status.sessionId ? 'resync' : 'session-reset', result.snapshot);\n\n return false;\n }\n\n for (const frame of result.frames) {\n const outcome = store.applyFrame(frame);\n\n if (outcome.kind === 'resync-required') {\n resync('resync', current.getSnapshot());\n\n return false;\n }\n }\n\n // A byte-limited batch can be shorter than maxFrames with more commits still queued. Only an empty or\n // non-progressing batch ends the drain; a stale producer cannot make the continuation spin forever.\n return store.status.lastSequence > cursor;\n };\n\n /** A slot so the scheduled task and `request` can refer to each other without a forward reference. */\n const scheduledDrain: { run: () => void } = { run: () => undefined };\n\n const request = (): void => {\n if (closed || scheduled) return;\n\n scheduled = true;\n\n // A synchronous custom scheduler must not recurse once the pull budget is exhausted. The microtask only\n // trampolines that scheduler; the default animation-frame scheduler continues on its next animation frame.\n if (scheduling) {\n queueMicrotask(() => {\n scheduled = false;\n request();\n });\n\n return;\n }\n\n let ran = false;\n scheduling = true;\n\n try {\n const cancel = schedule(() => {\n ran = true;\n scheduledDrain.run();\n });\n\n if (!ran && scheduled) cancelScheduled = cancel;\n } catch (reason) {\n fail('producer-threw', reason);\n } finally {\n scheduling = false;\n }\n };\n\n scheduledDrain.run = (): void => {\n cancelScheduled = undefined;\n scheduled = false;\n\n if (closed) return;\n\n try {\n for (let pulls = 0; pulls < maxPullsPerDrain; pulls += 1) {\n if (!pull()) return;\n }\n } catch (reason) {\n fail('producer-threw', reason);\n\n return;\n }\n\n // The pull budget ran out with frames still waiting: continue on the next scheduled slot.\n request();\n };\n\n try {\n const unsubscribe = session.subscribe(request);\n\n // subscribe may notify synchronously and its first pull may fail before the release function is returned.\n if (closed) unsubscribe();\n else release = unsubscribe;\n\n // §3.3: subscribe, then read once unconditionally, so a commit landing between the two is never lost.\n request();\n } catch (reason) {\n fail('producer-threw', reason);\n\n throw reason;\n }\n\n return { close, store };\n}\n\nexport { connectDevtoolsSession };\nexport type {\n DevtoolsSession,\n DevtoolsSessionFailure,\n DevtoolsSessionOptions,\n ReadLimits,\n ReadResult,\n RuntimeInspectionSession,\n};\n"],"names":["graphSchemaRevision","frameSchemaRevision","conditionPositions","groupPositions","instancePositions","attachmentPositions","contributionPositions","portPositions","hostContractPositions","positionsByNodeKind","unknownPosition","nodePosition","node","nodeAxes","desired","lifecycle","health","displayByHealth","displayByLifecycle","nodeDisplayState","axes","ownerRefOf","maxOwnerHops","emptyEdges","endpoint","index","id","bucket","DiagnosticGraphIndex","snapshot","plan","runtime","condition","edge","_a","group","current","hop","owner","feature","previous","nodes","application","rows","owned","ids","edges","declaration","_b","features","featureId","defaultTimelineLimits","bytesPerEntry","bytesPerOperation","DevtoolsTimeline","limits","entry","frame","reason","dropped","missing","oldest","cost","maxSteps","defaultChainLimit","representativeOf","touched","representative","operation","now","DevtoolsGraphStore","rejection","started","limit","related","picked","cursor","recorded","sessionChanged","listener","operations","cause","defaultReadLimits","maxPullsPerDrain","animationFrameScheduler","task","timer","handle","connectDevtoolsSession","session","options","schedule","producer","cancelScheduled","release","closed","scheduled","scheduling","close","cancel","unsubscribe","retiring","fail","kind","failures","cleanupError","failure","store","resync","pull","result","scheduledDrain","request","ran","pulls"],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The observation contract of `docs/devtools.md` §3.3 and the client that drives it.
|
|
3
|
+
*
|
|
4
|
+
* `RuntimeInspectionSession` is a *consumed* interface: the application-level Opetope runtime owns the semantics and
|
|
5
|
+
* implements it behind its own trusted seam, and this package deliberately does not import `@opetope/runtime`.
|
|
6
|
+
* Structural typing is the whole boundary — runtime never learns about devtools (§3.1), and devtools never reaches into
|
|
7
|
+
* runtime internals, scans private WeakMaps or reconstructs the graph from logs (§3.1).
|
|
8
|
+
*
|
|
9
|
+
* Delivery is pull by cursor: the runtime commits a frame and only notifies, the client reads the batch itself. A
|
|
10
|
+
* closed or slow panel therefore cannot create backpressure on the application (§3.3).
|
|
11
|
+
*/
|
|
12
|
+
import type { RuntimeGraphFrame, RuntimeGraphSnapshot } from './graph.js';
|
|
13
|
+
import { DevtoolsGraphStore } from './graph-store.js';
|
|
14
|
+
import type { DiagnosticSequence } from './protocol.js';
|
|
15
|
+
import type { TimelineLimits } from './timeline.js';
|
|
16
|
+
type ReadLimits = Readonly<{
|
|
17
|
+
maxBytes: number;
|
|
18
|
+
maxFrames: number;
|
|
19
|
+
}>;
|
|
20
|
+
type ReadResult = Readonly<{
|
|
21
|
+
frames: readonly RuntimeGraphFrame[];
|
|
22
|
+
kind: 'changes';
|
|
23
|
+
}> | Readonly<{
|
|
24
|
+
kind: 'resync-required';
|
|
25
|
+
snapshot: RuntimeGraphSnapshot;
|
|
26
|
+
}>;
|
|
27
|
+
interface RuntimeInspectionSession {
|
|
28
|
+
close(): void;
|
|
29
|
+
getSnapshot(): RuntimeGraphSnapshot;
|
|
30
|
+
readSince(cursor: DiagnosticSequence, limits: ReadLimits): ReadResult;
|
|
31
|
+
subscribe(listener: () => void): () => void;
|
|
32
|
+
}
|
|
33
|
+
type DevtoolsSessionFailure = Readonly<{
|
|
34
|
+
kind: 'producer-threw' | 'snapshot-failed';
|
|
35
|
+
reason: unknown;
|
|
36
|
+
}>;
|
|
37
|
+
type DevtoolsSessionOptions = Readonly<{
|
|
38
|
+
limits?: ReadLimits;
|
|
39
|
+
/**
|
|
40
|
+
* Where a diagnostics failure goes. §3.3: it is reported out of band to the host, never published back into the
|
|
41
|
+
* same feed, so a failure path cannot recurse.
|
|
42
|
+
*/
|
|
43
|
+
onFailure?: (failure: DevtoolsSessionFailure) => void;
|
|
44
|
+
/** Coalescing hook. Defaults to one drain per animation frame (§6); tests pass a synchronous scheduler. */
|
|
45
|
+
schedule?: (task: () => void) => () => void;
|
|
46
|
+
timeline?: TimelineLimits;
|
|
47
|
+
}>;
|
|
48
|
+
type DevtoolsSession = Readonly<{
|
|
49
|
+
close: () => void;
|
|
50
|
+
store: DevtoolsGraphStore;
|
|
51
|
+
}>;
|
|
52
|
+
/**
|
|
53
|
+
* Attaches to a runtime inspection session and keeps a `DevtoolsGraphStore` in step with it. Zero, one or many
|
|
54
|
+
* attached clients must leave the application's demand store identical (§3.4): this reads and never asks for
|
|
55
|
+
* anything to stay alive.
|
|
56
|
+
*/
|
|
57
|
+
declare function connectDevtoolsSession(session: RuntimeInspectionSession, options?: DevtoolsSessionOptions): DevtoolsSession;
|
|
58
|
+
export { connectDevtoolsSession };
|
|
59
|
+
export type { DevtoolsSession, DevtoolsSessionFailure, DevtoolsSessionOptions, ReadLimits, ReadResult, RuntimeInspectionSession, };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fixture surface for tests and for a host that wants to see the panel without a runtime attached yet. Kept out of
|
|
3
|
+
* `./index` so the sample graph cannot end up in an application bundle by accident.
|
|
4
|
+
*/
|
|
5
|
+
export { assertInspectionSessionContract, InspectionContractError } from './conformance.js';
|
|
6
|
+
export type { ContractCheck, ContractCheckStatus, InspectionSessionFactory, InspectionSessionHarness, } from './conformance.js';
|
|
7
|
+
export { createFixtureSession } from './fixture.js';
|
|
8
|
+
export type { FixtureSession, FixtureSessionOptions } from './fixture.js';
|
|
9
|
+
export { authorizedConditionId, fixtureContributionIds, fixtureEdgeKinds, fixtureIds, fixturePlan, } from './fixture-plan.js';
|
|
10
|
+
export { fixtureAttachmentIds, fixtureFrames, fixtureInstanceIds, fixtureSessionId, fixtureSnapshot, } from './fixture-runtime.js';
|
package/dist/testing.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{s as L,f as U}from"./fold-snapshot-DjiURn8v.js";import{c as F,D as Q,f as Z,g as pe}from"./session-qjKT0E69.js";import{a as $,b as I,e as J,g as me,c as G,h as he,d as fe,f as ke}from"./protocol-joKTjlMj.js";class P{names=new Map;name(n){let t=this.names.get(n);return t===void 0&&(t=`known:${this.names.size}`,this.names.set(n,t)),t}}function ge(e,n,t){return e===null?null:{...e,blockedBy:e.blockedBy==="unknown"?"unknown":e.blockedBy.map(s=>n.get(s)??`unresolved:${s}`),id:t.name(e.id)}}function be(e){if(e===void 0)return;const n=new P,t=new P,s=new P,i=new P,r=new P,a=new Map(e.calls.map(d=>[d.id,t.name(d.id)]));return{...e,calls:e.calls.map(d=>({...d,id:t.name(d.id),lane:ge(d.lane,a,s)})),executionId:"execution",features:e.features.map(d=>({...d,id:n.name(d.id)})),resources:e.resources.map(d=>({...d,id:i.name(d.id),loads:d.loads==="unknown"?"unknown":d.loads.map(p=>({...p,id:r.name(p.id)}))}))}}class W extends Error{checks;constructor(n){const t=n.filter(s=>s.status==="failed");super(`RuntimeInspectionSession failed ${t.length} of ${n.length} contract checks:
|
|
2
|
+
${t.map(s=>` - ${s.name}: ${s.detail??"no detail"}`).join(`
|
|
3
|
+
`)}`),this.checks=n,this.name="InspectionContractError"}}const X={maxBytes:8*1024*1024,maxFrames:1024},q=e=>(e(),()=>{});function ve(){const e=[];return{check:(n,t,s)=>{e.push({...t||s===void 0?{}:{detail:s},name:n,status:t?"passed":"failed"})},checks:e,skip:(n,t)=>{e.push({detail:t,name:n,status:"skipped"})}}}function _(e,n){var i;const t=[];let s=n;for(let r=0;r<64;r+=1){const a=e.readSince(s,X);if(a.kind==="resync-required"||a.frames.length===0)return t;t.push(...a.frames),s=((i=a.frames[a.frames.length-1])==null?void 0:i.lastSequence)??s}return t}function Re(e,n,t){return e.schemaRevision!==Z?"has a foreign schema":e.baseRevision!==n?"does not continue the revision":e.firstSequence!==t+1?"leaves a sequence hole":e.operations.length===0&&e.activity===void 0?"commits nothing":void 0}function we(e,n){let t=n.stateRevision,s=n.lastSequence;for(const i of e){const r=Re(i,t,s);if(r!==void 0)return`frame ${i.lastSequence} ${r}`;t=i.nextRevision,s=i.lastSequence}}function Y(e){const{sessionId:n,...t}=e;return{...t,activity:be(e.activity)}}function Se(e,n){var p;const{session:t}=e,s=t.getSnapshot(),i=[];let r=0,a,d=s.lastSequence;for(;e.commit();){const S=_(t,d);i.push(...S),d=((p=i[i.length-1])==null?void 0:p.lastSequence)??d,r+=1,a===void 0&&!L(U(s,i),t.getSnapshot())&&(a=`snapshot and fold disagree after commit ${r}`)}n.check("snapshot equals snapshot plus frames at every commit boundary",a===void 0,a),n.check("the corpus commits at least one transaction",r>0,"the harness never committed")}function Ce(e,n){const{session:t}=e,s=t.getSnapshot(),i=t.readSince(s.lastSequence,X);for(n.check("nothing is readable before the first commit",i.kind==="changes"&&i.frames.length===0,"the producer served a frame the application had not committed");e.commit(););const r=we(_(t,s.lastSequence),s);n.check("frames arrive contiguous and whole",r===void 0,r)}function Ae(e,n){const t=e();for(;t.commit(););const s=t.session.getSnapshot();t.session.close();const i=e(),r=F(i.session,{schedule:q}),a=F(i.session,{schedule:q});for(;i.commit(););const d=i.session.getSnapshot(),p=L(Y(s),Y(d));n.check("the number of inspectors does not change what the producer reports",p,"an observed run reached a different workspace snapshot than an unobserved one"),n.check("every attached inspector reduces the same state",r.store.status.stateRevision===a.store.status.stateRevision,"two clients of one producer disagreed on the state revision"),r.close(),a.close()}function ye(e,n){const{session:t}=e,s=t.getSnapshot();if(!e.commit()){n.skip("rejects duplicate, gapped and stale frames","the harness committed nothing to replay");return}const[i]=_(t,s.lastSequence);if(i===void 0){n.skip("rejects duplicate, gapped and stale frames","the producer served no frame to replay");return}const r=new Q(s);n.check("accepts the first contiguous frame",r.applyFrame(i).kind==="applied"),n.check("rejects a duplicate frame",r.applyFrame(i).kind==="resync-required","a replayed frame advanced the graph twice");const a=new Q(s),d={...i,firstSequence:I(i.firstSequence+5),lastSequence:I(i.lastSequence+5),nextRevision:$(i.nextRevision+5)};n.check("rejects a frame that leaves a hole",a.applyFrame(d).kind==="resync-required","a gapped frame was applied instead of forcing a resync");const p=new Q(s),S={...i,sessionId:J("conformance-foreign-session")},g=p.applyFrame(S);n.check("ignores a frame from another session",g.kind==="ignored","a frame from a replaced plan reached the graph"),n.check("a rejected frame leaves the graph untouched",p.status.stateRevision===s.stateRevision,"a rejected frame still moved the state revision")}function Fe(e,n){const{session:t}=e;let s,i;const r=t.subscribe(()=>{try{s??(s=t.getSnapshot())}catch(a){i??(i=a)}});if(e.commit(),r(),n.check("reading from inside a listener does not throw",i===void 0,String(i)),s===void 0){const a="the producer did not notify while commit() ran, which \xA73.3 allows";n.skip("a listener observes a settled snapshot",a),n.skip("the listener did not consume the frame it was notified about",a);return}n.check("a listener observes a settled snapshot",s.stateRevision>=0,"the listener could not read the graph it was notified about"),n.check("the listener did not consume the frame it was notified about",L(t.getSnapshot(),s),"reading inside the listener changed what a later read returns")}function Ie(e,n){const t=[];let s=0;const r=F({close:()=>{},getSnapshot:()=>e.session.getSnapshot(),readSince:()=>{throw s+=1,new Error("conformance: the producer refused to serve")},subscribe:a=>e.session.subscribe(a)},{onFailure:a=>{t.push(a)},schedule:q});e.commit(),e.commit(),n.check("a throwing producer is reported out of band",t.length===1,`${t.length} reports`),n.check("a throwing producer is read once and then detached",s===1,`${s} reads`),r.close()}function Pe(e,n){const t=e();let s=0;const r=F({close:()=>t.session.close(),getSnapshot:()=>t.session.getSnapshot(),readSince:(d,p)=>t.session.readSince(d,p),subscribe:d=>{s+=1;const p=t.session.subscribe(d);return()=>{s-=1,p()}}},{schedule:q});n.check("connecting subscribes exactly once",s===1,`${s} listeners`),t.commit();const a=r.store.status.stateRevision;for(r.close();t.commit(););n.check("close releases the subscription",s===0,`${s} listeners survived close`),n.check("a closed client stops reducing",r.store.status.stateRevision===a,"the store advanced after close")}function qe(e){const n=ve();Se(e(),n),Ce(e(),n),Ae(e,n),ye(e(),n),Fe(e(),n),Ie(e(),n),Pe(e,n);const t=e();if(t.dropCommit===void 0)n.skip("a dropped frame forces a snapshot resync","the harness cannot drop a committed frame");else{const s=F(t.session,{schedule:q});for(t.dropCommit();t.commit(););n.check("a dropped frame forces a snapshot resync",t.session.getSnapshot().stateRevision===s.store.status.stateRevision,"the client did not recover the state it missed"),n.check("a resync leaves a gap marker in the history",s.store.timeline.list().some(i=>i.kind==="gap"),"history closed over a hole without marking it"),s.close()}if(n.checks.some(s=>s.status==="failed"))throw new W(n.checks);return n.checks}function xe(e,n){const t=e.session;let s=!1;const i=()=>{s||(s=!0,n.delete(i),t.close())};return n.add(i),{commit:()=>e.commit(),...e.dropCommit===void 0?{}:{dropCommit:()=>{var r;return((r=e.dropCommit)==null?void 0:r.call(e))??!1}},session:{close:i,getSnapshot:()=>t.getSnapshot(),readSince:(r,a)=>t.readSince(r,a),subscribe:r=>t.subscribe(r)}}}function ze(e){let n=!1,t;for(const s of e)try{s()}catch(i){n||(n=!0,t=i)}return{failed:n,failure:t}}function He(e){const n=new Set;let t;try{t={checks:qe(()=>xe(e(),n)),failed:!1}}catch(i){t={failed:!0,failure:i}}const s=ze(n);if(t.failed)throw t.failure;if(s.failed)throw s.failure;return t.checks}const Te=new Map([["/","_s"],[":","_c"],["_","__"],["|","_p"]]);function ee(e){let n="";for(const t of e){const s=Te.get(t);if(s!==void 0){n+=s;continue}n+=/[A-Za-z0-9.-]/u.test(t)?t:`_u${(t.codePointAt(0)??0).toString(16)}_`}return n}const c=G,o={absentExperiments:c("absent:experiments.exports"),accountReminder:c("accountReminder.autoOpen"),application:c("sampleApp"),appInfo:c("appInfo.polling"),catalogResolve:c("catalog.resolve"),authorizedGroup:c("group:sampleApp.authorized"),condition:c("sampleApp.authorized"),checkoutItemLookup:c("checkout.itemLookup"),checkoutCreateForm:c("checkout.createForm"),inventoryFeed:c("inventoryFeed"),hostCatalogPlatform:c("host:catalog.resolve.platform"),hostQuoteTelemetry:c("host:inventoryFeed.telemetry"),hostConfirmActionCommands:c("host:sessions.confirmAction.commands"),hostConfirmActionView:c("host:sessions.confirmAction.view"),hostHelpPlatform:c("host:utility.contributions.platform"),hostTasksPlatform:c("host:tasks.resource.platform"),dashboardPage:c("dashboard.page"),portQuote:c("port:inventoryFeed.quote"),portReceiptSink:c("port:checkout.receiptSink"),portResolveItem:c("port:catalog.resolveItem"),reportsPage:c("reports.page"),confirmAction:c("sessions.confirmAction"),helpContributions:c("utility.contributions"),targetHomeHeader:c("target:utility.homeHeader"),targetDashboardPage:c("target:dashboard.page"),targetOrderToolbar:c("target:checkout.orderHeaderToolbar"),targetConfirmActionContent:c("target:confirmAction.content"),tasksResource:c("tasks.resource")},v={dashboardPage:c("contribution:dashboard.page.page"),orderToolbar:c("contribution:checkout.createForm.toolbar"),confirmActionContent:c("contribution:sessions.confirmAction.content"),supportHomeHeader:c("contribution:utility.contributions.homeHeader")},E=me("sampleApp.authorized");function N(e,n,t){return he(`${e}:${ee(n)}:${ee(t)}`)}function f(e,n,t){return{from:n,id:N(e,n,t),kind:e,to:t}}function x(e,n,t,s=!1){return{from:n,id:N(e,n,t),kind:e,pending:s,to:t}}function z(e,n,t,s){return{from:n,id:N(e,n,t),kind:e,lookup:s,to:t}}const te=[o.accountReminder,o.appInfo,o.catalogResolve,o.checkoutItemLookup,o.checkoutCreateForm,o.inventoryFeed,o.dashboardPage,o.reportsPage,o.helpContributions],oe=[o.confirmAction,o.tasksResource];function B(e,n,t){return{id:e,kind:"feature",label:e,owner:n,...t===void 0?{}:{provenance:t}}}const ne=[...te.map(e=>B(e,o.application)),B(o.confirmAction,o.authorizedGroup,"examples/workspace/sessions/confirm-action"),B(o.tasksResource,o.authorizedGroup,"examples/workspace/tasks")],$e=[{conditionId:E,id:o.condition,kind:"condition",label:"sampleApp.authorized",provenance:"examples/workspace/auth/conditions.contract.ts",source:"host"}],se=[{conditions:[E],id:o.authorizedGroup,kind:"condition-group",label:"when sampleApp.authorized",order:oe}],Ge=[{id:o.portResolveItem,kind:"port",label:"catalog.resolveItem",provider:o.catalogResolve},{id:o.portQuote,kind:"port",label:"inventoryFeed.quote",provider:o.inventoryFeed},{id:o.portReceiptSink,kind:"port",label:"checkout.receiptSink"}];function C(e,n,t="instance",s=!1){return{demand:t,id:e,kind:"host-contract",label:n,optional:s}}const Ee=[C(o.hostCatalogPlatform,"catalog.resolve.platform"),C(o.hostQuoteTelemetry,"inventoryFeed.telemetry","instance",!0),C(o.hostConfirmActionCommands,"sessions.confirmAction.commands","onDemand"),C(o.hostConfirmActionView,"sessions.confirmAction.view"),C(o.hostHelpPlatform,"utility.contributions.platform"),C(o.hostTasksPlatform,"tasks.resource.platform")],De=[{id:o.absentExperiments,kind:"absent-provider",label:"experiments.exports"}],je=[{id:o.targetHomeHeader,kind:"contribution-target",label:"utility.homeHeader"},{id:o.targetDashboardPage,kind:"contribution-target",label:"dashboard.page"},{id:o.targetOrderToolbar,kind:"contribution-target",label:"checkout.orderHeaderToolbar"},{id:o.targetConfirmActionContent,kind:"contribution-target",label:"confirmAction.content"}];function D(e,n,t,s,i){return{contributor:t,id:e,kind:"contribution",label:n,priority:i,target:s}}const ie=[D(v.dashboardPage,"dashboard.page",o.dashboardPage,o.targetDashboardPage,0),D(v.orderToolbar,"checkout.createForm.toolbar",o.checkoutCreateForm,o.targetOrderToolbar,10),D(v.confirmActionContent,"sessions.confirmAction.content",o.confirmAction,o.targetConfirmActionContent,0),D(v.supportHomeHeader,"utility.contributions.homeHeader",o.helpContributions,o.targetHomeHeader,0)],Le=[...te.map(e=>f("owns",o.application,e)),...oe.map(e=>f("owns",o.authorizedGroup,e)),f("condition-control",o.condition,o.authorizedGroup),f("provides-port",o.catalogResolve,o.portResolveItem),f("provides-port",o.inventoryFeed,o.portQuote),f("on-demand-import",o.hostConfirmActionCommands,o.confirmAction),...ie.flatMap(e=>[f("owns",e.contributor,e.id),f("contributes-to",e.id,e.target)])],j={absentProviders:De,application:{features:ne.length,groups:se.length,id:o.application,kind:"application",label:"sampleApp"},conditions:$e,contributions:ie,edges:Le,features:ne,groups:se,hostContracts:Ee,ports:Ge,targets:je},Qe=["absent-import","absent-port","condition-control","contributes-to","hard-import","on-demand-import","optional-import","optional-port","owns","provides-port","requires-port"],V=J("session-7"),_e=ke("a3f9c2"),Ne=fe(1),M=1280,O=508,l=Date.UTC(2026,8,3,14,2,31,72);function h(e){return G(`instance:${e}`)}const u={accountReminder:h(o.accountReminder),appInfo:h(o.appInfo),catalogResolve:h(o.catalogResolve),checkoutItemLookup:h(o.checkoutItemLookup),checkoutCreateForm:h(o.checkoutCreateForm),inventoryFeed:h(o.inventoryFeed),dashboardPage:h(o.dashboardPage),confirmAction:h(o.confirmAction),helpContributions:h(o.helpContributions),tasksResource:h(o.tasksResource)},k={confirmActionCommands:G("attachment:sessions.confirmAction.commands"),tasksResource:G("attachment:tasks.resource.tasks")},R=e=>({at:e,condition:E,kind:"condition-change"});function re(e,n){return{...n===void 0?{}:{cause:n},id:o.condition,kind:"condition",label:"sampleApp.authorized",state:e?{kind:"true"}:{kind:"false"}}}function K(e,n,t){const s=n?"active":"inactive";return{...t===void 0?{}:{cause:t},desired:{effective:s,override:"none",source:s},id:o.authorizedGroup,kind:"condition-group",label:"when sampleApp.authorized",state:e}}function m(e,n,t,s,i){return{...i===void 0?{}:{cause:i},declaration:e,generation:n,...s===void 0?{}:{group:s},id:h(e),kind:"feature-instance",label:e,state:t}}const b={kind:"ready"};function H(e,n,t,s){return{id:e,kind:"attachment",label:n,owner:t,state:s}}function T(e,n){const t=j.contributions.find(s=>s.id===e);return{contributor:h((t==null?void 0:t.contributor)??e),declaration:e,id:e,kind:"contribution",label:(t==null?void 0:t.label)??e,state:n,target:(t==null?void 0:t.target)??e}}const Be=m(o.reportsPage,1,{kind:"opening"},void 0,{at:l,kind:"instance-transition",node:h(o.reportsPage)}),ae=[m(o.accountReminder,1,b),m(o.appInfo,1,b),m(o.catalogResolve,1,b),m(o.checkoutItemLookup,1,b),m(o.checkoutCreateForm,1,b),m(o.inventoryFeed,1,b),m(o.dashboardPage,1,b),Be,m(o.helpContributions,1,b)],Ve=m(o.confirmAction,3,b,o.authorizedGroup,R(l)),Me=m(o.tasksResource,3,b,o.authorizedGroup,R(l)),Oe=[{declaration:o.portResolveItem,id:o.portResolveItem,kind:"port",label:"catalog.resolveItem",state:{instance:u.catalogResolve,kind:"available"}},{declaration:o.portQuote,id:o.portQuote,kind:"port",label:"inventoryFeed.quote",state:{instance:u.inventoryFeed,kind:"available"}},{declaration:o.portReceiptSink,id:o.portReceiptSink,kind:"port",label:"checkout.receiptSink",state:{kind:"absent"}}];function A(e,n,t){return{declaration:e,id:e,kind:"host-contract",label:n,state:t}}const Ke=[A(o.hostCatalogPlatform,"catalog.resolve.platform",{kind:"bound"}),A(o.hostQuoteTelemetry,"inventoryFeed.telemetry",{kind:"unbound"}),A(o.hostConfirmActionCommands,"sessions.confirmAction.commands",{kind:"deferred"}),A(o.hostConfirmActionView,"sessions.confirmAction.view",{kind:"bound"}),A(o.hostHelpPlatform,"utility.contributions.platform",{kind:"bound"}),A(o.hostTasksPlatform,"tasks.resource.platform",{kind:"bound"})],Ue=[T(v.dashboardPage,{kind:"published"}),T(v.orderToolbar,{kind:"withheld"}),T(v.confirmActionContent,{kind:"published"}),T(v.supportHomeHeader,{kind:"published"})],Ze=[H(k.confirmActionCommands,"commands",u.confirmAction,{kind:"ready"}),H(k.tasksResource,"tasks",u.tasksResource,{kind:"ready"})],Je=[...ae.map(e=>f("owns",o.application,e.id)),f("owns",o.authorizedGroup,u.confirmAction),f("owns",o.authorizedGroup,u.tasksResource),f("owns",u.confirmAction,k.confirmActionCommands),f("owns",u.tasksResource,k.tasksResource),...j.contributions.map(e=>f("owns",h(e.contributor),e.id))],We=[x("hard-import",o.hostCatalogPlatform,u.catalogResolve),x("hard-import",o.hostConfirmActionView,u.confirmAction),x("hard-import",o.hostHelpPlatform,u.helpContributions),x("hard-import",o.hostTasksPlatform,u.tasksResource),x("requires-port",o.portResolveItem,u.checkoutItemLookup),z("absent-port",o.portReceiptSink,u.checkoutCreateForm,"missing"),z("optional-port",o.portQuote,u.checkoutCreateForm,"found"),z("absent-import",o.absentExperiments,u.inventoryFeed,"missing"),z("optional-import",o.hostQuoteTelemetry,u.inventoryFeed,"missing")],ce=e=>z("optional-import",u.tasksResource,u.helpContributions,e),Xe={attachments:Ze,conditions:[re(!0)],contributions:Ue,edges:[...Je,...We,ce("found")],groups:[K({kind:"active"},!0)],hostContracts:Ke,instances:[...ae,Ve,Me],ports:Oe},de={lastSequence:I(M),plan:j,planFingerprint:_e,runtime:Xe,schemaRevision:pe,sessionId:V,stateRevision:$(O),topologyRevision:Ne};function w(e,n,t){return{baseRevision:$(O+e-1),cause:n,firstSequence:I(M+e),lastSequence:I(M+e),nextRevision:$(O+e),operations:t,schemaRevision:Z,sessionId:V}}const Ye={kind:"retired",reason:"condition-inactive"},et={cause:{kind:"failure",node:k.tasksResource},code:"cleanup-failed",phase:"drain",subject:"feature"},tt={cause:{kind:"failure",node:k.tasksResource},code:"quarantined",phase:"drain",subject:"feature"},ue=[w(1,{...R(l),node:o.condition},[{node:re(!1,R(l)),op:"upsert-node"},{node:K({kind:"retiring",remaining:2},!1,R(l)),op:"upsert-node"}]),w(2,{at:l+3,kind:"instance-transition",node:u.confirmAction},[{node:m(o.confirmAction,3,{kind:"fencing"},o.authorizedGroup,R(l)),op:"upsert-node"},{node:T(v.confirmActionContent,{kind:"withdrawn"}),op:"upsert-node"}]),w(3,{at:l+9,kind:"instance-transition",node:u.confirmAction},[{node:m(o.confirmAction,3,{kind:"draining"},o.authorizedGroup,R(l)),op:"upsert-node"},{node:H(k.confirmActionCommands,"commands",u.confirmAction,{kind:"closing",phase:"close"}),op:"upsert-node"}]),w(4,{at:l+21,kind:"group-transition",node:o.authorizedGroup},[{node:m(o.confirmAction,3,Ye,o.authorizedGroup,R(l)),op:"upsert-node"},{id:k.confirmActionCommands,op:"remove-node"},{node:K({kind:"retiring",remaining:1},!1,R(l)),op:"upsert-node"}]),w(5,{at:l+24,kind:"instance-transition",node:u.tasksResource},[{node:m(o.tasksResource,3,{kind:"draining"},o.authorizedGroup,R(l)),op:"upsert-node"},{node:H(k.tasksResource,"tasks",u.tasksResource,{kind:"closing",phase:"close"}),op:"upsert-node"},{edge:ce("missing"),op:"upsert-edge"}]),w(6,{at:l+102,kind:"failure",node:k.tasksResource},[{node:H(k.tasksResource,"tasks",u.tasksResource,{failure:et,kind:"failed-close"}),op:"upsert-node"},{node:m(o.tasksResource,3,{failure:tt,kind:"quarantined"},o.authorizedGroup,{at:l+102,kind:"failure",node:k.tasksResource}),op:"upsert-node"}]),w(7,{at:l+140,kind:"instance-transition",node:h(o.reportsPage)},[{node:m(o.reportsPage,1,b,void 0,{at:l+140,kind:"instance-transition",node:h(o.reportsPage)}),op:"upsert-node"}])];function ot(e={}){const n=e.snapshot??de,t=[...e.frames??ue],s=[],i=new Set;let r=n.lastSequence+1,a=!1;const d=()=>{for(const g of i)g()},p=g=>{const y=t.shift();return y===void 0?!1:(s.push(y),g||(r=y.lastSequence+1),d(),!0)},S=()=>U(n,s);return{close:()=>{a=!0,i.clear(),t.length=0},dropNext:()=>p(!1),emitAll:()=>{for(;p(!0););},emitNext:()=>p(!0),getSnapshot:S,pendingCount:()=>t.length,readSince:(g,y)=>a?{frames:[],kind:"changes"}:g+1<r?{kind:"resync-required",snapshot:S()}:{frames:s.filter(le=>le.firstSequence>g).slice(0,y.maxFrames),kind:"changes"},subscribe:g=>(i.add(g),()=>{i.delete(g)})}}export{W as InspectionContractError,He as assertInspectionSessionContract,E as authorizedConditionId,ot as createFixtureSession,k as fixtureAttachmentIds,v as fixtureContributionIds,Qe as fixtureEdgeKinds,ue as fixtureFrames,o as fixtureIds,u as fixtureInstanceIds,j as fixturePlan,V as fixtureSessionId,de as fixtureSnapshot};
|
|
4
|
+
//# sourceMappingURL=testing.js.map
|