@navels/neal 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +527 -0
- package/SECURITY.md +91 -0
- package/config.yml +104 -0
- package/dist/neal/activity-footer.js +177 -0
- package/dist/neal/activity-reporting.js +1 -0
- package/dist/neal/adjudicator/artifacts.js +58 -0
- package/dist/neal/adjudicator/blocked-adjudicator.js +223 -0
- package/dist/neal/adjudicator/contracts.js +139 -0
- package/dist/neal/adjudicator/execute.js +611 -0
- package/dist/neal/adjudicator/final-completion.js +104 -0
- package/dist/neal/adjudicator/planning.js +145 -0
- package/dist/neal/adjudicator/specs.js +453 -0
- package/dist/neal/agents/prompts.js +120 -0
- package/dist/neal/agents/rounds.js +706 -0
- package/dist/neal/agents/schemas.js +832 -0
- package/dist/neal/agents/structured-coder.js +82 -0
- package/dist/neal/agents/structured-json.js +528 -0
- package/dist/neal/agents.js +4 -0
- package/dist/neal/atomic-write.js +18 -0
- package/dist/neal/blocked-guidance.js +406 -0
- package/dist/neal/cli.js +471 -0
- package/dist/neal/commands/check.js +401 -0
- package/dist/neal/commands/compat.js +807 -0
- package/dist/neal/commands/interactive-activity.js +57 -0
- package/dist/neal/commands/new-run.js +79 -0
- package/dist/neal/commands/plan-and-execute.js +44 -0
- package/dist/neal/commands/recovery-guidance.js +217 -0
- package/dist/neal/commands/resume-run.js +395 -0
- package/dist/neal/commands/review.js +21 -0
- package/dist/neal/commands/runtime.js +557 -0
- package/dist/neal/commands/setup.js +596 -0
- package/dist/neal/commands/squash.js +113 -0
- package/dist/neal/commands/status.js +33 -0
- package/dist/neal/commands/writer-exit-codes.js +42 -0
- package/dist/neal/commit-message.js +17 -0
- package/dist/neal/config.js +432 -0
- package/dist/neal/context/artifacts.js +140 -0
- package/dist/neal/context/context.js +324 -0
- package/dist/neal/context/inline-review-context.js +131 -0
- package/dist/neal/context/reviewer-context.js +166 -0
- package/dist/neal/context/shared.js +117 -0
- package/dist/neal/context/types.js +1 -0
- package/dist/neal/diagnostic.js +208 -0
- package/dist/neal/execute-finalization.js +5 -0
- package/dist/neal/final-completion-review.js +188 -0
- package/dist/neal/final-completion.js +229 -0
- package/dist/neal/git.js +339 -0
- package/dist/neal/index.js +135 -0
- package/dist/neal/interactive-controls.js +85 -0
- package/dist/neal/logger.js +102 -0
- package/dist/neal/manual-gates.js +121 -0
- package/dist/neal/orchestrator/artifacts.js +70 -0
- package/dist/neal/orchestrator/completion.js +531 -0
- package/dist/neal/orchestrator/failures.js +31 -0
- package/dist/neal/orchestrator/notifications.js +175 -0
- package/dist/neal/orchestrator/phases/coder.js +516 -0
- package/dist/neal/orchestrator/phases/planning.js +540 -0
- package/dist/neal/orchestrator/phases/recovery.js +798 -0
- package/dist/neal/orchestrator/phases/review.js +136 -0
- package/dist/neal/orchestrator/phases/shared.js +279 -0
- package/dist/neal/orchestrator/run-loop.js +113 -0
- package/dist/neal/orchestrator/split-plan.js +235 -0
- package/dist/neal/orchestrator/transitions.js +309 -0
- package/dist/neal/orchestrator.js +215 -0
- package/dist/neal/phase-display.js +27 -0
- package/dist/neal/plan-doc.js +154 -0
- package/dist/neal/plan-queue.js +1092 -0
- package/dist/neal/plan-refinement.js +39 -0
- package/dist/neal/plan-validation.js +525 -0
- package/dist/neal/progress.js +237 -0
- package/dist/neal/prompts/assert-builder.js +13 -0
- package/dist/neal/prompts/execute.js +290 -0
- package/dist/neal/prompts/guidance.js +70 -0
- package/dist/neal/prompts/planning.js +313 -0
- package/dist/neal/prompts/review-doctrine.js +142 -0
- package/dist/neal/prompts/shared.js +101 -0
- package/dist/neal/prompts/specialized.js +212 -0
- package/dist/neal/prompts/specs.js +572 -0
- package/dist/neal/providers/anthropic-claude.js +1599 -0
- package/dist/neal/providers/detection.js +139 -0
- package/dist/neal/providers/generic-agentic-tools.js +586 -0
- package/dist/neal/providers/generic-agentic.js +1238 -0
- package/dist/neal/providers/liveness.js +151 -0
- package/dist/neal/providers/openai-codex.js +1014 -0
- package/dist/neal/providers/openai-compatible.js +654 -0
- package/dist/neal/providers/registry.js +389 -0
- package/dist/neal/providers/telemetry.js +208 -0
- package/dist/neal/providers/types.js +21 -0
- package/dist/neal/recovery-artifacts.js +50 -0
- package/dist/neal/resume-decision.js +220 -0
- package/dist/neal/resume-planner.js +265 -0
- package/dist/neal/retrospective.js +391 -0
- package/dist/neal/review-debt.js +18 -0
- package/dist/neal/review-findings/artifacts.js +173 -0
- package/dist/neal/review-findings/prompts.js +172 -0
- package/dist/neal/review-findings/provider.js +330 -0
- package/dist/neal/review-findings/run.js +373 -0
- package/dist/neal/review-findings/types.js +1 -0
- package/dist/neal/review-mode.js +67 -0
- package/dist/neal/review.js +137 -0
- package/dist/neal/run-lock.js +334 -0
- package/dist/neal/run-metrics.js +355 -0
- package/dist/neal/run-narrative-types.js +1 -0
- package/dist/neal/run-narrative.js +1374 -0
- package/dist/neal/run-registry.js +218 -0
- package/dist/neal/run-status.js +25 -0
- package/dist/neal/scopes.js +451 -0
- package/dist/neal/sensitive-text.js +8 -0
- package/dist/neal/squash-message.js +379 -0
- package/dist/neal/squash.js +591 -0
- package/dist/neal/state-invariants.js +496 -0
- package/dist/neal/state-views.js +344 -0
- package/dist/neal/state.js +887 -0
- package/dist/neal/status-footer.js +258 -0
- package/dist/neal/status.js +1260 -0
- package/dist/neal/storage-paths.js +57 -0
- package/dist/neal/support.js +58 -0
- package/dist/neal/terminal-narrator.js +435 -0
- package/dist/neal/types.js +1 -0
- package/dist/neal/verification-events.js +81 -0
- package/dist/neal/version.js +37 -0
- package/dist/neal/worktree-status.js +137 -0
- package/dist/notifier.js +44 -0
- package/docs/ADJUDICATOR_INVENTORY.md +310 -0
- package/docs/PROMPT_SPECS.md +266 -0
- package/docs/README.md +22 -0
- package/docs/architecture.md +113 -0
- package/docs/assets/neal-execution-flow.png +0 -0
- package/docs/automation.md +65 -0
- package/docs/comparison.md +105 -0
- package/docs/compat.md +269 -0
- package/docs/compatible-models.md +135 -0
- package/docs/demo.md +55 -0
- package/docs/maintenance.md +64 -0
- package/docs/plan-format.md +213 -0
- package/docs/providers.md +751 -0
- package/docs/release.md +147 -0
- package/docs/state-machine.md +266 -0
- package/docs/storage.md +207 -0
- package/docs/troubleshooting.md +152 -0
- package/examples/compat/add-edit-verify/PLAN.md +29 -0
- package/examples/compat/add-edit-verify/broken.diff +8 -0
- package/examples/compat/add-edit-verify/good.diff +8 -0
- package/examples/compat/add-edit-verify/package.json +5 -0
- package/examples/compat/add-edit-verify/src/add.js +2 -0
- package/examples/compat/add-edit-verify/test/add.test.js +9 -0
- package/examples/compat/is-even-add-test/PLAN.md +30 -0
- package/examples/compat/is-even-add-test/broken.diff +11 -0
- package/examples/compat/is-even-add-test/good.diff +11 -0
- package/examples/compat/is-even-add-test/package.json +5 -0
- package/examples/compat/is-even-add-test/src/is-even.js +3 -0
- package/examples/compat/is-even-add-test/test/is-even.test.js +9 -0
- package/examples/compat/manifest.json +60 -0
- package/examples/compat/plan-greeting/ISSUE.md +25 -0
- package/examples/compat/plan-greeting/package.json +5 -0
- package/examples/compat/plan-greeting/src/greet.js +2 -0
- package/examples/compat/plan-greeting/test/greet.test.js +8 -0
- package/examples/compat/reverse-grep-edit/PLAN.md +32 -0
- package/examples/compat/reverse-grep-edit/broken.diff +12 -0
- package/examples/compat/reverse-grep-edit/good.diff +12 -0
- package/examples/compat/reverse-grep-edit/package.json +5 -0
- package/examples/compat/reverse-grep-edit/src/strings.js +10 -0
- package/examples/compat/reverse-grep-edit/test/strings.test.js +15 -0
- package/examples/issue-triage-js/PLAN.md +83 -0
- package/examples/issue-triage-js/README.md +76 -0
- package/examples/issue-triage-js/package.json +9 -0
- package/examples/issue-triage-js/src/issue-triage.js +87 -0
- package/examples/issue-triage-js/test/issue-triage.test.js +107 -0
- package/package.json +70 -0
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
import { getPromptSpec } from '../prompts/specs.js';
|
|
2
|
+
import { validateAdjudicatedLoopContract } from './contracts.js';
|
|
3
|
+
const FAMILY_RUNTIME_TRANSITION_SIGNALS = {
|
|
4
|
+
plan_review: ['accept_plan', 'accept_derived_plan', 'request_revision', 'optional_revision', 'block_for_operator'],
|
|
5
|
+
execute_review: ['accept_scope', 'request_revision', 'optional_revision', 'block_for_operator', 'replace_plan', 'advance_parent'],
|
|
6
|
+
final_completion: ['accept_complete', 'continue_execution', 'block_for_operator'],
|
|
7
|
+
};
|
|
8
|
+
const SPEC_RUNTIME_TRANSITION_SIGNALS = {
|
|
9
|
+
plan_review: ['accept_plan', 'request_revision', 'optional_revision', 'block_for_operator'],
|
|
10
|
+
derived_plan_review: ['accept_derived_plan', 'request_revision', 'optional_revision', 'block_for_operator'],
|
|
11
|
+
execute_review: ['accept_scope', 'request_revision', 'optional_revision', 'block_for_operator', 'replace_plan', 'advance_parent'],
|
|
12
|
+
final_completion_review: ['accept_complete', 'continue_execution', 'block_for_operator'],
|
|
13
|
+
};
|
|
14
|
+
export const ADJUDICATION_SPECS = [
|
|
15
|
+
{
|
|
16
|
+
id: 'plan_review',
|
|
17
|
+
family: 'plan_review',
|
|
18
|
+
status: 'in_scope_v1',
|
|
19
|
+
roundLabel: 'plan-review',
|
|
20
|
+
currentEntrypoints: ['runCoderPlanRound', 'runPlanReviewerRound', 'runCoderPlanResponseRound(reviewMode=plan)'],
|
|
21
|
+
artifactUnderReview: 'Top-level Neal-executable plan markdown.',
|
|
22
|
+
contextAssembly: {
|
|
23
|
+
owner: 'orchestrator',
|
|
24
|
+
inputs: ['planDoc', 'reviewMarkdownPath', 'openFindings', 'repositoryState'],
|
|
25
|
+
notes: 'Ordinary plan review keeps execution-shape validation and review history in the existing plan-review artifacts.',
|
|
26
|
+
},
|
|
27
|
+
coder: {
|
|
28
|
+
primary: {
|
|
29
|
+
prompt: {
|
|
30
|
+
role: 'coder',
|
|
31
|
+
promptSpecId: 'plan_author',
|
|
32
|
+
variantKind: 'primary',
|
|
33
|
+
exportName: 'buildPlanningPrompt',
|
|
34
|
+
},
|
|
35
|
+
output: {
|
|
36
|
+
protocol: 'structured_json',
|
|
37
|
+
schemaBuilder: 'buildCoderPlanSchema',
|
|
38
|
+
parser: 'validateCoderPlanPayload',
|
|
39
|
+
providerSurface: 'coder_structured_schema',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
response: {
|
|
43
|
+
prompt: {
|
|
44
|
+
role: 'coder',
|
|
45
|
+
promptSpecId: 'plan_author',
|
|
46
|
+
variantKind: 'response',
|
|
47
|
+
exportName: 'buildCoderPlanResponsePrompt',
|
|
48
|
+
},
|
|
49
|
+
output: {
|
|
50
|
+
protocol: 'structured_json',
|
|
51
|
+
schemaBuilder: 'buildCoderPlanResponseSchema',
|
|
52
|
+
parser: 'validateCoderPlanResponsePayload',
|
|
53
|
+
providerSurface: 'coder_structured_schema',
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
reviewer: {
|
|
58
|
+
prompt: {
|
|
59
|
+
role: 'reviewer',
|
|
60
|
+
promptSpecId: 'plan_reviewer',
|
|
61
|
+
variantKind: 'primary',
|
|
62
|
+
exportName: 'buildPlanReviewerPrompt',
|
|
63
|
+
},
|
|
64
|
+
output: {
|
|
65
|
+
protocol: 'structured_json',
|
|
66
|
+
schemaBuilder: 'buildPlanReviewerSchema',
|
|
67
|
+
parser: 'PlanReviewerPayload',
|
|
68
|
+
providerSurface: 'structured_advisor_schema',
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
convergence: {
|
|
72
|
+
settledWhen: 'Reviewer returns no open findings and the plan remains structurally valid.',
|
|
73
|
+
reviseWhen: 'Open findings route back to a required or optional coder plan-response round.',
|
|
74
|
+
blockedWhen: 'Coder returns structured action=blocked instead of a revised plan; round code still renders compatibility markers for downstream state.',
|
|
75
|
+
},
|
|
76
|
+
transitionSignals: ['accept_plan', 'request_revision', 'optional_revision', 'block_for_operator'],
|
|
77
|
+
loopContract: {
|
|
78
|
+
loopKind: 'plan',
|
|
79
|
+
sideEffectPolicy: 'plan_doc_only',
|
|
80
|
+
allowedOutcomes: ['accepted', 'revise', 'blocked', 'failed', 'cap_reached'],
|
|
81
|
+
terminalOutcomes: ['accepted', 'blocked', 'failed', 'cap_reached'],
|
|
82
|
+
roundCap: {
|
|
83
|
+
source: 'state.maxRounds',
|
|
84
|
+
appliesTo: 'review_iterations',
|
|
85
|
+
outcomeWhenReached: 'cap_reached',
|
|
86
|
+
notes: 'Plan refinement stops at the configured review-round cap and routes to operator blocking instead of accepting an unreviewed plan.',
|
|
87
|
+
},
|
|
88
|
+
terminalArtifact: {
|
|
89
|
+
kind: 'plan_document',
|
|
90
|
+
storage: 'state.planDoc',
|
|
91
|
+
description: 'Accepted top-level Neal-executable plan markdown revised in place.',
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
successCondition: 'Ordinary plan-mode review can settle without bespoke loop wiring outside the adjudicator family.',
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
id: 'derived_plan_review',
|
|
98
|
+
family: 'plan_review',
|
|
99
|
+
status: 'in_scope_v1',
|
|
100
|
+
roundLabel: 'plan-review',
|
|
101
|
+
currentEntrypoints: ['runPlanReviewerRound(mode=derived-plan)', 'runCoderPlanResponseRound(reviewMode=derived-plan)'],
|
|
102
|
+
artifactUnderReview: 'Derived replacement plan that targets one stale execute scope.',
|
|
103
|
+
contextAssembly: {
|
|
104
|
+
owner: 'orchestrator',
|
|
105
|
+
inputs: ['derivedPlanPath', 'parentPlanDoc', 'derivedFromScopeNumber', 'reviewMarkdownPath'],
|
|
106
|
+
notes: 'The loop mechanics match ordinary plan review while adoption semantics remain in the transition layer.',
|
|
107
|
+
},
|
|
108
|
+
coder: {
|
|
109
|
+
primary: {
|
|
110
|
+
prompt: {
|
|
111
|
+
role: 'coder',
|
|
112
|
+
promptSpecId: 'plan_author',
|
|
113
|
+
variantKind: 'response',
|
|
114
|
+
exportName: 'buildCoderPlanResponsePrompt',
|
|
115
|
+
},
|
|
116
|
+
output: {
|
|
117
|
+
protocol: 'structured_json',
|
|
118
|
+
schemaBuilder: 'buildCoderPlanResponseSchema',
|
|
119
|
+
parser: 'validateCoderPlanResponsePayload',
|
|
120
|
+
providerSurface: 'coder_structured_schema',
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
response: null,
|
|
124
|
+
},
|
|
125
|
+
reviewer: {
|
|
126
|
+
prompt: {
|
|
127
|
+
role: 'reviewer',
|
|
128
|
+
promptSpecId: 'plan_reviewer',
|
|
129
|
+
variantKind: 'derived_plan',
|
|
130
|
+
exportName: 'buildPlanReviewerPrompt',
|
|
131
|
+
},
|
|
132
|
+
output: {
|
|
133
|
+
protocol: 'structured_json',
|
|
134
|
+
schemaBuilder: 'buildPlanReviewerSchema',
|
|
135
|
+
parser: 'PlanReviewerPayload',
|
|
136
|
+
providerSurface: 'structured_advisor_schema',
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
convergence: {
|
|
140
|
+
settledWhen: 'Reviewer returns no open findings and the derived plan is safe to adopt.',
|
|
141
|
+
reviseWhen: 'Derived-plan findings loop through the same plan-response path as ordinary plan review.',
|
|
142
|
+
blockedWhen: 'Coder blocks or the derived plan remains structurally invalid.',
|
|
143
|
+
},
|
|
144
|
+
transitionSignals: ['accept_derived_plan', 'request_revision', 'optional_revision', 'block_for_operator'],
|
|
145
|
+
loopContract: {
|
|
146
|
+
loopKind: 'plan',
|
|
147
|
+
sideEffectPolicy: 'plan_doc_only',
|
|
148
|
+
allowedOutcomes: ['accepted', 'revise', 'blocked', 'failed', 'cap_reached'],
|
|
149
|
+
terminalOutcomes: ['accepted', 'blocked', 'failed', 'cap_reached'],
|
|
150
|
+
roundCap: {
|
|
151
|
+
source: 'derivedPlan.counters.maxDerivedPlanReviewRounds',
|
|
152
|
+
appliesTo: 'review_iterations',
|
|
153
|
+
outcomeWhenReached: 'cap_reached',
|
|
154
|
+
notes: 'Derived-plan review uses the derived-plan review cap and blocks rather than adopting an unresolved replacement plan.',
|
|
155
|
+
},
|
|
156
|
+
terminalArtifact: {
|
|
157
|
+
kind: 'derived_plan_document',
|
|
158
|
+
storage: 'state.derivedPlanPath',
|
|
159
|
+
description: 'Accepted derived replacement plan for one stale execute scope.',
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
successCondition: 'Derived-plan review shares planning-side adjudication mechanics while keeping replacement/adoption explicit.',
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
id: 'execute_review',
|
|
166
|
+
family: 'execute_review',
|
|
167
|
+
status: 'in_scope_v1',
|
|
168
|
+
roundLabel: 'review',
|
|
169
|
+
currentEntrypoints: ['runCoderScopeRound', 'runReviewerRound', 'runCoderResponseRound'],
|
|
170
|
+
artifactUnderReview: 'Execute-mode scope diff plus persisted meaningful-progress history for the active parent objective.',
|
|
171
|
+
contextAssembly: {
|
|
172
|
+
owner: 'review_artifact',
|
|
173
|
+
inputs: ['planDoc', 'baseCommit', 'headCommit', 'changedFiles', 'reviewMarkdownPath', 'currentScopeProgressJustification', 'recentHistorySummary'],
|
|
174
|
+
notes: 'Execute review is the only in-scope adjudication spec with meaningful-progress capability layered onto the reviewer prompt surface.',
|
|
175
|
+
},
|
|
176
|
+
coder: {
|
|
177
|
+
primary: {
|
|
178
|
+
prompt: {
|
|
179
|
+
role: 'coder',
|
|
180
|
+
promptSpecId: 'scope_coder',
|
|
181
|
+
variantKind: 'primary',
|
|
182
|
+
exportName: 'buildScopePrompt',
|
|
183
|
+
},
|
|
184
|
+
output: {
|
|
185
|
+
protocol: 'structured_json',
|
|
186
|
+
schemaBuilder: 'buildCoderScopeSchema',
|
|
187
|
+
parser: 'validateCoderScopePayload',
|
|
188
|
+
providerSurface: 'coder_structured_schema',
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
response: {
|
|
192
|
+
prompt: {
|
|
193
|
+
role: 'coder',
|
|
194
|
+
promptSpecId: 'scope_coder',
|
|
195
|
+
variantKind: 'response',
|
|
196
|
+
exportName: 'buildCoderResponsePrompt',
|
|
197
|
+
},
|
|
198
|
+
output: {
|
|
199
|
+
protocol: 'structured_json',
|
|
200
|
+
schemaBuilder: 'buildCoderResponseSchema',
|
|
201
|
+
parser: 'validateCoderResponsePayload',
|
|
202
|
+
providerSurface: 'coder_structured_schema',
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
reviewer: {
|
|
207
|
+
prompt: {
|
|
208
|
+
role: 'reviewer',
|
|
209
|
+
promptSpecId: 'scope_reviewer',
|
|
210
|
+
variantKind: 'primary',
|
|
211
|
+
exportName: 'buildReviewerPrompt',
|
|
212
|
+
},
|
|
213
|
+
output: {
|
|
214
|
+
protocol: 'structured_json',
|
|
215
|
+
schemaBuilder: 'buildReviewerSchema',
|
|
216
|
+
parser: 'ReviewerPayload',
|
|
217
|
+
providerSurface: 'structured_advisor_schema',
|
|
218
|
+
},
|
|
219
|
+
capabilities: [
|
|
220
|
+
{
|
|
221
|
+
role: 'reviewer',
|
|
222
|
+
promptSpecId: 'scope_reviewer',
|
|
223
|
+
variantKind: 'meaningful_progress',
|
|
224
|
+
exportName: 'buildReviewerPrompt',
|
|
225
|
+
},
|
|
226
|
+
],
|
|
227
|
+
},
|
|
228
|
+
convergence: {
|
|
229
|
+
settledWhen: 'Reviewer returns no blocking findings and meaningfulProgressAction === accept, including top-level scopes already satisfied by prior accepted work; advance_parent is a distinct empty-derived-scope parent-advancement signal.',
|
|
230
|
+
reviseWhen: 'Findings reopen coder_response or coder_optional_response without changing execute-scope transition semantics.',
|
|
231
|
+
blockedWhen: 'Reviewer returns block_for_operator, replace_plan, or an unsafe advance_parent, or coder returns structured action=blocked/split_plan; round code still renders compatibility markers for downstream state.',
|
|
232
|
+
},
|
|
233
|
+
transitionSignals: ['accept_scope', 'request_revision', 'optional_revision', 'block_for_operator', 'replace_plan', 'advance_parent'],
|
|
234
|
+
loopContract: {
|
|
235
|
+
loopKind: 'execute',
|
|
236
|
+
sideEffectPolicy: 'code_changes',
|
|
237
|
+
allowedOutcomes: ['accepted', 'revise', 'blocked', 'failed', 'cap_reached'],
|
|
238
|
+
terminalOutcomes: ['accepted', 'blocked', 'failed', 'cap_reached'],
|
|
239
|
+
roundCap: {
|
|
240
|
+
source: 'state.maxRounds',
|
|
241
|
+
appliesTo: 'review_iterations',
|
|
242
|
+
outcomeWhenReached: 'cap_reached',
|
|
243
|
+
notes: 'Execute review stops at the configured review-round cap when blocking findings remain and records a blocked writer run.',
|
|
244
|
+
},
|
|
245
|
+
terminalArtifact: {
|
|
246
|
+
kind: 'implementation_scope',
|
|
247
|
+
storage: 'state.createdCommits plus state.reviewMarkdownPath',
|
|
248
|
+
description: 'Accepted implementation scope commits and the corresponding scope-review artifact.',
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
successCondition: 'Ordinary execute review and meaningful-progress gating share one adjudication spec family rather than branching by phase.',
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
id: 'final_completion_review',
|
|
255
|
+
family: 'final_completion',
|
|
256
|
+
status: 'in_scope_v1',
|
|
257
|
+
roundLabel: 'final-completion',
|
|
258
|
+
currentEntrypoints: ['runCoderFinalCompletionSummaryRound', 'runReviewerFinalCompletionRound'],
|
|
259
|
+
artifactUnderReview: 'Whole-plan completion packet assembled after the terminal execute scope settles.',
|
|
260
|
+
contextAssembly: {
|
|
261
|
+
owner: 'final_completion_packet',
|
|
262
|
+
inputs: ['planDoc', 'FinalCompletionPacket', 'FinalCompletionSummary'],
|
|
263
|
+
notes: 'Final completion review is plan-review-adjacent, but its accept/continue/block transitions stay outside the adjudicator.',
|
|
264
|
+
},
|
|
265
|
+
coder: {
|
|
266
|
+
primary: {
|
|
267
|
+
prompt: {
|
|
268
|
+
role: 'coder',
|
|
269
|
+
promptSpecId: 'completion_coder',
|
|
270
|
+
variantKind: 'final_completion',
|
|
271
|
+
exportName: 'buildFinalCompletionSummaryPrompt',
|
|
272
|
+
},
|
|
273
|
+
output: {
|
|
274
|
+
protocol: 'structured_json',
|
|
275
|
+
schemaBuilder: 'buildFinalCompletionSummarySchema',
|
|
276
|
+
parser: 'parseFinalCompletionSummaryPayload',
|
|
277
|
+
providerSurface: 'structured_advisor_schema',
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
response: null,
|
|
281
|
+
},
|
|
282
|
+
reviewer: {
|
|
283
|
+
prompt: {
|
|
284
|
+
role: 'reviewer',
|
|
285
|
+
promptSpecId: 'completion_reviewer',
|
|
286
|
+
variantKind: 'final_completion',
|
|
287
|
+
exportName: 'buildFinalCompletionReviewerPrompt',
|
|
288
|
+
},
|
|
289
|
+
output: {
|
|
290
|
+
protocol: 'structured_json',
|
|
291
|
+
schemaBuilder: 'buildFinalCompletionReviewerSchema',
|
|
292
|
+
parser: 'parseFinalCompletionReviewerPayload',
|
|
293
|
+
providerSurface: 'structured_advisor_schema',
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
convergence: {
|
|
297
|
+
settledWhen: 'Reviewer returns accept_complete, continue_execution, or block_for_operator for the whole plan.',
|
|
298
|
+
reviseWhen: 'No coder-response loop exists in v1; continue_execution returns control to execute-mode transitions instead.',
|
|
299
|
+
blockedWhen: 'Transition-layer continue_execution cap or explicit block_for_operator escalates to operator guidance.',
|
|
300
|
+
},
|
|
301
|
+
transitionSignals: ['accept_complete', 'continue_execution', 'block_for_operator'],
|
|
302
|
+
loopContract: {
|
|
303
|
+
loopKind: 'final_completion',
|
|
304
|
+
sideEffectPolicy: 'code_changes',
|
|
305
|
+
allowedOutcomes: ['accepted', 'revise', 'blocked', 'failed', 'cap_reached'],
|
|
306
|
+
terminalOutcomes: ['accepted', 'blocked', 'failed', 'cap_reached'],
|
|
307
|
+
roundCap: {
|
|
308
|
+
source: 'state.finalCompletionContinueExecutionMax',
|
|
309
|
+
appliesTo: 'continued_execution',
|
|
310
|
+
outcomeWhenReached: 'cap_reached',
|
|
311
|
+
notes: 'Final completion can reopen execution only up to its continue-execution cap before routing to operator blocking.',
|
|
312
|
+
},
|
|
313
|
+
terminalArtifact: {
|
|
314
|
+
kind: 'final_completion_review',
|
|
315
|
+
storage: 'FINAL_COMPLETION_REVIEW.md and state.finalCompletionReviewVerdict',
|
|
316
|
+
description: 'Whole-plan final-completion review artifact and resolved reviewer verdict.',
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
successCondition: 'Whole-plan completion review uses the shared adjudication model without hiding execute-mode completion semantics.',
|
|
320
|
+
},
|
|
321
|
+
];
|
|
322
|
+
export const ADJUDICATION_ADJACENT_FLOWS = [
|
|
323
|
+
{
|
|
324
|
+
id: 'interactive_blocked_recovery',
|
|
325
|
+
status: 'adjacent_v1',
|
|
326
|
+
currentEntrypoints: ['runInteractiveBlockedRecoveryPhase'],
|
|
327
|
+
reason: 'Interactive blocked recovery mixes operator input, coder dispositions, and transition routing rather than a pure coder/reviewer adjudication loop.',
|
|
328
|
+
futureRelationship: 'Keep adjacent until Neal decides to formalize operator-in-the-loop adjudication as its own family.',
|
|
329
|
+
},
|
|
330
|
+
];
|
|
331
|
+
const STRUCTURED_SCHEMA_BUILDERS = new Set([
|
|
332
|
+
'buildReviewerSchema',
|
|
333
|
+
'buildPlanReviewerSchema',
|
|
334
|
+
'buildCoderPlanSchema',
|
|
335
|
+
'buildCoderScopeSchema',
|
|
336
|
+
'buildCoderResponseSchema',
|
|
337
|
+
'buildCoderPlanResponseSchema',
|
|
338
|
+
'buildFinalCompletionSummarySchema',
|
|
339
|
+
'buildFinalCompletionReviewerSchema',
|
|
340
|
+
]);
|
|
341
|
+
const PARSER_SURFACES = new Set([
|
|
342
|
+
'validateCoderPlanPayload',
|
|
343
|
+
'validateCoderPlanResponsePayload',
|
|
344
|
+
'validateCoderScopePayload',
|
|
345
|
+
'validateCoderResponsePayload',
|
|
346
|
+
'PlanReviewerPayload',
|
|
347
|
+
'ReviewerPayload',
|
|
348
|
+
'parseFinalCompletionSummaryPayload',
|
|
349
|
+
'parseFinalCompletionReviewerPayload',
|
|
350
|
+
]);
|
|
351
|
+
const PROVIDER_SURFACES = new Set(['coder_structured_schema', 'structured_advisor_schema']);
|
|
352
|
+
function validatePromptSurfaceReference(specId, label, reference) {
|
|
353
|
+
const promptSpec = getPromptSpec(reference.promptSpecId);
|
|
354
|
+
if (promptSpec.role !== reference.role) {
|
|
355
|
+
throw new Error(`Adjudication spec ${specId} ${label} role mismatch: expected ${reference.role}, prompt spec ${reference.promptSpecId} is ${promptSpec.role}.`);
|
|
356
|
+
}
|
|
357
|
+
const variant = promptSpec.variants.find((candidate) => candidate.kind === reference.variantKind && candidate.baseInstructions.exportName === reference.exportName);
|
|
358
|
+
if (!variant) {
|
|
359
|
+
throw new Error(`Adjudication spec ${specId} ${label} references missing prompt surface ${reference.promptSpecId}.${reference.variantKind}/${reference.exportName}.`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
function validateOutputSurface(specId, label, surface) {
|
|
363
|
+
const protocol = surface.protocol;
|
|
364
|
+
if (protocol !== 'structured_json') {
|
|
365
|
+
throw new Error(`Adjudication spec ${specId} ${label} references unsupported output protocol ${String(protocol)}.`);
|
|
366
|
+
}
|
|
367
|
+
if (!STRUCTURED_SCHEMA_BUILDERS.has(surface.schemaBuilder)) {
|
|
368
|
+
throw new Error(`Adjudication spec ${specId} ${label} references unknown schema builder ${surface.schemaBuilder}.`);
|
|
369
|
+
}
|
|
370
|
+
if (!PARSER_SURFACES.has(surface.parser)) {
|
|
371
|
+
throw new Error(`Adjudication spec ${specId} ${label} references unknown parser ${surface.parser}.`);
|
|
372
|
+
}
|
|
373
|
+
if (!PROVIDER_SURFACES.has(surface.providerSurface)) {
|
|
374
|
+
throw new Error(`Adjudication spec ${specId} ${label} references unknown provider surface ${surface.providerSurface}.`);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
function validateTransitionSignals(spec) {
|
|
378
|
+
const familySignals = new Set(FAMILY_RUNTIME_TRANSITION_SIGNALS[spec.family]);
|
|
379
|
+
const specSignals = new Set(spec.transitionSignals);
|
|
380
|
+
const requiredSignals = SPEC_RUNTIME_TRANSITION_SIGNALS[spec.id];
|
|
381
|
+
if (specSignals.size !== spec.transitionSignals.length) {
|
|
382
|
+
throw new Error(`Adjudication spec ${spec.id} family ${spec.family} declares duplicate transition signals.`);
|
|
383
|
+
}
|
|
384
|
+
for (const signal of spec.transitionSignals) {
|
|
385
|
+
if (!familySignals.has(signal)) {
|
|
386
|
+
throw new Error(`Adjudication spec ${spec.id} family ${spec.family} declares impossible transition signal ${signal}.`);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
for (const signal of requiredSignals) {
|
|
390
|
+
if (!specSignals.has(signal)) {
|
|
391
|
+
throw new Error(`Adjudication spec ${spec.id} family ${spec.family} is missing runtime transition signal ${signal}.`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
function validateFamilyRuntimeCoverage(specs) {
|
|
396
|
+
const signalsByFamily = new Map();
|
|
397
|
+
for (const spec of specs) {
|
|
398
|
+
const signals = signalsByFamily.get(spec.family) ?? new Set();
|
|
399
|
+
for (const signal of SPEC_RUNTIME_TRANSITION_SIGNALS[spec.id]) {
|
|
400
|
+
signals.add(signal);
|
|
401
|
+
}
|
|
402
|
+
signalsByFamily.set(spec.family, signals);
|
|
403
|
+
}
|
|
404
|
+
for (const [family, allowedSignals] of Object.entries(FAMILY_RUNTIME_TRANSITION_SIGNALS)) {
|
|
405
|
+
const coveredSignals = signalsByFamily.get(family) ?? new Set();
|
|
406
|
+
for (const signal of allowedSignals) {
|
|
407
|
+
if (!coveredSignals.has(signal)) {
|
|
408
|
+
throw new Error(`Adjudication family ${family} is missing runtime transition coverage for signal ${signal}.`);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
export function validateAdjudicationSpecContracts(specs) {
|
|
414
|
+
for (const spec of specs) {
|
|
415
|
+
validateAdjudicatedLoopContract(spec.id, spec.loopContract);
|
|
416
|
+
validatePromptSurfaceReference(spec.id, 'coder.primary.prompt', spec.coder.primary.prompt);
|
|
417
|
+
validateOutputSurface(spec.id, 'coder.primary.output', spec.coder.primary.output);
|
|
418
|
+
if (spec.coder.response) {
|
|
419
|
+
validatePromptSurfaceReference(spec.id, 'coder.response.prompt', spec.coder.response.prompt);
|
|
420
|
+
validateOutputSurface(spec.id, 'coder.response.output', spec.coder.response.output);
|
|
421
|
+
}
|
|
422
|
+
validatePromptSurfaceReference(spec.id, 'reviewer.prompt', spec.reviewer.prompt);
|
|
423
|
+
validateOutputSurface(spec.id, 'reviewer.output', spec.reviewer.output);
|
|
424
|
+
for (const capability of spec.reviewer.capabilities ?? []) {
|
|
425
|
+
validatePromptSurfaceReference(spec.id, 'reviewer.capability', capability);
|
|
426
|
+
}
|
|
427
|
+
validateTransitionSignals(spec);
|
|
428
|
+
}
|
|
429
|
+
validateFamilyRuntimeCoverage(specs);
|
|
430
|
+
}
|
|
431
|
+
validateAdjudicationSpecContracts(ADJUDICATION_SPECS);
|
|
432
|
+
const ADJUDICATION_SPEC_MAP = new Map(ADJUDICATION_SPECS.map((spec) => [spec.id, spec]));
|
|
433
|
+
export function getAdjudicationSpec(id) {
|
|
434
|
+
const spec = ADJUDICATION_SPEC_MAP.get(id);
|
|
435
|
+
if (!spec) {
|
|
436
|
+
throw new Error(`Unknown adjudication spec: ${id}`);
|
|
437
|
+
}
|
|
438
|
+
return spec;
|
|
439
|
+
}
|
|
440
|
+
export function assertAdjudicationTransitionSignal(spec, signal, callerLabel) {
|
|
441
|
+
if (spec.transitionSignals.includes(signal)) {
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
throw new Error(`${callerLabel} resolved transition signal ${signal} for adjudication spec ${spec.id} ` +
|
|
445
|
+
`family ${spec.family}, but allowed signals are: ${spec.transitionSignals.join(', ')}.`);
|
|
446
|
+
}
|
|
447
|
+
export function getReviewerCapability(spec, variantKind) {
|
|
448
|
+
const capability = spec.reviewer.capabilities?.find((candidate) => candidate.variantKind === variantKind);
|
|
449
|
+
if (!capability) {
|
|
450
|
+
throw new Error(`Adjudication spec ${spec.id} reviewer is missing capability ${variantKind}.`);
|
|
451
|
+
}
|
|
452
|
+
return capability;
|
|
453
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { assertNoReadPromptInstructionText, renderInlineReviewerContext, } from '../context/inline-review-context.js';
|
|
2
|
+
import { renderReviewerContextMarkdown } from '../context/reviewer-context.js';
|
|
3
|
+
import { AUTONOMY_BLOCKED as SHARED_AUTONOMY_BLOCKED, AUTONOMY_CHUNK_DONE as SHARED_AUTONOMY_CHUNK_DONE, AUTONOMY_DONE as SHARED_AUTONOMY_DONE, AUTONOMY_SCOPE_DONE as SHARED_AUTONOMY_SCOPE_DONE, AUTONOMY_SPLIT_PLAN as SHARED_AUTONOMY_SPLIT_PLAN, buildProgressSection, getCanonicalPlanContractLines, getProtocolMarkerArtifactProhibitionLines, getStandalonePlanPayloadSourceOfTruthLines, } from '../prompts/shared.js';
|
|
4
|
+
import { getUserGuidanceLines } from '../prompts/guidance.js';
|
|
5
|
+
export { buildCoderResponsePrompt, buildLegacyScopePrompt, buildReviewerPrompt, buildScopePrompt } from '../prompts/execute.js';
|
|
6
|
+
export { buildCoderPlanResponsePrompt, buildLegacyPlanningPrompt, buildPlanReviewerPrompt, buildPlanningPrompt, } from '../prompts/planning.js';
|
|
7
|
+
export { buildFinalCompletionReviewerPrompt, buildFinalCompletionSummaryPrompt, } from '../prompts/specialized.js';
|
|
8
|
+
export const AUTONOMY_BLOCKED = SHARED_AUTONOMY_BLOCKED;
|
|
9
|
+
export const AUTONOMY_CHUNK_DONE = SHARED_AUTONOMY_CHUNK_DONE;
|
|
10
|
+
export const AUTONOMY_DONE = SHARED_AUTONOMY_DONE;
|
|
11
|
+
export const AUTONOMY_SCOPE_DONE = SHARED_AUTONOMY_SCOPE_DONE;
|
|
12
|
+
export const AUTONOMY_SPLIT_PLAN = SHARED_AUTONOMY_SPLIT_PLAN;
|
|
13
|
+
// Single no-read-safe prompt variant for the read-only blocked-run adjudicator.
|
|
14
|
+
// It generalizes across every triaged block class (a coder-blocked signal or a
|
|
15
|
+
// reviewer `review_stuck` deadlock): it takes a NON-null InlineReviewerContext
|
|
16
|
+
// (the round runner narrows before calling it) and judges entirely from whatever
|
|
17
|
+
// sections that context supplies, making no assumptions about which sections are
|
|
18
|
+
// present. The static Neal-authored instructions must never reference
|
|
19
|
+
// repository/file/shell access, so they pass through the shared no-read guard.
|
|
20
|
+
export function buildBlockedAdjudicatorPrompt(args) {
|
|
21
|
+
const staticInstructionLines = [
|
|
22
|
+
'You are a read-only adjudicator for a blocked neal run. The run has stopped because a coder or reviewer turn reported a blocker it could not resolve on its own.',
|
|
23
|
+
'Judge entirely from the inlined context sections below. You make no changes, run nothing, and look at nothing outside this prompt.',
|
|
24
|
+
'Decide whether the block is an autonomously recoverable misunderstanding that can be resolved WITHIN the existing scope, or a genuine wall that must escalate to a human.',
|
|
25
|
+
'Return `recoverable:true` with `triageCategory:"misunderstanding"` and a concrete, in-scope `resolutionDirective` ONLY when ALL of these hold:',
|
|
26
|
+
'- the block stems from a genuine misunderstanding (the blocked party means something different from, or missed something already present in, the plan or the inlined context),',
|
|
27
|
+
'- it can be resolved within the current scope as written, with no new authorization, credentials, network access, external services, external state, or scope expansion,',
|
|
28
|
+
'- the resolution does not require asking the operator a question (a bounded clarification that needs an operator answer is NOT in scope here; treat it as a genuine wall).',
|
|
29
|
+
'The `resolutionDirective` must be a concrete instruction the blocked party can act on immediately, naming the specific in-scope action that breaks the block.',
|
|
30
|
+
'Otherwise return `recoverable:false` with the matching genuine-wall category:',
|
|
31
|
+
'- `authorization`: the next useful step needs explicit new authorization, credentials, or permission.',
|
|
32
|
+
'- `external_precondition`: it needs network access, external services, or external state that cannot be created in-scope.',
|
|
33
|
+
'- `impossible_task`: the scope as written cannot be satisfied.',
|
|
34
|
+
'If the inlined context lists specific blocking findings, set `targetCanonicalIds` to the canonical ids your verdict addresses; otherwise leave it empty.',
|
|
35
|
+
'Always provide a non-empty `rationale` explaining the triage.',
|
|
36
|
+
];
|
|
37
|
+
assertNoReadPromptInstructionText(staticInstructionLines.join('\n'), 'buildBlockedAdjudicatorPrompt');
|
|
38
|
+
return [
|
|
39
|
+
...staticInstructionLines,
|
|
40
|
+
'',
|
|
41
|
+
'Blocked reason:',
|
|
42
|
+
args.blockedReason,
|
|
43
|
+
'',
|
|
44
|
+
renderInlineReviewerContext(args.inlineContext),
|
|
45
|
+
].join('\n');
|
|
46
|
+
}
|
|
47
|
+
function getReviewerContextLines(reviewerContext, mode = 'tool-access') {
|
|
48
|
+
if (!reviewerContext) {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
return [
|
|
52
|
+
'',
|
|
53
|
+
'Bounded current-run continuity context:',
|
|
54
|
+
mode === 'inline' ? renderReviewerContextMarkdown(reviewerContext, { mode: 'inline' }) : reviewerContext.promptMarkdown,
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
export function buildBlockedRecoveryCoderPrompt(args) {
|
|
58
|
+
const allowReplacement = args.allowReplacement ?? true;
|
|
59
|
+
const actionLines = [
|
|
60
|
+
'- `resume_current_scope`',
|
|
61
|
+
...(allowReplacement ? ['- `replace_current_scope`'] : []),
|
|
62
|
+
...(args.terminalOnly && !allowReplacement ? [] : ['- `stay_blocked`']),
|
|
63
|
+
'- `terminal_block`',
|
|
64
|
+
];
|
|
65
|
+
const terminalOnlyInstruction = args.terminalOnly && allowReplacement
|
|
66
|
+
? 'The recovery turn cap has been reached. You must choose either `replace_current_scope` or `terminal_block`. Do not use `resume_current_scope` or `stay_blocked`.'
|
|
67
|
+
: args.terminalOnly
|
|
68
|
+
? 'The recovery turn cap has been reached. You must choose `terminal_block`. Do not use `resume_current_scope` or `stay_blocked`.'
|
|
69
|
+
: 'Use `resume_current_scope` when the current scope is still correct and the operator guidance gives enough direction to continue normally.';
|
|
70
|
+
return [
|
|
71
|
+
`Continue blocked recovery for the current neal scope in ${args.planDoc}.`,
|
|
72
|
+
`Read ${args.recoveryMarkdownPath} before responding so you understand the blocked-recovery history.`,
|
|
73
|
+
'Blocked recovery is now in-band inside Neal. Do not tell the operator to leave Neal or resume the coder session separately.',
|
|
74
|
+
'Use the inlined progress state below to stay on the current scope.',
|
|
75
|
+
'You are still handling the same blocked scope. Do not start a new scope.',
|
|
76
|
+
...getUserGuidanceLines('coder'),
|
|
77
|
+
'Choose exactly one recovery action in your structured response:',
|
|
78
|
+
...actionLines,
|
|
79
|
+
terminalOnlyInstruction,
|
|
80
|
+
allowReplacement
|
|
81
|
+
? 'Use `replace_current_scope` when the current scope shape is wrong and Neal should route the replacement through the existing split-plan / derived-plan machinery.'
|
|
82
|
+
: '`replace_current_scope` is not available for this run because replacing the scope would discard or rewrite externally authored commits.',
|
|
83
|
+
args.terminalOnly
|
|
84
|
+
? 'Use `terminal_block` when no safe in-repo path remains and the run must finalize as truly blocked.'
|
|
85
|
+
: 'Use `stay_blocked` when more operator guidance is still required and the run should remain in interactive blocked recovery.',
|
|
86
|
+
args.terminalOnly
|
|
87
|
+
? 'Do not ask for additional operator guidance in this turn.'
|
|
88
|
+
: 'Use `terminal_block` only when no safe in-repo path remains and the run should finalize as truly blocked.',
|
|
89
|
+
'Always include a `summary` and `rationale`.',
|
|
90
|
+
allowReplacement
|
|
91
|
+
? 'Always include a `blocker` string. Use an empty string only when action=`resume_current_scope` or action=`replace_current_scope`.'
|
|
92
|
+
: 'Always include a `blocker` string. Use an empty string only when action=`resume_current_scope`.',
|
|
93
|
+
allowReplacement
|
|
94
|
+
? 'Always include a `replacementPlan` string. Use an empty string unless action=`replace_current_scope`.'
|
|
95
|
+
: 'Always include an empty `replacementPlan` string.',
|
|
96
|
+
...(allowReplacement
|
|
97
|
+
? [
|
|
98
|
+
'When action=`replace_current_scope`, `replacementPlan` must use the same Neal-executable contract as a top-level plan.',
|
|
99
|
+
'Any replacement-specific rationale sections are optional additive context only; they must not replace or rename the canonical machine-consumed sections.',
|
|
100
|
+
...getStandalonePlanPayloadSourceOfTruthLines({
|
|
101
|
+
planLabel: 'replacement plan',
|
|
102
|
+
payloadLabel: '`replacementPlan` field',
|
|
103
|
+
resetWorkLabel: 'Abandoned scope work',
|
|
104
|
+
}),
|
|
105
|
+
...getProtocolMarkerArtifactProhibitionLines(),
|
|
106
|
+
...getCanonicalPlanContractLines(),
|
|
107
|
+
]
|
|
108
|
+
: []),
|
|
109
|
+
'Do not invent a new recovery taxonomy or extra top-level actions.',
|
|
110
|
+
'Do not treat operator guidance as authorization to skip verification, waive policy, or reinterpret the target beyond the current scope.',
|
|
111
|
+
'',
|
|
112
|
+
'Blocked recovery context:',
|
|
113
|
+
`- Blocked reason: ${args.blockedReason}`,
|
|
114
|
+
`- Recovery turns used: ${args.turnsTaken} of ${args.maxTurns}`,
|
|
115
|
+
`- Latest operator guidance: ${args.operatorGuidance}`,
|
|
116
|
+
'',
|
|
117
|
+
'Current progress state:',
|
|
118
|
+
buildProgressSection(args.progressText),
|
|
119
|
+
].join('\n');
|
|
120
|
+
}
|