harnery 0.34.0 → 0.35.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.
Files changed (212) hide show
  1. package/dist/commander.d.ts.map +1 -1
  2. package/dist/commander.js +2 -0
  3. package/dist/commands/agents.d.ts +15 -4
  4. package/dist/commands/agents.d.ts.map +1 -1
  5. package/dist/commands/agents.js +91 -162
  6. package/dist/commands/browse.d.ts.map +1 -1
  7. package/dist/commands/browse.js +26 -2
  8. package/dist/commands/decision.d.ts.map +1 -1
  9. package/dist/commands/decision.js +2 -2
  10. package/dist/commands/events.d.ts.map +1 -1
  11. package/dist/commands/events.js +18 -1
  12. package/dist/commands/presence.d.ts.map +1 -1
  13. package/dist/commands/presence.js +2 -2
  14. package/dist/commands/semantic.d.ts +4 -0
  15. package/dist/commands/semantic.d.ts.map +1 -0
  16. package/dist/commands/semantic.js +147 -0
  17. package/dist/commands/web.d.ts.map +1 -1
  18. package/dist/commands/web.js +17 -0
  19. package/dist/core/agents/canonical-emit.d.ts +3 -0
  20. package/dist/core/agents/canonical-emit.d.ts.map +1 -1
  21. package/dist/core/agents/canonical-emit.js +12 -0
  22. package/dist/core/agents/claim-path.d.ts +11 -0
  23. package/dist/core/agents/claim-path.d.ts.map +1 -0
  24. package/dist/core/agents/claim-path.js +22 -0
  25. package/dist/core/agents/coord-client.d.ts +29 -3
  26. package/dist/core/agents/coord-client.d.ts.map +1 -1
  27. package/dist/core/agents/coord-client.js +88 -9
  28. package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
  29. package/dist/core/agents/live-authority-v3.js +1 -3
  30. package/dist/core/agents/live-lifecycle-v3.js +3 -3
  31. package/dist/core/agents/live-observation-v3.d.ts.map +1 -1
  32. package/dist/core/agents/live-observation-v3.js +2 -2
  33. package/dist/core/agents/render/prompt-context.js +12 -10
  34. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  35. package/dist/core/agents/rules/stop-hook.js +23 -11
  36. package/dist/core/agents/session-name-display.d.ts +2 -1
  37. package/dist/core/agents/session-name-display.d.ts.map +1 -1
  38. package/dist/core/agents/session-name-display.js +10 -3
  39. package/dist/core/agents/state/heartbeat-reader.d.ts +46 -0
  40. package/dist/core/agents/state/heartbeat-reader.d.ts.map +1 -0
  41. package/dist/core/agents/state/heartbeat-reader.js +25 -0
  42. package/dist/core/agents/state/heartbeat-writer.d.ts +3 -48
  43. package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
  44. package/dist/core/agents/state/heartbeat-writer.js +16 -34
  45. package/dist/core/agents/state/live-coordination-view.d.ts +1 -1
  46. package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
  47. package/dist/core/agents/state/live-coordination-view.js +25 -1
  48. package/dist/core/agents/state/names.d.ts +9 -1
  49. package/dist/core/agents/state/names.d.ts.map +1 -1
  50. package/dist/core/agents/state/names.js +190 -182
  51. package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
  52. package/dist/core/agents/state/stale-sweep.js +23 -5
  53. package/dist/core/artifacts/constants.d.ts +5 -0
  54. package/dist/core/artifacts/constants.d.ts.map +1 -0
  55. package/dist/core/artifacts/constants.js +4 -0
  56. package/dist/core/artifacts/index.d.ts +3 -3
  57. package/dist/core/artifacts/index.d.ts.map +1 -1
  58. package/dist/core/artifacts/index.js +50 -7
  59. package/dist/core/events/v3/base-contract.d.ts +795 -0
  60. package/dist/core/events/v3/base-contract.d.ts.map +1 -1
  61. package/dist/core/events/v3/base-contract.js +33 -0
  62. package/dist/core/events/v3/capabilities.d.ts +11 -0
  63. package/dist/core/events/v3/capabilities.d.ts.map +1 -1
  64. package/dist/core/events/v3/capabilities.js +23 -0
  65. package/dist/core/events/v3/generated.d.ts +1 -1
  66. package/dist/core/events/v3/generated.js +1 -1
  67. package/dist/core/events/v3/index.d.ts +4 -3
  68. package/dist/core/events/v3/index.d.ts.map +1 -1
  69. package/dist/core/events/v3/index.js +4 -3
  70. package/dist/core/events/v3/latency.d.ts +31 -1
  71. package/dist/core/events/v3/latency.d.ts.map +1 -1
  72. package/dist/core/events/v3/latency.js +127 -3
  73. package/dist/core/events/v3/live-routing.d.ts +30 -0
  74. package/dist/core/events/v3/live-routing.d.ts.map +1 -1
  75. package/dist/core/events/v3/live-routing.js +109 -1
  76. package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -1
  77. package/dist/core/events/v3/producers/command-recorder.js +10 -1
  78. package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
  79. package/dist/core/events/v3/producers/coordination-recorder.js +14 -3
  80. package/dist/core/events/v3/producers/hook-base.d.ts +17 -1
  81. package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
  82. package/dist/core/events/v3/producers/hook-base.js +82 -1
  83. package/dist/core/events/v3/producers/intake.d.ts +6 -0
  84. package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
  85. package/dist/core/events/v3/producers/intake.js +11 -0
  86. package/dist/core/events/v3/producers/recorder.d.ts +62 -0
  87. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  88. package/dist/core/events/v3/producers/recorder.js +654 -18
  89. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts +51 -0
  90. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts.map +1 -0
  91. package/dist/core/events/v3/runtime-telemetry-capabilities.js +54 -0
  92. package/dist/core/events/v3/turn-telemetry.d.ts +9 -0
  93. package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -1
  94. package/dist/core/hooks/adapter/parse.d.ts +3 -0
  95. package/dist/core/hooks/adapter/parse.d.ts.map +1 -1
  96. package/dist/core/hooks/adapter/parse.js +14 -0
  97. package/dist/core/hooks/adapter/runtime-telemetry.d.ts +119 -0
  98. package/dist/core/hooks/adapter/runtime-telemetry.d.ts.map +1 -0
  99. package/dist/core/hooks/adapter/runtime-telemetry.js +568 -0
  100. package/dist/core/hooks/cli.js +114 -38
  101. package/dist/core/hooks/remediation-cap.d.ts +34 -0
  102. package/dist/core/hooks/remediation-cap.d.ts.map +1 -0
  103. package/dist/core/hooks/remediation-cap.js +71 -0
  104. package/dist/core/hooks/resolve/transcript.d.ts +25 -9
  105. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  106. package/dist/core/hooks/resolve/transcript.js +35 -17
  107. package/dist/core/semantic/adapters.d.ts +34 -0
  108. package/dist/core/semantic/adapters.d.ts.map +1 -0
  109. package/dist/core/semantic/adapters.js +222 -0
  110. package/dist/core/semantic/contract.d.ts +588 -0
  111. package/dist/core/semantic/contract.d.ts.map +1 -0
  112. package/dist/core/semantic/contract.js +230 -0
  113. package/dist/core/semantic/evidence.d.ts +11 -0
  114. package/dist/core/semantic/evidence.d.ts.map +1 -0
  115. package/dist/core/semantic/evidence.js +262 -0
  116. package/dist/core/semantic/index.d.ts +10 -0
  117. package/dist/core/semantic/index.d.ts.map +1 -0
  118. package/dist/core/semantic/index.js +9 -0
  119. package/dist/core/semantic/once.d.ts +33 -0
  120. package/dist/core/semantic/once.d.ts.map +1 -0
  121. package/dist/core/semantic/once.js +293 -0
  122. package/dist/core/semantic/prompt.d.ts +12 -0
  123. package/dist/core/semantic/prompt.d.ts.map +1 -0
  124. package/dist/core/semantic/prompt.js +70 -0
  125. package/dist/core/semantic/scheduler.d.ts +16 -0
  126. package/dist/core/semantic/scheduler.d.ts.map +1 -0
  127. package/dist/core/semantic/scheduler.js +67 -0
  128. package/dist/core/semantic/service-status.d.ts +31 -0
  129. package/dist/core/semantic/service-status.d.ts.map +1 -0
  130. package/dist/core/semantic/service-status.js +84 -0
  131. package/dist/core/semantic/service.d.ts +51 -0
  132. package/dist/core/semantic/service.d.ts.map +1 -0
  133. package/dist/core/semantic/service.js +470 -0
  134. package/dist/core/semantic/storage.d.ts +71 -0
  135. package/dist/core/semantic/storage.d.ts.map +1 -0
  136. package/dist/core/semantic/storage.js +179 -0
  137. package/dist/core/semantic/validate.d.ts +16 -0
  138. package/dist/core/semantic/validate.d.ts.map +1 -0
  139. package/dist/core/semantic/validate.js +174 -0
  140. package/dist/lib/browser/client.d.ts +11 -0
  141. package/dist/lib/browser/client.d.ts.map +1 -1
  142. package/dist/lib/browser/client.js +13 -0
  143. package/dist/lib/browser/index.d.ts +1 -0
  144. package/dist/lib/browser/index.d.ts.map +1 -1
  145. package/dist/lib/browser/standalone-html.d.ts +25 -0
  146. package/dist/lib/browser/standalone-html.d.ts.map +1 -0
  147. package/dist/lib/browser/standalone-html.js +284 -0
  148. package/dist/lib/instructions/apply.d.ts.map +1 -1
  149. package/dist/lib/instructions/apply.js +1 -0
  150. package/dist/lib/instructions/templates.d.ts +2 -0
  151. package/dist/lib/instructions/templates.d.ts.map +1 -1
  152. package/dist/lib/instructions/templates.js +144 -4
  153. package/package.json +6 -1
  154. package/schemas/event-v3.schema.json +2758 -478
  155. package/src/commander.ts +2 -0
  156. package/src/commands/agents.ts +104 -152
  157. package/src/commands/browse.ts +25 -2
  158. package/src/commands/decision.ts +8 -2
  159. package/src/commands/events.ts +21 -1
  160. package/src/commands/presence.ts +7 -2
  161. package/src/commands/semantic.ts +179 -0
  162. package/src/commands/web.ts +15 -0
  163. package/src/core/agents/canonical-emit.ts +15 -0
  164. package/src/core/agents/claim-path.ts +23 -0
  165. package/src/core/agents/coord-client.ts +92 -8
  166. package/src/core/agents/live-authority-v3.ts +1 -4
  167. package/src/core/agents/live-lifecycle-v3.ts +8 -3
  168. package/src/core/agents/live-observation-v3.ts +7 -2
  169. package/src/core/agents/render/prompt-context.ts +13 -10
  170. package/src/core/agents/rules/stop-hook.ts +24 -11
  171. package/src/core/agents/session-name-display.ts +11 -3
  172. package/src/core/agents/state/heartbeat-reader.ts +69 -0
  173. package/src/core/agents/state/heartbeat-writer.ts +20 -84
  174. package/src/core/agents/state/live-coordination-view.ts +26 -1
  175. package/src/core/agents/state/names.ts +190 -182
  176. package/src/core/agents/state/stale-sweep.ts +25 -5
  177. package/src/core/artifacts/constants.ts +4 -0
  178. package/src/core/artifacts/index.ts +49 -7
  179. package/src/core/events/v3/base-contract.ts +39 -0
  180. package/src/core/events/v3/capabilities.ts +34 -0
  181. package/src/core/events/v3/generated.ts +1 -1
  182. package/src/core/events/v3/index.ts +21 -0
  183. package/src/core/events/v3/latency.ts +213 -2
  184. package/src/core/events/v3/live-routing.ts +120 -1
  185. package/src/core/events/v3/producers/command-recorder.ts +10 -1
  186. package/src/core/events/v3/producers/coordination-recorder.ts +17 -5
  187. package/src/core/events/v3/producers/hook-base.ts +115 -1
  188. package/src/core/events/v3/producers/intake.ts +18 -0
  189. package/src/core/events/v3/producers/recorder.ts +856 -21
  190. package/src/core/events/v3/runtime-telemetry-capabilities.ts +137 -0
  191. package/src/core/events/v3/turn-telemetry.ts +10 -0
  192. package/src/core/hooks/adapter/parse.ts +16 -0
  193. package/src/core/hooks/adapter/runtime-telemetry.ts +805 -0
  194. package/src/core/hooks/cli.ts +126 -41
  195. package/src/core/hooks/remediation-cap.ts +77 -0
  196. package/src/core/hooks/resolve/transcript.ts +49 -17
  197. package/src/core/semantic/adapters.ts +293 -0
  198. package/src/core/semantic/contract.ts +298 -0
  199. package/src/core/semantic/evidence.ts +336 -0
  200. package/src/core/semantic/index.ts +127 -0
  201. package/src/core/semantic/once.ts +410 -0
  202. package/src/core/semantic/prompt.ts +84 -0
  203. package/src/core/semantic/scheduler.ts +107 -0
  204. package/src/core/semantic/service-status.ts +118 -0
  205. package/src/core/semantic/service.ts +580 -0
  206. package/src/core/semantic/storage.ts +286 -0
  207. package/src/core/semantic/validate.ts +212 -0
  208. package/src/lib/browser/client.ts +21 -0
  209. package/src/lib/browser/index.ts +4 -0
  210. package/src/lib/browser/standalone-html.ts +312 -0
  211. package/src/lib/instructions/apply.ts +1 -0
  212. package/src/lib/instructions/templates.ts +149 -4
@@ -38,7 +38,7 @@ import {
38
38
  type CoordinationObservationBySignalV3,
39
39
  normalizeCoordinationAuthorityV3,
40
40
  } from "./coordination.ts";
41
- import { readHookProducerStateV3 } from "./recorder.ts";
41
+ import { readJoinableHookProducerStateV3 } from "./recorder.ts";
42
42
 
43
43
  const COORDINATION_STATE_FORMAT = "harnery-v3-coordination-producer" as const;
44
44
  const COORDINATION_STATE_VERSION = 2 as const;
@@ -124,10 +124,11 @@ export function recordCoordinationAuthorityV3<S extends CoordinationAuthoritySig
124
124
  ): RecordCoordinationAuthorityV3Result {
125
125
  const control = readEventV3ControlState(input.coordRoot);
126
126
  if (control.state !== input.mode) return { state: "gate_closed", reason: control.state };
127
- const hook = readHookProducerStateV3(
127
+ const hook = readJoinableHookProducerStateV3(
128
128
  input.coordRoot,
129
129
  input.adapter,
130
130
  input.native_actor_session_id,
131
+ input.actor_instance_id,
131
132
  );
132
133
  if (
133
134
  !hook ||
@@ -158,6 +159,16 @@ export function recordCoordinationAuthorityV3<S extends CoordinationAuthoritySig
158
159
  if (state && !matchesHookState(state, hook, input, epochId)) {
159
160
  throw new Error("V3 coordination producer state does not match the joined hook generation");
160
161
  }
162
+ if (state && state.attestation_id !== hook.attestation_id) {
163
+ // A mid-generation re-attestation (session.attestation_changed) moves
164
+ // the hook's attestation id without opening a new generation. The
165
+ // producer keeps its one continuous sequence, clock, and observation
166
+ // dedupe for the generation and stamps later events with the live
167
+ // attestation — the same in-place adoption the hook producer performs.
168
+ // Refusing here would wedge the producer forever, since its state path
169
+ // is derived from the generation alone and can never be superseded.
170
+ state.attestation_id = hook.attestation_id;
171
+ }
161
172
  if (state?.pending) {
162
173
  if (state.pending.source_id !== sourceId) {
163
174
  // A writer that died mid-commit leaves `pending` owned by an
@@ -313,7 +324,7 @@ export function recordCoordinationAuthorityV3<S extends CoordinationAuthoritySig
313
324
 
314
325
  function newCoordinationState<S extends CoordinationAuthoritySignalV3>(
315
326
  input: RecordCoordinationAuthorityV3Input<S>,
316
- hook: NonNullable<ReturnType<typeof readHookProducerStateV3>>,
327
+ hook: NonNullable<ReturnType<typeof readJoinableHookProducerStateV3>>,
317
328
  epochId: `pep_${string}`,
318
329
  ): CoordinationRecorderStateV3 {
319
330
  return {
@@ -340,7 +351,7 @@ function newCoordinationState<S extends CoordinationAuthoritySignalV3>(
340
351
 
341
352
  function matchesHookState<S extends CoordinationAuthoritySignalV3>(
342
353
  state: CoordinationRecorderStateV3,
343
- hook: NonNullable<ReturnType<typeof readHookProducerStateV3>>,
354
+ hook: NonNullable<ReturnType<typeof readJoinableHookProducerStateV3>>,
344
355
  input: RecordCoordinationAuthorityV3Input<S>,
345
356
  epochId: string,
346
357
  ): boolean {
@@ -349,7 +360,8 @@ function matchesHookState<S extends CoordinationAuthoritySignalV3>(
349
360
  state.actor_instance_id === input.actor_instance_id &&
350
361
  state.session_id === hook.session_id &&
351
362
  state.generation_id === hook.generation_id &&
352
- state.attestation_id === hook.attestation_id &&
363
+ // attestation_id is deliberately absent: a re-attestation within the
364
+ // generation is a continuation, adopted by the caller, not a mismatch.
353
365
  state.privacy_epoch_id === epochId &&
354
366
  state.producer_id === input.producer_id &&
355
367
  state.build_id === input.build_id &&
@@ -3,8 +3,16 @@ import type { ParsedPayload } from "../../../hooks/adapter/parse.ts";
3
3
  import { buildEventV3Base } from "../base-builder.ts";
4
4
  import type { EventV3Base, RuntimeAttestationV3Base } from "../base-contract.ts";
5
5
  import { type FingerprintContextV3, fingerprintV3, normalizeNativeIdV3 } from "../canonical.ts";
6
- import { adapterSignalSupportV3, adapterTurnWaitCountSupportV3 } from "../capabilities.ts";
6
+ import {
7
+ adapterSignalSupportV3,
8
+ adapterTurnWaitCountSupportV3,
9
+ type CursorExecutionModeV3,
10
+ } from "../capabilities.ts";
7
11
  import { eventIdV3 } from "../ids.ts";
12
+ import {
13
+ effectiveRuntimeTelemetryCapabilitiesV3,
14
+ type RuntimeTelemetryCapabilitiesV3,
15
+ } from "../runtime-telemetry-capabilities.ts";
8
16
  import { exactToolInputFingerprintV3, extractTargetsV3 } from "../targets.ts";
9
17
 
10
18
  export type HookSignalV3Base =
@@ -41,6 +49,7 @@ export interface HookProducerContextV3Base {
41
49
  platform: "linux" | "windows" | "macos" | "unknown";
42
50
  bridge?: "codex-wsl";
43
51
  capability_profile: `cap_${string}`;
52
+ cursor_mode?: CursorExecutionModeV3;
44
53
  fingerprintContext: FingerprintContextV3;
45
54
  turn_native_id?: string;
46
55
  turn_id?: `tid_${string}`;
@@ -61,6 +70,12 @@ export interface HookProducerContextV3Base {
61
70
  agent_role?: string;
62
71
  stop_remediation?: boolean;
63
72
  turn_ritual?: TurnRitualEvidenceV3;
73
+ /** Tuning read from a local runtime transcript by the recorder; hook-base
74
+ * itself performs no I/O. */
75
+ runtime_tuning?: RuntimeTuningContextV3;
76
+ /** Effective telemetry evidence resolved by the recorder. When absent, the
77
+ * session-start attestation records only what hook delivery can prove. */
78
+ runtime_telemetry?: RuntimeTelemetryCapabilitiesV3;
64
79
  }
65
80
 
66
81
  export interface TurnRitualEvidenceV3 {
@@ -176,6 +191,8 @@ export function normalizeHookEventV3Base(
176
191
  confidence: "exact",
177
192
  }
178
193
  : { state: "expected_but_missing", capability: "model_identity", reason: "not_reported" },
194
+ tuning: tuningObservation(context, payload),
195
+ telemetry: context.runtime_telemetry ?? initialTelemetryCapabilities(context),
179
196
  capability_profile: context.capability_profile,
180
197
  declared_by_event_id: eventId,
181
198
  };
@@ -520,6 +537,103 @@ function plainRecord(value: unknown): Record<string, unknown> | undefined {
520
537
  : undefined;
521
538
  }
522
539
 
540
+ /** Cursor encodes tuning in its parameterized model ids (…-high-fast). Other
541
+ * adapters do not, so absent tuning stays honest instead of being guessed. */
542
+ const MODEL_ID_EFFORT_TOKENS = new Set([
543
+ "none",
544
+ "minimal",
545
+ "low",
546
+ "medium",
547
+ "high",
548
+ "xhigh",
549
+ "max",
550
+ "ultra",
551
+ ]);
552
+
553
+ export type RuntimeTuningObservationV3 = RuntimeAttestationV3Base["tuning"];
554
+
555
+ function initialTelemetryCapabilities(
556
+ context: HookProducerContextV3Base,
557
+ ): RuntimeTelemetryCapabilitiesV3 {
558
+ return effectiveRuntimeTelemetryCapabilitiesV3({
559
+ adapter: context.adapter,
560
+ ...(context.cursor_mode ? { cursor_mode: context.cursor_mode } : {}),
561
+ context:
562
+ context.adapter === "cursor"
563
+ ? { state: "unsupported" }
564
+ : { state: "partial", reason: "context_source_not_ready" },
565
+ canonical_turn_boundaries:
566
+ adapterSignalSupportV3(context.adapter, "turn_completion") !== "unsupported",
567
+ });
568
+ }
569
+
570
+ /** Recorder-supplied tuning read from a local runtime transcript. */
571
+ export interface RuntimeTuningContextV3 {
572
+ effort?: string;
573
+ speed?: string;
574
+ attestation: "native" | "derived";
575
+ }
576
+
577
+ /**
578
+ * Attest the runtime's tuning identity for one generation.
579
+ *
580
+ * Precedence: a recorder-read transcript observation, then the native payload
581
+ * field (CC stamps `effort.level` on tool hooks and Stop, never on
582
+ * SessionStart), then Cursor's model-id tokens. A payload/transcript source
583
+ * that was READ but carried no effort is proof the model has no dial —
584
+ * `unsupported` with capability `effort_selection` — while nothing-read-yet
585
+ * stays `expected_but_missing` so a later attestation can still land.
586
+ */
587
+ function tuningObservation(
588
+ context: HookProducerContextV3Base,
589
+ payload: ParsedPayload,
590
+ ): RuntimeTuningObservationV3 {
591
+ const read = context.runtime_tuning;
592
+ if (read) {
593
+ if (read.effort || read.speed) {
594
+ return {
595
+ state: "observed",
596
+ value: {
597
+ ...(read.effort ? { effort: safeToken(read.effort, "unknown-effort") } : {}),
598
+ ...(read.speed ? { speed: safeToken(read.speed, "unknown-speed") } : {}),
599
+ },
600
+ attestation: read.attestation,
601
+ confidence: "exact",
602
+ };
603
+ }
604
+ return { state: "unsupported", capability: "effort_selection" };
605
+ }
606
+ if (payload.effort) {
607
+ return {
608
+ state: "observed",
609
+ value: { effort: safeToken(payload.effort, "unknown-effort") },
610
+ attestation: "native",
611
+ confidence: "exact",
612
+ };
613
+ }
614
+ if (context.adapter === "cursor" && payload.model) {
615
+ const tokens = payload.model.toLowerCase().split("-");
616
+ let effort: string | undefined;
617
+ for (let index = tokens.length - 1; index >= 0; index -= 1) {
618
+ const token = tokens[index];
619
+ if (token && MODEL_ID_EFFORT_TOKENS.has(token)) {
620
+ effort = token;
621
+ break;
622
+ }
623
+ }
624
+ const speed = tokens.includes("fast") ? "fast" : undefined;
625
+ if (effort || speed) {
626
+ return {
627
+ state: "observed",
628
+ value: { ...(effort ? { effort } : {}), ...(speed ? { speed } : {}) },
629
+ attestation: "derived",
630
+ confidence: "high",
631
+ };
632
+ }
633
+ }
634
+ return { state: "expected_but_missing", capability: "effort_selection", reason: "not_reported" };
635
+ }
636
+
523
637
  function observedIdentity(id: string, version: string | undefined) {
524
638
  return {
525
639
  state: "observed" as const,
@@ -95,6 +95,12 @@ export interface HookIntakeRecordV3 {
95
95
  hook_duration_ms?: number;
96
96
  stop_remediation?: boolean;
97
97
  turn_ritual?: TurnRitualEvidenceV3;
98
+ delegated_child?: {
99
+ generation_id: `gen_${string}`;
100
+ parent_generation_id: `gen_${string}`;
101
+ delegation_id: `del_${string}`;
102
+ caused_by_event_id: `evt_${string}`;
103
+ };
98
104
  }
99
105
 
100
106
  export interface HookIntakeGroupV3 {
@@ -245,6 +251,7 @@ function readIntakeRecord(path: string): HookIntakeRecordV3 | undefined {
245
251
  (record.hook_duration_ms !== undefined &&
246
252
  (!Number.isSafeInteger(record.hook_duration_ms) || record.hook_duration_ms < 0)) ||
247
253
  (record.stop_remediation !== undefined && typeof record.stop_remediation !== "boolean") ||
254
+ !validDelegatedChild(record.delegated_child) ||
248
255
  !validTurnRitual(record.turn_ritual)
249
256
  ) {
250
257
  return undefined;
@@ -252,6 +259,17 @@ function readIntakeRecord(path: string): HookIntakeRecordV3 | undefined {
252
259
  return record;
253
260
  }
254
261
 
262
+ function validDelegatedChild(value: HookIntakeRecordV3["delegated_child"]): boolean {
263
+ if (value === undefined) return true;
264
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
265
+ return (
266
+ /^gen_[0-9a-f-]{36}$/.test(value.generation_id) &&
267
+ /^gen_[0-9a-f-]{36}$/.test(value.parent_generation_id) &&
268
+ /^del_[0-9a-f-]{36}$/.test(value.delegation_id) &&
269
+ /^evt_[0-9a-f-]{36}$/.test(value.caused_by_event_id)
270
+ );
271
+ }
272
+
255
273
  function validTurnRitual(value: TurnRitualEvidenceV3 | undefined): boolean {
256
274
  if (value === undefined) return true;
257
275
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;