@generative-a11y/devtools 0.1.0 → 0.1.1

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/README.md CHANGED
@@ -75,15 +75,20 @@ Pass `source` when attaching a runtime driven by an adapter. This is an
75
75
  explicit, serializable declaration from the integration, not framework detection
76
76
  by devtools. It lets an inspector show the adapter name, documented public
77
77
  evidence and declared fidelity without filling gaps in the lifecycle trace.
78
- `interruption` and `retries` accept `exact`, `action-wrapper`, or `unavailable`.
79
- `connection` accepts those values plus `inferred`, because some integrations can
80
- only derive connection state from another documented public signal. The store
81
- freezes a copy of this metadata and includes it in its redacted export. Each
82
- captured record references an opaque `runtimeSourceId`. Source revisions remain
83
- immutable and exportable for as long as a retained record references them, even
84
- after a runtime detaches or the same runtime ID is reattached with different
85
- metadata. Unreferenced revisions are removed with ring-buffer eviction so
86
- repeated attachment cannot create unbounded source history.
78
+ Workflow fidelity distinguishes runs, steps, hierarchy, tools, interactions,
79
+ replay, reconnection, and unsupported custom events as exact, partial, or
80
+ unavailable where applicable. The inspector also shows content-free run and step
81
+ parentage, attempt boundaries, active or terminal state, and associated entity
82
+ IDs from the core diagnostic snapshot. `interruption` and `retries` accept
83
+ `exact`, `action-wrapper`, or `unavailable`. `connection` accepts those values
84
+ plus `inferred`, because some integrations can only derive connection state from
85
+ another documented public signal. The store freezes a copy of this metadata and
86
+ includes it in its redacted export. Each captured record references an opaque
87
+ `runtimeSourceId`. Source revisions remain immutable and exportable for as long
88
+ as a retained record references them, even after a runtime detaches or the same
89
+ runtime ID is reattached with different metadata. Unreferenced revisions are
90
+ removed with ring-buffer eviction so repeated attachment cannot create unbounded
91
+ source history.
87
92
 
88
93
  Use an adapter package's exported metadata where it fits the integration. For
89
94
  custom adapters, provide only public signals that justify normalized events. Do
package/dist/index.cjs CHANGED
@@ -34,6 +34,18 @@ function asRecord(runtimeId, event, captureSequence, runtimeSourceId) {
34
34
  kind: event.kind,
35
35
  sourceType: event.event.type,
36
36
  ...event.event.eventId ? { sourceEventId: event.event.eventId } : {},
37
+ ..."runId" in event.event && event.event.runId ? { runId: event.event.runId } : {},
38
+ ..."runInstanceId" in event.event && event.event.runInstanceId ? { runInstanceId: event.event.runInstanceId } : {},
39
+ ..."nextRunInstanceId" in event.event && event.event.nextRunInstanceId ? { nextRunInstanceId: event.event.nextRunInstanceId } : {},
40
+ ..."parentRunId" in event.event && event.event.parentRunId ? { parentRunId: event.event.parentRunId } : {},
41
+ ..."parentRunInstanceId" in event.event && event.event.parentRunInstanceId ? { parentRunInstanceId: event.event.parentRunInstanceId } : {},
42
+ ..."stepId" in event.event && event.event.stepId ? { stepId: event.event.stepId } : {},
43
+ ..."stepInstanceId" in event.event && event.event.stepInstanceId ? { stepInstanceId: event.event.stepInstanceId } : {},
44
+ ..."nextStepInstanceId" in event.event && event.event.nextStepInstanceId ? { nextStepInstanceId: event.event.nextStepInstanceId } : {},
45
+ ..."parentStepId" in event.event && event.event.parentStepId ? { parentStepId: event.event.parentStepId } : {},
46
+ ..."parentStepInstanceId" in event.event && event.event.parentStepInstanceId ? { parentStepInstanceId: event.event.parentStepInstanceId } : {},
47
+ ..."parentToolId" in event.event && event.event.parentToolId ? { parentToolId: event.event.parentToolId } : {},
48
+ ..."parentResponseId" in event.event && event.event.parentResponseId ? { parentResponseId: event.event.parentResponseId } : {},
37
49
  ..."responseId" in event.event ? { responseId: event.event.responseId } : {},
38
50
  ..."responseInstanceId" in event.event && event.event.responseInstanceId ? { responseInstanceId: event.event.responseInstanceId } : {},
39
51
  ..."nextResponseInstanceId" in event.event && event.event.nextResponseInstanceId ? { nextResponseInstanceId: event.event.nextResponseInstanceId } : {},
@@ -63,6 +75,10 @@ function asRecord(runtimeId, event, captureSequence, runtimeSourceId) {
63
75
  ...event.decision.responseId ? { responseId: event.decision.responseId } : {},
64
76
  ...event.decision.toolId ? { toolId: event.decision.toolId } : {},
65
77
  ...event.decision.interactionId ? { interactionId: event.decision.interactionId } : {},
78
+ ...event.decision.runId ? { runId: event.decision.runId } : {},
79
+ ...event.decision.runInstanceId ? { runInstanceId: event.decision.runInstanceId } : {},
80
+ ...event.decision.stepId ? { stepId: event.decision.stepId } : {},
81
+ ...event.decision.stepInstanceId ? { stepInstanceId: event.decision.stepInstanceId } : {},
66
82
  ...event.decision.scheduledAt !== void 0 ? { scheduledAt: event.decision.scheduledAt } : {},
67
83
  ...event.decision.dueAt !== void 0 ? { dueAt: event.decision.dueAt } : {},
68
84
  ...event.decision.delayMs !== void 0 ? { delayMs: event.decision.delayMs } : {},
@@ -86,6 +102,25 @@ function copyRuntimeSource(source) {
86
102
  throw new TypeError("source fidelity must be an object");
87
103
  const lifecycleFidelity = /* @__PURE__ */ new Set(["exact", "action-wrapper", "unavailable"]);
88
104
  const connectionFidelity = /* @__PURE__ */ new Set([...lifecycleFidelity, "inferred"]);
105
+ const workflowFidelity = /* @__PURE__ */ new Set(["exact", "partial", "unavailable"]);
106
+ for (const field of [
107
+ "runs",
108
+ "steps",
109
+ "hierarchy",
110
+ "tools",
111
+ "interactions",
112
+ "replay",
113
+ "reconnection"
114
+ ]) {
115
+ if (fidelity[field] !== void 0 && !workflowFidelity.has(fidelity[field]))
116
+ throw new TypeError(
117
+ `source ${field} fidelity contains an unsupported value`
118
+ );
119
+ }
120
+ if (fidelity.customEvents !== void 0 && fidelity.customEvents !== "explicit-mapping" && fidelity.customEvents !== "unsupported")
121
+ throw new TypeError(
122
+ "source custom event fidelity contains an unsupported value"
123
+ );
89
124
  if (!lifecycleFidelity.has(fidelity.interruption))
90
125
  throw new TypeError(
91
126
  "source interruption fidelity contains an unsupported value"
@@ -109,6 +144,14 @@ function copyRuntimeSource(source) {
109
144
  adapter: source.adapter.trim(),
110
145
  evidence: Object.freeze(source.evidence.map((item) => item.trim())),
111
146
  fidelity: Object.freeze({
147
+ ...fidelity.runs ? { runs: fidelity.runs } : {},
148
+ ...fidelity.steps ? { steps: fidelity.steps } : {},
149
+ ...fidelity.hierarchy ? { hierarchy: fidelity.hierarchy } : {},
150
+ ...fidelity.tools ? { tools: fidelity.tools } : {},
151
+ ...fidelity.interactions ? { interactions: fidelity.interactions } : {},
152
+ ...fidelity.replay ? { replay: fidelity.replay } : {},
153
+ ...fidelity.reconnection ? { reconnection: fidelity.reconnection } : {},
154
+ ...fidelity.customEvents ? { customEvents: fidelity.customEvents } : {},
112
155
  interruption: fidelity.interruption,
113
156
  retries: fidelity.retries,
114
157
  connection: fidelity.connection,
@@ -133,6 +176,10 @@ function asDeliveryRecord(input, captureSequence, runtimeSourceId) {
133
176
  ...result.responseId ? { responseId: result.responseId } : {},
134
177
  ...result.toolId ? { toolId: result.toolId } : {},
135
178
  ...result.interactionId ? { interactionId: result.interactionId } : {},
179
+ ...result.runId ? { runId: result.runId } : {},
180
+ ...result.runInstanceId ? { runInstanceId: result.runInstanceId } : {},
181
+ ...result.stepId ? { stepId: result.stepId } : {},
182
+ ...result.stepInstanceId ? { stepInstanceId: result.stepInstanceId } : {},
136
183
  ...result.error?.name ? { errorName: result.error.name } : {}
137
184
  });
138
185
  }
@@ -143,7 +190,8 @@ function copyRuntimeSnapshot(source) {
143
190
  policy: Object.freeze({
144
191
  ...source.policy,
145
192
  text: Object.freeze({ ...source.policy.text }),
146
- tools: Object.freeze({ ...source.policy.tools })
193
+ tools: Object.freeze({ ...source.policy.tools }),
194
+ workflows: Object.freeze({ ...source.policy.workflows })
147
195
  }),
148
196
  pending: Object.freeze({
149
197
  announcements: Object.freeze(
@@ -159,6 +207,16 @@ function copyRuntimeSnapshot(source) {
159
207
  tools: Object.freeze(
160
208
  source.tools.map((item) => Object.freeze({ ...item }))
161
209
  ),
210
+ ...source.runs ? {
211
+ runs: Object.freeze(
212
+ source.runs.map((item) => Object.freeze({ ...item }))
213
+ )
214
+ } : {},
215
+ ...source.steps ? {
216
+ steps: Object.freeze(
217
+ source.steps.map((item) => Object.freeze({ ...item }))
218
+ )
219
+ } : {},
162
220
  pendingCount: source.pendingCount
163
221
  });
164
222
  }
package/dist/index.d.cts CHANGED
@@ -22,6 +22,30 @@ interface DevtoolsRecord {
22
22
  readonly toolInstanceId?: string;
23
23
  readonly interactionId?: string;
24
24
  readonly approvalId?: string;
25
+ /** Stable logical run identity retained as content-free correlation data. */
26
+ readonly runId?: string;
27
+ /** Stable run attempt identity retained as correlation data. */
28
+ readonly runInstanceId?: string;
29
+ /** Replacement run attempt identity on retry evidence. */
30
+ readonly nextRunInstanceId?: string;
31
+ /** Explicit logical parent run identity. */
32
+ readonly parentRunId?: string;
33
+ /** Explicit parent run attempt identity. */
34
+ readonly parentRunInstanceId?: string;
35
+ /** Stable logical step identity retained as content-free correlation data. */
36
+ readonly stepId?: string;
37
+ /** Stable step attempt identity retained as correlation data. */
38
+ readonly stepInstanceId?: string;
39
+ /** Replacement step attempt identity on retry evidence. */
40
+ readonly nextStepInstanceId?: string;
41
+ /** Explicit logical parent step identity. */
42
+ readonly parentStepId?: string;
43
+ /** Explicit parent step attempt identity. */
44
+ readonly parentStepInstanceId?: string;
45
+ /** Explicit tool that delegated to a child run. */
46
+ readonly parentToolId?: string;
47
+ /** Explicit response that owns a child run. */
48
+ readonly parentResponseId?: string;
25
49
  readonly progress?: number;
26
50
  readonly outcome?: string;
27
51
  readonly count?: number;
@@ -41,7 +65,7 @@ interface DevtoolsRecord {
41
65
  interface DevtoolsRuntimeSource {
42
66
  readonly adapter: string;
43
67
  readonly evidence: readonly string[];
44
- readonly fidelity: Readonly<Omit<AdapterFidelity, "optionalEvents"> & {
68
+ readonly fidelity: Readonly<Pick<AdapterFidelity, "interruption" | "retries" | "connection"> & Partial<Pick<AdapterFidelity, "runs" | "steps" | "hierarchy" | "tools" | "interactions" | "replay" | "reconnection" | "customEvents">> & {
45
69
  readonly optionalEvents?: readonly NonNullable<AdapterFidelity["optionalEvents"]>[number][];
46
70
  }>;
47
71
  }
@@ -58,6 +82,14 @@ interface DeliveryRecordInput {
58
82
  readonly responseId?: string;
59
83
  readonly toolId?: string;
60
84
  readonly interactionId?: string;
85
+ /** Stable logical run identity copied from the delivered intent. */
86
+ readonly runId?: string;
87
+ /** Stable run attempt identity copied from the delivered intent. */
88
+ readonly runInstanceId?: string;
89
+ /** Stable logical step identity copied from the delivered intent. */
90
+ readonly stepId?: string;
91
+ /** Stable step attempt identity copied from the delivered intent. */
92
+ readonly stepInstanceId?: string;
61
93
  readonly error?: {
62
94
  readonly name: string;
63
95
  readonly message?: string;
package/dist/index.d.ts CHANGED
@@ -22,6 +22,30 @@ interface DevtoolsRecord {
22
22
  readonly toolInstanceId?: string;
23
23
  readonly interactionId?: string;
24
24
  readonly approvalId?: string;
25
+ /** Stable logical run identity retained as content-free correlation data. */
26
+ readonly runId?: string;
27
+ /** Stable run attempt identity retained as correlation data. */
28
+ readonly runInstanceId?: string;
29
+ /** Replacement run attempt identity on retry evidence. */
30
+ readonly nextRunInstanceId?: string;
31
+ /** Explicit logical parent run identity. */
32
+ readonly parentRunId?: string;
33
+ /** Explicit parent run attempt identity. */
34
+ readonly parentRunInstanceId?: string;
35
+ /** Stable logical step identity retained as content-free correlation data. */
36
+ readonly stepId?: string;
37
+ /** Stable step attempt identity retained as correlation data. */
38
+ readonly stepInstanceId?: string;
39
+ /** Replacement step attempt identity on retry evidence. */
40
+ readonly nextStepInstanceId?: string;
41
+ /** Explicit logical parent step identity. */
42
+ readonly parentStepId?: string;
43
+ /** Explicit parent step attempt identity. */
44
+ readonly parentStepInstanceId?: string;
45
+ /** Explicit tool that delegated to a child run. */
46
+ readonly parentToolId?: string;
47
+ /** Explicit response that owns a child run. */
48
+ readonly parentResponseId?: string;
25
49
  readonly progress?: number;
26
50
  readonly outcome?: string;
27
51
  readonly count?: number;
@@ -41,7 +65,7 @@ interface DevtoolsRecord {
41
65
  interface DevtoolsRuntimeSource {
42
66
  readonly adapter: string;
43
67
  readonly evidence: readonly string[];
44
- readonly fidelity: Readonly<Omit<AdapterFidelity, "optionalEvents"> & {
68
+ readonly fidelity: Readonly<Pick<AdapterFidelity, "interruption" | "retries" | "connection"> & Partial<Pick<AdapterFidelity, "runs" | "steps" | "hierarchy" | "tools" | "interactions" | "replay" | "reconnection" | "customEvents">> & {
45
69
  readonly optionalEvents?: readonly NonNullable<AdapterFidelity["optionalEvents"]>[number][];
46
70
  }>;
47
71
  }
@@ -58,6 +82,14 @@ interface DeliveryRecordInput {
58
82
  readonly responseId?: string;
59
83
  readonly toolId?: string;
60
84
  readonly interactionId?: string;
85
+ /** Stable logical run identity copied from the delivered intent. */
86
+ readonly runId?: string;
87
+ /** Stable run attempt identity copied from the delivered intent. */
88
+ readonly runInstanceId?: string;
89
+ /** Stable logical step identity copied from the delivered intent. */
90
+ readonly stepId?: string;
91
+ /** Stable step attempt identity copied from the delivered intent. */
92
+ readonly stepInstanceId?: string;
61
93
  readonly error?: {
62
94
  readonly name: string;
63
95
  readonly message?: string;
package/dist/index.js CHANGED
@@ -10,6 +10,18 @@ function asRecord(runtimeId, event, captureSequence, runtimeSourceId) {
10
10
  kind: event.kind,
11
11
  sourceType: event.event.type,
12
12
  ...event.event.eventId ? { sourceEventId: event.event.eventId } : {},
13
+ ..."runId" in event.event && event.event.runId ? { runId: event.event.runId } : {},
14
+ ..."runInstanceId" in event.event && event.event.runInstanceId ? { runInstanceId: event.event.runInstanceId } : {},
15
+ ..."nextRunInstanceId" in event.event && event.event.nextRunInstanceId ? { nextRunInstanceId: event.event.nextRunInstanceId } : {},
16
+ ..."parentRunId" in event.event && event.event.parentRunId ? { parentRunId: event.event.parentRunId } : {},
17
+ ..."parentRunInstanceId" in event.event && event.event.parentRunInstanceId ? { parentRunInstanceId: event.event.parentRunInstanceId } : {},
18
+ ..."stepId" in event.event && event.event.stepId ? { stepId: event.event.stepId } : {},
19
+ ..."stepInstanceId" in event.event && event.event.stepInstanceId ? { stepInstanceId: event.event.stepInstanceId } : {},
20
+ ..."nextStepInstanceId" in event.event && event.event.nextStepInstanceId ? { nextStepInstanceId: event.event.nextStepInstanceId } : {},
21
+ ..."parentStepId" in event.event && event.event.parentStepId ? { parentStepId: event.event.parentStepId } : {},
22
+ ..."parentStepInstanceId" in event.event && event.event.parentStepInstanceId ? { parentStepInstanceId: event.event.parentStepInstanceId } : {},
23
+ ..."parentToolId" in event.event && event.event.parentToolId ? { parentToolId: event.event.parentToolId } : {},
24
+ ..."parentResponseId" in event.event && event.event.parentResponseId ? { parentResponseId: event.event.parentResponseId } : {},
13
25
  ..."responseId" in event.event ? { responseId: event.event.responseId } : {},
14
26
  ..."responseInstanceId" in event.event && event.event.responseInstanceId ? { responseInstanceId: event.event.responseInstanceId } : {},
15
27
  ..."nextResponseInstanceId" in event.event && event.event.nextResponseInstanceId ? { nextResponseInstanceId: event.event.nextResponseInstanceId } : {},
@@ -39,6 +51,10 @@ function asRecord(runtimeId, event, captureSequence, runtimeSourceId) {
39
51
  ...event.decision.responseId ? { responseId: event.decision.responseId } : {},
40
52
  ...event.decision.toolId ? { toolId: event.decision.toolId } : {},
41
53
  ...event.decision.interactionId ? { interactionId: event.decision.interactionId } : {},
54
+ ...event.decision.runId ? { runId: event.decision.runId } : {},
55
+ ...event.decision.runInstanceId ? { runInstanceId: event.decision.runInstanceId } : {},
56
+ ...event.decision.stepId ? { stepId: event.decision.stepId } : {},
57
+ ...event.decision.stepInstanceId ? { stepInstanceId: event.decision.stepInstanceId } : {},
42
58
  ...event.decision.scheduledAt !== void 0 ? { scheduledAt: event.decision.scheduledAt } : {},
43
59
  ...event.decision.dueAt !== void 0 ? { dueAt: event.decision.dueAt } : {},
44
60
  ...event.decision.delayMs !== void 0 ? { delayMs: event.decision.delayMs } : {},
@@ -62,6 +78,25 @@ function copyRuntimeSource(source) {
62
78
  throw new TypeError("source fidelity must be an object");
63
79
  const lifecycleFidelity = /* @__PURE__ */ new Set(["exact", "action-wrapper", "unavailable"]);
64
80
  const connectionFidelity = /* @__PURE__ */ new Set([...lifecycleFidelity, "inferred"]);
81
+ const workflowFidelity = /* @__PURE__ */ new Set(["exact", "partial", "unavailable"]);
82
+ for (const field of [
83
+ "runs",
84
+ "steps",
85
+ "hierarchy",
86
+ "tools",
87
+ "interactions",
88
+ "replay",
89
+ "reconnection"
90
+ ]) {
91
+ if (fidelity[field] !== void 0 && !workflowFidelity.has(fidelity[field]))
92
+ throw new TypeError(
93
+ `source ${field} fidelity contains an unsupported value`
94
+ );
95
+ }
96
+ if (fidelity.customEvents !== void 0 && fidelity.customEvents !== "explicit-mapping" && fidelity.customEvents !== "unsupported")
97
+ throw new TypeError(
98
+ "source custom event fidelity contains an unsupported value"
99
+ );
65
100
  if (!lifecycleFidelity.has(fidelity.interruption))
66
101
  throw new TypeError(
67
102
  "source interruption fidelity contains an unsupported value"
@@ -85,6 +120,14 @@ function copyRuntimeSource(source) {
85
120
  adapter: source.adapter.trim(),
86
121
  evidence: Object.freeze(source.evidence.map((item) => item.trim())),
87
122
  fidelity: Object.freeze({
123
+ ...fidelity.runs ? { runs: fidelity.runs } : {},
124
+ ...fidelity.steps ? { steps: fidelity.steps } : {},
125
+ ...fidelity.hierarchy ? { hierarchy: fidelity.hierarchy } : {},
126
+ ...fidelity.tools ? { tools: fidelity.tools } : {},
127
+ ...fidelity.interactions ? { interactions: fidelity.interactions } : {},
128
+ ...fidelity.replay ? { replay: fidelity.replay } : {},
129
+ ...fidelity.reconnection ? { reconnection: fidelity.reconnection } : {},
130
+ ...fidelity.customEvents ? { customEvents: fidelity.customEvents } : {},
88
131
  interruption: fidelity.interruption,
89
132
  retries: fidelity.retries,
90
133
  connection: fidelity.connection,
@@ -109,6 +152,10 @@ function asDeliveryRecord(input, captureSequence, runtimeSourceId) {
109
152
  ...result.responseId ? { responseId: result.responseId } : {},
110
153
  ...result.toolId ? { toolId: result.toolId } : {},
111
154
  ...result.interactionId ? { interactionId: result.interactionId } : {},
155
+ ...result.runId ? { runId: result.runId } : {},
156
+ ...result.runInstanceId ? { runInstanceId: result.runInstanceId } : {},
157
+ ...result.stepId ? { stepId: result.stepId } : {},
158
+ ...result.stepInstanceId ? { stepInstanceId: result.stepInstanceId } : {},
112
159
  ...result.error?.name ? { errorName: result.error.name } : {}
113
160
  });
114
161
  }
@@ -119,7 +166,8 @@ function copyRuntimeSnapshot(source) {
119
166
  policy: Object.freeze({
120
167
  ...source.policy,
121
168
  text: Object.freeze({ ...source.policy.text }),
122
- tools: Object.freeze({ ...source.policy.tools })
169
+ tools: Object.freeze({ ...source.policy.tools }),
170
+ workflows: Object.freeze({ ...source.policy.workflows })
123
171
  }),
124
172
  pending: Object.freeze({
125
173
  announcements: Object.freeze(
@@ -135,6 +183,16 @@ function copyRuntimeSnapshot(source) {
135
183
  tools: Object.freeze(
136
184
  source.tools.map((item) => Object.freeze({ ...item }))
137
185
  ),
186
+ ...source.runs ? {
187
+ runs: Object.freeze(
188
+ source.runs.map((item) => Object.freeze({ ...item }))
189
+ )
190
+ } : {},
191
+ ...source.steps ? {
192
+ steps: Object.freeze(
193
+ source.steps.map((item) => Object.freeze({ ...item }))
194
+ )
195
+ } : {},
138
196
  pendingCount: source.pendingCount
139
197
  });
140
198
  }
package/dist/overlay.cjs CHANGED
@@ -226,19 +226,61 @@ var key = (record) => String(record.captureSequence);
226
226
  var time = (value) => value >= 1e10 ? new Date(value).toISOString().slice(11, 23) : `+${(value / 1e3).toFixed(2)}s`;
227
227
  var stage = (record) => record.kind === "event-observed" ? "Source evidence" : record.kind === "decision" ? "Runtime decision" : "DOM delivery";
228
228
  var title = (record) => record.kind === "event-observed" ? record.sourceType ?? "Observed event" : record.kind === "dom-delivery" ? `${record.deliveryStatus ?? "Delivery"} via ${record.deliveryMethod ?? "browser"}` : record.reason ?? record.disposition ?? "Runtime decision";
229
- function correlation(record) {
229
+ function correlationKeys(record) {
230
230
  const prefix = `${record.runtimeId}:`;
231
- if (record.sourceEventId) return `${prefix}event:${record.sourceEventId}`;
232
- if (record.responseId)
233
- return `${prefix}response:${record.responseId}:${record.sourceType ?? "unknown"}`;
234
- if (record.toolId)
235
- return `${prefix}tool:${record.toolId}:${record.sourceType ?? "unknown"}`;
231
+ const keys = /* @__PURE__ */ new Set();
232
+ if (record.sourceEventId) keys.add(`${prefix}event:${record.sourceEventId}`);
233
+ if (record.responseId) keys.add(`${prefix}response:${record.responseId}`);
234
+ if (record.toolId) keys.add(`${prefix}tool:${record.toolId}`);
236
235
  if (record.interactionId)
237
- return `${prefix}interaction:${record.interactionId}`;
238
- if (record.approvalId) return `${prefix}approval:${record.approvalId}`;
236
+ keys.add(`${prefix}interaction:${record.interactionId}`);
237
+ if (record.approvalId) keys.add(`${prefix}approval:${record.approvalId}`);
239
238
  if (record.announcementId)
240
- return `${prefix}announcement:${record.announcementId}`;
241
- return `${prefix}record:${record.captureSequence}`;
239
+ keys.add(`${prefix}announcement:${record.announcementId}`);
240
+ if (record.runId)
241
+ keys.add(
242
+ `${prefix}run:${record.runId}:${record.runInstanceId ?? "unidentified"}`
243
+ );
244
+ if (record.runId && record.nextRunInstanceId)
245
+ keys.add(`${prefix}run:${record.runId}:${record.nextRunInstanceId}`);
246
+ if (record.parentRunId)
247
+ keys.add(
248
+ `${prefix}run:${record.parentRunId}:${record.parentRunInstanceId ?? "unidentified"}`
249
+ );
250
+ if (record.stepId)
251
+ keys.add(
252
+ `${prefix}step:${record.runId ?? "unknown"}:${record.runInstanceId ?? "unidentified"}:${record.stepId}:${record.stepInstanceId ?? "unidentified"}`
253
+ );
254
+ if (record.stepId && record.nextStepInstanceId)
255
+ keys.add(
256
+ `${prefix}step:${record.runId ?? "unknown"}:${record.runInstanceId ?? "unidentified"}:${record.stepId}:${record.nextStepInstanceId}`
257
+ );
258
+ if (record.parentStepId)
259
+ keys.add(
260
+ `${prefix}step:${record.runId ?? "unknown"}:${record.runInstanceId ?? "unidentified"}:${record.parentStepId}:${record.parentStepInstanceId ?? "unidentified"}`
261
+ );
262
+ if (record.parentToolId) keys.add(`${prefix}tool:${record.parentToolId}`);
263
+ if (record.parentResponseId)
264
+ keys.add(`${prefix}response:${record.parentResponseId}`);
265
+ if (keys.size === 0) keys.add(`${prefix}record:${record.captureSequence}`);
266
+ return [...keys];
267
+ }
268
+ function relatedRecords(records, selected) {
269
+ const related = /* @__PURE__ */ new Set();
270
+ const keys = new Set(correlationKeys(selected));
271
+ let changed = true;
272
+ while (changed) {
273
+ changed = false;
274
+ for (const record of records) {
275
+ if (related.has(record)) continue;
276
+ const recordKeys = correlationKeys(record);
277
+ if (!recordKeys.some((value) => keys.has(value))) continue;
278
+ related.add(record);
279
+ for (const value of recordKeys) keys.add(value);
280
+ changed = true;
281
+ }
282
+ }
283
+ return [...related];
242
284
  }
243
285
  function explain(record) {
244
286
  if (record.kind === "event-observed")
@@ -302,6 +344,12 @@ function Detail({
302
344
  ] }) });
303
345
  const source = snapshot.runtimeSources[record.runtimeSourceId ?? record.runtimeId];
304
346
  const runtime = snapshot.runtimeSnapshots[record.runtimeId];
347
+ const run = record.runInstanceId ? runtime?.runs?.find(
348
+ (item) => item.runId === record.runId && item.instanceId === record.runInstanceId
349
+ ) : void 0;
350
+ const step = record.runInstanceId && record.stepInstanceId ? runtime?.steps?.find(
351
+ (item) => item.runId === record.runId && item.stepId === record.stepId && item.runInstanceId === record.runInstanceId && item.instanceId === record.stepInstanceId
352
+ ) : void 0;
305
353
  const deliveries = related.filter((item) => item.kind === "dom-delivery");
306
354
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("aside", { className: "ga-trace-detail", "data-testid": "trace-detail", children: [
307
355
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ga-detail-intro", children: [
@@ -314,6 +362,43 @@ function Detail({
314
362
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: record.reason?.startsWith("stale") ? "Compare the instance with the current runtime snapshot." : "Inspect related evidence and queue context if this was unexpected." })
315
363
  ] }),
316
364
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CausalChain, { records: related }),
365
+ record.runId ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "ga-detail-section", children: [
366
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h4", { children: "Workflow hierarchy" }),
367
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("dl", { className: "ga-key-values", children: [
368
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
369
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Run" }),
370
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: record.runId })
371
+ ] }),
372
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
373
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Run attempt" }),
374
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: record.runInstanceId ?? run?.instanceId ?? "Not supplied" })
375
+ ] }),
376
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
377
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Parent run" }),
378
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: record.parentRunId ?? run?.parentRunId ?? "None" })
379
+ ] }),
380
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
381
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Run state" }),
382
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: run?.status ?? "Not retained" })
383
+ ] }),
384
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
385
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Step" }),
386
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: record.stepId ?? "Partial identity" })
387
+ ] }),
388
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
389
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Step attempt" }),
390
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: record.stepInstanceId ?? step?.instanceId ?? "Not supplied" })
391
+ ] }),
392
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
393
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Parent step" }),
394
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: record.parentStepId ?? step?.parentStepId ?? "None" })
395
+ ] }),
396
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
397
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Step state" }),
398
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: step?.status ?? "Not retained" })
399
+ ] })
400
+ ] })
401
+ ] }) : null,
317
402
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "ga-detail-section", children: [
318
403
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h4", { children: "Source evidence" }),
319
404
  source ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("dl", { className: "ga-key-values", children: [
@@ -321,6 +406,22 @@ function Detail({
321
406
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Adapter" }),
322
407
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: source.adapter })
323
408
  ] }),
409
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
410
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Runs" }),
411
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: source.fidelity.runs ?? "Not declared" })
412
+ ] }),
413
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
414
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Steps" }),
415
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: source.fidelity.steps ?? "Not declared" })
416
+ ] }),
417
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
418
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Hierarchy" }),
419
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: source.fidelity.hierarchy ?? "Not declared" })
420
+ ] }),
421
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
422
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Replay" }),
423
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: source.fidelity.replay ?? "Not declared" })
424
+ ] }),
324
425
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
325
426
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Interruption" }),
326
427
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: source.fidelity.interruption })
@@ -453,13 +554,15 @@ function DevtoolsInspector({
453
554
  record.responseId,
454
555
  record.toolId,
455
556
  record.interactionId,
456
- record.approvalId
557
+ record.approvalId,
558
+ record.runId,
559
+ record.runInstanceId,
560
+ record.stepId,
561
+ record.stepInstanceId
457
562
  ].filter(Boolean).join(" ").toLowerCase().includes(query.trim().toLowerCase())
458
563
  ).slice().reverse();
459
564
  const selected = visible.find((record) => key(record) === selectedKey) ?? visible[0];
460
- const related = selected ? snapshot.records.filter(
461
- (record) => correlation(record) === correlation(selected)
462
- ) : [];
565
+ const related = selected ? relatedRecords(snapshot.records, selected) : [];
463
566
  React4.useEffect(
464
567
  () => () => {
465
568
  if (feedbackTimer.current !== void 0)
package/dist/overlay.js CHANGED
@@ -192,19 +192,61 @@ var key = (record) => String(record.captureSequence);
192
192
  var time = (value) => value >= 1e10 ? new Date(value).toISOString().slice(11, 23) : `+${(value / 1e3).toFixed(2)}s`;
193
193
  var stage = (record) => record.kind === "event-observed" ? "Source evidence" : record.kind === "decision" ? "Runtime decision" : "DOM delivery";
194
194
  var title = (record) => record.kind === "event-observed" ? record.sourceType ?? "Observed event" : record.kind === "dom-delivery" ? `${record.deliveryStatus ?? "Delivery"} via ${record.deliveryMethod ?? "browser"}` : record.reason ?? record.disposition ?? "Runtime decision";
195
- function correlation(record) {
195
+ function correlationKeys(record) {
196
196
  const prefix = `${record.runtimeId}:`;
197
- if (record.sourceEventId) return `${prefix}event:${record.sourceEventId}`;
198
- if (record.responseId)
199
- return `${prefix}response:${record.responseId}:${record.sourceType ?? "unknown"}`;
200
- if (record.toolId)
201
- return `${prefix}tool:${record.toolId}:${record.sourceType ?? "unknown"}`;
197
+ const keys = /* @__PURE__ */ new Set();
198
+ if (record.sourceEventId) keys.add(`${prefix}event:${record.sourceEventId}`);
199
+ if (record.responseId) keys.add(`${prefix}response:${record.responseId}`);
200
+ if (record.toolId) keys.add(`${prefix}tool:${record.toolId}`);
202
201
  if (record.interactionId)
203
- return `${prefix}interaction:${record.interactionId}`;
204
- if (record.approvalId) return `${prefix}approval:${record.approvalId}`;
202
+ keys.add(`${prefix}interaction:${record.interactionId}`);
203
+ if (record.approvalId) keys.add(`${prefix}approval:${record.approvalId}`);
205
204
  if (record.announcementId)
206
- return `${prefix}announcement:${record.announcementId}`;
207
- return `${prefix}record:${record.captureSequence}`;
205
+ keys.add(`${prefix}announcement:${record.announcementId}`);
206
+ if (record.runId)
207
+ keys.add(
208
+ `${prefix}run:${record.runId}:${record.runInstanceId ?? "unidentified"}`
209
+ );
210
+ if (record.runId && record.nextRunInstanceId)
211
+ keys.add(`${prefix}run:${record.runId}:${record.nextRunInstanceId}`);
212
+ if (record.parentRunId)
213
+ keys.add(
214
+ `${prefix}run:${record.parentRunId}:${record.parentRunInstanceId ?? "unidentified"}`
215
+ );
216
+ if (record.stepId)
217
+ keys.add(
218
+ `${prefix}step:${record.runId ?? "unknown"}:${record.runInstanceId ?? "unidentified"}:${record.stepId}:${record.stepInstanceId ?? "unidentified"}`
219
+ );
220
+ if (record.stepId && record.nextStepInstanceId)
221
+ keys.add(
222
+ `${prefix}step:${record.runId ?? "unknown"}:${record.runInstanceId ?? "unidentified"}:${record.stepId}:${record.nextStepInstanceId}`
223
+ );
224
+ if (record.parentStepId)
225
+ keys.add(
226
+ `${prefix}step:${record.runId ?? "unknown"}:${record.runInstanceId ?? "unidentified"}:${record.parentStepId}:${record.parentStepInstanceId ?? "unidentified"}`
227
+ );
228
+ if (record.parentToolId) keys.add(`${prefix}tool:${record.parentToolId}`);
229
+ if (record.parentResponseId)
230
+ keys.add(`${prefix}response:${record.parentResponseId}`);
231
+ if (keys.size === 0) keys.add(`${prefix}record:${record.captureSequence}`);
232
+ return [...keys];
233
+ }
234
+ function relatedRecords(records, selected) {
235
+ const related = /* @__PURE__ */ new Set();
236
+ const keys = new Set(correlationKeys(selected));
237
+ let changed = true;
238
+ while (changed) {
239
+ changed = false;
240
+ for (const record of records) {
241
+ if (related.has(record)) continue;
242
+ const recordKeys = correlationKeys(record);
243
+ if (!recordKeys.some((value) => keys.has(value))) continue;
244
+ related.add(record);
245
+ for (const value of recordKeys) keys.add(value);
246
+ changed = true;
247
+ }
248
+ }
249
+ return [...related];
208
250
  }
209
251
  function explain(record) {
210
252
  if (record.kind === "event-observed")
@@ -268,6 +310,12 @@ function Detail({
268
310
  ] }) });
269
311
  const source = snapshot.runtimeSources[record.runtimeSourceId ?? record.runtimeId];
270
312
  const runtime = snapshot.runtimeSnapshots[record.runtimeId];
313
+ const run = record.runInstanceId ? runtime?.runs?.find(
314
+ (item) => item.runId === record.runId && item.instanceId === record.runInstanceId
315
+ ) : void 0;
316
+ const step = record.runInstanceId && record.stepInstanceId ? runtime?.steps?.find(
317
+ (item) => item.runId === record.runId && item.stepId === record.stepId && item.runInstanceId === record.runInstanceId && item.instanceId === record.stepInstanceId
318
+ ) : void 0;
271
319
  const deliveries = related.filter((item) => item.kind === "dom-delivery");
272
320
  return /* @__PURE__ */ jsxs2("aside", { className: "ga-trace-detail", "data-testid": "trace-detail", children: [
273
321
  /* @__PURE__ */ jsxs2("div", { className: "ga-detail-intro", children: [
@@ -280,6 +328,43 @@ function Detail({
280
328
  /* @__PURE__ */ jsx5("p", { children: record.reason?.startsWith("stale") ? "Compare the instance with the current runtime snapshot." : "Inspect related evidence and queue context if this was unexpected." })
281
329
  ] }),
282
330
  /* @__PURE__ */ jsx5(CausalChain, { records: related }),
331
+ record.runId ? /* @__PURE__ */ jsxs2("section", { className: "ga-detail-section", children: [
332
+ /* @__PURE__ */ jsx5("h4", { children: "Workflow hierarchy" }),
333
+ /* @__PURE__ */ jsxs2("dl", { className: "ga-key-values", children: [
334
+ /* @__PURE__ */ jsxs2("div", { children: [
335
+ /* @__PURE__ */ jsx5("dt", { children: "Run" }),
336
+ /* @__PURE__ */ jsx5("dd", { children: record.runId })
337
+ ] }),
338
+ /* @__PURE__ */ jsxs2("div", { children: [
339
+ /* @__PURE__ */ jsx5("dt", { children: "Run attempt" }),
340
+ /* @__PURE__ */ jsx5("dd", { children: record.runInstanceId ?? run?.instanceId ?? "Not supplied" })
341
+ ] }),
342
+ /* @__PURE__ */ jsxs2("div", { children: [
343
+ /* @__PURE__ */ jsx5("dt", { children: "Parent run" }),
344
+ /* @__PURE__ */ jsx5("dd", { children: record.parentRunId ?? run?.parentRunId ?? "None" })
345
+ ] }),
346
+ /* @__PURE__ */ jsxs2("div", { children: [
347
+ /* @__PURE__ */ jsx5("dt", { children: "Run state" }),
348
+ /* @__PURE__ */ jsx5("dd", { children: run?.status ?? "Not retained" })
349
+ ] }),
350
+ /* @__PURE__ */ jsxs2("div", { children: [
351
+ /* @__PURE__ */ jsx5("dt", { children: "Step" }),
352
+ /* @__PURE__ */ jsx5("dd", { children: record.stepId ?? "Partial identity" })
353
+ ] }),
354
+ /* @__PURE__ */ jsxs2("div", { children: [
355
+ /* @__PURE__ */ jsx5("dt", { children: "Step attempt" }),
356
+ /* @__PURE__ */ jsx5("dd", { children: record.stepInstanceId ?? step?.instanceId ?? "Not supplied" })
357
+ ] }),
358
+ /* @__PURE__ */ jsxs2("div", { children: [
359
+ /* @__PURE__ */ jsx5("dt", { children: "Parent step" }),
360
+ /* @__PURE__ */ jsx5("dd", { children: record.parentStepId ?? step?.parentStepId ?? "None" })
361
+ ] }),
362
+ /* @__PURE__ */ jsxs2("div", { children: [
363
+ /* @__PURE__ */ jsx5("dt", { children: "Step state" }),
364
+ /* @__PURE__ */ jsx5("dd", { children: step?.status ?? "Not retained" })
365
+ ] })
366
+ ] })
367
+ ] }) : null,
283
368
  /* @__PURE__ */ jsxs2("section", { className: "ga-detail-section", children: [
284
369
  /* @__PURE__ */ jsx5("h4", { children: "Source evidence" }),
285
370
  source ? /* @__PURE__ */ jsxs2("dl", { className: "ga-key-values", children: [
@@ -287,6 +372,22 @@ function Detail({
287
372
  /* @__PURE__ */ jsx5("dt", { children: "Adapter" }),
288
373
  /* @__PURE__ */ jsx5("dd", { children: source.adapter })
289
374
  ] }),
375
+ /* @__PURE__ */ jsxs2("div", { children: [
376
+ /* @__PURE__ */ jsx5("dt", { children: "Runs" }),
377
+ /* @__PURE__ */ jsx5("dd", { children: source.fidelity.runs ?? "Not declared" })
378
+ ] }),
379
+ /* @__PURE__ */ jsxs2("div", { children: [
380
+ /* @__PURE__ */ jsx5("dt", { children: "Steps" }),
381
+ /* @__PURE__ */ jsx5("dd", { children: source.fidelity.steps ?? "Not declared" })
382
+ ] }),
383
+ /* @__PURE__ */ jsxs2("div", { children: [
384
+ /* @__PURE__ */ jsx5("dt", { children: "Hierarchy" }),
385
+ /* @__PURE__ */ jsx5("dd", { children: source.fidelity.hierarchy ?? "Not declared" })
386
+ ] }),
387
+ /* @__PURE__ */ jsxs2("div", { children: [
388
+ /* @__PURE__ */ jsx5("dt", { children: "Replay" }),
389
+ /* @__PURE__ */ jsx5("dd", { children: source.fidelity.replay ?? "Not declared" })
390
+ ] }),
290
391
  /* @__PURE__ */ jsxs2("div", { children: [
291
392
  /* @__PURE__ */ jsx5("dt", { children: "Interruption" }),
292
393
  /* @__PURE__ */ jsx5("dd", { children: source.fidelity.interruption })
@@ -419,13 +520,15 @@ function DevtoolsInspector({
419
520
  record.responseId,
420
521
  record.toolId,
421
522
  record.interactionId,
422
- record.approvalId
523
+ record.approvalId,
524
+ record.runId,
525
+ record.runInstanceId,
526
+ record.stepId,
527
+ record.stepInstanceId
423
528
  ].filter(Boolean).join(" ").toLowerCase().includes(query.trim().toLowerCase())
424
529
  ).slice().reverse();
425
530
  const selected = visible.find((record) => key(record) === selectedKey) ?? visible[0];
426
- const related = selected ? snapshot.records.filter(
427
- (record) => correlation(record) === correlation(selected)
428
- ) : [];
531
+ const related = selected ? relatedRecords(snapshot.records, selected) : [];
429
532
  React4.useEffect(
430
533
  () => () => {
431
534
  if (feedbackTimer.current !== void 0)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@generative-a11y/devtools",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Development-only accessibility diagnostics and a redacted trace explorer for screen-reader announcements in AI runtimes.",
5
5
  "keywords": [
6
6
  "accessibility",
@@ -60,7 +60,7 @@
60
60
  "radix-ui": "1.6.7",
61
61
  "react-resizable-panels": "^4.12.3",
62
62
  "tailwind-merge": "3.6.0",
63
- "@generative-a11y/core": "0.2.0"
63
+ "@generative-a11y/core": "0.3.0"
64
64
  },
65
65
  "peerDependencies": {
66
66
  "react": "^19.0.0",