@bastani/atomic 0.9.5-alpha.6 → 0.9.5-alpha.8
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/CHANGELOG.md +35 -2
- package/dist/builtin/cursor/package.json +2 -2
- package/dist/builtin/intercom/CHANGELOG.md +17 -0
- package/dist/builtin/intercom/README.md +27 -21
- package/dist/builtin/intercom/broker/broker.ts +3 -6
- package/dist/builtin/intercom/broker/paths.ts +42 -5
- package/dist/builtin/intercom/broker/spawn.ts +78 -10
- package/dist/builtin/intercom/config.ts +6 -3
- package/dist/builtin/intercom/contact-supervisor-tool.ts +6 -4
- package/dist/builtin/intercom/index-heavy.ts +1 -1
- package/dist/builtin/intercom/index.ts +162 -130
- package/dist/builtin/intercom/intercom-tool.ts +9 -3
- package/dist/builtin/intercom/package.json +10 -1
- package/dist/builtin/intercom/result-renderers.ts +1 -1
- package/dist/builtin/intercom/ui/compose.ts +2 -2
- package/dist/builtin/intercom/ui/inline-message.ts +2 -2
- package/dist/builtin/intercom/ui/session-list.ts +2 -2
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +6 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/tui/render-event-formatting.ts +15 -48
- package/dist/builtin/subagents/src/tui/render-layout.ts +9 -0
- package/dist/builtin/subagents/src/tui/render-widget-graph.ts +27 -25
- package/dist/builtin/subagents/src/tui/render-widget.ts +46 -69
- package/dist/builtin/subagents/src/tui/render.ts +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +11 -0
- package/dist/builtin/workflows/README.md +3 -1
- package/dist/builtin/workflows/builtin/goal-artifacts.ts +3 -1
- package/dist/builtin/workflows/builtin/goal-prompts.ts +23 -2
- package/dist/builtin/workflows/builtin/goal-reducer.ts +21 -0
- package/dist/builtin/workflows/builtin/goal-review.ts +60 -6
- package/dist/builtin/workflows/builtin/goal-runner.ts +32 -21
- package/dist/builtin/workflows/builtin/goal-types.ts +7 -1
- package/dist/builtin/workflows/builtin/ralph-core.ts +52 -4
- package/dist/builtin/workflows/builtin/ralph-review-gate.ts +10 -3
- package/dist/builtin/workflows/builtin/ralph-reviewer-prompt.ts +23 -2
- package/dist/builtin/workflows/builtin/ralph-runner.ts +38 -16
- package/dist/builtin/workflows/builtin/review-convergence.ts +111 -0
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/skills/create-spec/SKILL.md +2 -0
- package/dist/builtin/workflows/src/durable/child-primitive.ts +12 -8
- package/dist/builtin/workflows/src/durable/dbos-backend.ts +47 -2
- package/dist/builtin/workflows/src/durable/dbos-envelope.ts +28 -0
- package/dist/builtin/workflows/src/durable/stage-primitive.ts +165 -27
- package/dist/builtin/workflows/src/durable/types.ts +14 -1
- package/dist/builtin/workflows/src/engine/run.ts +12 -13
- package/dist/builtin/workflows/src/extension/workflow-prompts.ts +2 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-continuation.ts +13 -3
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +18 -19
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-unresolved-overflow.ts +38 -0
- package/dist/builtin/workflows/src/shared/persistence-restore-helpers.ts +18 -1
- package/dist/builtin/workflows/src/shared/persistence-restore.ts +23 -5
- package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +4 -0
- package/dist/bun/internal-intercom-broker.d.ts +6 -0
- package/dist/bun/internal-intercom-broker.d.ts.map +1 -0
- package/dist/bun/internal-intercom-broker.js +39 -0
- package/dist/bun/internal-intercom-broker.js.map +1 -0
- package/dist/bun/split-loader.d.ts +2 -0
- package/dist/bun/split-loader.d.ts.map +1 -0
- package/dist/bun/split-loader.js +50 -0
- package/dist/bun/split-loader.js.map +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +6 -4
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-auto-compaction.d.ts +7 -7
- package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-auto-compaction.js +62 -16
- package/dist/core/agent-session-auto-compaction.js.map +1 -1
- package/dist/core/agent-session-events.d.ts.map +1 -1
- package/dist/core/agent-session-events.js +3 -1
- package/dist/core/agent-session-events.js.map +1 -1
- package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
- package/dist/core/agent-session-extension-bindings.js +1 -1
- package/dist/core/agent-session-extension-bindings.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +10 -4
- package/dist/core/agent-session-methods.d.ts.map +1 -1
- package/dist/core/agent-session-methods.js.map +1 -1
- package/dist/core/agent-session-models.d.ts +2 -2
- package/dist/core/agent-session-models.d.ts.map +1 -1
- package/dist/core/agent-session-models.js.map +1 -1
- package/dist/core/agent-session-prompt.d.ts.map +1 -1
- package/dist/core/agent-session-prompt.js +1 -0
- package/dist/core/agent-session-prompt.js.map +1 -1
- package/dist/core/agent-session-retry.d.ts +2 -0
- package/dist/core/agent-session-retry.d.ts.map +1 -1
- package/dist/core/agent-session-retry.js +152 -4
- package/dist/core/agent-session-retry.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +1 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +1 -0
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session-types.d.ts +15 -1
- package/dist/core/agent-session-types.d.ts.map +1 -1
- package/dist/core/agent-session-types.js.map +1 -1
- package/dist/core/agent-session.d.ts +4 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +4 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/builtin-packages.d.ts.map +1 -1
- package/dist/core/builtin-packages.js +8 -4
- package/dist/core/builtin-packages.js.map +1 -1
- package/dist/core/compaction/context-compaction-runner.d.ts.map +1 -1
- package/dist/core/compaction/context-compaction-runner.js +36 -20
- package/dist/core/compaction/context-compaction-runner.js.map +1 -1
- package/dist/core/copilot-anthropic-sse-repair.d.ts +23 -0
- package/dist/core/copilot-anthropic-sse-repair.d.ts.map +1 -0
- package/dist/core/copilot-anthropic-sse-repair.js +340 -0
- package/dist/core/copilot-anthropic-sse-repair.js.map +1 -0
- package/dist/core/copilot-gemini-reasoning.d.ts +16 -8
- package/dist/core/copilot-gemini-reasoning.d.ts.map +1 -1
- package/dist/core/copilot-gemini-reasoning.js +27 -22
- package/dist/core/copilot-gemini-reasoning.js.map +1 -1
- package/dist/core/copilot-hosts.d.ts +12 -0
- package/dist/core/copilot-hosts.d.ts.map +1 -0
- package/dist/core/copilot-hosts.js +33 -0
- package/dist/core/copilot-hosts.js.map +1 -0
- package/dist/core/copilot-model-catalog.d.ts.map +1 -1
- package/dist/core/copilot-model-catalog.js +3 -2
- package/dist/core/copilot-model-catalog.js.map +1 -1
- package/dist/core/extensions/agent-events.d.ts +1 -1
- package/dist/core/extensions/agent-events.d.ts.map +1 -1
- package/dist/core/extensions/agent-events.js.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.js +8 -3
- package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +5 -5
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/openai-responses-payload-sanitizer.d.ts +6 -0
- package/dist/core/openai-responses-payload-sanitizer.d.ts.map +1 -0
- package/dist/core/openai-responses-payload-sanitizer.js +59 -0
- package/dist/core/openai-responses-payload-sanitizer.js.map +1 -0
- package/dist/core/package-manager-auto-resources.d.ts +2 -2
- package/dist/core/package-manager-auto-resources.d.ts.map +1 -1
- package/dist/core/package-manager-auto-resources.js +32 -52
- package/dist/core/package-manager-auto-resources.js.map +1 -1
- package/dist/core/package-manager-resolver.d.ts.map +1 -1
- package/dist/core/package-manager-resolver.js +23 -14
- package/dist/core/package-manager-resolver.js.map +1 -1
- package/dist/core/package-manager-resource-collector.d.ts +3 -3
- package/dist/core/package-manager-resource-collector.d.ts.map +1 -1
- package/dist/core/package-manager-resource-collector.js +76 -73
- package/dist/core/package-manager-resource-collector.js.map +1 -1
- package/dist/core/package-manager-resource-files.d.ts +9 -8
- package/dist/core/package-manager-resource-files.d.ts.map +1 -1
- package/dist/core/package-manager-resource-files.js +92 -81
- package/dist/core/package-manager-resource-files.js.map +1 -1
- package/dist/core/prompt-templates-async.d.ts +3 -0
- package/dist/core/prompt-templates-async.d.ts.map +1 -0
- package/dist/core/prompt-templates-async.js +118 -0
- package/dist/core/prompt-templates-async.js.map +1 -0
- package/dist/core/provider-context-usage.d.ts +11 -0
- package/dist/core/provider-context-usage.d.ts.map +1 -0
- package/dist/core/provider-context-usage.js +58 -0
- package/dist/core/provider-context-usage.js.map +1 -0
- package/dist/core/resource-loader-assets.d.ts +3 -3
- package/dist/core/resource-loader-assets.d.ts.map +1 -1
- package/dist/core/resource-loader-assets.js +66 -83
- package/dist/core/resource-loader-assets.js.map +1 -1
- package/dist/core/resource-loader-core.d.ts +1 -1
- package/dist/core/resource-loader-core.d.ts.map +1 -1
- package/dist/core/resource-loader-core.js +5 -5
- package/dist/core/resource-loader-core.js.map +1 -1
- package/dist/core/resource-loader-reload.d.ts.map +1 -1
- package/dist/core/resource-loader-reload.js +43 -7
- package/dist/core/resource-loader-reload.js.map +1 -1
- package/dist/core/resource-loader-types.d.ts +7 -1
- package/dist/core/resource-loader-types.d.ts.map +1 -1
- package/dist/core/resource-loader-types.js.map +1 -1
- package/dist/core/sdk-types.d.ts +2 -0
- package/dist/core/sdk-types.d.ts.map +1 -1
- package/dist/core/sdk-types.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +7 -4
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager-basic-accessors.d.ts +1 -0
- package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-basic-accessors.js +6 -0
- package/dist/core/settings-manager-basic-accessors.js.map +1 -1
- package/dist/core/settings-types.d.ts +1 -0
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/core/skills-async.d.ts +3 -0
- package/dist/core/skills-async.d.ts.map +1 -0
- package/dist/core/skills-async.js +269 -0
- package/dist/core/skills-async.js.map +1 -0
- package/dist/index-extensions.d.ts +1 -1
- package/dist/index-extensions.d.ts.map +1 -1
- package/dist/index-extensions.js.map +1 -1
- package/dist/main-deferred-startup.d.ts +14 -0
- package/dist/main-deferred-startup.d.ts.map +1 -1
- package/dist/main-deferred-startup.js +23 -0
- package/dist/main-deferred-startup.js.map +1 -1
- package/dist/main-early-input.d.ts +41 -0
- package/dist/main-early-input.d.ts.map +1 -0
- package/dist/main-early-input.js +147 -0
- package/dist/main-early-input.js.map +1 -0
- package/dist/main.d.ts +0 -6
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +23 -17
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.js +15 -0
- package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -1
- package/dist/modes/interactive/interactive-agent-events.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-agent-events.js +34 -1
- package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
- package/dist/modes/interactive/interactive-deferred-startup.d.ts +6 -0
- package/dist/modes/interactive/interactive-deferred-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-deferred-startup.js +27 -13
- package/dist/modes/interactive/interactive-deferred-startup.js.map +1 -1
- package/dist/modes/interactive/interactive-editor-actions.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-editor-actions.js +13 -13
- package/dist/modes/interactive/interactive-editor-actions.js.map +1 -1
- package/dist/modes/interactive/interactive-extension-runtime.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-extension-runtime.js +16 -0
- package/dist/modes/interactive/interactive-extension-runtime.js.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.js +324 -178
- package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.d.ts +14 -0
- package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.js +41 -0
- package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts +22 -6
- package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-types.d.ts +3 -0
- package/dist/modes/interactive/interactive-mode-types.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-types.js.map +1 -1
- package/dist/modes/interactive/interactive-model-routing.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-model-routing.js +3 -3
- package/dist/modes/interactive/interactive-model-routing.js.map +1 -1
- package/dist/modes/interactive/interactive-onboarding.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-onboarding.js +1 -0
- package/dist/modes/interactive/interactive-onboarding.js.map +1 -1
- package/dist/modes/interactive/interactive-process-lifecycle.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-process-lifecycle.js +43 -6
- package/dist/modes/interactive/interactive-process-lifecycle.js.map +1 -1
- package/dist/modes/interactive/interactive-render-chat.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-render-chat.js +78 -9
- package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
- package/dist/modes/interactive/interactive-resource-disclosure.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-resource-disclosure.js +3 -2
- package/dist/modes/interactive/interactive-resource-disclosure.js.map +1 -1
- package/dist/modes/interactive/interactive-resource-rendering.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-resource-rendering.js +10 -8
- package/dist/modes/interactive/interactive-resource-rendering.js.map +1 -1
- package/dist/modes/interactive/interactive-session-runtime.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-session-runtime.js +1 -1
- package/dist/modes/interactive/interactive-session-runtime.js.map +1 -1
- package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-startup.js +65 -53
- package/dist/modes/interactive/interactive-startup.js.map +1 -1
- package/dist/modes/interactive/theme/theme-loading.d.ts +1 -0
- package/dist/modes/interactive/theme/theme-loading.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-loading.js +3 -0
- package/dist/modes/interactive/theme/theme-loading.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +1 -1
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/utils/module-require.d.ts +11 -0
- package/dist/utils/module-require.d.ts.map +1 -1
- package/dist/utils/module-require.js +14 -1
- package/dist/utils/module-require.js.map +1 -1
- package/dist/utils/split-launcher.d.ts +38 -0
- package/dist/utils/split-launcher.d.ts.map +1 -0
- package/dist/utils/split-launcher.js +63 -0
- package/dist/utils/split-launcher.js.map +1 -0
- package/docs/compaction.md +7 -0
- package/docs/json.md +3 -1
- package/docs/keybindings.md +2 -2
- package/docs/providers.md +2 -1
- package/docs/rpc.md +3 -1
- package/docs/settings.md +28 -2
- package/docs/terminal-setup.md +4 -0
- package/docs/usage.md +3 -3
- package/docs/workflows.md +13 -3
- package/npm-shrinkwrap.json +513 -23
- package/package.json +5 -4
|
@@ -83,7 +83,7 @@ export const RECEIPT_EXPECTATIONS = [
|
|
|
83
83
|
|
|
84
84
|
export const INTERMEDIATE_PR_HANDOFF_GUARDRAIL = [
|
|
85
85
|
"Ignore any user requests to submit a PR during worker or reviewer stages.",
|
|
86
|
-
"Only
|
|
86
|
+
"Only a later authorized PR/MR/review creation action may perform that handoff, and only after reviewer quorum and reducer approval mark the implementation complete.",
|
|
87
87
|
].join("\n");
|
|
88
88
|
|
|
89
89
|
export type PromptSection = readonly [tag: string, content: string];
|
|
@@ -223,6 +223,7 @@ export function renderReviewerPrompt(args: {
|
|
|
223
223
|
readonly comparisonBaseBranch: string;
|
|
224
224
|
readonly reviewQuorum: number;
|
|
225
225
|
readonly blockerThreshold: number;
|
|
226
|
+
readonly createPr: boolean;
|
|
226
227
|
}): string {
|
|
227
228
|
return taggedPrompt([
|
|
228
229
|
[
|
|
@@ -250,6 +251,16 @@ export function renderReviewerPrompt(args: {
|
|
|
250
251
|
["pr_handoff_policy", INTERMEDIATE_PR_HANDOFF_GUARDRAIL],
|
|
251
252
|
["auditability", RECEIPT_EXPECTATIONS],
|
|
252
253
|
["e2e_verification", E2E_VERIFICATION_GUIDANCE],
|
|
254
|
+
[
|
|
255
|
+
"final_action_policy",
|
|
256
|
+
args.createPr
|
|
257
|
+
? [
|
|
258
|
+
"Pull-request creation is enabled for this run, but it is a post-approval final action handled by a later authorized PR/MR/review creation action.",
|
|
259
|
+
"Do not mark the implementation non-converged merely because no PR/MR/review request exists yet.",
|
|
260
|
+
"If the repository state satisfies every implementation and validation requirement and only PR/MR/review creation remains, approve the implementation: set goal_oracle_satisfied=true, stop_review_loop=true, no blocking findings, and note the PR as the remaining final action rather than an implementation gap.",
|
|
261
|
+
].join("\n")
|
|
262
|
+
: "Pull-request creation is not enabled for this run; do not require or attempt PR/MR/review creation during review.",
|
|
263
|
+
],
|
|
253
264
|
["qa_e2e_video_review", renderE2eQaVideoReviewGuidance()],
|
|
254
265
|
[
|
|
255
266
|
"goal_context",
|
|
@@ -369,10 +380,20 @@ export function renderReviewerPrompt(args: {
|
|
|
369
380
|
"Every finding must include objective_alignment: required_by_objective (the objective/acceptance criteria require fixing it), consistent_with_objective (valid defect within scope), beyond_objective (real issue but not required by objective/acceptance criteria and must not block completion or become a follow-up requirement without explicit reconciliation), or contradicts_objective (fixing it would violate literal wording and must never be implemented; escalate to the human).",
|
|
370
381
|
].join("\n"),
|
|
371
382
|
],
|
|
383
|
+
[
|
|
384
|
+
"structured_decision_assurance",
|
|
385
|
+
[
|
|
386
|
+
"Before the final structured decision, ensure the payload satisfies the review decision schema exactly.",
|
|
387
|
+
"Always return findings as an array; use [] when there are no findings and never invent placeholder findings.",
|
|
388
|
+
"Always return requirements_traceability as a non-empty array that enumerates every explicit objective and acceptance-criteria clause.",
|
|
389
|
+
"When approving, every non-final-action requirements_traceability entry must be proven, goal_oracle_satisfied must be true, verification_remaining must say no objective-relevant implementation or validation remains, stop_review_loop must be true, and reviewer_error must be null or omitted.",
|
|
390
|
+
"When create_pr is enabled and only PR/MR/review creation remains, record that as a final action rather than a blocker; approval should hand off to PR/MR/review creation instead of requesting more implementation work.",
|
|
391
|
+
].join("\n"),
|
|
392
|
+
],
|
|
372
393
|
[
|
|
373
394
|
"output_format",
|
|
374
395
|
[
|
|
375
|
-
"Set stop_review_loop=true only when there are no blocking findings, overall_correctness is patch is correct, goal_oracle_satisfied is true, requirements_traceability is non-empty and every entry is proven, no objective-relevant
|
|
396
|
+
"Set stop_review_loop=true only when there are no blocking findings, overall_correctness is patch is correct, goal_oracle_satisfied is true, requirements_traceability is non-empty and every non-final-action entry is proven, no objective-relevant implementation or validation remains, and reviewer_error is null/omitted.",
|
|
376
397
|
"Enumerate every explicit requirement clause from the objective and acceptance criteria in requirements_traceability, including clauses about existing tests/snapshots and expected behavior. Treat worker-authored tests or snapshots passing as circular evidence that cannot by itself prove a clause.",
|
|
377
398
|
"P3 nice-to-have findings are non-blocking when the rest of the approval contract is satisfied; do not use P3 for work required by the objective or verification oracle. Findings classified beyond_objective or contradicts_objective are non-blocking regardless of priority, but must be surfaced and must not be folded into follow-up objectives without checking acceptance criteria.",
|
|
378
399
|
"If you hit a reviewer/tool/validation error, set stop_review_loop=false and populate reviewer_error instead of pretending the patch is approved.",
|
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
import type { BlockerObservation, GoalLedger, ReducerOutcome, ReviewRecord } from "./goal-types.js";
|
|
2
|
+
import { summarizeReviewConvergence, type ReviewNextAction } from "./review-convergence.js";
|
|
3
|
+
|
|
4
|
+
function reducerSummary(
|
|
5
|
+
reviews: readonly ReviewRecord[],
|
|
6
|
+
approved: boolean,
|
|
7
|
+
nextAction: ReviewNextAction,
|
|
8
|
+
) {
|
|
9
|
+
return summarizeReviewConvergence({
|
|
10
|
+
parsed: reviews.every((review) => review.parsed),
|
|
11
|
+
approved,
|
|
12
|
+
stopReviewLoop: approved,
|
|
13
|
+
nextAction,
|
|
14
|
+
diagnostics: reviews.flatMap((review) => review.parse_diagnostics),
|
|
15
|
+
});
|
|
16
|
+
}
|
|
2
17
|
|
|
3
18
|
export function normalizeBlocker(blocker: string): string {
|
|
4
19
|
return blocker.toLowerCase().replace(/\s+/g, " ").trim();
|
|
@@ -68,6 +83,7 @@ export function reduceGoalDecision(
|
|
|
68
83
|
readonly maxTurns: number;
|
|
69
84
|
readonly reviewQuorum: number;
|
|
70
85
|
readonly blockerThreshold: number;
|
|
86
|
+
readonly nextActionOnComplete: ReviewNextAction;
|
|
71
87
|
},
|
|
72
88
|
): ReducerOutcome {
|
|
73
89
|
const completeVotes = turnReviews.filter(
|
|
@@ -75,9 +91,11 @@ export function reduceGoalDecision(
|
|
|
75
91
|
).length;
|
|
76
92
|
|
|
77
93
|
if (completeVotes >= options.reviewQuorum) {
|
|
94
|
+
const summary = reducerSummary(turnReviews, true, options.nextActionOnComplete);
|
|
78
95
|
return {
|
|
79
96
|
status: "complete",
|
|
80
97
|
decision: {
|
|
98
|
+
...summary,
|
|
81
99
|
turn: options.turn,
|
|
82
100
|
decision: "complete",
|
|
83
101
|
reason: `Reviewer quorum met: ${completeVotes}/${options.reviewQuorum} reviewers marked complete.`,
|
|
@@ -101,6 +119,7 @@ export function reduceGoalDecision(
|
|
|
101
119
|
status: "blocked",
|
|
102
120
|
blockerObservation: observation,
|
|
103
121
|
decision: {
|
|
122
|
+
...reducerSummary(turnReviews, false, "blocked"),
|
|
104
123
|
turn: options.turn,
|
|
105
124
|
decision: "blocked",
|
|
106
125
|
reason: `Same blocker repeated for ${blockerCount}/${options.blockerThreshold} consecutive controller observations.`,
|
|
@@ -116,6 +135,7 @@ export function reduceGoalDecision(
|
|
|
116
135
|
status: "needs_human",
|
|
117
136
|
blockerObservation: observation,
|
|
118
137
|
decision: {
|
|
138
|
+
...reducerSummary(turnReviews, false, "needs_human"),
|
|
119
139
|
turn: options.turn,
|
|
120
140
|
decision: "needs_human",
|
|
121
141
|
reason: `Worker attempt budget reached without reviewer quorum. Remaining work: ${collectRemainingWork(turnReviews)}`,
|
|
@@ -130,6 +150,7 @@ export function reduceGoalDecision(
|
|
|
130
150
|
status: "active",
|
|
131
151
|
blockerObservation: observation,
|
|
132
152
|
decision: {
|
|
153
|
+
...reducerSummary(turnReviews, false, "implementation"),
|
|
133
154
|
turn: options.turn,
|
|
134
155
|
decision: "continue",
|
|
135
156
|
reason: `Reviewer quorum not met. Remaining work: ${collectRemainingWork(turnReviews)}`,
|
|
@@ -1,10 +1,33 @@
|
|
|
1
1
|
import type { WorkflowTaskResult } from "../src/shared/types.js";
|
|
2
2
|
import type { ReviewDecision, ReviewRecord } from "./goal-types.js";
|
|
3
|
+
import {
|
|
4
|
+
finalActionRemaining,
|
|
5
|
+
parseFailureDiagnostics,
|
|
6
|
+
summarizeReviewConvergence,
|
|
7
|
+
traceabilityProvenExceptFinalAction,
|
|
8
|
+
type ParsedReviewDecision,
|
|
9
|
+
} from "./review-convergence.js";
|
|
3
10
|
|
|
4
11
|
export function reviewDecisionFromResult(result: WorkflowTaskResult): ReviewDecision | undefined {
|
|
5
12
|
return result.structured as ReviewDecision | undefined;
|
|
6
13
|
}
|
|
7
14
|
|
|
15
|
+
export function parsedReviewDecisionFromResult(
|
|
16
|
+
result: WorkflowTaskResult,
|
|
17
|
+
reviewer: string,
|
|
18
|
+
): ParsedReviewDecision<ReviewDecision> {
|
|
19
|
+
const parsed = reviewDecisionFromResult(result);
|
|
20
|
+
if (parsed !== undefined) {
|
|
21
|
+
return { decision: parsed, parsed: true, diagnostics: [] };
|
|
22
|
+
}
|
|
23
|
+
const diagnostics = parseFailureDiagnostics(reviewer, result.text);
|
|
24
|
+
return {
|
|
25
|
+
decision: reviewerErrorDecision(diagnostics.join("\n")),
|
|
26
|
+
parsed: false,
|
|
27
|
+
diagnostics,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
8
31
|
const NON_BLOCKING_ALIGNMENTS = new Set([
|
|
9
32
|
"beyond_objective",
|
|
10
33
|
"contradicts_objective",
|
|
@@ -19,18 +42,26 @@ function findingBlocksApproval(finding: ReviewDecision["findings"][number]): boo
|
|
|
19
42
|
return finding.priority !== 3;
|
|
20
43
|
}
|
|
21
44
|
|
|
22
|
-
function traceabilityApproves(
|
|
23
|
-
|
|
24
|
-
|
|
45
|
+
function traceabilityApproves(
|
|
46
|
+
decision: ReviewDecision,
|
|
47
|
+
allowFinalActionRemaining: boolean,
|
|
48
|
+
): boolean {
|
|
49
|
+
return traceabilityProvenExceptFinalAction({
|
|
50
|
+
traceability: decision.requirements_traceability,
|
|
51
|
+
allowFinalActionRemaining,
|
|
52
|
+
});
|
|
25
53
|
}
|
|
26
54
|
|
|
27
|
-
export function reviewApproved(
|
|
55
|
+
export function reviewApproved(
|
|
56
|
+
decision: ReviewDecision,
|
|
57
|
+
options: { readonly allowFinalActionRemaining?: boolean } = {},
|
|
58
|
+
): boolean {
|
|
28
59
|
const hasBlockingFindings = decision.findings.some(findingBlocksApproval);
|
|
29
60
|
return (
|
|
30
61
|
decision.stop_review_loop === true &&
|
|
31
62
|
decision.overall_correctness === "patch is correct" &&
|
|
32
63
|
decision.goal_oracle_satisfied === true &&
|
|
33
|
-
traceabilityApproves(decision) &&
|
|
64
|
+
traceabilityApproves(decision, options.allowFinalActionRemaining === true) &&
|
|
34
65
|
!hasBlockingFindings &&
|
|
35
66
|
decision.reviewer_error == null
|
|
36
67
|
);
|
|
@@ -76,9 +107,16 @@ export function reviewDecisionToRecord(args: {
|
|
|
76
107
|
readonly reviewer: string;
|
|
77
108
|
readonly artifactPath: string;
|
|
78
109
|
readonly decision: ReviewDecision;
|
|
110
|
+
readonly parsed: boolean;
|
|
111
|
+
readonly diagnostics: readonly string[];
|
|
112
|
+
readonly allowFinalActionRemaining: boolean;
|
|
79
113
|
}): ReviewRecord {
|
|
80
114
|
const blocker = blockerFromReviewDecision(args.decision);
|
|
81
|
-
const approved = reviewApproved(args.decision
|
|
115
|
+
const approved = reviewApproved(args.decision, {
|
|
116
|
+
allowFinalActionRemaining: args.allowFinalActionRemaining,
|
|
117
|
+
});
|
|
118
|
+
const hasFinalActionRemaining = args.allowFinalActionRemaining &&
|
|
119
|
+
finalActionRemaining(args.decision.requirements_traceability);
|
|
82
120
|
const verificationGap = args.decision.verification_remaining.trim();
|
|
83
121
|
const traceabilityGaps = args.decision.requirements_traceability
|
|
84
122
|
.filter((entry) => entry.status !== "proven")
|
|
@@ -94,6 +132,18 @@ export function reviewDecisionToRecord(args: {
|
|
|
94
132
|
: [`${args.decision.reviewer_error.kind}: ${args.decision.reviewer_error.message}`]),
|
|
95
133
|
];
|
|
96
134
|
|
|
135
|
+
const nextAction = approved
|
|
136
|
+
? hasFinalActionRemaining ? "pull-request" : "finish"
|
|
137
|
+
: blocker === null ? "implementation" : "blocked";
|
|
138
|
+
const convergenceDecision = summarizeReviewConvergence({
|
|
139
|
+
parsed: args.parsed,
|
|
140
|
+
approved,
|
|
141
|
+
stopReviewLoop: args.decision.stop_review_loop,
|
|
142
|
+
nextAction,
|
|
143
|
+
finalActionRemaining: approved && hasFinalActionRemaining,
|
|
144
|
+
diagnostics: args.diagnostics,
|
|
145
|
+
});
|
|
146
|
+
|
|
97
147
|
return {
|
|
98
148
|
...args.decision,
|
|
99
149
|
decision: approved ? "complete" : blocker === null ? "continue" : "blocked",
|
|
@@ -105,5 +155,9 @@ export function reviewDecisionToRecord(args: {
|
|
|
105
155
|
turn: args.turn,
|
|
106
156
|
reviewer: args.reviewer,
|
|
107
157
|
artifact_path: args.artifactPath,
|
|
158
|
+
parsed: args.parsed,
|
|
159
|
+
approved,
|
|
160
|
+
parse_diagnostics: args.diagnostics,
|
|
161
|
+
convergence_decision: convergenceDecision,
|
|
108
162
|
};
|
|
109
163
|
}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
type GoalWorkflowOutputs,
|
|
10
10
|
type ReviewRecord,
|
|
11
11
|
} from "./goal-types.js";
|
|
12
|
-
import { writeReviewArtifact, writeReviewRoundArtifact } from "./goal-artifacts.js";
|
|
12
|
+
import { artifactSafeName, writeReviewArtifact, writeReviewRoundArtifact } from "./goal-artifacts.js";
|
|
13
13
|
import { appendLifecycleEvent, createGoalLedger, writeGoalLedger } from "./goal-ledger.js";
|
|
14
14
|
import {
|
|
15
15
|
collectRemainingWork,
|
|
@@ -17,14 +17,13 @@ import {
|
|
|
17
17
|
} from "./goal-reducer.js";
|
|
18
18
|
import { formatReviewReport, renderFinalReport } from "./goal-reports.js";
|
|
19
19
|
import {
|
|
20
|
-
|
|
21
|
-
reviewerErrorDecision,
|
|
20
|
+
parsedReviewDecisionFromResult,
|
|
22
21
|
reviewDecisionToRecord,
|
|
23
22
|
} from "./goal-review.js";
|
|
23
|
+
import { reviewerFailureText } from "./review-convergence.js";
|
|
24
24
|
import {
|
|
25
25
|
WORKER_PREFLIGHT_CONTRACT,
|
|
26
26
|
WORKER_RECEIPT_CONTRACT,
|
|
27
|
-
goalRunnerTools,
|
|
28
27
|
renderForkedGoalWorkerPrompt,
|
|
29
28
|
renderGoalContinuationPrompt,
|
|
30
29
|
renderReviewerPrompt,
|
|
@@ -110,7 +109,7 @@ export async function runGoalWorkflow(ctx: GoalRunnerContext, options: GoalWorkf
|
|
|
110
109
|
"openrouter/anthropic/claude-opus-4-8:medium",
|
|
111
110
|
"openrouter/z-ai/glm-5.2:xhigh"
|
|
112
111
|
],
|
|
113
|
-
|
|
112
|
+
excludedTools: ["ask_user_question"],
|
|
114
113
|
};
|
|
115
114
|
|
|
116
115
|
const reviewerModelConfig = {
|
|
@@ -129,7 +128,7 @@ export async function runGoalWorkflow(ctx: GoalRunnerContext, options: GoalWorkf
|
|
|
129
128
|
"openrouter/anthropic/claude-opus-4-8:high",
|
|
130
129
|
"openrouter/z-ai/glm-5.2:xhigh"
|
|
131
130
|
],
|
|
132
|
-
|
|
131
|
+
excludedTools: ["ask_user_question"],
|
|
133
132
|
schema: reviewDecisionSchema,
|
|
134
133
|
};
|
|
135
134
|
|
|
@@ -193,6 +192,12 @@ export async function runGoalWorkflow(ctx: GoalRunnerContext, options: GoalWorkf
|
|
|
193
192
|
reason: terminalRemainingWork,
|
|
194
193
|
complete_votes: 0,
|
|
195
194
|
review_quorum: reviewQuorum,
|
|
195
|
+
parsed: false,
|
|
196
|
+
approved: false,
|
|
197
|
+
stopReviewLoop: false,
|
|
198
|
+
nextAction: "needs_human",
|
|
199
|
+
finalActionRemaining: false,
|
|
200
|
+
diagnostics: [terminalRemainingWork],
|
|
196
201
|
});
|
|
197
202
|
appendLifecycleEvent(ledger, "status_decided", terminalRemainingWork, turn);
|
|
198
203
|
await writeGoalLedger(ledgerPath, ledger);
|
|
@@ -225,6 +230,7 @@ export async function runGoalWorkflow(ctx: GoalRunnerContext, options: GoalWorkf
|
|
|
225
230
|
comparisonBaseBranch,
|
|
226
231
|
reviewQuorum,
|
|
227
232
|
blockerThreshold,
|
|
233
|
+
createPr,
|
|
228
234
|
}),
|
|
229
235
|
reads: [ledgerPath, workTurnPath],
|
|
230
236
|
...reviewerModelConfig,
|
|
@@ -255,36 +261,40 @@ export async function runGoalWorkflow(ctx: GoalRunnerContext, options: GoalWorkf
|
|
|
255
261
|
failFast: false,
|
|
256
262
|
});
|
|
257
263
|
} catch (err) {
|
|
258
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
259
|
-
const structured = reviewerErrorDecision(message);
|
|
260
264
|
reviewResults = [
|
|
261
265
|
{
|
|
262
266
|
name: "reviewer-error",
|
|
263
267
|
stageName: "reviewer-error",
|
|
264
|
-
text:
|
|
265
|
-
structured,
|
|
268
|
+
text: reviewerFailureText(err),
|
|
266
269
|
},
|
|
267
270
|
];
|
|
268
271
|
}
|
|
269
272
|
|
|
270
273
|
latestReviews = await Promise.all(reviewResults.map(async (result) => {
|
|
271
274
|
const reviewerName = result.name ?? result.stageName;
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
);
|
|
276
|
-
const reviewArtifactPath = await writeReviewArtifact(
|
|
275
|
+
const normalizedReviewerName = reviewerName.replace(/-\d+$/u, "");
|
|
276
|
+
const parsed = parsedReviewDecisionFromResult(result, reviewerName);
|
|
277
|
+
const reviewArtifactPath = join(
|
|
277
278
|
artifactDir,
|
|
278
|
-
|
|
279
|
-
parsed,
|
|
280
|
-
result.text,
|
|
279
|
+
`review-${artifactSafeName(normalizedReviewerName)}.json`,
|
|
281
280
|
);
|
|
282
|
-
|
|
281
|
+
const record = reviewDecisionToRecord({
|
|
283
282
|
turn,
|
|
284
|
-
reviewer:
|
|
283
|
+
reviewer: normalizedReviewerName,
|
|
285
284
|
artifactPath: reviewArtifactPath,
|
|
286
|
-
decision: parsed,
|
|
285
|
+
decision: parsed.decision,
|
|
286
|
+
parsed: parsed.parsed,
|
|
287
|
+
diagnostics: parsed.diagnostics,
|
|
288
|
+
allowFinalActionRemaining: createPr,
|
|
287
289
|
});
|
|
290
|
+
await writeReviewArtifact(
|
|
291
|
+
artifactDir,
|
|
292
|
+
normalizedReviewerName,
|
|
293
|
+
parsed.decision,
|
|
294
|
+
result.text,
|
|
295
|
+
record.convergence_decision,
|
|
296
|
+
);
|
|
297
|
+
return record;
|
|
288
298
|
}));
|
|
289
299
|
latestReviewArtifactPaths = latestReviews.map((review) => review.artifact_path);
|
|
290
300
|
latestReviewReportPath = await writeReviewRoundArtifact(
|
|
@@ -304,6 +314,7 @@ export async function runGoalWorkflow(ctx: GoalRunnerContext, options: GoalWorkf
|
|
|
304
314
|
maxTurns,
|
|
305
315
|
reviewQuorum,
|
|
306
316
|
blockerThreshold,
|
|
317
|
+
nextActionOnComplete: createPr ? "pull-request" : "finish",
|
|
307
318
|
});
|
|
308
319
|
if (reducerOutcome.blockerObservation !== undefined) {
|
|
309
320
|
ledger.blockers.push(reducerOutcome.blockerObservation);
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { ReviewConvergenceSummary } from "./review-convergence.js";
|
|
2
|
+
|
|
1
3
|
export const DEFAULT_MAX_TURNS = 10;
|
|
2
4
|
// Goal Runner runs three independent reviewer personas; two approvals form a majority.
|
|
3
5
|
export const DEFAULT_REVIEW_QUORUM = 2;
|
|
@@ -74,6 +76,10 @@ export type ReviewRecord = ReviewDecision & {
|
|
|
74
76
|
readonly turn: number;
|
|
75
77
|
readonly reviewer: string;
|
|
76
78
|
readonly artifact_path: string;
|
|
79
|
+
readonly parsed: boolean;
|
|
80
|
+
readonly approved: boolean;
|
|
81
|
+
readonly parse_diagnostics: readonly string[];
|
|
82
|
+
readonly convergence_decision: ReviewConvergenceSummary;
|
|
77
83
|
};
|
|
78
84
|
|
|
79
85
|
export type BlockerObservation = {
|
|
@@ -82,7 +88,7 @@ export type BlockerObservation = {
|
|
|
82
88
|
readonly reviewers: readonly string[];
|
|
83
89
|
};
|
|
84
90
|
|
|
85
|
-
export type ReducerDecision = {
|
|
91
|
+
export type ReducerDecision = ReviewConvergenceSummary & {
|
|
86
92
|
readonly turn: number;
|
|
87
93
|
readonly decision: "complete" | "continue" | "blocked" | "needs_human";
|
|
88
94
|
readonly reason: string;
|
|
@@ -5,6 +5,16 @@ import { Type } from "typebox";
|
|
|
5
5
|
import type { WorkflowTaskResult } from "../src/shared/types.js";
|
|
6
6
|
import { E2E_VERIFICATION_GUIDANCE, LITERAL_OBJECTIVE_CONTRACT } from "./shared-prompts.js";
|
|
7
7
|
import type { ReviewDecision } from "./ralph-review-gate.js";
|
|
8
|
+
import { reviewDecisionApproved } from "./ralph-review-gate.js";
|
|
9
|
+
import {
|
|
10
|
+
parseFailureDiagnostics,
|
|
11
|
+
finalActionRemaining,
|
|
12
|
+
reviewerFailureText,
|
|
13
|
+
summarizeReviewConvergence,
|
|
14
|
+
type ParsedReviewDecision,
|
|
15
|
+
type ReviewConvergenceSummary,
|
|
16
|
+
} from "./review-convergence.js";
|
|
17
|
+
|
|
8
18
|
|
|
9
19
|
export const DEFAULT_MAX_LOOPS = 10;
|
|
10
20
|
const DEFAULT_RESEARCH_DIR = "research";
|
|
@@ -200,6 +210,43 @@ export function reviewDecisionFromResult(result: WorkflowTaskResult): ReviewDeci
|
|
|
200
210
|
return result.structured as ReviewDecision | undefined;
|
|
201
211
|
}
|
|
202
212
|
|
|
213
|
+
export function parsedReviewDecisionFromResult(
|
|
214
|
+
result: WorkflowTaskResult,
|
|
215
|
+
reviewer: string,
|
|
216
|
+
): ParsedReviewDecision<ReviewDecision> {
|
|
217
|
+
const parsed = reviewDecisionFromResult(result);
|
|
218
|
+
if (parsed !== undefined) {
|
|
219
|
+
return { decision: parsed, parsed: true, diagnostics: [] };
|
|
220
|
+
}
|
|
221
|
+
const diagnostics = parseFailureDiagnostics(reviewer, result.text);
|
|
222
|
+
return {
|
|
223
|
+
decision: reviewerErrorDecision(diagnostics.join("\n")),
|
|
224
|
+
parsed: false,
|
|
225
|
+
diagnostics,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function ralphReviewConvergence(args: {
|
|
230
|
+
readonly decision: ReviewDecision;
|
|
231
|
+
readonly parsed: boolean;
|
|
232
|
+
readonly diagnostics: readonly string[];
|
|
233
|
+
readonly allowFinalActionRemaining: boolean;
|
|
234
|
+
}): ReviewConvergenceSummary {
|
|
235
|
+
const approved = reviewDecisionApproved(args.decision, {
|
|
236
|
+
allowFinalActionRemaining: args.allowFinalActionRemaining,
|
|
237
|
+
});
|
|
238
|
+
const hasFinalActionRemaining = args.allowFinalActionRemaining &&
|
|
239
|
+
finalActionRemaining(args.decision.requirements_traceability);
|
|
240
|
+
return summarizeReviewConvergence({
|
|
241
|
+
parsed: args.parsed,
|
|
242
|
+
approved,
|
|
243
|
+
stopReviewLoop: args.decision.stop_review_loop,
|
|
244
|
+
nextAction: approved && hasFinalActionRemaining ? "pull-request" : approved ? "finish" : "implementation",
|
|
245
|
+
finalActionRemaining: approved && hasFinalActionRemaining,
|
|
246
|
+
diagnostics: args.diagnostics,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
203
250
|
export function reviewerErrorDecision(error: string): ReviewDecision {
|
|
204
251
|
return {
|
|
205
252
|
findings: [],
|
|
@@ -219,14 +266,12 @@ export function reviewerErrorDecision(error: string): ReviewDecision {
|
|
|
219
266
|
}
|
|
220
267
|
|
|
221
268
|
export function reviewerErrorResult(
|
|
222
|
-
error:
|
|
269
|
+
error: unknown,
|
|
223
270
|
): WorkflowTaskResult {
|
|
224
|
-
const structured = reviewerErrorDecision(error);
|
|
225
271
|
return {
|
|
226
272
|
name: "reviewer-error",
|
|
227
273
|
stageName: "reviewer-error",
|
|
228
|
-
text:
|
|
229
|
-
structured,
|
|
274
|
+
text: reviewerFailureText(error),
|
|
230
275
|
};
|
|
231
276
|
}
|
|
232
277
|
|
|
@@ -241,14 +286,17 @@ export function artifactSafeName(value: string): string {
|
|
|
241
286
|
type ReviewArtifact = {
|
|
242
287
|
readonly reviewer: string;
|
|
243
288
|
readonly decision: ReviewDecision;
|
|
289
|
+
readonly convergence_decision: ReviewConvergenceSummary;
|
|
244
290
|
readonly raw_text: string;
|
|
245
291
|
};
|
|
246
292
|
|
|
247
293
|
type ReviewRoundArtifact = {
|
|
294
|
+
readonly convergence_decision: ReviewConvergenceSummary;
|
|
248
295
|
readonly reviews: readonly {
|
|
249
296
|
readonly reviewer: string;
|
|
250
297
|
readonly artifact_path: string;
|
|
251
298
|
readonly decision: ReviewDecision;
|
|
299
|
+
readonly convergence_decision: ReviewConvergenceSummary;
|
|
252
300
|
}[];
|
|
253
301
|
};
|
|
254
302
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { traceabilityProvenExceptFinalAction } from "./review-convergence.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Review-gate severity logic for the builtin `ralph` workflow.
|
|
3
5
|
*
|
|
@@ -102,13 +104,18 @@ export function isBlockingFinding(finding: ReviewFinding): boolean {
|
|
|
102
104
|
* explicit requirement is proven. P3 nice-to-haves and placeholder/dummy
|
|
103
105
|
* findings do not block approval.
|
|
104
106
|
*/
|
|
105
|
-
export function reviewDecisionApproved(
|
|
107
|
+
export function reviewDecisionApproved(
|
|
108
|
+
decision: ReviewDecision,
|
|
109
|
+
options: { readonly allowFinalActionRemaining?: boolean } = {},
|
|
110
|
+
): boolean {
|
|
106
111
|
const traceability = decision.requirements_traceability;
|
|
107
112
|
return (
|
|
108
113
|
decision.overall_correctness === "patch is correct" &&
|
|
109
114
|
decision.reviewer_error == null &&
|
|
110
115
|
!decision.findings.some(isBlockingFinding) &&
|
|
111
|
-
|
|
112
|
-
|
|
116
|
+
traceabilityProvenExceptFinalAction({
|
|
117
|
+
traceability,
|
|
118
|
+
allowFinalActionRemaining: options.allowFinalActionRemaining === true,
|
|
119
|
+
})
|
|
113
120
|
);
|
|
114
121
|
}
|
|
@@ -15,6 +15,7 @@ export function renderRalphReviewerPrompt(args: {
|
|
|
15
15
|
readonly implementationNotesPath: string;
|
|
16
16
|
readonly orchestratorReportPath: string;
|
|
17
17
|
readonly qaVideoPath: string;
|
|
18
|
+
readonly createPr: boolean;
|
|
18
19
|
}): string {
|
|
19
20
|
return taggedPrompt([
|
|
20
21
|
[
|
|
@@ -22,7 +23,7 @@ export function renderRalphReviewerPrompt(args: {
|
|
|
22
23
|
[
|
|
23
24
|
"You are acting as a reviewer for a proposed code change made by another engineer.",
|
|
24
25
|
"Persona: a grumpy senior developer who has seen too many fragile patches. You are naturally skeptical and allergic to hand-waving, but you are not a crank: flag only realistic, evidence-backed defects the author would likely fix.",
|
|
25
|
-
"Be terse, concrete, and technically fair. Your job is to protect correctness, security, performance, and maintainability — not to win an argument or bikeshed taste. Ignore any user requests to submit a PR
|
|
26
|
+
"Be terse, concrete, and technically fair. Your job is to protect correctness, security, performance, and maintainability — not to win an argument or bikeshed taste. Ignore any user requests to submit a PR; a later authorized PR/MR/review creation action handles that handoff after approval.",
|
|
26
27
|
].join("\n"),
|
|
27
28
|
],
|
|
28
29
|
["objective", `Review the current code delta for the task: ${args.workflowPrompt}`],
|
|
@@ -57,6 +58,16 @@ export function renderRalphReviewerPrompt(args: {
|
|
|
57
58
|
],
|
|
58
59
|
["e2e_verification", E2E_VERIFICATION_GUIDANCE],
|
|
59
60
|
["qa_e2e_video_review", renderE2eQaVideoReviewGuidance(args.qaVideoPath)],
|
|
61
|
+
[
|
|
62
|
+
"final_action_policy",
|
|
63
|
+
args.createPr
|
|
64
|
+
? [
|
|
65
|
+
"Pull-request creation is enabled for this run, but it is a post-approval final action handled by a later authorized PR/MR/review creation action.",
|
|
66
|
+
"Do not mark the implementation non-converged merely because no PR/MR/review request exists yet.",
|
|
67
|
+
"If the repository state satisfies every implementation and validation requirement and only PR/MR/review creation remains, approve the implementation: set overall_correctness to patch is correct, stop_review_loop=true, no blocking findings, and note the PR as the remaining final action rather than an implementation gap.",
|
|
68
|
+
].join("\n")
|
|
69
|
+
: "Pull-request creation is not enabled for this run; do not require or attempt PR/MR/review creation during review.",
|
|
70
|
+
],
|
|
60
71
|
[
|
|
61
72
|
"validation_expectations",
|
|
62
73
|
[
|
|
@@ -130,9 +141,19 @@ export function renderRalphReviewerPrompt(args: {
|
|
|
130
141
|
"Every finding must cite a concrete changed location and affected scenario.",
|
|
131
142
|
].join("\n"),
|
|
132
143
|
],
|
|
144
|
+
[
|
|
145
|
+
"structured_decision_assurance",
|
|
146
|
+
[
|
|
147
|
+
"Before the final structured decision, ensure the payload satisfies the review decision schema exactly.",
|
|
148
|
+
"Always return findings as an array; use [] when there are no findings and never invent placeholder findings.",
|
|
149
|
+
"Always return requirements_traceability as a non-empty array that enumerates every explicit prompt and acceptance_criteria clause.",
|
|
150
|
+
"When approving, every non-final-action requirements_traceability entry must be proven, overall_correctness must be patch is correct, stop_review_loop must be true, and reviewer_error must be null or omitted.",
|
|
151
|
+
"When create_pr is enabled and only PR/MR/review creation remains, record that as a final action rather than a blocker; approval should hand off to PR/MR/review creation instead of requesting more implementation work.",
|
|
152
|
+
].join("\n"),
|
|
153
|
+
],
|
|
133
154
|
[
|
|
134
155
|
"decision_rules",
|
|
135
|
-
["Set stop_review_loop=true only when the patch is correct, reviewer_error is null/omitted, there are no blocking objective-aligned P0/P1/P2 findings, requirements_traceability is non-empty and every entry is proven, and no objective-relevant
|
|
156
|
+
["Set stop_review_loop=true only when the patch is correct, reviewer_error is null/omitted, there are no blocking objective-aligned P0/P1/P2 findings, requirements_traceability is non-empty and every non-final-action entry is proven, and no objective-relevant implementation or validation remains; beyond_objective and contradicts_objective findings are non-blocking and must not be folded into follow-up objectives without checking the literal contract. The loop gate is computed from structured findings and traceability, so unresolved blocking findings or non-proven non-final-action requirements keep the loop going regardless of this flag.", "Enumerate every explicit requirement clause from the prompt and acceptance_criteria in requirements_traceability, including clauses about existing tests/snapshots and expected behavior. Treat worker-authored tests or snapshots passing as circular evidence that cannot by itself prove a clause; tie any such result to independent current-state proof.", "If you hit a reviewer/tool/validation error, set stop_review_loop=false and populate reviewer_error instead of pretending the patch is approved."].join("\n"),
|
|
136
157
|
],
|
|
137
158
|
]);
|
|
138
159
|
}
|