tickmarkr 2.6.0 → 2.6.2

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 (103) hide show
  1. package/README.md +14 -3
  2. package/dist/adapters/catalog-remote.js +89 -47
  3. package/dist/adapters/claude-code.js +9 -6
  4. package/dist/adapters/codex.js +7 -4
  5. package/dist/adapters/prompt.d.ts +3 -1
  6. package/dist/adapters/prompt.js +21 -3
  7. package/dist/adapters/registry.js +3 -3
  8. package/dist/adapters/types.d.ts +13 -4
  9. package/dist/adapters/types.js +16 -0
  10. package/dist/cli/commands/approve.d.ts +5 -1
  11. package/dist/cli/commands/approve.js +66 -23
  12. package/dist/cli/commands/compile.js +13 -3
  13. package/dist/cli/commands/doctor.d.ts +2 -0
  14. package/dist/cli/commands/doctor.js +11 -3
  15. package/dist/cli/commands/fleet.js +71 -8
  16. package/dist/cli/commands/plan.js +7 -3
  17. package/dist/cli/commands/report.js +18 -2
  18. package/dist/cli/commands/resume.js +4 -2
  19. package/dist/cli/commands/status.js +37 -22
  20. package/dist/cli/help.d.ts +4 -0
  21. package/dist/cli/help.js +11 -2
  22. package/dist/config/config.d.ts +20 -0
  23. package/dist/config/config.js +47 -8
  24. package/dist/config/fleet-overlay.d.ts +1 -0
  25. package/dist/config/fleet-overlay.js +56 -0
  26. package/dist/drivers/orca.d.ts +26 -1
  27. package/dist/drivers/orca.js +199 -61
  28. package/dist/eval/canary.d.ts +2 -1
  29. package/dist/eval/canary.js +2 -2
  30. package/dist/eval/dispatch.js +1 -0
  31. package/dist/gates/acceptance.d.ts +2 -1
  32. package/dist/gates/acceptance.js +7 -2
  33. package/dist/gates/baseline.d.ts +12 -1
  34. package/dist/gates/baseline.js +11 -4
  35. package/dist/gates/cache.d.ts +3 -1
  36. package/dist/gates/cache.js +10 -3
  37. package/dist/gates/llm.d.ts +5 -4
  38. package/dist/gates/llm.js +17 -14
  39. package/dist/gates/review.d.ts +8 -0
  40. package/dist/gates/review.js +47 -15
  41. package/dist/gates/run-gates.d.ts +6 -1
  42. package/dist/gates/run-gates.js +34 -17
  43. package/dist/gates/test-manifest.d.ts +14 -0
  44. package/dist/gates/test-manifest.js +33 -6
  45. package/dist/graph/graph.d.ts +6 -2
  46. package/dist/graph/graph.js +15 -4
  47. package/dist/graph/schema.d.ts +2 -0
  48. package/dist/graph/schema.js +2 -0
  49. package/dist/plan/scope.js +2 -2
  50. package/dist/route/preference.d.ts +20 -2
  51. package/dist/route/preference.js +48 -13
  52. package/dist/route/role-pick.d.ts +16 -0
  53. package/dist/route/role-pick.js +15 -0
  54. package/dist/route/router.d.ts +14 -0
  55. package/dist/route/router.js +39 -16
  56. package/dist/run/consult.d.ts +13 -1
  57. package/dist/run/consult.js +19 -14
  58. package/dist/run/daemon.d.ts +46 -2
  59. package/dist/run/daemon.js +964 -190
  60. package/dist/run/git.d.ts +44 -1
  61. package/dist/run/git.js +103 -5
  62. package/dist/run/host-health.d.ts +20 -0
  63. package/dist/run/host-health.js +64 -0
  64. package/dist/run/journal.d.ts +126 -3
  65. package/dist/run/journal.js +418 -36
  66. package/dist/run/merge.d.ts +3 -1
  67. package/dist/run/merge.js +3 -2
  68. package/dist/run/operator-state.d.ts +24 -2
  69. package/dist/run/operator-state.js +41 -5
  70. package/dist/run/operator-summary.d.ts +3 -0
  71. package/dist/run/operator-summary.js +3 -1
  72. package/dist/run/protocol.d.ts +31 -1
  73. package/dist/run/protocol.js +3 -1
  74. package/dist/run/stall.d.ts +38 -2
  75. package/dist/run/stall.js +276 -6
  76. package/dist/run/supervision.d.ts +7 -1
  77. package/dist/run/supervision.js +5 -2
  78. package/dist/tui/cockpit/board.d.ts +1 -1
  79. package/dist/tui/cockpit/board.js +30 -22
  80. package/dist/tui/cockpit/decision-actions.d.ts +8 -5
  81. package/dist/tui/cockpit/decision-actions.js +55 -32
  82. package/dist/tui/cockpit/derive.d.ts +2 -0
  83. package/dist/tui/cockpit/derive.js +17 -2
  84. package/dist/tui/cockpit/live-runtime.d.ts +10 -0
  85. package/dist/tui/cockpit/live-runtime.js +50 -3
  86. package/dist/tui/cockpit/live-store.d.ts +1 -0
  87. package/dist/tui/cockpit/live-store.js +31 -8
  88. package/dist/tui/cockpit/run-cockpit.d.ts +3 -0
  89. package/dist/tui/cockpit/run-cockpit.js +28 -2
  90. package/dist/tui/cockpit/run-view.d.ts +11 -7
  91. package/dist/tui/cockpit/run-view.js +69 -15
  92. package/dist/tui/cockpit/setup-cockpit.d.ts +4 -0
  93. package/dist/tui/cockpit/setup-cockpit.js +6 -3
  94. package/dist/tui/ink/fleet-app.d.ts +15 -3
  95. package/dist/tui/ink/fleet-app.js +91 -22
  96. package/package.json +2 -1
  97. package/schema/config.schema.json +818 -0
  98. package/skills/tickmarkr-loop/SKILL.md +8 -2
  99. package/skills/tickmarkr-overseer/SKILL.md +85 -6
  100. package/skills/tickmarkr-overseer/scripts/classify-vitest-log.sh +88 -0
  101. package/skills/tickmarkr-overseer/scripts/context-statusline.sh +81 -0
  102. package/skills/tickmarkr-overseer/scripts/grade-ci.sh +36 -34
  103. package/skills/tickmarkr-overseer/scripts/watch-journal.sh +6 -4
@@ -1,5 +1,5 @@
1
1
  import type { TickmarkrConfig } from "../config/config.js";
2
- import { type Baseline, type GateEvidenceOptions, type FailureClassification } from "../gates/baseline.js";
2
+ import { type Baseline, type BaselineProvenance, type GateEvidenceOptions, type FailureClassification } from "../gates/baseline.js";
3
3
  import type { GateEvidenceReceipt } from "./protocol.js";
4
4
  export interface TipVerifyResult {
5
5
  evidenceReceipt?: GateEvidenceReceipt;
@@ -21,6 +21,8 @@ export interface TipVerifyResult {
21
21
  spawnedCommand?: string;
22
22
  /** Q121s: nonzero exit whose failures are ALL baseline-recorded — forgiven exactly as the battery forgives. */
23
23
  forgiven?: boolean;
24
+ /** OBS-1123: the capture that recorded the forgiven fingerprints; absent for a legacy baseline that never said. */
25
+ baselineProvenance?: BaselineProvenance;
24
26
  /** D-131: carried from a persisted per-gate verdict — this cycle did NOT execute the command. */
25
27
  reused?: true;
26
28
  /**
package/dist/run/merge.js CHANGED
@@ -225,6 +225,7 @@ export async function verifyIntegrationTip(intWt, commands, runDir, baseline, ev
225
225
  exitCode: hit.exitCode ?? 0,
226
226
  fingerprints: hit.meta?.fingerprints ?? [],
227
227
  ...(hit.meta?.forgiven ? { forgiven: true } : {}),
228
+ ...(hit.meta?.forgiven && hit.meta.baselineProvenance ? { baselineProvenance: hit.meta.baselineProvenance } : {}),
228
229
  details: formatReusedDetails(hit.details, id),
229
230
  ...(hit.meta?.reportPath ? { reportPath: hit.meta.reportPath } : {}),
230
231
  ...(hit.meta?.spawnedCommand ? { spawnedCommand: hit.meta.spawnedCommand } : {}),
@@ -382,7 +383,7 @@ export async function verifyIntegrationTip(intWt, commands, runDir, baseline, ev
382
383
  + `${describeCapacity(entry?.capacity)} and this verification ran under ${describeCapacity(r.capacity)} `
383
384
  + `— forgiveness across a changed capacity is not evidence`
384
385
  : `exit ${r.code}`)),
385
- ...(forgiven && !deficit ? { forgiven: true } : {}),
386
+ ...(forgiven && !deficit ? { forgiven: true, ...(baseline?.provenance ? { baselineProvenance: baseline.provenance } : {}) } : {}),
386
387
  ...(cause ? { cause } : {}),
387
388
  ...(pass ? {} : { artifact }),
388
389
  };
@@ -401,7 +402,7 @@ export async function verifyIntegrationTip(intWt, commands, runDir, baseline, ev
401
402
  const id = pending.get(result.gate);
402
403
  if (id && id.tree === completedTree && !isInfraResult(result)) {
403
404
  store.set(id, { ...result, meta: {
404
- fingerprints: result.fingerprints, forgiven: result.forgiven,
405
+ fingerprints: result.fingerprints, forgiven: result.forgiven, baselineProvenance: result.baselineProvenance,
405
406
  reportPath: result.reportPath, spawnedCommand: result.spawnedCommand,
406
407
  artifact: result.artifact,
407
408
  evidenceReceipt: result.evidenceReceipt, evidenceReceipts: result.evidenceReceipts,
@@ -11,11 +11,18 @@ export interface OperatorRecord extends EvidenceIdentity {
11
11
  event: JournalEvent;
12
12
  }
13
13
  export type OperatorTaskState = "unknown" | "pending" | "running" | "completed" | "merged" | "failed" | "human" | "blocked";
14
- export type OperatorGateState = "unknown" | "not-run" | "disabled" | "running" | "passed" | "failed";
14
+ export type OperatorGateState = "unknown" | "not-run" | "disabled" | "queued" | "running" | "passed" | "failed";
15
15
  export interface OperatorGate {
16
16
  state: OperatorGateState;
17
17
  evidence?: EvidenceIdentity;
18
18
  }
19
+ export interface GateActivity {
20
+ state: "queued" | "running";
21
+ gate?: string;
22
+ reason?: "suite-wait" | "host-degraded";
23
+ count?: number;
24
+ evidence: EvidenceIdentity;
25
+ }
19
26
  export interface OperatorTask {
20
27
  id: string;
21
28
  title?: string;
@@ -30,10 +37,14 @@ export interface OperatorTask {
30
37
  evidence?: EvidenceIdentity;
31
38
  mergeEvidence?: EvidenceIdentity;
32
39
  gates: Record<string, OperatorGate>;
40
+ gateActivity?: GateActivity;
33
41
  /** BD-1: the board's per-task counters — latest dispatch channel, review verdicts drawn, human parks. */
34
42
  channel?: string;
35
43
  reviewRounds: number;
36
44
  parks: number;
45
+ /** Distinct producing channels of the merged subject from task-done; "unknown" names unattributed preserved work.
46
+ * Kept apart from `channel`: the last-dispatched seat may have authored nothing. */
47
+ authors?: readonly string[];
37
48
  }
38
49
  export interface OperatorSnapshot {
39
50
  sequence: number;
@@ -47,6 +58,10 @@ export interface OperatorSnapshot {
47
58
  label: string;
48
59
  green: boolean;
49
60
  currentTip: "passed" | "not required" | "pending" | "failed" | "unknown";
61
+ graphAvailability?: {
62
+ status: "readable" | "absent" | "unreadable";
63
+ error?: string;
64
+ };
50
65
  comparable: boolean;
51
66
  comparison: "matching graph" | "not comparable";
52
67
  merged: number;
@@ -60,6 +75,12 @@ export interface OperatorSnapshot {
60
75
  latestRunEnd?: EvidenceIdentity;
61
76
  approvedResumeRequired: boolean;
62
77
  }
78
+ /** Author channels recorded on a task-done row. A row written before authors were recorded carries none and
79
+ * projects nothing (never the dispatch); unattributed preserved work arrives as an explicit "unknown" entry. */
80
+ export declare const doneAuthors: (data: Record<string, unknown>) => string[] | undefined;
81
+ /** The note a status row or board row shows beside the last-dispatched channel when the merged
82
+ * authors are not exactly that channel (a carry-only seat, a mixed subject, or legacy unknown). */
83
+ export declare const authorsNote: (authors: readonly string[] | undefined, channel: string | undefined) => string | undefined;
63
84
  /** Incremental pure lifecycle fold. Retains facts per task/gate, never verdict bodies or event history. */
64
85
  export declare class OperatorStateFold {
65
86
  private tasks;
@@ -78,11 +99,12 @@ export declare class OperatorStateFold {
78
99
  private total;
79
100
  apply(record: OperatorRecord): void;
80
101
  private task;
81
- snapshot({ graph, sequence, observedAt, readable }?: {
102
+ snapshot({ graph, sequence, observedAt, readable, graphAvailability }?: {
82
103
  graph?: RunGraph;
83
104
  sequence?: number;
84
105
  observedAt?: number;
85
106
  readable?: boolean;
107
+ graphAvailability?: OperatorSnapshot["graphAvailability"];
86
108
  }): OperatorSnapshot;
87
109
  private comparableTo;
88
110
  }
@@ -5,6 +5,12 @@ const bucketNames = ["failed", "human", "blocked", "pending"];
5
5
  const strings = (value) => Array.isArray(value) && value.every(v => typeof v === "string") ? [...value] : undefined;
6
6
  const identity = ({ source, line, id, generation }) => ({ source, line, id, generation });
7
7
  const emptyGates = () => Object.fromEntries(GATE_NAMES.map(g => [g, { state: "not-run" }]));
8
+ /** Author channels recorded on a task-done row. A row written before authors were recorded carries none and
9
+ * projects nothing (never the dispatch); unattributed preserved work arrives as an explicit "unknown" entry. */
10
+ export const doneAuthors = (data) => strings(data.authors);
11
+ /** The note a status row or board row shows beside the last-dispatched channel when the merged
12
+ * authors are not exactly that channel (a carry-only seat, a mixed subject, or legacy unknown). */
13
+ export const authorsNote = (authors, channel) => authors === undefined || (authors.length === 1 && authors[0] === channel) ? undefined : `authors ${authors.join("+")}`;
8
14
  /** Incremental pure lifecycle fold. Retains facts per task/gate, never verdict bodies or event history. */
9
15
  export class OperatorStateFold {
10
16
  tasks = new Map();
@@ -75,6 +81,7 @@ export class OperatorStateFold {
75
81
  t.dispatches++;
76
82
  t.parkKind = undefined;
77
83
  t.gates = emptyGates();
84
+ t.gateActivity = undefined;
78
85
  t.attempt = typeof e.data.attempt === "number" ? e.data.attempt : undefined;
79
86
  // These are recorded values only: no guessed directory or universal silence threshold.
80
87
  t.path = typeof e.data.worktree === "string" ? e.data.worktree : typeof e.data.cwd === "string" ? e.data.cwd : undefined;
@@ -84,8 +91,10 @@ export class OperatorStateFold {
84
91
  if (a && typeof a.adapter === "string" && typeof a.model === "string")
85
92
  t.channel = `${a.adapter}:${a.model}`;
86
93
  }
87
- if (e.event === "task-done")
94
+ if (e.event === "task-done") {
88
95
  t.state = "completed";
96
+ t.authors = doneAuthors(e.data);
97
+ }
89
98
  if (e.event === "merge") {
90
99
  t.state = "merged";
91
100
  t.merged = true;
@@ -104,12 +113,39 @@ export class OperatorStateFold {
104
113
  if (e.event === "task-approved") {
105
114
  t.state = "pending";
106
115
  t.parkKind = undefined;
116
+ t.gateActivity = undefined;
107
117
  this.approved = !this.active;
118
+ if (e.data.release === "recheck")
119
+ t.gates = emptyGates();
120
+ }
121
+ if (e.event === "phase-start" && e.data.phase === "gates")
122
+ t.gateActivity = undefined;
123
+ if (e.event === "suite-wait" || e.event === "host-degraded") {
124
+ // Only this row's attribution is authority. Legacy task-only waits must not borrow a red gate.
125
+ const gate = typeof e.data.gate === "string" && GATE_NAMES.includes(e.data.gate) ? e.data.gate : undefined;
126
+ t.gateActivity = { state: "queued", gate, reason: e.event, evidence: ref,
127
+ ...(typeof e.data.count === "number" ? { count: e.data.count } : {}) };
128
+ if (gate)
129
+ t.gates[gate] = { state: "queued", evidence: ref };
130
+ }
131
+ if (e.event === "suite-admitted")
132
+ t.gateActivity = undefined;
133
+ if (["task-done", "merge", "task-failed", "task-human", "task-blocked"].includes(e.event))
134
+ t.gateActivity = undefined;
135
+ const phaseGate = e.event === "phase-start" && typeof e.data.phase === "string"
136
+ ? e.data.phase.startsWith("gate:") ? e.data.phase.slice(5) : e.data.phase === "judge" ? "acceptance" : e.data.phase === "review" ? "review" : undefined
137
+ : undefined;
138
+ const gate = e.data.gate ?? phaseGate;
139
+ if ((e.event === "phase-start" && (phaseGate !== undefined || e.data.gate !== undefined)) || e.event === "gate-start" || e.event === "gate-phase-start") {
140
+ t.gateActivity = { state: "running", evidence: ref };
108
141
  }
109
- const gate = e.data.gate;
110
142
  if (typeof gate === "string" && GATE_NAMES.includes(gate)) {
111
- if (e.event === "gate-start")
143
+ if (e.event === "gate-start" || e.event === "gate-phase-start" || e.event === "phase-start") {
112
144
  t.gates[gate] = { state: "running", evidence: ref };
145
+ t.gateActivity = { state: "running", gate, evidence: ref };
146
+ }
147
+ if (e.event === "gate-result" && t.gateActivity?.gate === gate)
148
+ t.gateActivity = undefined;
113
149
  if (e.event === "gate-result" && gate === "review")
114
150
  t.reviewRounds++;
115
151
  if (e.event === "gate-result")
@@ -126,7 +162,7 @@ export class OperatorStateFold {
126
162
  }
127
163
  return t;
128
164
  }
129
- snapshot({ graph, sequence = 0, observedAt = Date.now(), readable = true } = {}) {
165
+ snapshot({ graph, sequence = 0, observedAt = Date.now(), readable = true, graphAvailability } = {}) {
130
166
  const hash = graph && graphDefinitionHash(graph);
131
167
  const comparable = this.comparableTo(hash);
132
168
  const ids = comparable ? [...graph.tasks.map(t => t.id), ...[...this.tasks.keys()].filter(id => !graph.tasks.some(t => t.id === id))] : [...this.tasks.keys()];
@@ -150,7 +186,7 @@ export class OperatorStateFold {
150
186
  return {
151
187
  sequence, observedAt, lastEventAt: this.lastEventAt, firstEventAt: this.firstEventAt, resumes: this.resumes, escalations: this.escalations, lifecycle,
152
188
  label: this.approved ? "approved; resume required" : lifecycle,
153
- green, currentTip, comparable, comparison: comparable ? "matching graph" : "not comparable",
189
+ green, currentTip, graphAvailability, comparable, comparison: comparable ? "matching graph" : "not comparable",
154
190
  merged,
155
191
  planned, tasks, buckets,
156
192
  gatesRan: { passed: this.passed, total: this.total }, latestRunEnd: this.end?.evidence,
@@ -13,6 +13,9 @@ export interface OperatorDecisionSnapshot {
13
13
  readonly kind: string | undefined;
14
14
  readonly tombstone: boolean;
15
15
  readonly reason?: string;
16
+ /** OBS-1178: the park row's physical line and timestamp — the token a decision binds to. */
17
+ readonly line?: number;
18
+ readonly ts?: string;
16
19
  };
17
20
  readonly verbs: readonly string[];
18
21
  readonly diagnostic?: string;
@@ -25,7 +25,9 @@ export function projectOperatorSummary(tasks, decisions) {
25
25
  decisionRequired: verbs.length > 0,
26
26
  ...(diagnostic !== undefined || park.reason !== undefined
27
27
  ? { diagnostic: diagnostic ?? park.reason } : {}),
28
- nextAction: verbs.length > 0 ? `Choose a decision: ${verbs.join(", ")}` : null,
28
+ nextAction: verbs.length > 0
29
+ ? `Choose a decision: ${verbs.join(", ")}${park.line !== undefined && park.ts !== undefined ? ` (--park ${park.line}@${park.ts})` : ""}`
30
+ : null,
29
31
  };
30
32
  if (!park.tombstone && park.kind === "infra" && task.missingCapability) {
31
33
  const { capability, diagnostic: capabilityDiagnostic } = task.missingCapability;
@@ -66,10 +66,10 @@ export declare const GateEvidenceReceiptSchema: z.ZodObject<{
66
66
  termination: z.ZodObject<{
67
67
  kind: z.ZodEnum<{
68
68
  unknown: "unknown";
69
+ timeout: "timeout";
69
70
  signal: "signal";
70
71
  "not-started": "not-started";
71
72
  exit: "exit";
72
- timeout: "timeout";
73
73
  }>;
74
74
  exitCode: z.ZodNullable<z.ZodNumber>;
75
75
  signal: z.ZodNullable<z.ZodString>;
@@ -222,6 +222,11 @@ export declare const RoleInvocationStartEventSchema: z.ZodObject<{
222
222
  adapter: z.ZodOptional<z.ZodString>;
223
223
  model: z.ZodOptional<z.ZodString>;
224
224
  vendor: z.ZodOptional<z.ZodString>;
225
+ effort: z.ZodOptional<z.ZodEnum<{
226
+ low: "low";
227
+ medium: "medium";
228
+ high: "high";
229
+ }>>;
225
230
  evidence: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
226
231
  }, z.core.$strict>;
227
232
  }, z.core.$strict>;
@@ -240,6 +245,11 @@ export declare const RoleInvocationTerminalEventSchema: z.ZodObject<{
240
245
  adapter: z.ZodOptional<z.ZodString>;
241
246
  model: z.ZodOptional<z.ZodString>;
242
247
  vendor: z.ZodOptional<z.ZodString>;
248
+ effort: z.ZodOptional<z.ZodEnum<{
249
+ low: "low";
250
+ medium: "medium";
251
+ high: "high";
252
+ }>>;
243
253
  evidence: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
244
254
  outcome: z.ZodEnum<{
245
255
  failed: "failed";
@@ -352,6 +362,11 @@ export declare const DecisionEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
352
362
  adapter: z.ZodOptional<z.ZodString>;
353
363
  model: z.ZodOptional<z.ZodString>;
354
364
  vendor: z.ZodOptional<z.ZodString>;
365
+ effort: z.ZodOptional<z.ZodEnum<{
366
+ low: "low";
367
+ medium: "medium";
368
+ high: "high";
369
+ }>>;
355
370
  evidence: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
356
371
  }, z.core.$strict>;
357
372
  }, z.core.$strict>, z.ZodObject<{
@@ -369,6 +384,11 @@ export declare const DecisionEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
369
384
  adapter: z.ZodOptional<z.ZodString>;
370
385
  model: z.ZodOptional<z.ZodString>;
371
386
  vendor: z.ZodOptional<z.ZodString>;
387
+ effort: z.ZodOptional<z.ZodEnum<{
388
+ low: "low";
389
+ medium: "medium";
390
+ high: "high";
391
+ }>>;
372
392
  evidence: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
373
393
  outcome: z.ZodEnum<{
374
394
  failed: "failed";
@@ -473,6 +493,11 @@ export declare const DecisionEventWriteSchema: z.ZodDiscriminatedUnion<[z.ZodObj
473
493
  adapter: z.ZodOptional<z.ZodString>;
474
494
  model: z.ZodOptional<z.ZodString>;
475
495
  vendor: z.ZodOptional<z.ZodString>;
496
+ effort: z.ZodOptional<z.ZodEnum<{
497
+ low: "low";
498
+ medium: "medium";
499
+ high: "high";
500
+ }>>;
476
501
  evidence: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
477
502
  }, z.core.$strict>;
478
503
  event: z.ZodLiteral<"role-invocation-start">;
@@ -489,6 +514,11 @@ export declare const DecisionEventWriteSchema: z.ZodDiscriminatedUnion<[z.ZodObj
489
514
  adapter: z.ZodOptional<z.ZodString>;
490
515
  model: z.ZodOptional<z.ZodString>;
491
516
  vendor: z.ZodOptional<z.ZodString>;
517
+ effort: z.ZodOptional<z.ZodEnum<{
518
+ low: "low";
519
+ medium: "medium";
520
+ high: "high";
521
+ }>>;
492
522
  evidence: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
493
523
  outcome: z.ZodEnum<{
494
524
  failed: "failed";
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { GATE_NAMES } from "../graph/schema.js";
2
+ import { EFFORTS, GATE_NAMES } from "../graph/schema.js";
3
3
  import { normalizeGateOutcome } from "./outcome.js";
4
4
  // T32 (F2): the decision protocol is deliberately smaller than the journal. Existing journals contain
5
5
  // many observational event types and must remain readable; only the five event names below assert a
@@ -133,6 +133,8 @@ const RoleInvocationIdentityDataSchema = z.object({
133
133
  adapter: NonEmptyStringSchema.optional(),
134
134
  model: NonEmptyStringSchema.optional(),
135
135
  vendor: NonEmptyStringSchema.optional(),
136
+ // OBS-1182: the effort the seat actually launched at; absent = the CLI's own default, never a level.
137
+ effort: z.enum(EFFORTS).optional(),
136
138
  evidence: EvidenceSchema.optional(),
137
139
  });
138
140
  const RoleInvocationStartDataSchema = RoleInvocationIdentityDataSchema.strict();
@@ -13,7 +13,42 @@ export declare function resetHarvestCpuFlatMsForTests(): void;
13
13
  /** The dispatch shell records its foreground group in an attempt-unique artifact. */
14
14
  export declare function readOwnedProcessGroup(path: string): number | undefined;
15
15
  /** Never infer ownership from a task name or scan another attempt's marker when reaping. */
16
- export declare function reapOwnedProcessGroup(group: number | undefined, cwd: string): Promise<number[] | null>;
16
+ export declare function reapOwnedProcessGroup(group: number | undefined, cwd: string, ownership?: WorkerReapOwnership): Promise<number[] | null>;
17
+ export interface ReapProcess {
18
+ pid: number;
19
+ ppid: number;
20
+ group: number;
21
+ session: string;
22
+ identity: string;
23
+ command: string;
24
+ startedAt?: string;
25
+ }
26
+ export interface WorkerReapOwnership {
27
+ marker: string;
28
+ /** Session recorded by the dispatch shell before its children can detach. */
29
+ session?: string;
30
+ parent?: {
31
+ pid: number;
32
+ startedAt: string;
33
+ };
34
+ identities?: Map<number, string>;
35
+ /** Descendants observed while the dispatch root was still alive. */
36
+ descendants?: Map<number, string>;
37
+ excludedGroups: number[];
38
+ excludedWorktrees: string[];
39
+ /** Discovery evidence is distinct from the final survivor census. */
40
+ strays: number[];
41
+ }
42
+ /** Bounded host boundary, also used to inject unreadability and pid reuse in regressions. */
43
+ export declare const workerReapHost: {
44
+ snapshot(): Promise<ReapProcess[] | undefined>;
45
+ inspect(pid: number): Promise<{
46
+ cwd: string;
47
+ suiteParent?: number;
48
+ } | undefined>;
49
+ identity: (pid: number) => Promise<string | null | undefined>;
50
+ kill(pid: number): void;
51
+ };
17
52
  export declare function workerTreeCpuMs(marker: string, cwd: string): Promise<{
18
53
  ms: number;
19
54
  resolutionMs: number;
@@ -22,6 +57,7 @@ export declare class WorkerTreeCpuAccountant {
22
57
  private marker;
23
58
  private cwd;
24
59
  private group?;
60
+ private identities?;
25
61
  private active;
26
62
  private loop;
27
63
  private live;
@@ -29,7 +65,7 @@ export declare class WorkerTreeCpuAccountant {
29
65
  private gaps;
30
66
  private consecutiveGaps;
31
67
  private latest;
32
- constructor(marker: string, cwd: string, group?: (() => number | undefined) | undefined);
68
+ constructor(marker: string, cwd: string, group?: (() => number | undefined) | undefined, identities?: Map<number, string> | undefined);
33
69
  private sample;
34
70
  start(): Promise<void>;
35
71
  read(): {