@tea-agent/loop-agent 0.22.0 → 0.24.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 (103) hide show
  1. package/AGENTS.md +42 -108
  2. package/CHANGELOG.md +85 -0
  3. package/README.md +8 -5
  4. package/bin/agent-worker.js +0 -0
  5. package/dist/application/context-usage/skill-resolution-stats.js +263 -0
  6. package/dist/application/dag/generate-task-dag.js +17 -3
  7. package/dist/cli/command-definitions.js +8 -7
  8. package/dist/cli/program.js +17 -15
  9. package/dist/commands/doctor.js +269 -18
  10. package/dist/commands/init.js +101 -86
  11. package/dist/commands/stats.js +40 -11
  12. package/dist/executors/shell-executor.js +20 -7
  13. package/dist/shared/operator/capabilities.js +486 -3
  14. package/dist/worker/console/app-data.js +6 -0
  15. package/dist/worker/console/chat/artifact-card.js +23 -0
  16. package/dist/worker/console/chat/chat-event-store.js +495 -0
  17. package/dist/worker/console/chat/chat-ui-policy.js +25 -0
  18. package/dist/worker/console/chat/composer-draft-store.js +45 -0
  19. package/dist/worker/console/chat/context-panel.js +54 -0
  20. package/dist/worker/console/chat/contract-apply-receipt-store.js +174 -0
  21. package/dist/worker/console/chat/explore-tools.js +299 -0
  22. package/dist/worker/console/chat/human-gate-card.js +37 -0
  23. package/dist/worker/console/chat/instruction-skills.js +217 -0
  24. package/dist/worker/console/chat/interview-adapter.js +136 -0
  25. package/dist/worker/console/chat/model-resolver.js +106 -0
  26. package/dist/worker/console/chat/operation-card.js +23 -0
  27. package/dist/worker/console/chat/pi-console-config.js +158 -0
  28. package/dist/worker/console/chat/pi-runtime.js +1143 -0
  29. package/dist/worker/console/chat/repo-browser.js +140 -0
  30. package/dist/worker/console/chat/repo-walk.js +116 -0
  31. package/dist/worker/console/chat/resource-loader.js +67 -0
  32. package/dist/worker/console/chat/routes.js +1646 -0
  33. package/dist/worker/console/chat/runtime-context.js +24 -0
  34. package/dist/worker/console/chat/runtime-selection.js +37 -0
  35. package/dist/worker/console/chat/session-store.js +437 -0
  36. package/dist/worker/console/chat/shortcuts.js +15 -0
  37. package/dist/worker/console/chat/tool-adapter.js +125 -0
  38. package/dist/worker/console/chat/tools.js +195 -0
  39. package/dist/worker/console/chat/usage.js +37 -0
  40. package/dist/worker/console/chat/workspace-landing.js +56 -0
  41. package/dist/worker/console/dag-confirmation.js +42 -8
  42. package/dist/worker/console/human-gate-token.js +130 -0
  43. package/dist/worker/console/mutation-gate-receipt-store.js +184 -0
  44. package/dist/worker/console/operation-runner.js +6 -2
  45. package/dist/worker/console/operation-sse.js +26 -0
  46. package/dist/worker/console/operator-actions.js +420 -7
  47. package/dist/worker/console/server.js +68 -1
  48. package/dist/worker/console/static/assets/index-BTbrEHnO.css +1 -0
  49. package/dist/worker/console/static/assets/index-D9qLevoP.js +27 -0
  50. package/dist/worker/console/static/index.html +2 -2
  51. package/dist/worker/feature/profile-schema.js +1 -1
  52. package/dist/workflows/dag/backend-test-markdown-workflow.js +9 -5
  53. package/dist/workflows/dag/backend-test-result-contract.js +229 -0
  54. package/dist/workflows/dag/frontend-lint-baseline.js +4 -4
  55. package/dist/workflows/dag/init-hybrid.js +71 -22
  56. package/dist/workflows/dag/node-execution.js +38 -1
  57. package/dist/workflows/dag/output-protocol.js +89 -0
  58. package/dist/workflows/dag/prompt.js +35 -1
  59. package/dist/workflows/dag/recovery-recommendation.js +45 -0
  60. package/dist/workflows/dag/report.js +28 -1
  61. package/dist/workflows/dag/rerun-task.js +1 -1
  62. package/dist/workflows/dag/scheduler.js +9 -0
  63. package/dist/workflows/dag/types.js +12 -0
  64. package/dist/workflows/dag/validate.js +55 -0
  65. package/docs/README.md +73 -156
  66. package/docs/architecture/README.md +7 -6
  67. package/docs/architecture/dag-execution.md +2 -2
  68. package/docs/architecture/evolution.md +16 -14
  69. package/docs/architecture/system-overview.md +1 -1
  70. package/docs/architecture/worker-and-feature.md +3 -3
  71. package/docs/governance/README.md +15 -0
  72. package/docs/{harness-methodology-debugging.md → governance/harness-methodology-debugging.md} +27 -3
  73. package/docs/init-surface.manifest.json +22 -4
  74. package/docs/operations/README.md +12 -0
  75. package/docs/{local-development-environment.md → operations/local-development-environment.md} +1 -1
  76. package/docs/skills/vetted-skill-registry.md +23 -3
  77. package/docs/templates/README.md +55 -0
  78. package/docs/templates/backend-test-dag.json +2 -2
  79. package/docs/templates/evaluation/agents-map-slim-v1.candidate.json +9 -0
  80. package/docs/templates/evaluation/agents-map-slim-v1.md +87 -0
  81. package/docs/templates/evaluation/agents-map-verbose-v0.candidate.json +9 -0
  82. package/docs/templates/evaluation/agents-map-verbose-v0.md +153 -0
  83. package/docs/templates/hybrid-dag.json +1 -1
  84. package/docs/templates/progress-log.md +9 -2
  85. package/harness.json +4 -4
  86. package/package.json +5 -5
  87. package/scripts/kb-bootstrap-init-skeleton.sh +2 -2
  88. package/skills/agent-worker/SKILL.md +1 -1
  89. package/skills/grill-with-docs/SKILL.md +44 -52
  90. package/skills/grill-with-docs/adr-format.md +37 -26
  91. package/skills/grill-with-docs/context-format.md +18 -26
  92. package/skills/loop-agent/SKILL.md +28 -112
  93. package/skills/loop-agent/references/command-reference.md +9 -3
  94. package/skills/loop-agent/references/harness-policy.md +3 -3
  95. package/skills/loop-agent/references/hybrid-dag.md +1 -1
  96. package/skills/loop-agent/references/orchestrator-and-interventions.md +1 -1
  97. package/skills/loop-agent/references/task-workflow.md +2 -0
  98. package/skills/systematic-debugging/SKILL.md +20 -4
  99. package/skills/test-driven-development/SKILL.md +10 -3
  100. package/dist/worker/console/static/assets/index-CUDke82y.js +0 -18
  101. package/dist/worker/console/static/assets/index-wSEksVSO.css +0 -1
  102. /package/docs/{harness-methodology-tdd.md → governance/harness-methodology-tdd.md} +0 -0
  103. /package/docs/{harness-methodology-verification.md → governance/harness-methodology-verification.md} +0 -0
@@ -1,4 +1,82 @@
1
1
  import { OPERATOR_ERROR_CODES_V1, OPERATOR_OUTCOMES_V1 } from "./registry.js";
2
+ const officialAction = (action, cli, kind, coverage) => ({
3
+ action,
4
+ cli,
5
+ kind,
6
+ inputSchemaVersion: 1,
7
+ resultSchemaVersion: 1,
8
+ envelopeSchemaVersion: 1,
9
+ requiredErrorCodes: kind === "read"
10
+ ? ["INVALID_INPUT", "NOT_FOUND"]
11
+ : ["INVALID_INPUT", "REQUEST_ID_REUSE_CONFLICT", "REVISION_CONFLICT", "OBSERVED_HASH_CONFLICT", "LEASE_HELD", "TRANSACTION_INCOMPLETE", "NOT_FOUND"],
12
+ description: `Official CLI action coverage for ${cli}.`,
13
+ inputParams: [
14
+ { name: "args", type: "array", itemsType: "string", required: false, description: "validated trailing CLI arguments" },
15
+ ...(coverage === "human-gated-required" ? [{ name: "confirmationId", type: "string", required: true, description: "human confirmation receipt id" }] : []),
16
+ ],
17
+ modelCallable: coverage === "human-gated-required"
18
+ ? "prepare-only"
19
+ : coverage === "advanced" && kind !== "read"
20
+ ? "never"
21
+ : "always",
22
+ humanConfirmation: coverage === "human-gated-required" ? "required" : "none",
23
+ });
24
+ const OFFICIAL_ACTIONS = [
25
+ ...[
26
+ ["dagDoctor", "loop-agent dag doctor", "read", "model-callable"],
27
+ ["dagStatus", "loop-agent dag status", "read", "model-callable"],
28
+ ["dagDecisionInspect", "loop-agent dag decision inspect", "read", "model-callable"],
29
+ ["dagDecisionValidate", "loop-agent dag decision validate", "read", "model-callable"],
30
+ ["dagCloseoutDraft", "loop-agent dag closeout-draft", "read", "model-callable"],
31
+ ["dagApprove", "loop-agent dag approve", "mutation", "human-gated-required"],
32
+ ["dagReject", "loop-agent dag reject", "mutation", "human-gated-required"],
33
+ ["dagResume", "loop-agent dag resume", "long-running", "human-gated-required"],
34
+ ["dagReconcileRun", "loop-agent dag reconcile-run", "mutation", "human-gated-required"],
35
+ ["dagReconcileTasks", "loop-agent dag reconcile-tasks", "mutation", "human-gated-required"],
36
+ ["dagFinalVerification", "loop-agent dag final-verification", "long-running", "human-gated-required"],
37
+ ["dagInitHybrid", "loop-agent dag init-hybrid", "mutation", "advanced"],
38
+ ["dagWorkflowPlan", "loop-agent dag workflow-plan", "read", "advanced"],
39
+ ["dagWorkflowValidate", "loop-agent dag workflow-validate", "read", "advanced"],
40
+ ["dagWorkflowCompile", "loop-agent dag workflow-compile", "mutation", "advanced"],
41
+ ["planList", "loop-agent plan list", "read", "model-callable"],
42
+ ["planCreate", "loop-agent plan create", "mutation", "model-callable"],
43
+ ["planComplete", "loop-agent plan complete", "mutation", "model-callable"],
44
+ ["planCheck", "loop-agent plan check", "read", "model-callable"],
45
+ ["docsAudit", "loop-agent docs audit", "read", "model-callable"],
46
+ ["docsArchive", "loop-agent docs archive", "mutation", "advanced"],
47
+ ["handoffCheck", "loop-agent handoff check", "read", "model-callable"],
48
+ ["handoffCoverage", "loop-agent handoff coverage", "read", "model-callable"],
49
+ ["coverageReport", "loop-agent coverage report", "read", "model-callable"],
50
+ ["stats", "loop-agent stats", "read", "model-callable"],
51
+ ["promoteRun", "loop-agent promote-run", "mutation", "model-callable"],
52
+ ["closeoutTask", "loop-agent closeout task", "mutation", "model-callable"],
53
+ ["piReuseBenchmark", "loop-agent pi-reuse-benchmark", "read", "advanced"],
54
+ ["loopBenchmark", "loop-agent loop-benchmark", "read", "advanced"],
55
+ ["knowledgeCurate", "loop-agent knowledge curate", "read", "model-callable"],
56
+ ["knowledgeQuery", "loop-agent knowledge query", "read", "model-callable"],
57
+ ["knowledgeGraphInit", "loop-agent knowledge graph-init", "mutation", "advanced"],
58
+ ["knowledgeGraphMaterialize", "loop-agent knowledge graph-materialize", "mutation", "advanced"],
59
+ ["knowledgeGraphPromote", "loop-agent knowledge graph-promote", "mutation", "advanced"],
60
+ ["knowledgeGraphIncrementalPrepare", "loop-agent knowledge graph-incremental-prepare", "mutation", "advanced"],
61
+ ...["init", "status", "run", "record-round", "add-signal", "closeout"].map((leaf) => [`loop${leaf.replace(/(^|-)(.)/g, (_m, _d, c) => c.toUpperCase())}`, `loop-agent loop ${leaf}`, leaf === "status" ? "read" : "mutation", "advanced"]),
62
+ ...["list", "inspect", "save", "run", "diff", "replay"].map((leaf) => [`workflow${leaf[0].toUpperCase()}${leaf.slice(1)}`, `loop-agent workflow ${leaf}`, ["list", "inspect", "diff"].includes(leaf) ? "read" : "mutation", "advanced"]),
63
+ ["workerFeatureReview", "agent-worker feature review", "read", "model-callable"],
64
+ ["workerFeatureRun", "agent-worker feature run", "long-running", "human-gated-required"],
65
+ ["workerFeatureVerifyFinal", "agent-worker feature verify-final", "long-running", "human-gated-required"],
66
+ ["workerFeatureDelivery", "agent-worker feature delivery", "mutation", "human-gated-required"],
67
+ ["workerFeatureCloseout", "agent-worker feature closeout", "mutation", "human-gated-required"],
68
+ ["workerTaskValidate", "agent-worker task validate", "read", "model-callable"],
69
+ ["workerTaskReconcile", "agent-worker task reconcile", "mutation", "human-gated-required"],
70
+ ["workerTaskDraftFollowup", "agent-worker task draft-followup", "mutation", "advanced"],
71
+ ["workerFeatureApproveFollowup", "agent-worker feature approve-followup", "mutation", "advanced"],
72
+ ["workerBatchPlanReady", "agent-worker batch plan-ready", "read", "model-callable"],
73
+ ["workerBatchRunReady", "agent-worker batch run-ready", "long-running", "advanced"],
74
+ ["workerPoolDoctor", "agent-worker pool doctor", "read", "model-callable"],
75
+ ["workerPoolMarkFailed", "agent-worker pool mark-failed", "mutation", "human-gated-required"],
76
+ ["workerReportMorning", "agent-worker report morning", "read", "model-callable"],
77
+ ["workerReportMetrics", "agent-worker report metrics", "read", "model-callable"],
78
+ ]
79
+ ].map(([action, cli, kind, coverage]) => officialAction(action, cli, kind, coverage));
2
80
  /** Shared constants so dag + dagSpecVersions cannot diverge. */
3
81
  const DAG_SPEC_SUPPORTED_PARSE = [1, 2, 3, 4];
4
82
  const DAG_SPEC_NEW_WRITER_DEFAULT = 4;
@@ -25,6 +103,60 @@ export function buildOperatorCapabilitiesDocument() {
25
103
  envelopeSchemaVersion: 1,
26
104
  requiredErrorCodes: ["UNSUPPORTED_SCHEMA_VERSION", "INVALID_INPUT"],
27
105
  description: "Publish action/schema/error registry for Console negotiation.",
106
+ inputParams: [],
107
+ modelCallable: "always",
108
+ humanConfirmation: "none",
109
+ },
110
+ {
111
+ action: "operationGet",
112
+ cli: "console canonical operation read model (single operation)",
113
+ kind: "read",
114
+ inputSchemaVersion: 1,
115
+ resultSchemaVersion: 1,
116
+ resultPolicy: { readOnly: true, bounded: true, redacted: true },
117
+ envelopeSchemaVersion: 1,
118
+ requiredErrorCodes: ["NOT_FOUND", "INVALID_INPUT"],
119
+ description: "Read one canonical Console operation as a bounded redacted projection.",
120
+ inputParams: [
121
+ { name: "operationId", type: "string", required: true, description: "canonical operation id" },
122
+ ],
123
+ modelCallable: "always",
124
+ humanConfirmation: "none",
125
+ },
126
+ {
127
+ action: "operationList",
128
+ cli: "console canonical operation read model (bounded list)",
129
+ kind: "read",
130
+ inputSchemaVersion: 1,
131
+ resultSchemaVersion: 1,
132
+ resultPolicy: { readOnly: true, bounded: true, redacted: true },
133
+ envelopeSchemaVersion: 1,
134
+ requiredErrorCodes: ["INVALID_INPUT"],
135
+ description: "List canonical Console operations using bounded read-only filters.",
136
+ inputParams: [
137
+ { name: "limit", type: "number", required: false, description: "maximum results (1-50, default 20)" },
138
+ { name: "state", type: "string", required: false, description: "optional operation state filter" },
139
+ { name: "action", type: "string", required: false, description: "optional exact action filter" },
140
+ ],
141
+ modelCallable: "always",
142
+ humanConfirmation: "none",
143
+ },
144
+ {
145
+ action: "operationEventSummary",
146
+ cli: "console canonical operation event store (bounded summary)",
147
+ kind: "read",
148
+ inputSchemaVersion: 1,
149
+ resultSchemaVersion: 1,
150
+ resultPolicy: { readOnly: true, bounded: true, redacted: true },
151
+ envelopeSchemaVersion: 1,
152
+ requiredErrorCodes: ["NOT_FOUND", "INVALID_INPUT"],
153
+ description: "Read a bounded redacted summary from the canonical operation event ring.",
154
+ inputParams: [
155
+ { name: "operationId", type: "string", required: true, description: "canonical operation id" },
156
+ { name: "limit", type: "number", required: false, description: "maximum newest events (1-100, default 20)" },
157
+ ],
158
+ modelCallable: "always",
159
+ humanConfirmation: "none",
28
160
  },
29
161
  {
30
162
  action: "contractShow",
@@ -35,6 +167,11 @@ export function buildOperatorCapabilitiesDocument() {
35
167
  envelopeSchemaVersion: 1,
36
168
  requiredErrorCodes: ["NOT_FOUND", "INVALID_INPUT"],
37
169
  description: "Return TaskContractStateV1 + observed hashes.",
170
+ inputParams: [
171
+ { name: "taskId", type: "string", required: true, description: "task id" },
172
+ ],
173
+ modelCallable: "always",
174
+ humanConfirmation: "none",
38
175
  },
39
176
  {
40
177
  action: "contractValidate",
@@ -45,6 +182,20 @@ export function buildOperatorCapabilitiesDocument() {
45
182
  envelopeSchemaVersion: 1,
46
183
  requiredErrorCodes: ["INVALID_INPUT", "NOT_FOUND", "PATH_OUTSIDE_REPO"],
47
184
  description: "Schema/path/traceability validation for a Draft (read-only).",
185
+ // Dispatcher reads draftJson/inputText (a JSON string staged to a file),
186
+ // NOT a `draft` object. draftJson is optional — dispatcher falls back to
187
+ // the saved draft.
188
+ inputParams: [
189
+ { name: "taskId", type: "string", required: true, description: "task id" },
190
+ {
191
+ name: "draftJson",
192
+ type: "string",
193
+ required: false,
194
+ description: "draft JSON string (optional; omit to validate the saved draft)",
195
+ },
196
+ ],
197
+ modelCallable: "always",
198
+ humanConfirmation: "none",
48
199
  },
49
200
  {
50
201
  action: "contractDiff",
@@ -55,6 +206,17 @@ export function buildOperatorCapabilitiesDocument() {
55
206
  envelopeSchemaVersion: 1,
56
207
  requiredErrorCodes: ["INVALID_INPUT", "NOT_FOUND", "PATH_OUTSIDE_REPO"],
57
208
  description: "Risk-classified diff against current managed/legacy state.",
209
+ inputParams: [
210
+ { name: "taskId", type: "string", required: true, description: "task id" },
211
+ {
212
+ name: "draftJson",
213
+ type: "string",
214
+ required: false,
215
+ description: "draft JSON string (optional; omit to diff the saved draft)",
216
+ },
217
+ ],
218
+ modelCallable: "always",
219
+ humanConfirmation: "none",
58
220
  },
59
221
  {
60
222
  action: "contractApply",
@@ -65,6 +227,14 @@ export function buildOperatorCapabilitiesDocument() {
65
227
  envelopeSchemaVersion: 1,
66
228
  requiredErrorCodes: [...COMMON_MUTATION_ERRORS, "EXTERNALLY_MODIFIED"],
67
229
  description: "Journaled apply of Draft to canonical task facts.",
230
+ inputParams: [
231
+ { name: "taskId", type: "string", required: true, description: "task id" },
232
+ { name: "assessmentId", type: "string", required: false, description: "assessment id binding (defaults to the draft's bound assessment)" },
233
+ { name: "expectedRevision", type: "string", required: false, description: "expected contract revision (defaults to live observed)" },
234
+ { name: "expectedObservedHash", type: "string", required: false, description: "expected observed hash (defaults to live observed)" },
235
+ ],
236
+ modelCallable: "always",
237
+ humanConfirmation: "conditional",
68
238
  },
69
239
  {
70
240
  action: "newTask",
@@ -75,6 +245,12 @@ export function buildOperatorCapabilitiesDocument() {
75
245
  envelopeSchemaVersion: 1,
76
246
  requiredErrorCodes: [...COMMON_MUTATION_ERRORS],
77
247
  description: "Create a new task harness skeleton via sibling CLI.",
248
+ inputParams: [
249
+ { name: "taskId", type: "string", required: true, description: "task id" },
250
+ { name: "title", type: "string", required: false, description: "task title (defaults to taskId)" },
251
+ ],
252
+ modelCallable: "always",
253
+ humanConfirmation: "none",
78
254
  },
79
255
  {
80
256
  action: "importPrd",
@@ -85,6 +261,12 @@ export function buildOperatorCapabilitiesDocument() {
85
261
  envelopeSchemaVersion: 1,
86
262
  requiredErrorCodes: [...COMMON_MUTATION_ERRORS, "PATH_OUTSIDE_REPO"],
87
263
  description: "Import immutable PRD/source reference via sibling CLI (server-staged file).",
264
+ inputParams: [
265
+ { name: "taskId", type: "string", required: true, description: "task id" },
266
+ { name: "content", type: "string", required: true, description: "PRD markdown content" },
267
+ ],
268
+ modelCallable: "always",
269
+ humanConfirmation: "none",
88
270
  },
89
271
  {
90
272
  action: "sourceInstructions",
@@ -95,6 +277,11 @@ export function buildOperatorCapabilitiesDocument() {
95
277
  envelopeSchemaVersion: 1,
96
278
  requiredErrorCodes: ["NOT_FOUND", "INVALID_INPUT"],
97
279
  description: "Read source instruction contract for a task.",
280
+ inputParams: [
281
+ { name: "taskId", type: "string", required: true, description: "task id" },
282
+ ],
283
+ modelCallable: "always",
284
+ humanConfirmation: "none",
98
285
  },
99
286
  {
100
287
  action: "contractDraftSave",
@@ -105,6 +292,17 @@ export function buildOperatorCapabilitiesDocument() {
105
292
  envelopeSchemaVersion: 1,
106
293
  requiredErrorCodes: ["INVALID_INPUT"],
107
294
  description: "Save TaskContractDraftV1 to Console application data only (not repo .harness).",
295
+ inputParams: [
296
+ { name: "taskId", type: "string", required: false, description: "task id (defaults to draft.taskId)" },
297
+ {
298
+ name: "draft",
299
+ type: "object",
300
+ required: true,
301
+ description: "TaskContractDraftV1 object",
302
+ },
303
+ ],
304
+ modelCallable: "always",
305
+ humanConfirmation: "none",
108
306
  },
109
307
  {
110
308
  action: "prepareDagConfirmation",
@@ -119,6 +317,14 @@ export function buildOperatorCapabilitiesDocument() {
119
317
  "HUMAN_CONFIRMATION_REQUIRED",
120
318
  ],
121
319
  description: "Prepare server-side DagConfirmationV1 receipt for human challenge.",
320
+ inputParams: [
321
+ { name: "taskId", type: "string", required: true, description: "task id" },
322
+ { name: "dagPath", type: "string", required: false, description: "staged DAG path (optional; resolved from the last dagRunTask result)" },
323
+ { name: "operatorAction", type: "string", required: false, description: "required official action to bind to this single-use human confirmation receipt" },
324
+ { name: "operatorActionArgs", type: "array", itemsType: "string", required: false, description: "exact trailing CLI arguments bound to the official action receipt" },
325
+ ],
326
+ modelCallable: "always",
327
+ humanConfirmation: "none",
122
328
  },
123
329
  {
124
330
  action: "confirmDagConfirmation",
@@ -136,6 +342,15 @@ export function buildOperatorCapabilitiesDocument() {
136
342
  "HUMAN_CONFIRMATION_REQUIRED",
137
343
  ],
138
344
  description: "Human challenge confirm of DagConfirmationV1 using server-derived current bindings.",
345
+ // M0-B: confirmDagConfirmation is NEVER model-callable. It IS the human
346
+ // confirmation — the model cannot self-confirm (roadmap G03). The model
347
+ // only prepares via prepareDagConfirmation; the browser mutation gate
348
+ // executes the confirm with a server-signed confirmationToken.
349
+ inputParams: [
350
+ { name: "confirmationId", type: "string", required: true, description: "confirmation id from prepareDagConfirmation" },
351
+ ],
352
+ modelCallable: "never",
353
+ humanConfirmation: "required",
139
354
  },
140
355
  {
141
356
  action: "observeLink",
@@ -146,6 +361,9 @@ export function buildOperatorCapabilitiesDocument() {
146
361
  envelopeSchemaVersion: 1,
147
362
  requiredErrorCodes: ["INVALID_INPUT"],
148
363
  description: "Build Observe deep link from stable object identity.",
364
+ inputParams: [],
365
+ modelCallable: "always",
366
+ humanConfirmation: "none",
149
367
  },
150
368
  {
151
369
  action: "inspect",
@@ -156,6 +374,9 @@ export function buildOperatorCapabilitiesDocument() {
156
374
  envelopeSchemaVersion: 1,
157
375
  requiredErrorCodes: ["INVALID_INPUT"],
158
376
  description: "Repo preflight (registry entry; envelope migration follow-up).",
377
+ inputParams: [],
378
+ modelCallable: "always",
379
+ humanConfirmation: "none",
159
380
  },
160
381
  {
161
382
  action: "doctor",
@@ -165,7 +386,23 @@ export function buildOperatorCapabilitiesDocument() {
165
386
  resultSchemaVersion: 1,
166
387
  envelopeSchemaVersion: 1,
167
388
  requiredErrorCodes: ["INVALID_INPUT", "OPERATION_NEEDS_RECONCILE"],
168
- description: "Repo doctor (registry entry; envelope migration follow-up).",
389
+ description: "Repo health doctor with machine-readable report and read-only context audit (--context).",
390
+ inputParams: [],
391
+ modelCallable: "always",
392
+ humanConfirmation: "none",
393
+ },
394
+ {
395
+ action: "statsContext",
396
+ cli: "loop-agent stats context --last 50 --json",
397
+ kind: "read",
398
+ inputSchemaVersion: 1,
399
+ resultSchemaVersion: 1,
400
+ envelopeSchemaVersion: 1,
401
+ requiredErrorCodes: ["INVALID_INPUT"],
402
+ description: "Bounded skill-resolution / node-outcome telemetry over recent DAG runs (not compliance rates).",
403
+ inputParams: [],
404
+ modelCallable: "always",
405
+ humanConfirmation: "none",
169
406
  },
170
407
  {
171
408
  action: "dagReport",
@@ -176,6 +413,11 @@ export function buildOperatorCapabilitiesDocument() {
176
413
  envelopeSchemaVersion: 1,
177
414
  requiredErrorCodes: ["NOT_FOUND", "INVALID_INPUT"],
178
415
  description: "DAG run handoff report by run id.",
416
+ inputParams: [
417
+ { name: "runId", type: "string", required: true, description: "dag run id" },
418
+ ],
419
+ modelCallable: "always",
420
+ humanConfirmation: "none",
179
421
  },
180
422
  {
181
423
  action: "status",
@@ -186,6 +428,11 @@ export function buildOperatorCapabilitiesDocument() {
186
428
  envelopeSchemaVersion: 1,
187
429
  requiredErrorCodes: ["NOT_FOUND", "INVALID_INPUT"],
188
430
  description: "Task status (registry entry).",
431
+ inputParams: [
432
+ { name: "taskId", type: "string", required: true, description: "task id" },
433
+ ],
434
+ modelCallable: "always",
435
+ humanConfirmation: "none",
189
436
  },
190
437
  {
191
438
  action: "spineCheck",
@@ -196,6 +443,11 @@ export function buildOperatorCapabilitiesDocument() {
196
443
  envelopeSchemaVersion: 1,
197
444
  requiredErrorCodes: ["NOT_FOUND", "INVALID_INPUT"],
198
445
  description: "Spine audit (registry entry).",
446
+ inputParams: [
447
+ { name: "taskId", type: "string", required: true, description: "task id" },
448
+ ],
449
+ modelCallable: "always",
450
+ humanConfirmation: "none",
199
451
  },
200
452
  {
201
453
  action: "dagRunTask",
@@ -211,6 +463,12 @@ export function buildOperatorCapabilitiesDocument() {
211
463
  "INVALID_INPUT",
212
464
  ],
213
465
  description: "Generate DagSpec v4 with taskContractBinding (managed required).",
466
+ inputParams: [
467
+ { name: "taskId", type: "string", required: true, description: "task id to run as a DAG" },
468
+ { name: "profile", type: "string", required: false, description: "DAG profile (defaults to auto)" },
469
+ ],
470
+ modelCallable: "always",
471
+ humanConfirmation: "none",
214
472
  },
215
473
  {
216
474
  action: "dagValidate",
@@ -221,6 +479,12 @@ export function buildOperatorCapabilitiesDocument() {
221
479
  envelopeSchemaVersion: 1,
222
480
  requiredErrorCodes: ["INVALID_INPUT", "BINDING_DRIFT"],
223
481
  description: "Validate DAG including taskContractBinding drift checks.",
482
+ inputParams: [
483
+ { name: "dagPath", type: "string", required: true, description: "DAG file path to validate" },
484
+ { name: "taskId", type: "string", required: false, description: "spine task id (optional, for strict-governance spine check)" },
485
+ ],
486
+ modelCallable: "always",
487
+ humanConfirmation: "none",
224
488
  },
225
489
  {
226
490
  action: "runDag",
@@ -235,6 +499,13 @@ export function buildOperatorCapabilitiesDocument() {
235
499
  "INVALID_INPUT",
236
500
  ],
237
501
  description: "Execute reviewed DAG; revalidate binding before writer start.",
502
+ inputParams: [
503
+ { name: "confirmationId", type: "string", required: true, description: "confirmation id (from prepareDagConfirmation) — raw dag path is never accepted from the model" },
504
+ ],
505
+ // prepare-only: the model can invoke runDag but it MUST carry a
506
+ // confirmationId that was consumed by a human-origin confirm (M0-B).
507
+ modelCallable: "prepare-only",
508
+ humanConfirmation: "required",
238
509
  },
239
510
  {
240
511
  action: "dagRerunPlan",
@@ -245,6 +516,12 @@ export function buildOperatorCapabilitiesDocument() {
245
516
  envelopeSchemaVersion: 1,
246
517
  requiredErrorCodes: ["INVALID_INPUT", "NOT_FOUND"],
247
518
  description: "Read-only subgraph rerun plan for confirmation (no mutation).",
519
+ inputParams: [
520
+ { name: "runId", type: "string", required: true, description: "dag run id" },
521
+ { name: "fromNode", type: "string", required: true, description: "node id to rerun from" },
522
+ ],
523
+ modelCallable: "always",
524
+ humanConfirmation: "none",
248
525
  },
249
526
  {
250
527
  action: "dagRerun",
@@ -259,6 +536,30 @@ export function buildOperatorCapabilitiesDocument() {
259
536
  "INVALID_INPUT",
260
537
  ],
261
538
  description: "Execute continuation run from effective node with confirmed plan hash.",
539
+ inputParams: [
540
+ { name: "runId", type: "string", required: true, description: "dag run id" },
541
+ { name: "fromNode", type: "string", required: true, description: "node id to rerun from" },
542
+ { name: "planHash", type: "string", required: true, description: "rerun plan hash" },
543
+ { name: "reason", type: "string", required: true, description: "rerun reason" },
544
+ ],
545
+ modelCallable: "prepare-only",
546
+ humanConfirmation: "required",
547
+ },
548
+ {
549
+ action: "prepareMutationGate",
550
+ cli: "console prepare-mutation-gate",
551
+ kind: "mutation",
552
+ inputSchemaVersion: 1,
553
+ resultSchemaVersion: 1,
554
+ envelopeSchemaVersion: 1,
555
+ requiredErrorCodes: ["INVALID_INPUT", "NOT_FOUND"],
556
+ description: "Prepare a one-shot Human Gate receipt for standaloneTaskRerun / workerTaskRetry. Model may prepare; only the browser mutation gate may consume.",
557
+ inputParams: [
558
+ { name: "action", type: "string", required: true, description: "target action: standaloneTaskRerun | workerTaskRetry" },
559
+ { name: "actionParams", type: "object", required: true, description: "params that will be bound into the receipt hash" },
560
+ ],
561
+ modelCallable: "always",
562
+ humanConfirmation: "none",
262
563
  },
263
564
  {
264
565
  action: "standaloneTaskRerun",
@@ -267,8 +568,16 @@ export function buildOperatorCapabilitiesDocument() {
267
568
  inputSchemaVersion: 1,
268
569
  resultSchemaVersion: 1,
269
570
  envelopeSchemaVersion: 1,
270
- requiredErrorCodes: [...COMMON_MUTATION_ERRORS, "INVALID_INPUT"],
571
+ requiredErrorCodes: [...COMMON_MUTATION_ERRORS, "INVALID_INPUT", "HUMAN_CONFIRMATION_REQUIRED"],
271
572
  description: "Full standalone task regenerate → validate → execute with parent lineage.",
573
+ inputParams: [
574
+ { name: "runId", type: "string", required: true, description: "dag run id" },
575
+ { name: "reason", type: "string", required: true, description: "rerun reason" },
576
+ { name: "confirmationId", type: "string", required: true, description: "mutation-gate receipt id from prepareMutationGate" },
577
+ { name: "humanGateToken", type: "object", required: true, description: "server-signed human-gate token from prepareMutationGate" },
578
+ ],
579
+ modelCallable: "prepare-only",
580
+ humanConfirmation: "required",
272
581
  },
273
582
  {
274
583
  action: "workerTaskRetry",
@@ -277,9 +586,19 @@ export function buildOperatorCapabilitiesDocument() {
277
586
  inputSchemaVersion: 1,
278
587
  resultSchemaVersion: 1,
279
588
  envelopeSchemaVersion: 1,
280
- requiredErrorCodes: [...COMMON_MUTATION_ERRORS, "INVALID_INPUT"],
589
+ requiredErrorCodes: [...COMMON_MUTATION_ERRORS, "INVALID_INPUT", "HUMAN_CONFIRMATION_REQUIRED"],
281
590
  description: "Requeue failed Task Pool task (Failed → Ready) via in-package pool store.",
591
+ inputParams: [
592
+ { name: "taskId", type: "string", required: true, description: "task id" },
593
+ { name: "featureId", type: "string", required: false, description: "feature id (canonical retry carries Feature identity; passed to the CLI as --feature-id when present)" },
594
+ { name: "reason", type: "string", required: true, description: "retry reason" },
595
+ { name: "confirmationId", type: "string", required: true, description: "mutation-gate receipt id from prepareMutationGate" },
596
+ { name: "humanGateToken", type: "object", required: true, description: "server-signed human-gate token from prepareMutationGate" },
597
+ ],
598
+ modelCallable: "prepare-only",
599
+ humanConfirmation: "required",
282
600
  },
601
+ ...OFFICIAL_ACTIONS,
283
602
  ];
284
603
  return {
285
604
  schemaVersion: 1,
@@ -307,3 +626,167 @@ export function buildOperatorCapabilitiesDocument() {
307
626
  actions,
308
627
  };
309
628
  }
629
+ export const OPERATOR_COMMAND_COVERAGE = Object.freeze([
630
+ { command: "loop-agent inspect", coverage: "model-callable", action: "inspect", source: "loop-agent" },
631
+ { command: "loop-agent doctor", coverage: "model-callable", action: "doctor", source: "loop-agent" },
632
+ { command: "loop-agent new-task", coverage: "model-callable", action: "newTask", source: "loop-agent" },
633
+ { command: "loop-agent import-prd", coverage: "model-callable", action: "importPrd", source: "loop-agent" },
634
+ { command: "loop-agent status", coverage: "model-callable", action: "status", source: "loop-agent" },
635
+ { command: "loop-agent promote-run", coverage: "model-callable", action: "promoteRun", source: "loop-agent" },
636
+ { command: "loop-agent pi-reuse-benchmark", coverage: "advanced", action: "piReuseBenchmark", source: "loop-agent" },
637
+ { command: "loop-agent loop-benchmark", coverage: "advanced", action: "loopBenchmark", source: "loop-agent" },
638
+ { command: "loop-agent run-dag", coverage: "human-gated-required", action: "runDag", source: "loop-agent" },
639
+ { command: "loop-agent cursor-prompt", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
640
+ { command: "loop-agent pi-prompt", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
641
+ { command: "loop-agent delegate", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
642
+ { command: "loop-agent harvest", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
643
+ { command: "loop-agent goal", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
644
+ { command: "loop-agent docs audit", coverage: "model-callable", action: "docsAudit", source: "loop-agent" },
645
+ { command: "loop-agent docs archive", coverage: "advanced", action: "docsArchive", source: "loop-agent" },
646
+ { command: "loop-agent init instructions", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
647
+ { command: "loop-agent init doctor", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
648
+ { command: "loop-agent init check-update", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
649
+ { command: "loop-agent init update", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
650
+ { command: "loop-agent init reconcile", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
651
+ { command: "loop-agent examples list", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
652
+ { command: "loop-agent examples show", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
653
+ { command: "loop-agent examples copy", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
654
+ { command: "loop-agent eval replay", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
655
+ { command: "loop-agent eval report", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
656
+ { command: "loop-agent eval candidate", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
657
+ { command: "loop-agent eval alias", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
658
+ { command: "loop-agent eval promote", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
659
+ { command: "loop-agent eval rollback", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
660
+ { command: "loop-agent eval corpus", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
661
+ { command: "loop-agent eval context-policy", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
662
+ { command: "loop-agent eval budget", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
663
+ { command: "loop-agent eval private-verifier", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
664
+ { command: "loop-agent eval campaign", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
665
+ { command: "loop-agent eval experiment", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
666
+ { command: "loop-agent eval propose", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
667
+ { command: "loop-agent eval outer-loop", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
668
+ { command: "loop-agent eval ignition", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
669
+ { command: "loop-agent closeout task", coverage: "model-callable", action: "closeoutTask", source: "loop-agent" },
670
+ { command: "loop-agent plan list", coverage: "model-callable", action: "planList", source: "loop-agent" },
671
+ { command: "loop-agent plan create", coverage: "model-callable", action: "planCreate", source: "loop-agent" },
672
+ { command: "loop-agent plan complete", coverage: "model-callable", action: "planComplete", source: "loop-agent" },
673
+ { command: "loop-agent plan check", coverage: "model-callable", action: "planCheck", source: "loop-agent" },
674
+ { command: "loop-agent spine audit", coverage: "model-callable", action: "spineCheck", source: "loop-agent" },
675
+ { command: "loop-agent handoff check", coverage: "model-callable", action: "handoffCheck", source: "loop-agent" },
676
+ { command: "loop-agent handoff coverage", coverage: "model-callable", action: "handoffCoverage", source: "loop-agent" },
677
+ { command: "loop-agent coverage report", coverage: "model-callable", action: "coverageReport", source: "loop-agent" },
678
+ { command: "loop-agent reference index", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
679
+ { command: "loop-agent study init", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
680
+ { command: "loop-agent worktree create", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
681
+ { command: "loop-agent worktree list", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
682
+ { command: "loop-agent worktree remove", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
683
+ { command: "loop-agent knowledge curate", coverage: "model-callable", action: "knowledgeCurate", source: "loop-agent" },
684
+ { command: "loop-agent knowledge query", coverage: "model-callable", action: "knowledgeQuery", source: "loop-agent" },
685
+ { command: "loop-agent knowledge graph-init", coverage: "advanced", action: "knowledgeGraphInit", source: "loop-agent" },
686
+ { command: "loop-agent knowledge graph-materialize", coverage: "advanced", action: "knowledgeGraphMaterialize", source: "loop-agent" },
687
+ { command: "loop-agent knowledge graph-promote", coverage: "advanced", action: "knowledgeGraphPromote", source: "loop-agent" },
688
+ { command: "loop-agent knowledge graph-incremental-prepare", coverage: "advanced", action: "knowledgeGraphIncrementalPrepare", source: "loop-agent" },
689
+ { command: "loop-agent dag init-hybrid", coverage: "advanced", action: "dagInitHybrid", source: "loop-agent" },
690
+ { command: "loop-agent dag run-task", coverage: "model-callable", action: "dagRunTask", source: "loop-agent" },
691
+ { command: "loop-agent dag validate", coverage: "model-callable", action: "dagValidate", source: "loop-agent" },
692
+ { command: "loop-agent dag workflow-plan", coverage: "advanced", action: "dagWorkflowPlan", source: "loop-agent" },
693
+ { command: "loop-agent dag workflow-validate", coverage: "advanced", action: "dagWorkflowValidate", source: "loop-agent" },
694
+ { command: "loop-agent dag workflow-compile", coverage: "advanced", action: "dagWorkflowCompile", source: "loop-agent" },
695
+ { command: "loop-agent dag approve", coverage: "human-gated-required", action: "dagApprove", source: "loop-agent" },
696
+ { command: "loop-agent dag reject", coverage: "human-gated-required", action: "dagReject", source: "loop-agent" },
697
+ { command: "loop-agent dag resume", coverage: "human-gated-required", action: "dagResume", source: "loop-agent" },
698
+ { command: "loop-agent dag status", coverage: "model-callable", action: "dagStatus", source: "loop-agent" },
699
+ { command: "loop-agent dag doctor", coverage: "model-callable", action: "dagDoctor", source: "loop-agent" },
700
+ { command: "loop-agent dag report", coverage: "model-callable", action: "dagReport", source: "loop-agent" },
701
+ { command: "loop-agent dag closeout-draft", coverage: "model-callable", action: "dagCloseoutDraft", source: "loop-agent" },
702
+ { command: "loop-agent dag reconcile-run", coverage: "human-gated-required", action: "dagReconcileRun", source: "loop-agent" },
703
+ { command: "loop-agent dag rerun", coverage: "human-gated-required", action: "dagRerun", source: "loop-agent" },
704
+ { command: "loop-agent dag rerun-task", coverage: "human-gated-required", action: "standaloneTaskRerun", source: "loop-agent" },
705
+ { command: "loop-agent dag reconcile-tasks", coverage: "human-gated-required", action: "dagReconcileTasks", source: "loop-agent" },
706
+ { command: "loop-agent dag final-verification", coverage: "human-gated-required", action: "dagFinalVerification", source: "loop-agent" },
707
+ { command: "loop-agent workflow list", coverage: "advanced", action: "workflowList", source: "loop-agent" },
708
+ { command: "loop-agent workflow inspect", coverage: "advanced", action: "workflowInspect", source: "loop-agent" },
709
+ { command: "loop-agent workflow save", coverage: "advanced", action: "workflowSave", source: "loop-agent" },
710
+ { command: "loop-agent workflow run", coverage: "advanced", action: "workflowRun", source: "loop-agent" },
711
+ { command: "loop-agent workflow diff", coverage: "advanced", action: "workflowDiff", source: "loop-agent" },
712
+ { command: "loop-agent workflow replay", coverage: "advanced", action: "workflowReplay", source: "loop-agent" },
713
+ { command: "loop-agent loop init", coverage: "advanced", action: "loopInit", source: "loop-agent" },
714
+ { command: "loop-agent loop status", coverage: "advanced", action: "loopStatus", source: "loop-agent" },
715
+ { command: "loop-agent loop run", coverage: "advanced", action: "loopRun", source: "loop-agent" },
716
+ { command: "loop-agent loop record-round", coverage: "advanced", action: "loopRecordRound", source: "loop-agent" },
717
+ { command: "loop-agent loop add-signal", coverage: "advanced", action: "loopAddSignal", source: "loop-agent" },
718
+ { command: "loop-agent loop closeout", coverage: "advanced", action: "loopCloseout", source: "loop-agent" },
719
+ { command: "loop-agent dag decision inspect", coverage: "model-callable", action: "dagDecisionInspect", source: "loop-agent" },
720
+ { command: "loop-agent dag decision validate", coverage: "model-callable", action: "dagDecisionValidate", source: "loop-agent" },
721
+ { command: "loop-agent task contract show", coverage: "model-callable", action: "contractShow", source: "loop-agent" },
722
+ { command: "loop-agent task contract validate", coverage: "model-callable", action: "contractValidate", source: "loop-agent" },
723
+ { command: "loop-agent task contract diff", coverage: "model-callable", action: "contractDiff", source: "loop-agent" },
724
+ { command: "loop-agent task contract apply", coverage: "human-gated-conditional", action: "contractApply", source: "loop-agent" },
725
+ { command: "loop-agent task contract adopt", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Managed recovery face remains outside Chat in M5." },
726
+ { command: "loop-agent task contract doctor", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Managed recovery face remains outside Chat in M5." },
727
+ { command: "loop-agent task contract recover", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Managed recovery face remains outside Chat in M5." },
728
+ { command: "loop-agent operator capabilities", coverage: "model-callable", action: "operatorCapabilities", source: "loop-agent" },
729
+ { command: "loop-agent instructions source", coverage: "model-callable", action: "sourceInstructions", source: "loop-agent" },
730
+ { command: "loop-agent instructions dag-draft", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
731
+ { command: "loop-agent instructions task-artifacts", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
732
+ { command: "loop-agent instructions promotion", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
733
+ { command: "loop-agent instructions closeout", coverage: "excluded", action: null, source: "loop-agent", exclusionReason: "Not exposed to Operator Chat in M5." },
734
+ { command: "loop-agent stats", coverage: "model-callable", action: "stats", source: "loop-agent" },
735
+ { command: "loop-agent stats context", coverage: "model-callable", action: "statsContext", source: "loop-agent" },
736
+ { command: "agent-worker feature review", coverage: "model-callable", action: "workerFeatureReview", source: "agent-worker" },
737
+ { command: "agent-worker feature run", coverage: "human-gated-required", action: "workerFeatureRun", source: "agent-worker" },
738
+ { command: "agent-worker feature verify-final", coverage: "human-gated-required", action: "workerFeatureVerifyFinal", source: "agent-worker" },
739
+ { command: "agent-worker feature delivery", coverage: "human-gated-required", action: "workerFeatureDelivery", source: "agent-worker" },
740
+ { command: "agent-worker feature closeout", coverage: "human-gated-required", action: "workerFeatureCloseout", source: "agent-worker" },
741
+ { command: "agent-worker feature approve-followup", coverage: "advanced", action: "workerFeatureApproveFollowup", source: "agent-worker" },
742
+ { command: "agent-worker task validate", coverage: "model-callable", action: "workerTaskValidate", source: "agent-worker" },
743
+ { command: "agent-worker task explain-profile", coverage: "excluded", action: null, source: "agent-worker", exclusionReason: "Not exposed to Operator Chat in M5." },
744
+ { command: "agent-worker task validate-feature", coverage: "excluded", action: null, source: "agent-worker", exclusionReason: "Not exposed to Operator Chat in M5." },
745
+ { command: "agent-worker task reconcile", coverage: "human-gated-required", action: "workerTaskReconcile", source: "agent-worker" },
746
+ { command: "agent-worker task retry", coverage: "human-gated-required", action: "workerTaskRetry", source: "agent-worker" },
747
+ { command: "agent-worker task draft-followup", coverage: "advanced", action: "workerTaskDraftFollowup", source: "agent-worker" },
748
+ { command: "agent-worker batch plan-ready", coverage: "model-callable", action: "workerBatchPlanReady", source: "agent-worker" },
749
+ { command: "agent-worker batch run-ready", coverage: "advanced", action: "workerBatchRunReady", source: "agent-worker" },
750
+ { command: "agent-worker pool mark-failed", coverage: "human-gated-required", action: "workerPoolMarkFailed", source: "agent-worker" },
751
+ { command: "agent-worker pool doctor", coverage: "model-callable", action: "workerPoolDoctor", source: "agent-worker" },
752
+ { command: "agent-worker pool migrate-state", coverage: "excluded", action: null, source: "agent-worker", exclusionReason: "Not exposed to Operator Chat in M5." },
753
+ { command: "agent-worker feature git advance-checkpoint", coverage: "excluded", action: null, source: "agent-worker", exclusionReason: "Not exposed to Operator Chat in M5." },
754
+ { command: "agent-worker report morning", coverage: "model-callable", action: "workerReportMorning", source: "agent-worker" },
755
+ { command: "agent-worker report metrics", coverage: "model-callable", action: "workerReportMetrics", source: "agent-worker" },
756
+ { command: "agent-worker observe serve", coverage: "excluded", action: null, source: "agent-worker", exclusionReason: "Not exposed to Operator Chat in M5." },
757
+ { command: "agent-worker observe snapshot", coverage: "excluded", action: null, source: "agent-worker", exclusionReason: "Not exposed to Operator Chat in M5." },
758
+ { command: "agent-worker console serve", coverage: "excluded", action: null, source: "agent-worker", exclusionReason: "Not exposed to Operator Chat in M5." },
759
+ { command: "agent-worker console doctor", coverage: "excluded", action: null, source: "agent-worker", exclusionReason: "Not exposed to Operator Chat in M5." },
760
+ ]);
761
+ export function assertCoverageManifestConsistent() {
762
+ const actions = new Map(buildOperatorCapabilitiesDocument().actions.map((entry) => [entry.action, entry]));
763
+ const seen = new Set();
764
+ for (const entry of OPERATOR_COMMAND_COVERAGE) {
765
+ if (seen.has(entry.command))
766
+ throw new Error(`duplicate operator command coverage: ${entry.command}`);
767
+ seen.add(entry.command);
768
+ if (entry.action === null) {
769
+ if (entry.coverage !== "excluded")
770
+ throw new Error(`non-excluded command has no action: ${entry.command}`);
771
+ continue;
772
+ }
773
+ const capability = actions.get(entry.action);
774
+ if (!capability)
775
+ throw new Error(`coverage references unknown action: ${entry.action}`);
776
+ if (entry.coverage === "excluded" && capability.modelCallable !== "never")
777
+ throw new Error(`excluded action is model-callable: ${entry.action}`);
778
+ if (entry.coverage === "model-callable" && (capability.modelCallable !== "always" || capability.humanConfirmation !== "none"))
779
+ throw new Error(`invalid model-callable classification: ${entry.action}`);
780
+ if (entry.coverage === "human-gated-conditional" && (capability.modelCallable !== "always" || capability.humanConfirmation !== "conditional"))
781
+ throw new Error(`invalid conditional gate classification: ${entry.action}`);
782
+ if (entry.coverage === "human-gated-required" && (capability.modelCallable !== "prepare-only" || capability.humanConfirmation !== "required"))
783
+ throw new Error(`invalid required gate classification: ${entry.action}`);
784
+ if (entry.coverage === "advanced") {
785
+ const expected = capability.kind === "read" ? "always" : "never";
786
+ if (capability.modelCallable !== expected) {
787
+ throw new Error(`invalid advanced classification: ${entry.action} (expected modelCallable=${expected} for kind=${capability.kind})`);
788
+ }
789
+ }
790
+ }
791
+ }
792
+ assertCoverageManifestConsistent();