@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,313 @@
|
|
|
1
|
+
import { assertNoReadPromptInstructionText, renderInlineReviewerContext, } from '../context/inline-review-context.js';
|
|
2
|
+
import { renderReviewerContextMarkdown } from '../context/reviewer-context.js';
|
|
3
|
+
import { AUTONOMY_BLOCKED, AUTONOMY_DONE, getCanonicalPlanContractLines, getDerivedPlanSectionContractLines, getProtocolMarkerArtifactProhibitionLines, getTerminalMarkerArtifactBoundaryLines, getUnattendedAutonomyLines, } from './shared.js';
|
|
4
|
+
import { assertPromptBuilder } from './assert-builder.js';
|
|
5
|
+
import { getUserGuidanceLines } from './guidance.js';
|
|
6
|
+
import { getAdversarialReviewDoctrineLines, getPlanReviewFalsificationLines, getVerificationSkepticismLines, resolveReviewerPromptAccessMode, } from './review-doctrine.js';
|
|
7
|
+
const PROMPT_MODULE_PATH = 'src/neal/prompts/planning.ts';
|
|
8
|
+
function getPlanningPromptBaseLines(planDoc) {
|
|
9
|
+
return [
|
|
10
|
+
`Refine the existing plan document at ${planDoc} into a stronger future execution plan for neal.`,
|
|
11
|
+
'',
|
|
12
|
+
'Before doing anything else:',
|
|
13
|
+
`1. Read ${planDoc} when it is accessible. If that path is outside your file-tool jail, use the inlined current plan content below as the authoritative plan text.`,
|
|
14
|
+
'2. Read any companion docs explicitly referenced by that plan.',
|
|
15
|
+
'3. Reset your instructions for this turn from the current contents of the plan and referenced context.',
|
|
16
|
+
'',
|
|
17
|
+
'Then identify weaknesses in the current plan and improve it. Look specifically for:',
|
|
18
|
+
'- Underdeveloped scopes that need more implementation detail.',
|
|
19
|
+
'- Vague or missing acceptance criteria / completion criteria.',
|
|
20
|
+
'- Ambiguous scope boundaries or hidden assumptions about the repository.',
|
|
21
|
+
'- Poor or unclear sequencing between scopes.',
|
|
22
|
+
'- Verification that is not executable or not concrete.',
|
|
23
|
+
'- Planning-task scaffolding left over from an earlier draft.',
|
|
24
|
+
'Produce a substantively improved revision in the same file.',
|
|
25
|
+
'If the current plan is already strong, do not invent new weaknesses; revise only what actually improves it.',
|
|
26
|
+
"Refine for executability without expanding the author's scope. Include refactoring only when the plan calls for it, the objective genuinely requires it, or implementing the change would otherwise increase complexity such that a refactor is a natural outgrowth — not opportunistically.",
|
|
27
|
+
'',
|
|
28
|
+
'Revise only plan-related artifacts.',
|
|
29
|
+
'Do not edit runtime source code outside the plan itself and adjacent planning notes.',
|
|
30
|
+
'Do not make git commits.',
|
|
31
|
+
'Your output must be a pure future execution plan, not a planning-task checklist.',
|
|
32
|
+
'Replace the plan in place so the resulting file is meant to be run later with `neal execute`, not `neal plan`.',
|
|
33
|
+
'Do not leave planning-only scaffolding in the final file. Remove or replace sections such as planning mode instructions, Required Inputs for the planner, Verification For This Planning Task, and Completion Criteria For This Planning Task.',
|
|
34
|
+
'Ground the plan in the actual current repository state. Inspect the real target files and write steps against the symbols, exports, and file structure that actually exist.',
|
|
35
|
+
'Do not leave avoidable ambiguity in the plan when the repository already answers the question. Name concrete target functions, files, and exports when they are knowable from the repo.',
|
|
36
|
+
'Do not ask the future executor to perform redundant edits. If an export already propagates through an existing barrel file, say to verify that behavior instead of adding a fake extra edit step.',
|
|
37
|
+
'Make the final plan explicit about scope boundaries, allowed scope, forbidden paths, implementation steps, verification, completion criteria, blocker handling, and any repeated-scope selection rules.',
|
|
38
|
+
'Choose `multi_scope` when the work changes orchestration or state-machine behavior, resume semantics, persistence or schema shape, multiple independent subsystems, or otherwise naturally falls into staged rollout checkpoints.',
|
|
39
|
+
'Choose `multi_scope_unknown` when the work repeats one bounded recurring slice at a time and the total number of scopes is intentionally unknown until an explicit completion condition is satisfied.',
|
|
40
|
+
'Choose `one_shot` only when the work can realistically be executed, reviewed, and verified as one bounded scope without hidden staging assumptions.',
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
function getInlineCurrentPlanLines(planDocument) {
|
|
44
|
+
if (!planDocument) {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
return [
|
|
48
|
+
'',
|
|
49
|
+
'Current plan document content:',
|
|
50
|
+
'```markdown',
|
|
51
|
+
planDocument,
|
|
52
|
+
'```',
|
|
53
|
+
'Use the inlined plan content above as the source of truth if the plan path itself cannot be read by your tools.',
|
|
54
|
+
];
|
|
55
|
+
}
|
|
56
|
+
function getPlanReviewerModeLines(args) {
|
|
57
|
+
const { mode } = args;
|
|
58
|
+
const derivedPlanContractRule = [
|
|
59
|
+
'The derived plan should preserve the same target while replacing only the invalid scope shape, and it must use the same canonical Neal-executable shape contract as a top-level plan.',
|
|
60
|
+
...getDerivedPlanSectionContractLines(),
|
|
61
|
+
'Reviewers must require the exact section set for the declared shape: `multi_scope` uses `## Execution Queue` and forbids `## Execution Loop` and `## Completion Condition`; `multi_scope_unknown` uses `## Execution Loop` plus `## Completion Condition` and forbids `## Execution Queue`; `one_shot` forbids all three orchestration sections.',
|
|
62
|
+
].join(' ');
|
|
63
|
+
return {
|
|
64
|
+
heading: mode === 'derived-plan'
|
|
65
|
+
? `Review the derived implementation plan at ${args.planDoc} for scope ${args.derivedFromScopeNumber ?? 'unknown'} in parent plan ${args.parentPlanDoc ?? args.planDoc}.`
|
|
66
|
+
: `Review the plan document at ${args.planDoc}.`,
|
|
67
|
+
blockingRule: mode === 'derived-plan'
|
|
68
|
+
? 'Use blocking severity when the derived plan does not safely replace the abandoned scope shape, lacks concrete ordered scopes, leaves blast radius too broad, or does not define adequate verification.'
|
|
69
|
+
: 'Use blocking severity for missing information or plan structure that would prevent neal from executing safely.',
|
|
70
|
+
scaffoldingRule: mode === 'derived-plan'
|
|
71
|
+
? 'Reject vague replans such as "break it into smaller chunks" when they do not define the actual replacement sequence in the canonical Neal-executable plan shape.'
|
|
72
|
+
: 'Treat leftover planning-task scaffolding as blocking. A final plan must not still describe how to revise itself, how to run `neal plan`, or how to validate the planning task.',
|
|
73
|
+
wideningRule: mode === 'derived-plan'
|
|
74
|
+
? 'Also use blocking severity if the proposal appears to be a real blocker disguised as replanning rather than a safer in-repo execution shape.'
|
|
75
|
+
: 'Examples of blocking leftover scaffolding include planning-mode execution headers, planner-only required-input sections, "Verification For This Planning Task", and "Completion Criteria For This Planning Task".',
|
|
76
|
+
focusRule: mode === 'derived-plan'
|
|
77
|
+
? 'Focus on whether the derived plan actually addresses the failure mode, is concrete enough to execute, reduces blast radius, and is truly not a blocker.'
|
|
78
|
+
: 'Focus on plan quality for refinement: scopes that need more detail, acceptance criteria that are vague or missing, ambiguous boundaries, hidden assumptions about the repository, weak sequencing, and non-executable verification. Call out plan steps that are avoidably ambiguous or redundant when the current repository already provides a more specific answer, such as existing function names, current exports, or barrel re-export behavior.',
|
|
79
|
+
contractRule: mode === 'derived-plan'
|
|
80
|
+
? derivedPlanContractRule
|
|
81
|
+
: 'Focus on whether the plan is now a clean future execution plan, explicit about single-scope vs repeated-scope behavior, and clear about verification and completion.',
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function getAuthoredOneShotPlanningLines(authoredOneShot) {
|
|
85
|
+
if (!authoredOneShot) {
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
return [
|
|
89
|
+
'This plan was authored as a single-scope (`one_shot`) plan; keep it one scope, make the smallest complete change, and do not restructure it into multiple scopes.',
|
|
90
|
+
];
|
|
91
|
+
}
|
|
92
|
+
function getAuthoredOneShotReviewerLines(authoredOneShot) {
|
|
93
|
+
if (!authoredOneShot) {
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
return [
|
|
97
|
+
'This plan was authored `one_shot`; raise a blocking finding if the document declares any other execution shape or adds orchestration sections.',
|
|
98
|
+
];
|
|
99
|
+
}
|
|
100
|
+
export function buildPlanningPrompt(planDoc, planDocument, options) {
|
|
101
|
+
const spec = assertPromptBuilder('plan_author', 'buildPlanningPrompt', PROMPT_MODULE_PATH);
|
|
102
|
+
const primaryVariant = spec.variants.find((variant) => variant.kind === 'primary');
|
|
103
|
+
if (!primaryVariant) {
|
|
104
|
+
throw new Error('Prompt spec plan_author is missing a primary variant');
|
|
105
|
+
}
|
|
106
|
+
return [
|
|
107
|
+
...getPlanningPromptBaseLines(planDoc),
|
|
108
|
+
...getInlineCurrentPlanLines(planDocument),
|
|
109
|
+
...getAuthoredOneShotPlanningLines(options?.authoredOneShot),
|
|
110
|
+
...getUnattendedAutonomyLines(options?.unattended),
|
|
111
|
+
...getProtocolMarkerArtifactProhibitionLines(),
|
|
112
|
+
...getCanonicalPlanContractLines(),
|
|
113
|
+
'If critical information is missing, do not invent it. Surface the concrete missing questions in your final response.',
|
|
114
|
+
'Return only a structured planning envelope with these fields:',
|
|
115
|
+
'- `action`: `ready_for_review` after the plan file has been revised and is ready for review, or `blocked` when critical information is missing.',
|
|
116
|
+
'- `message`: concise human-readable summary of what changed or why you are blocked.',
|
|
117
|
+
'- `executionShape`: exactly the chosen shape for the final plan: `one_shot`, `multi_scope`, or `multi_scope_unknown`.',
|
|
118
|
+
'- `planBody`: the complete final contents of the plan file when `action` is `ready_for_review`; otherwise an empty string.',
|
|
119
|
+
'- `blockedReason`: concrete missing information when `action` is `blocked`; otherwise an empty string.',
|
|
120
|
+
'Do not use terminal marker lines for this primary planning response.',
|
|
121
|
+
...getUserGuidanceLines('planner'),
|
|
122
|
+
].join('\n');
|
|
123
|
+
}
|
|
124
|
+
export function buildLegacyPlanningPrompt(planDoc, planDocument) {
|
|
125
|
+
return [
|
|
126
|
+
...getPlanningPromptBaseLines(planDoc),
|
|
127
|
+
...getInlineCurrentPlanLines(planDocument),
|
|
128
|
+
...getTerminalMarkerArtifactBoundaryLines(),
|
|
129
|
+
...getCanonicalPlanContractLines(),
|
|
130
|
+
'If critical information is missing, do not invent it. Surface the concrete missing questions in your final response.',
|
|
131
|
+
...getUserGuidanceLines('planner'),
|
|
132
|
+
'',
|
|
133
|
+
'Final line must be exactly one of:',
|
|
134
|
+
`- ${AUTONOMY_DONE}`,
|
|
135
|
+
`- ${AUTONOMY_BLOCKED}`,
|
|
136
|
+
].join('\n');
|
|
137
|
+
}
|
|
138
|
+
export function buildPlanReviewerPrompt(args) {
|
|
139
|
+
const mode = args.mode ?? 'plan';
|
|
140
|
+
const spec = assertPromptBuilder('plan_reviewer', 'buildPlanReviewerPrompt', PROMPT_MODULE_PATH);
|
|
141
|
+
const expectedVariant = mode === 'derived-plan' ? 'derived_plan' : 'primary';
|
|
142
|
+
if (!spec.variants.some((variant) => variant.kind === expectedVariant)) {
|
|
143
|
+
throw new Error(`Prompt spec ${spec.id} is missing variant ${expectedVariant}`);
|
|
144
|
+
}
|
|
145
|
+
const accessMode = resolveReviewerPromptAccessMode({
|
|
146
|
+
builder: 'buildPlanReviewerPrompt',
|
|
147
|
+
accessMode: args.accessMode,
|
|
148
|
+
inlineContextSupplied: Boolean(args.inlineContext),
|
|
149
|
+
});
|
|
150
|
+
const noRead = accessMode === 'no-read';
|
|
151
|
+
const modeLines = getPlanReviewerModeLines({
|
|
152
|
+
mode,
|
|
153
|
+
planDoc: args.planDoc,
|
|
154
|
+
parentPlanDoc: args.parentPlanDoc,
|
|
155
|
+
derivedFromScopeNumber: args.derivedFromScopeNumber,
|
|
156
|
+
});
|
|
157
|
+
const skepticismLines = getVerificationSkepticismLines({
|
|
158
|
+
reviewTarget: 'planned behavior',
|
|
159
|
+
coverageTarget: 'planned behavior',
|
|
160
|
+
coverageGapDescription: 'the plan lacks, weakens, or fails to require meaningful coverage for the riskiest planned behavior',
|
|
161
|
+
insufficientCoverageTarget: 'planned behavior',
|
|
162
|
+
mode: accessMode,
|
|
163
|
+
});
|
|
164
|
+
const reviewHistoryLine = noRead
|
|
165
|
+
? 'Prior review history and coder responses are inlined below; consider them before finalizing findings.'
|
|
166
|
+
: `Read ${args.reviewMarkdownPath} before finalizing findings so you can inspect prior review history and coder responses.`;
|
|
167
|
+
const planInspectionLine = noRead
|
|
168
|
+
? 'The reviewed plan content (and any parent plan content) is inlined below; finalize findings entirely from the inlined context in this prompt.'
|
|
169
|
+
: accessMode === 'read-only'
|
|
170
|
+
? 'The reviewed plan content is inlined below; use your read-only file tools to inspect directly referenced companion docs and repository source files before finalizing findings.'
|
|
171
|
+
: 'The reviewed plan content is inlined below; use repository tools to inspect directly referenced companion docs and repository source files before finalizing findings.';
|
|
172
|
+
if (noRead) {
|
|
173
|
+
assertNoReadPromptInstructionText([...skepticismLines, reviewHistoryLine, planInspectionLine].join('\n'), 'buildPlanReviewerPrompt');
|
|
174
|
+
}
|
|
175
|
+
return [
|
|
176
|
+
modeLines.heading,
|
|
177
|
+
`Review round: ${args.round}.`,
|
|
178
|
+
'',
|
|
179
|
+
...getAdversarialReviewDoctrineLines({
|
|
180
|
+
reviewSubject: 'the plan-readiness claim',
|
|
181
|
+
falsificationTarget: 'whether the plan is actually Neal-executable',
|
|
182
|
+
creditPhrase: 'accept it as ready',
|
|
183
|
+
claimSources: 'the plan narrative, prior review history, or operator framing',
|
|
184
|
+
judgmentTarget: 'plan readiness',
|
|
185
|
+
proofTarget: 'the plan will guide safe execution',
|
|
186
|
+
}),
|
|
187
|
+
...skepticismLines,
|
|
188
|
+
'',
|
|
189
|
+
'Produce only structured review findings.',
|
|
190
|
+
'This is a read-only plan review. Do not edit files, create scratch artifacts, stage changes, commit, or otherwise mutate the repository.',
|
|
191
|
+
'The coder owns the plan document and must declare exactly one execution shape inside it: `one_shot`, `multi_scope`, or `multi_scope_unknown`.',
|
|
192
|
+
'You must confirm the declared execution shape and echo it in the required `executionShape` field of your structured output.',
|
|
193
|
+
'Raise a blocking finding when the declared shape is missing, internally inconsistent, or not safe for neal execution.',
|
|
194
|
+
'Assess execution readiness explicitly across these dimensions: scope granularity, verification concreteness, and resume safety.',
|
|
195
|
+
...getPlanReviewFalsificationLines(),
|
|
196
|
+
'When you raise a blocking finding about execution readiness, name the failing dimension directly in the claim or required action.',
|
|
197
|
+
'Every finding must rest on concrete evidence, not assumption. Any claim about the repository’s current state — whether a file, symbol, export, or test node id exists, or whether a verification command collects or passes — must be verified by direct inspection (read the file, search the tree, collect the tests) and cite what you found; any claim about the plan must quote the exact plan text it rests on. If you cannot verify a claim, state the uncertainty instead of raising it as blocking.',
|
|
198
|
+
'Never infer the repository’s current state from what the plan proposes to change. A plan proposing to add a file, class, or test is not evidence that it already exists; a plan introducing a new abstraction is not evidence that existing code or tests are already organized around it. Confirm presence or absence against the actual tree before asserting it.',
|
|
199
|
+
'Scope granularity means boundaries stay narrow, auditable, and avoid accidental widening.',
|
|
200
|
+
'Verification concreteness means the plan uses executable verification commands or deterministic repo-derived checks rather than vague instructions.',
|
|
201
|
+
'Resume safety means scopes have clean stopping points, understandable ordering, and no hidden staging assumptions.',
|
|
202
|
+
'A plan should generally be forced to `multi_scope` when it changes orchestration behavior, resume semantics, persistence/schema shape, multiple independent subsystems, or naturally staged rollout checkpoints.',
|
|
203
|
+
'A plan should generally be forced to `multi_scope_unknown` when the work is an intentionally open-ended recurring loop that still executes one bounded scope per cycle and ends only when a stated completion condition becomes true.',
|
|
204
|
+
modeLines.blockingRule,
|
|
205
|
+
modeLines.scaffoldingRule,
|
|
206
|
+
modeLines.wideningRule,
|
|
207
|
+
'Use non_blocking severity for clarity improvements that do not block execution.',
|
|
208
|
+
modeLines.focusRule,
|
|
209
|
+
modeLines.contractRule,
|
|
210
|
+
'If the plan is already Neal-executable, confirm that quickly and return no manufactured findings.',
|
|
211
|
+
reviewHistoryLine,
|
|
212
|
+
...getAuthoredOneShotReviewerLines(args.authoredOneShot),
|
|
213
|
+
...getReviewerContextLines(args.reviewerContext, noRead ? 'inline' : 'tool-access'),
|
|
214
|
+
...getUnattendedAutonomyLines(args.unattended),
|
|
215
|
+
...getUserGuidanceLines('reviewer'),
|
|
216
|
+
'',
|
|
217
|
+
planInspectionLine,
|
|
218
|
+
...getReviewedPlanContentLines({
|
|
219
|
+
noRead,
|
|
220
|
+
planDoc: args.planDoc,
|
|
221
|
+
reviewedPlanContent: args.reviewedPlanContent,
|
|
222
|
+
parentPlanDoc: args.parentPlanDoc,
|
|
223
|
+
parentPlanContent: args.parentPlanContent,
|
|
224
|
+
}),
|
|
225
|
+
...(args.inlineContext ? ['', renderInlineReviewerContext(args.inlineContext)] : []),
|
|
226
|
+
].join('\n');
|
|
227
|
+
}
|
|
228
|
+
function getReviewedPlanContentLines(args) {
|
|
229
|
+
if (args.noRead || !args.reviewedPlanContent) {
|
|
230
|
+
return [];
|
|
231
|
+
}
|
|
232
|
+
return [
|
|
233
|
+
'',
|
|
234
|
+
`Reviewed plan content from Neal (${args.planDoc}):`,
|
|
235
|
+
'```markdown',
|
|
236
|
+
args.reviewedPlanContent,
|
|
237
|
+
'```',
|
|
238
|
+
...(args.parentPlanDoc && args.parentPlanContent
|
|
239
|
+
? [
|
|
240
|
+
'',
|
|
241
|
+
`Parent plan content from Neal (${args.parentPlanDoc}):`,
|
|
242
|
+
'```markdown',
|
|
243
|
+
args.parentPlanContent,
|
|
244
|
+
'```',
|
|
245
|
+
]
|
|
246
|
+
: []),
|
|
247
|
+
'Use the inlined plan content above as the authoritative plan text for plan-readiness review. Repository inspection should focus on validating referenced files, symbols, assumptions, and companion docs.',
|
|
248
|
+
];
|
|
249
|
+
}
|
|
250
|
+
function getReviewerContextLines(reviewerContext, mode = 'tool-access') {
|
|
251
|
+
if (!reviewerContext) {
|
|
252
|
+
return [];
|
|
253
|
+
}
|
|
254
|
+
return [
|
|
255
|
+
'',
|
|
256
|
+
'Bounded current-run continuity context:',
|
|
257
|
+
mode === 'inline' ? renderReviewerContextMarkdown(reviewerContext, { mode: 'inline' }) : reviewerContext.promptMarkdown,
|
|
258
|
+
];
|
|
259
|
+
}
|
|
260
|
+
export function buildCoderPlanResponsePrompt(args) {
|
|
261
|
+
const mode = args.mode ?? 'blocking';
|
|
262
|
+
const reviewMode = args.reviewMode ?? 'plan';
|
|
263
|
+
const spec = assertPromptBuilder('plan_author', 'buildCoderPlanResponsePrompt', PROMPT_MODULE_PATH);
|
|
264
|
+
if (!spec.variants.some((variant) => variant.kind === 'response')) {
|
|
265
|
+
throw new Error(`Prompt spec ${spec.id} is missing a response variant`);
|
|
266
|
+
}
|
|
267
|
+
return [
|
|
268
|
+
reviewMode === 'derived-plan'
|
|
269
|
+
? `Continue refining the derived implementation plan at ${args.planDoc} for scope ${args.derivedFromScopeNumber ?? 'unknown'} in parent plan ${args.parentPlanDoc ?? args.planDoc}.`
|
|
270
|
+
: `Continue refining the plan document at ${args.planDoc} into a stronger future execution plan.`,
|
|
271
|
+
'',
|
|
272
|
+
mode === 'blocking'
|
|
273
|
+
? 'Address the currently open review findings provided below.'
|
|
274
|
+
: 'The currently open review findings below are non-blocking. Decide whether to address each one now or explicitly reject/defer it with rationale.',
|
|
275
|
+
reviewMode === 'derived-plan'
|
|
276
|
+
? 'Edit only the derived plan artifact and directly related planning notes for that derived plan.'
|
|
277
|
+
: 'Edit only the plan document and directly related planning artifacts.',
|
|
278
|
+
'Do not edit runtime source code.',
|
|
279
|
+
'Do not make git commits.',
|
|
280
|
+
reviewMode === 'derived-plan'
|
|
281
|
+
? 'Keep the same target, but make the derived plan concrete enough to replace the abandoned scope safely.'
|
|
282
|
+
: 'The final file must be a pure future execution plan for `neal execute`.',
|
|
283
|
+
reviewMode === 'derived-plan'
|
|
284
|
+
? 'Do not silently widen the target or convert a real blocker into a vague replan.'
|
|
285
|
+
: 'Do not leave planning-task scaffolding behind after you respond to the findings.',
|
|
286
|
+
reviewMode === 'derived-plan'
|
|
287
|
+
? 'Revise the derived plan so it uses the same Neal-executable contract as a top-level plan. Any derived-plan-specific rationale sections are optional additive context only; they must not replace the canonical machine-consumed sections.'
|
|
288
|
+
: 'Where the current repository already answers an implementation detail, revise the plan to use the concrete existing symbol names and exports instead of leaving generic or redundant instructions.',
|
|
289
|
+
...(reviewMode === 'derived-plan' ? getDerivedPlanSectionContractLines() : []),
|
|
290
|
+
...getProtocolMarkerArtifactProhibitionLines(),
|
|
291
|
+
...(reviewMode === 'derived-plan' ? getCanonicalPlanContractLines() : []),
|
|
292
|
+
'Use `fixed` only when you actually revised the plan to resolve the finding.',
|
|
293
|
+
'Use `rejected` only when the finding is incorrect and your summary explains why.',
|
|
294
|
+
'Use `deferred` only when the finding is real but not safe to resolve without user input.',
|
|
295
|
+
'Always include a `blocker` string. Use an empty string when outcome=`responded`.',
|
|
296
|
+
mode === 'blocking'
|
|
297
|
+
? 'If required information is missing, return outcome=`blocked` and explain the concrete questions in `blocker`.'
|
|
298
|
+
: 'Return outcome=`blocked` only if you are genuinely unable to make or explain a decision on these findings.',
|
|
299
|
+
...getUserGuidanceLines('planner'),
|
|
300
|
+
'',
|
|
301
|
+
...(args.planReviewGuidance
|
|
302
|
+
? [
|
|
303
|
+
'Operator guidance for this blocked plan-review recovery:',
|
|
304
|
+
args.planReviewGuidance.message,
|
|
305
|
+
'',
|
|
306
|
+
'This guidance supplements the open reviewer findings. It does not waive plan-contract requirements, verification requirements, or the need to address blocking findings.',
|
|
307
|
+
'',
|
|
308
|
+
]
|
|
309
|
+
: []),
|
|
310
|
+
'Open findings:',
|
|
311
|
+
JSON.stringify(args.openFindings, null, 2),
|
|
312
|
+
].join('\n');
|
|
313
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// Resolve the effective doctrine access mode for a reviewer prompt builder.
|
|
2
|
+
// Precedence: an explicit accessMode wins; when absent, derive exactly the
|
|
3
|
+
// legacy two-way behavior (inline context present -> 'no-read', else
|
|
4
|
+
// 'tool-access') so existing callers render byte-identically. Inline context
|
|
5
|
+
// combined with an explicit mode other than 'no-read' is mismatched wiring
|
|
6
|
+
// (the call site inlined context for a reviewer the capability registry says
|
|
7
|
+
// can read), which is a bug rather than a render choice.
|
|
8
|
+
export function resolveReviewerPromptAccessMode(args) {
|
|
9
|
+
if (args.inlineContextSupplied && args.accessMode !== undefined && args.accessMode !== 'no-read') {
|
|
10
|
+
throw new Error(`${args.builder} received Neal-inlined reviewer context with explicit access mode ${JSON.stringify(args.accessMode)}; ` +
|
|
11
|
+
"inline context is only valid with the 'no-read' access mode");
|
|
12
|
+
}
|
|
13
|
+
if (args.accessMode !== undefined) {
|
|
14
|
+
return args.accessMode;
|
|
15
|
+
}
|
|
16
|
+
return args.inlineContextSupplied ? 'no-read' : 'tool-access';
|
|
17
|
+
}
|
|
18
|
+
export function getAdversarialReviewDoctrineLines(context) {
|
|
19
|
+
const falsificationTarget = context.falsificationTarget ?? 'the implementation';
|
|
20
|
+
const creditPhrase = context.creditPhrase ?? 'give it credit for working';
|
|
21
|
+
const claimSources = context.claimSources ?? 'the coder narrative, progress justification, or prior acceptance history';
|
|
22
|
+
const judgmentTarget = context.judgmentTarget ?? 'correctness';
|
|
23
|
+
const proofTarget = context.proofTarget ?? 'the code is sound';
|
|
24
|
+
return [
|
|
25
|
+
`Treat ${context.reviewSubject} as hostile input. Try to falsify ${falsificationTarget} before you ${creditPhrase}.`,
|
|
26
|
+
`Do not anchor on ${claimSources} when judging ${judgmentTarget}. Those are convergence signals, not proof that ${proofTarget}.`,
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
export function getCodeReviewFalsificationLines(context) {
|
|
30
|
+
const mode = context.mode ?? 'tool-access';
|
|
31
|
+
const reviewTarget = context.reviewTarget ?? 'changed behavior';
|
|
32
|
+
const rangeDiffInlined = mode === 'read-only' && context.rangeDiffInlined === true;
|
|
33
|
+
const lines = [];
|
|
34
|
+
if (context.rangeLabel) {
|
|
35
|
+
lines.push(mode === 'no-read'
|
|
36
|
+
? `The diff inlined below is the source of truth for this review of that ${context.rangeLabel}. You have no repository access; judge entirely from the inlined context in this prompt.`
|
|
37
|
+
: mode === 'read-only'
|
|
38
|
+
? rangeDiffInlined
|
|
39
|
+
? `The commit-range diff for that ${context.rangeLabel} is inlined below and is the source of truth for exactly what the ${context.rangeLabel} changed (including deletions and renames). Use your read tools to verify the surrounding code; you have no commit-range diff tool, so rely on the inlined diff for what changed.`
|
|
40
|
+
: `Review that ${context.rangeLabel} directly with your read-only repository tools: use the git_diff tool to see exactly what the ${context.rangeLabel} changed (including deletions and renames), and your read tools to verify the surrounding code. The ${context.rangeLabel} is the source of truth for this review.`
|
|
41
|
+
: `Review that ${context.rangeLabel} directly with repository tools. The ${context.rangeLabel} is the source of truth for this review.`);
|
|
42
|
+
}
|
|
43
|
+
if (mode === 'no-read') {
|
|
44
|
+
lines.push('A diff shows only changed hunks; declarations such as imports, struct fields, or helpers may exist in unchanged parts of the file. Never raise a missing-import or missing-declaration finding from absence in the diff alone — only claim one when the diff itself removes the declaration or adds a new file that lacks it. If you cannot verify such a claim from the inlined context, state the uncertainty instead of asserting a defect.');
|
|
45
|
+
}
|
|
46
|
+
if (mode === 'read-only') {
|
|
47
|
+
lines.push('A diff shows only changed hunks; declarations such as imports, struct fields, or helpers may exist in unchanged parts of the file. Absence from the diff is not evidence of absence from the repository — open the affected file with your read tools and verify before claiming a missing import or missing declaration.');
|
|
48
|
+
}
|
|
49
|
+
if (context.gitInspectionExamples) {
|
|
50
|
+
if (mode === 'tool-access') {
|
|
51
|
+
lines.push(context.gitInspectionExamples);
|
|
52
|
+
}
|
|
53
|
+
else if (mode === 'read-only') {
|
|
54
|
+
lines.push(rangeDiffInlined
|
|
55
|
+
? 'Inspect the change using the inlined commit-range diff below for what changed (including deletions and renames), then read the changed files in full with your read tools and search the tree for affected symbols and callers to verify claims.'
|
|
56
|
+
: 'Inspect the change with your read-only tools: call git_diff with the base and head commits named in this prompt (stat:true first for the changed-file overview, then per-path diffs), read the changed files in full, and search the tree for affected symbols and callers to verify claims.');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
lines.push(`Trace the changed runtime path far enough to prove the happy path is reachable and that runtime invariants, data-shape transitions, persistence, and error paths line up with the implementation claims.`, mode === 'no-read'
|
|
60
|
+
? `Compare claimed behavior against the actual code and data transitions in the ${reviewTarget}; do not accept summaries when the inlined diff gives a more direct answer.`
|
|
61
|
+
: `Compare claimed behavior against the actual code and data transitions in the ${reviewTarget}; do not accept summaries when repository inspection gives a more direct answer.`, 'For refactors and config/runtime plumbing changes, actively look for implementation-quality regressions, not just behavioral correctness. Examples include replacing a robust library with a weaker hand-rolled parser, introducing repeated disk reads or reparsing in hot paths, silently weakening error handling, or otherwise making the implementation materially less robust than the prior version.');
|
|
62
|
+
lines.push('When the requirements enumerate multiple discrete items to change — a list of identifiers, fields, files, endpoints, or call sites — enumerate them yourself and confirm each maps to a concrete change before accepting; do not accept based only on the subset the implementation happened to touch.', 'Treat an unrequested change to a public or exported symbol — a renamed or removed exported function, type, field, constant, or signature that the requirements did not call for — as scope drift and a blocking finding unless the requirements require it: an unrequested public-symbol change widens the blast radius and can break callers the diff does not show.');
|
|
63
|
+
if (context.includeExecuteFailureClasses) {
|
|
64
|
+
lines.push('Bias your search toward execute-mode failure classes in this repository: persistence or state-shape mismatches, resume or recovery transition regressions, split-plan or execution-shape contract violations, artifact or reporting mismatches, and verification that does not actually cover the changed behavior.');
|
|
65
|
+
}
|
|
66
|
+
return lines;
|
|
67
|
+
}
|
|
68
|
+
export function getVerificationSkepticismLines(context = {}) {
|
|
69
|
+
const mode = context.mode ?? 'tool-access';
|
|
70
|
+
const reviewTarget = context.reviewTarget ?? 'changed behavior';
|
|
71
|
+
const coverageTarget = context.coverageTarget;
|
|
72
|
+
const coverageLine = coverageTarget
|
|
73
|
+
? [
|
|
74
|
+
`Check whether test coverage for the ${coverageTarget} is missing or degraded.`,
|
|
75
|
+
`If ${context.coverageGapDescription ?? `the review lacks, weakens, or fails to preserve meaningful test coverage for the ${coverageTarget}`}, treat that as a review finding.`,
|
|
76
|
+
`Use blocking severity when the missing or degraded coverage leaves the ${context.insufficientCoverageTarget ?? coverageTarget} insufficiently protected.`,
|
|
77
|
+
].join(' ')
|
|
78
|
+
: 'Check whether test coverage for the changed behavior degraded. If the change removes, weakens, or fails to preserve meaningful test coverage for the affected behavior, treat that as a review finding. Use blocking severity when the missing or degraded coverage leaves the changed behavior insufficiently protected.';
|
|
79
|
+
return [
|
|
80
|
+
mode === 'no-read'
|
|
81
|
+
? 'Do not infer that verification was skipped merely because this prompt does not embed full terminal output. Treat missing verification as a finding only when the inlined context, plan requirements, or review history give concrete evidence that required verification was not run or was insufficient.'
|
|
82
|
+
: 'Do not infer that verification was skipped merely because this prompt does not embed full terminal output. Treat missing verification as a finding only when the repository state, plan requirements, or review history give concrete evidence that required verification was not run or was insufficient.',
|
|
83
|
+
`Look for verification that cannot catch the failure mode, including tests that mock away the risky runtime path or only assert mocked adapters instead of the ${reviewTarget}.`,
|
|
84
|
+
coverageLine,
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
export function getRegressionPreservationLines(context = {}) {
|
|
88
|
+
const mode = context.mode ?? 'tool-access';
|
|
89
|
+
const reviewTarget = context.reviewTarget ?? 'changed behavior';
|
|
90
|
+
return [
|
|
91
|
+
`Identify the shared subsystems the ${reviewTarget} touches: state machines, event loops, parsers or byte framing, command dispatch, storage or shared-state abstractions, startup/load paths, and long-lived session or connection state.`,
|
|
92
|
+
'Existing behavior that depends on those subsystems remains part of the contract unless the plan explicitly changes it. Do not accept solely because the newly requested behavior appears implemented; also confirm that adjacent behavior sharing those paths still holds.',
|
|
93
|
+
mode === 'no-read'
|
|
94
|
+
? 'Before accepting, either cite existing tests in the inlined context that cover the plausible regression surfaces or reason through representative existing flows in the inlined diff at the level of state transitions and data ownership.'
|
|
95
|
+
: mode === 'read-only'
|
|
96
|
+
? 'Before accepting, either cite existing tests that cover the plausible regression surfaces — reading them with your read tools — or reason through representative existing flows at the level of state transitions and data ownership.'
|
|
97
|
+
: 'Before accepting, either cite existing tests that cover the plausible regression surfaces — running them when available — or reason through representative existing flows at the level of state transitions and data ownership.',
|
|
98
|
+
`Expand this regression check only along paths the ${reviewTarget} actually touches or depends on; you do not need to re-audit unrelated parts of the project.`,
|
|
99
|
+
];
|
|
100
|
+
}
|
|
101
|
+
export function getPreexistingFailureContractLines(context = {}) {
|
|
102
|
+
const mode = context.mode ?? 'tool-access';
|
|
103
|
+
const reviewTarget = context.reviewTarget ?? 'changed behavior';
|
|
104
|
+
return [
|
|
105
|
+
`When the plan requires existing behavior to keep working, this review is not limited to newly changed lines. Apply an acceptance-surface test to any pre-existing crash, failure, flaky behavior, or anomaly reported in the coder narrative, progress justification, or review history instead of discounting it because it predates the ${reviewTarget}.`,
|
|
106
|
+
"A pre-existing failure is inside the required acceptance surface when the plan explicitly requires the affected existing behavior to keep working, when the plan's stated verification fails because of it, or when the behavior the plan delivers cannot be exercised end-to-end without the failing path. Otherwise it is outside the surface.",
|
|
107
|
+
mode === 'no-read'
|
|
108
|
+
? "For a reported pre-existing failure inside the required surface, reason through the affected existing flows using the inlined context at the level of state transitions and data ownership rather than relying on the coder's dismissal."
|
|
109
|
+
: mode === 'read-only'
|
|
110
|
+
? "For a reported pre-existing failure inside the required surface, read the most relevant existing tests and affected code with your read tools and reason through the affected existing flows directly rather than relying on the coder's dismissal."
|
|
111
|
+
: "For a reported pre-existing failure inside the required surface, exercise or reason through the affected existing flows directly — run the most relevant existing tests or reproduce the reported behavior when practical — rather than relying on the coder's dismissal.",
|
|
112
|
+
'An in-surface pre-existing failure that was neither fixed nor surfaced as a blocking concern is a blocking finding, and a dismissal without a concrete out-of-surface reason is a finding.',
|
|
113
|
+
'Conversely, treat a fix for a pre-existing issue that fails the acceptance-surface test as scope drift rather than extra credit: flag it so the change stays bounded to the plan.',
|
|
114
|
+
];
|
|
115
|
+
}
|
|
116
|
+
export function getPlanReviewFalsificationLines() {
|
|
117
|
+
return [
|
|
118
|
+
'Try to falsify whether the plan would actually guide safe execution before accepting it as ready.',
|
|
119
|
+
'Check whether the proposed scopes, sequencing, and verification would catch the riskiest failure modes instead of merely describing plausible work.',
|
|
120
|
+
'Treat vague verification, hidden state assumptions, broad blast radius, and missing resume boundaries as evidence against plan readiness.',
|
|
121
|
+
];
|
|
122
|
+
}
|
|
123
|
+
export function getFindingQualityLines(context = {}) {
|
|
124
|
+
if (context.outputContract === 'completion_verdict') {
|
|
125
|
+
return [
|
|
126
|
+
'Treat completion-blocking issues like review findings: each one needs concrete evidence, affected files or runtime behavior, and a required correction.',
|
|
127
|
+
'Use `continue_execution` only for concrete missing work that is bounded enough for one follow-on scope; use `block_for_operator` for ambiguous or externally constrained gaps.',
|
|
128
|
+
'Do not turn low-signal style preferences, trivial code-shape preferences, or optional refactors into missing work.',
|
|
129
|
+
'If the plan is complete aside from low-signal trivia, return `accept_complete` rather than inventing a non-blocking completion concern.',
|
|
130
|
+
];
|
|
131
|
+
}
|
|
132
|
+
return [
|
|
133
|
+
'Produce only structured review findings.',
|
|
134
|
+
'Use blocking severity for correctness, regression, or missing-verification issues.',
|
|
135
|
+
'Also use blocking severity for substantive robustness or performance regressions introduced by the implementation, especially in infrastructure, config, parser, caching, retry, or orchestration code.',
|
|
136
|
+
'Use non_blocking severity for suggestions that do not block acceptance.',
|
|
137
|
+
'Only emit non_blocking findings when they identify a concrete maintenance, observability, or testability issue that is genuinely worth a later follow-up turn.',
|
|
138
|
+
'Do not emit non_blocking findings for formatting, whitespace, naming preferences, trivial code-shape preferences, or optional refactors.',
|
|
139
|
+
'If the scope is acceptable aside from low-signal trivia, return no finding rather than a non_blocking note.',
|
|
140
|
+
'Every finding must name the concrete issue, identify the affected files, explain the evidence or failure scenario that makes the issue credible, and state the required correction.',
|
|
141
|
+
];
|
|
142
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { EXECUTE_SCOPE_PROGRESS_PAYLOAD_END, EXECUTE_SCOPE_PROGRESS_PAYLOAD_START, } from '../agents/schemas.js';
|
|
2
|
+
export const AUTONOMY_SCOPE_DONE = 'AUTONOMY_SCOPE_DONE';
|
|
3
|
+
export const AUTONOMY_CHUNK_DONE = 'AUTONOMY_CHUNK_DONE';
|
|
4
|
+
export const AUTONOMY_DONE = 'AUTONOMY_DONE';
|
|
5
|
+
export const AUTONOMY_BLOCKED = 'AUTONOMY_BLOCKED';
|
|
6
|
+
export const AUTONOMY_SPLIT_PLAN = 'AUTONOMY_SPLIT_PLAN';
|
|
7
|
+
// Single autonomy line rendered into agent prompts when the run is unattended.
|
|
8
|
+
// It tells the agent no operator can answer while keeping every verification
|
|
9
|
+
// requirement intact (unattended means "no human to ask", not "skip checks").
|
|
10
|
+
export const UNATTENDED_AUTONOMY_PROMPT_LINE = 'No operator is available to answer. Resolve this autonomously: do not escalate for operator guidance; make your best judgment and keep all verification requirements intact.';
|
|
11
|
+
export function getUnattendedAutonomyLines(unattended) {
|
|
12
|
+
return unattended ? [UNATTENDED_AUTONOMY_PROMPT_LINE] : [];
|
|
13
|
+
}
|
|
14
|
+
export function getCanonicalPlanContractLines() {
|
|
15
|
+
return [
|
|
16
|
+
'Choose exactly one execution shape: `one_shot`, `multi_scope`, or `multi_scope_unknown`.',
|
|
17
|
+
'Declare that choice in the plan document with a literal `## Execution Shape` section followed by exactly one line: `executionShape: one_shot`, `executionShape: multi_scope`, or `executionShape: multi_scope_unknown`.',
|
|
18
|
+
'If the plan should complete in one scope, declare `executionShape: one_shot` and keep the plan single-scope.',
|
|
19
|
+
'If the plan requires multiple scopes, declare `executionShape: multi_scope` and make scope selection and completion rules explicit.',
|
|
20
|
+
'If the plan requires one bounded recurring scope at a time but the total number of scopes is intentionally unknown at authoring time, declare `executionShape: multi_scope_unknown` and use one recurring scope template plus an explicit completion condition.',
|
|
21
|
+
'Shape-specific section rules are mandatory:',
|
|
22
|
+
'`executionShape: one_shot` must not include a literal `## Execution Queue` section, literal `## Execution Loop` section, or standalone `## Completion Condition` section.',
|
|
23
|
+
'`executionShape: multi_scope` must include a literal `## Execution Queue` section and must not include a literal `## Execution Loop` section or standalone `## Completion Condition` section.',
|
|
24
|
+
'`executionShape: multi_scope_unknown` must include a literal `## Execution Loop` section and standalone `## Completion Condition` section and must not include a literal `## Execution Queue` section.',
|
|
25
|
+
'For `multi_scope` plans, include a literal `## Execution Queue` section.',
|
|
26
|
+
'Inside `## Execution Queue`, use literal `### Scope N:` headings with contiguous numbering starting at 1.',
|
|
27
|
+
'Each `### Scope N:` entry must include these labeled bullets: `- Goal:`, `- Verification:`, and `- Success Condition:`.',
|
|
28
|
+
'For `multi_scope_unknown` plans, include a literal `## Execution Loop` section containing exactly one literal `### Recurring Scope` entry with `- Goal:`, `- Verification:`, and `- Success Condition:` bullets, followed by a literal `## Completion Condition` section.',
|
|
29
|
+
'Minimal accepted multi-scope shape:',
|
|
30
|
+
'```md',
|
|
31
|
+
'## Execution Shape',
|
|
32
|
+
'',
|
|
33
|
+
'executionShape: multi_scope',
|
|
34
|
+
'',
|
|
35
|
+
'## Execution Queue',
|
|
36
|
+
'',
|
|
37
|
+
'### Scope 1: Example scope',
|
|
38
|
+
'- Goal: Implement one bounded slice.',
|
|
39
|
+
'- Verification: `pnpm typecheck`',
|
|
40
|
+
'- Success Condition: The bounded slice is complete and verified.',
|
|
41
|
+
'```',
|
|
42
|
+
'Minimal accepted multi-scope-unknown recurring shape:',
|
|
43
|
+
'```md',
|
|
44
|
+
'## Execution Shape',
|
|
45
|
+
'',
|
|
46
|
+
'executionShape: multi_scope_unknown',
|
|
47
|
+
'',
|
|
48
|
+
'## Execution Loop',
|
|
49
|
+
'',
|
|
50
|
+
'### Recurring Scope',
|
|
51
|
+
'- Goal: Implement one bounded recurring slice.',
|
|
52
|
+
'- Verification: `pnpm typecheck`',
|
|
53
|
+
'- Success Condition: The recurring slice is complete and reviewable.',
|
|
54
|
+
'',
|
|
55
|
+
'## Completion Condition',
|
|
56
|
+
'',
|
|
57
|
+
'Stop when the explicit plan-completion condition is satisfied.',
|
|
58
|
+
'```',
|
|
59
|
+
];
|
|
60
|
+
}
|
|
61
|
+
export function getDerivedPlanSectionContractLines() {
|
|
62
|
+
return [
|
|
63
|
+
'For a derived plan, choose the declared execution shape first, then include only the orchestration sections valid for that shape.',
|
|
64
|
+
'A `multi_scope` derived plan must not include a standalone `## Completion Condition` section; that section is valid only for `multi_scope_unknown` derived plans.',
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
export function getTerminalMarkerArtifactBoundaryLines() {
|
|
68
|
+
return [
|
|
69
|
+
'Protocol markers are terminal-response control signals, not artifact content.',
|
|
70
|
+
`Never write ${AUTONOMY_DONE}, ${AUTONOMY_BLOCKED}, ${AUTONOMY_SCOPE_DONE}, or ${AUTONOMY_SPLIT_PLAN} into any authored markdown or JSON artifact unless the file is explicitly about Neal protocol markers.`,
|
|
71
|
+
'Finish writing the artifact body first, stop editing files, and then emit exactly one terminal marker only in your final terminal response.',
|
|
72
|
+
'Bad example: appending a marker line to the plan or recovery artifact itself.',
|
|
73
|
+
'Good example: leave the file content marker-free, then output the marker as the final line of your terminal response.',
|
|
74
|
+
];
|
|
75
|
+
}
|
|
76
|
+
export function getProtocolMarkerArtifactProhibitionLines() {
|
|
77
|
+
return [
|
|
78
|
+
'Protocol markers are terminal-response control signals, not artifact content.',
|
|
79
|
+
`Never write ${AUTONOMY_DONE}, ${AUTONOMY_BLOCKED}, ${AUTONOMY_SCOPE_DONE}, or ${AUTONOMY_SPLIT_PLAN} into any authored markdown or JSON artifact unless the file is explicitly about Neal protocol markers.`,
|
|
80
|
+
'Bad example: appending a marker line to the plan or recovery artifact itself.',
|
|
81
|
+
'Good example: leave the file content marker-free.',
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
export function getStandalonePlanPayloadSourceOfTruthLines(args) {
|
|
85
|
+
return [
|
|
86
|
+
`The ${args.payloadLabel} is the source of truth for derived-plan review and must contain a complete standalone ${args.planLabel} body.`,
|
|
87
|
+
`Do not commit the ${args.planLabel} to the target repository as the source of truth; repo-local notes may help while drafting, but the returned ${args.payloadLabel} must carry the full plan.`,
|
|
88
|
+
'Do not return only a file path, commit SHA, branch name, reflog entry, PR link, external artifact, or a statement that another file was committed.',
|
|
89
|
+
`${args.resetWorkLabel} may be reset before derived-plan review begins, so anything needed to execute the replacement plan must be inside the returned ${args.payloadLabel}.`,
|
|
90
|
+
];
|
|
91
|
+
}
|
|
92
|
+
export function buildProgressSection(progressText) {
|
|
93
|
+
return progressText.trim() || '(no current progress summary available)';
|
|
94
|
+
}
|
|
95
|
+
export function getExecuteScopeProgressPayloadContractLines() {
|
|
96
|
+
return [
|
|
97
|
+
`Include exactly one progress-justification JSON payload between ${EXECUTE_SCOPE_PROGRESS_PAYLOAD_START} and ${EXECUTE_SCOPE_PROGRESS_PAYLOAD_END}.`,
|
|
98
|
+
'That JSON payload must contain non-empty string fields for `milestoneTargeted`, `newEvidence`, `whyNotRedundant`, and `nextStepUnlocked`.',
|
|
99
|
+
'Keep any prose explanation or derived plan body outside that payload block.',
|
|
100
|
+
];
|
|
101
|
+
}
|