@mjasnikovs/pi-task 0.38.29 → 0.38.31
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/dist/config/config.d.ts +70 -70
- package/dist/config/config.js +26 -35
- package/dist/config/extension-list.d.ts +6 -5
- package/dist/config/extension-list.js +3 -2
- package/dist/config/reasoning-args.d.ts +9 -7
- package/dist/config/reasoning-args.js +12 -10
- package/dist/config/reasoning.d.ts +44 -105
- package/dist/config/reasoning.js +27 -704
- package/dist/config/register.d.ts +34 -48
- package/dist/config/register.js +41 -51
- package/dist/config/tool-list.d.ts +16 -16
- package/dist/config/tool-list.js +1 -1
- package/dist/index.js +2 -0
- package/dist/remote/bridge.d.ts +19 -10
- package/dist/remote/bridge.js +3 -2
- package/dist/remote/broadcast.js +3 -1
- package/dist/remote/events.js +12 -11
- package/dist/remote/history.d.ts +1 -1
- package/dist/remote/protocol.d.ts +6 -3
- package/dist/remote/protocol.js +2 -1
- package/dist/remote/push.d.ts +16 -16
- package/dist/remote/push.js +27 -27
- package/dist/remote/register.d.ts +3 -3
- package/dist/remote/register.js +17 -19
- package/dist/remote/server.d.ts +9 -8
- package/dist/remote/server.js +15 -14
- package/dist/remote/session-state.d.ts +5 -4
- package/dist/remote/session-state.js +8 -5
- package/dist/remote/sw.d.ts +7 -6
- package/dist/remote/sw.js +7 -6
- package/dist/remote/tailscale.d.ts +4 -2
- package/dist/remote/tailscale.js +4 -2
- package/dist/remote/ui-highlight.js +6 -5
- package/dist/remote/ui-render.js +4 -4
- package/dist/remote/ui-script.js +24 -24
- package/dist/remote/ui-styles.d.ts +1 -1
- package/dist/remote/ui-styles.js +10 -13
- package/dist/remote/ui-tools.js +9 -6
- package/dist/shared/child-extensions.d.ts +29 -17
- package/dist/shared/child-extensions.js +29 -17
- package/dist/shared/child-output.d.ts +30 -24
- package/dist/shared/child-output.js +25 -17
- package/dist/shared/child-process.d.ts +47 -40
- package/dist/shared/child-process.js +50 -59
- package/dist/shared/command-watchdog.d.ts +85 -16
- package/dist/shared/command-watchdog.js +115 -21
- package/dist/shared/fs-text.d.ts +16 -10
- package/dist/shared/fs-text.js +16 -10
- package/dist/shared/git-runner.d.ts +25 -25
- package/dist/shared/git-runner.js +25 -25
- package/dist/shared/leaked-tool-call.d.ts +17 -11
- package/dist/shared/leaked-tool-call.js +23 -15
- package/dist/shared/model-endpoint.d.ts +29 -16
- package/dist/shared/model-endpoint.js +33 -21
- package/dist/shared/pi-invocation.d.ts +7 -4
- package/dist/shared/pi-invocation.js +12 -7
- package/dist/shared/pkg-version.d.ts +13 -5
- package/dist/shared/pkg-version.js +13 -5
- package/dist/shared/reasoning-capability.d.ts +35 -24
- package/dist/shared/reasoning-capability.js +35 -24
- package/dist/shared/stream-watchdog.d.ts +60 -44
- package/dist/shared/stream-watchdog.js +62 -45
- package/dist/task/accept-debt.d.ts +41 -43
- package/dist/task/accept-debt.js +73 -65
- package/dist/task/api-synthesis.d.ts +24 -21
- package/dist/task/api-synthesis.js +32 -26
- package/dist/task/apis-contract.d.ts +32 -64
- package/dist/task/apis-contract.js +32 -64
- package/dist/task/artifact-closure.d.ts +27 -13
- package/dist/task/artifact-closure.js +95 -67
- package/dist/task/auto-commit.d.ts +46 -35
- package/dist/task/auto-commit.js +51 -38
- package/dist/task/auto-io.d.ts +45 -25
- package/dist/task/auto-io.js +57 -29
- package/dist/task/auto-orchestrator.d.ts +26 -24
- package/dist/task/auto-orchestrator.js +192 -165
- package/dist/task/auto-prompts.d.ts +36 -24
- package/dist/task/auto-prompts.js +40 -26
- package/dist/task/autofix-ledger.d.ts +27 -25
- package/dist/task/autofix-ledger.js +29 -26
- package/dist/task/batch-test-task.d.ts +20 -12
- package/dist/task/batch-test-task.js +67 -60
- package/dist/task/boot-probe.d.ts +60 -44
- package/dist/task/boot-probe.js +91 -72
- package/dist/task/cancel-input.d.ts +30 -16
- package/dist/task/cancel-input.js +20 -11
- package/dist/task/cancel-points.d.ts +27 -20
- package/dist/task/cancel-points.js +30 -22
- package/dist/task/child-runner.d.ts +124 -55
- package/dist/task/child-runner.js +298 -90
- package/dist/task/child-status.d.ts +23 -16
- package/dist/task/child-status.js +23 -16
- package/dist/task/clamp-output.js +12 -5
- package/dist/task/command-run.d.ts +31 -28
- package/dist/task/command-run.js +44 -35
- package/dist/task/command-shrink.d.ts +25 -18
- package/dist/task/command-shrink.js +37 -31
- package/dist/task/command-watchdog.d.ts +9 -6
- package/dist/task/command-watchdog.js +21 -15
- package/dist/task/context-attribution.d.ts +34 -26
- package/dist/task/context-attribution.js +34 -26
- package/dist/task/context-silence.d.ts +39 -29
- package/dist/task/context-silence.js +35 -25
- package/dist/task/context-usage.d.ts +16 -9
- package/dist/task/context-usage.js +16 -9
- package/dist/task/contracts.d.ts +8 -4
- package/dist/task/contracts.js +25 -17
- package/dist/task/coverage-loop.d.ts +22 -18
- package/dist/task/coverage-loop.js +35 -30
- package/dist/task/critique-probes.d.ts +13 -14
- package/dist/task/critique-probes.js +50 -39
- package/dist/task/debug-log.d.ts +13 -5
- package/dist/task/debug-log.js +32 -20
- package/dist/task/decompose-fidelity.d.ts +11 -9
- package/dist/task/decompose-fidelity.js +38 -33
- package/dist/task/decompose-granularity.d.ts +41 -38
- package/dist/task/decompose-granularity.js +41 -38
- package/dist/task/deep-render-check.d.ts +22 -14
- package/dist/task/deep-render-check.js +40 -31
- package/dist/task/dropped-input.d.ts +12 -7
- package/dist/task/dropped-input.js +5 -2
- package/dist/task/enforce-attribution.d.ts +38 -47
- package/dist/task/enforce-attribution.js +46 -52
- package/dist/task/enforce-guidelines.d.ts +31 -20
- package/dist/task/enforce-guidelines.js +32 -21
- package/dist/task/enrichment.d.ts +7 -2
- package/dist/task/enrichment.js +26 -14
- package/dist/task/env-notes.d.ts +16 -7
- package/dist/task/env-notes.js +48 -31
- package/dist/task/env-template-closure.d.ts +4 -4
- package/dist/task/env-template-closure.js +42 -34
- package/dist/task/external-context.d.ts +28 -21
- package/dist/task/external-context.js +17 -12
- package/dist/task/failure-classifier.d.ts +4 -5
- package/dist/task/failure-classifier.js +30 -8
- package/dist/task/file-inventory.d.ts +15 -11
- package/dist/task/file-inventory.js +25 -22
- package/dist/task/final-gate-fix.d.ts +74 -86
- package/dist/task/final-gate-fix.js +97 -116
- package/dist/task/final-gate-progress.d.ts +29 -46
- package/dist/task/final-gate-progress.js +40 -51
- package/dist/task/final-gate.d.ts +64 -97
- package/dist/task/final-gate.js +192 -199
- package/dist/task/fix-child.d.ts +21 -27
- package/dist/task/fix-child.js +21 -27
- package/dist/task/foreign-path.d.ts +6 -5
- package/dist/task/foreign-path.js +0 -0
- package/dist/task/frozen-conflict.d.ts +9 -10
- package/dist/task/frozen-conflict.js +61 -64
- package/dist/task/frozen-path-guard.d.ts +35 -14
- package/dist/task/frozen-path-guard.js +56 -39
- package/dist/task/gate-child.d.ts +27 -28
- package/dist/task/gate-child.js +36 -35
- package/dist/task/gate-deps.d.ts +34 -27
- package/dist/task/gate-deps.js +169 -159
- package/dist/task/gate-tally.d.ts +77 -80
- package/dist/task/gate-tally.js +65 -68
- package/dist/task/git-state-guard.d.ts +15 -11
- package/dist/task/git-state-guard.js +76 -66
- package/dist/task/impl-widget.d.ts +25 -16
- package/dist/task/impl-widget.js +27 -17
- package/dist/task/implementation-guards.d.ts +26 -0
- package/dist/task/implementation-guards.js +177 -0
- package/dist/task/implementation-thinking.d.ts +33 -31
- package/dist/task/implementation-thinking.js +5 -6
- package/dist/task/implementation-turn.d.ts +39 -31
- package/dist/task/implementation-turn.js +41 -28
- package/dist/task/inline-markdown.d.ts +20 -7
- package/dist/task/inline-markdown.js +15 -6
- package/dist/task/launch-config-gap.js +25 -39
- package/dist/task/launch-contract.d.ts +18 -21
- package/dist/task/launch-contract.js +28 -30
- package/dist/task/launch-manifest.d.ts +6 -2
- package/dist/task/launch-manifest.js +35 -34
- package/dist/task/ledger.js +16 -14
- package/dist/task/lint-fix.d.ts +6 -8
- package/dist/task/lint-fix.js +67 -69
- package/dist/task/loop-detector.d.ts +27 -8
- package/dist/task/loop-detector.js +38 -14
- package/dist/task/mid-run-input.d.ts +17 -15
- package/dist/task/mid-run-input.js +17 -15
- package/dist/task/orchestrator.d.ts +24 -28
- package/dist/task/orchestrator.js +89 -66
- package/dist/task/orientation.d.ts +18 -23
- package/dist/task/orientation.js +24 -31
- package/dist/task/owned-freeze-conflict.d.ts +21 -20
- package/dist/task/owned-freeze-conflict.js +52 -85
- package/dist/task/owned-freeze-reassign.d.ts +40 -60
- package/dist/task/owned-freeze-reassign.js +41 -61
- package/dist/task/parsers.d.ts +4 -2
- package/dist/task/parsers.js +4 -4
- package/dist/task/phases.d.ts +41 -48
- package/dist/task/phases.js +196 -252
- package/dist/task/plan-io.d.ts +6 -7
- package/dist/task/plan-io.js +6 -7
- package/dist/task/plan-orchestrator.d.ts +10 -8
- package/dist/task/plan-orchestrator.js +14 -10
- package/dist/task/plan-prompts.d.ts +6 -5
- package/dist/task/plan-prompts.js +6 -5
- package/dist/task/plan-readonly.d.ts +4 -5
- package/dist/task/plan-readonly.js +4 -5
- package/dist/task/plan-rounds.d.ts +17 -29
- package/dist/task/plan-rounds.js +21 -34
- package/dist/task/plan-session.d.ts +58 -72
- package/dist/task/plan-session.js +61 -83
- package/dist/task/probe-gaming.d.ts +28 -27
- package/dist/task/probe-gaming.js +0 -0
- package/dist/task/prohibition-probe.d.ts +14 -16
- package/dist/task/prompts.d.ts +3 -4
- package/dist/task/prompts.js +17 -26
- package/dist/task/qa-transcript.d.ts +15 -22
- package/dist/task/qa-transcript.js +15 -21
- package/dist/task/question-box.d.ts +17 -13
- package/dist/task/question-box.js +19 -15
- package/dist/task/question-dedup.d.ts +6 -7
- package/dist/task/question-dedup.js +13 -14
- package/dist/task/question-dialog.d.ts +22 -32
- package/dist/task/question-dialog.js +22 -32
- package/dist/task/question-source.d.ts +18 -44
- package/dist/task/question-source.js +22 -51
- package/dist/task/refuted-constraint.d.ts +11 -31
- package/dist/task/refuted-constraint.js +27 -51
- package/dist/task/regenerable-artifacts.d.ts +12 -31
- package/dist/task/regenerable-artifacts.js +12 -31
- package/dist/task/render-check.d.ts +11 -22
- package/dist/task/render-check.js +33 -46
- package/dist/task/repo-health-check.d.ts +10 -14
- package/dist/task/repo-health-check.js +17 -23
- package/dist/task/requirements.d.ts +38 -71
- package/dist/task/requirements.js +78 -126
- package/dist/task/research-fanout-budget.d.ts +51 -88
- package/dist/task/research-fanout-budget.js +51 -88
- package/dist/task/research-worker.d.ts +29 -39
- package/dist/task/research-worker.js +37 -61
- package/dist/task/resume-gap.d.ts +14 -15
- package/dist/task/root-cause-repair.d.ts +9 -9
- package/dist/task/root-cause-repair.js +28 -40
- package/dist/task/run-bracket.d.ts +10 -13
- package/dist/task/run-end.d.ts +12 -22
- package/dist/task/run-end.js +8 -16
- package/dist/task/run-final-gate.d.ts +19 -21
- package/dist/task/run-final-gate.js +62 -80
- package/dist/task/runner-globs.d.ts +12 -13
- package/dist/task/runner-globs.js +12 -13
- package/dist/task/runner-resolve.d.ts +9 -9
- package/dist/task/runner-resolve.js +22 -23
- package/dist/task/script-escape.d.ts +10 -12
- package/dist/task/script-escape.js +13 -14
- package/dist/task/serve-entry.d.ts +1 -1
- package/dist/task/serve-entry.js +22 -25
- package/dist/task/service-blocks.js +4 -2
- package/dist/task/shipped-source.d.ts +11 -29
- package/dist/task/shipped-source.js +11 -29
- package/dist/task/skip-escape.js +10 -14
- package/dist/task/spec-urls.d.ts +26 -65
- package/dist/task/spec-urls.js +26 -65
- package/dist/task/spec-validation.d.ts +17 -20
- package/dist/task/spec-validation.js +17 -20
- package/dist/task/stall-detector.d.ts +23 -30
- package/dist/task/stall-detector.js +23 -30
- package/dist/task/stream-watchdog.d.ts +14 -12
- package/dist/task/stream-watchdog.js +14 -12
- package/dist/task/substitution-probe.d.ts +17 -20
- package/dist/task/substitution-probe.js +17 -20
- package/dist/task/task-gates.d.ts +36 -41
- package/dist/task/task-gates.js +95 -106
- package/dist/task/task-io.d.ts +4 -4
- package/dist/task/task-io.js +4 -4
- package/dist/task/task-parsers.js +4 -3
- package/dist/task/task-provenance.d.ts +2 -2
- package/dist/task/task-provenance.js +11 -13
- package/dist/task/task-types.d.ts +4 -3
- package/dist/task/terminal-outcome.d.ts +14 -16
- package/dist/task/terminal-outcome.js +12 -14
- package/dist/task/test-assembly.d.ts +13 -20
- package/dist/task/test-assembly.js +13 -20
- package/dist/task/timings.d.ts +5 -3
- package/dist/task/timings.js +5 -3
- package/dist/task/title-label.d.ts +9 -4
- package/dist/task/title-label.js +9 -4
- package/dist/task/type-only-answer.d.ts +44 -52
- package/dist/task/type-only-answer.js +44 -52
- package/dist/task/unfailable-command.d.ts +18 -24
- package/dist/task/unfailable-command.js +21 -27
- package/dist/task/unknown-routing.d.ts +10 -4
- package/dist/task/unknown-routing.js +10 -4
- package/dist/task/user-directives.d.ts +5 -8
- package/dist/task/user-directives.js +5 -8
- package/dist/task/verify-quality.d.ts +18 -22
- package/dist/task/verify-quality.js +45 -46
- package/dist/task/verify-reconcile.d.ts +15 -10
- package/dist/task/verify-reconcile.js +45 -43
- package/dist/task/verify-resolution.d.ts +24 -20
- package/dist/task/verify-resolution.js +51 -50
- package/dist/task/verify-work.d.ts +59 -66
- package/dist/task/verify-work.js +101 -138
- package/dist/task/widget.d.ts +15 -14
- package/dist/task/widget.js +22 -17
- package/dist/task/wiring-claims.d.ts +25 -32
- package/dist/task/wiring-claims.js +30 -35
- package/dist/task/write-guard.d.ts +39 -39
- package/dist/task/write-guard.js +48 -51
- package/dist/task/yolo.d.ts +34 -30
- package/dist/task/yolo.js +42 -37
- package/dist/workers/abstention.d.ts +21 -41
- package/dist/workers/abstention.js +27 -48
- package/dist/workers/brave-search.d.ts +4 -3
- package/dist/workers/brave-search.js +5 -2
- package/dist/workers/brave-warning.d.ts +7 -4
- package/dist/workers/brave-warning.js +19 -7
- package/dist/workers/ddg-search.d.ts +6 -6
- package/dist/workers/ddg-search.js +18 -12
- package/dist/workers/docs-cache.js +5 -2
- package/dist/workers/docs-chunk.d.ts +30 -37
- package/dist/workers/docs-chunk.js +37 -41
- package/dist/workers/docs-core.d.ts +28 -44
- package/dist/workers/docs-core.js +25 -44
- package/dist/workers/docs-index.js +4 -3
- package/dist/workers/docs-lookup.d.ts +15 -22
- package/dist/workers/docs-lookup.js +12 -21
- package/dist/workers/docs-project.d.ts +15 -9
- package/dist/workers/docs-project.js +17 -10
- package/dist/workers/docs-resolve.d.ts +19 -20
- package/dist/workers/docs-resolve.js +35 -32
- package/dist/workers/docs-retrieve.d.ts +5 -6
- package/dist/workers/docs-retrieve.js +18 -15
- package/dist/workers/exa-search.d.ts +9 -6
- package/dist/workers/exa-search.js +23 -12
- package/dist/workers/fetch-core.d.ts +13 -16
- package/dist/workers/fetch-core.js +23 -23
- package/dist/workers/focused-extractor.d.ts +13 -12
- package/dist/workers/focused-extractor.js +27 -19
- package/dist/workers/html-clean.js +24 -14
- package/dist/workers/http-request.d.ts +28 -20
- package/dist/workers/http-request.js +22 -17
- package/dist/workers/npm-version.d.ts +28 -11
- package/dist/workers/npm-version.js +24 -15
- package/dist/workers/phantom-imports.d.ts +15 -12
- package/dist/workers/phantom-imports.js +30 -24
- package/dist/workers/pi-worker-core.d.ts +65 -96
- package/dist/workers/pi-worker-core.js +93 -181
- package/dist/workers/pi-worker-docs.d.ts +24 -19
- package/dist/workers/pi-worker-docs.js +67 -76
- package/dist/workers/pi-worker-fetch.d.ts +7 -3
- package/dist/workers/pi-worker-fetch.js +27 -19
- package/dist/workers/pi-worker-search.js +12 -8
- package/dist/workers/pi-worker.d.ts +9 -4
- package/dist/workers/pi-worker.js +21 -14
- package/dist/workers/reasoning-warning.d.ts +18 -17
- package/dist/workers/reasoning-warning.js +22 -20
- package/dist/workers/research-cache.js +50 -78
- package/dist/workers/search-core.js +7 -5
- package/dist/workers/search-types.d.ts +10 -9
- package/dist/workers/search-types.js +9 -8
- package/dist/workers/session-hint.d.ts +13 -14
- package/dist/workers/session-hint.js +8 -9
- package/dist/workers/shared.d.ts +21 -25
- package/dist/workers/shared.js +0 -0
- package/dist/workers/single-read-extension.d.ts +14 -7
- package/dist/workers/single-read-extension.js +14 -7
- package/dist/workers/single-read-guard.d.ts +27 -30
- package/dist/workers/single-read-guard.js +36 -36
- package/dist/workers/typeonly-log.d.ts +12 -9
- package/dist/workers/typeonly-log.js +29 -33
- package/dist/workers/worker-channels.d.ts +15 -23
- package/dist/workers/worker-channels.js +15 -23
- package/dist/workers/worker-failure.d.ts +38 -46
- package/dist/workers/worker-failure.js +31 -39
- package/dist/workers/worker-kill.d.ts +25 -26
- package/dist/workers/worker-kill.js +16 -19
- package/dist/workers/worker-profiles.d.ts +54 -56
- package/dist/workers/worker-profiles.js +63 -39
- package/package.json +10 -8
package/dist/task/phases.js
CHANGED
|
@@ -23,8 +23,10 @@ import { REFINE_PROMPT, RESEARCH_FILES_PROMPT, RESEARCH_APIS_PROMPT, RESEARCH_CO
|
|
|
23
23
|
import { appendGateRecord, readSection, removeTaskSection, setTaskSection, updateTaskFrontMatter } from './task-io.js';
|
|
24
24
|
import { applyRefutations } from './refuted-constraint.js';
|
|
25
25
|
import { spawnSync } from 'node:child_process';
|
|
26
|
+
import {} from './task-types.js';
|
|
26
27
|
import { renderInlineMarkdown, stripInlineMarkdown } from './inline-markdown.js';
|
|
27
28
|
import { isDuplicateQuestion, MAX_DUP_STRIKES, DUP_REPROMPT_HINT } from './question-dedup.js';
|
|
29
|
+
import {} from './widget.js';
|
|
28
30
|
import { parseGrillQuestions, parseAutoAnswer, autoAnswerHasTag, parseVerifyToolingOutput, deriveTitle } from './parsers.js';
|
|
29
31
|
import { compressTitle } from './title-label.js';
|
|
30
32
|
import { parseVerifyBlock, validateSpecShape, validateRefineShape, stripSpecPreamble, isCritiqueClean } from './spec-validation.js';
|
|
@@ -36,7 +38,7 @@ import { readContracts, buildContractsBlock, buildContractsVerifyBlock } from '.
|
|
|
36
38
|
import { readRequirements, buildRequirementsBlock, buildOwnedRequirementsBlock, readOwnedRequirements, writeOwnedRequirements, ownedForTitle, appendOwnedConstraints } from './requirements.js';
|
|
37
39
|
import { detachUnsatisfiableRequirements, claimPendingRequirements, unclaimedPendingRequirements, formatReassignActions } from './owned-freeze-reassign.js';
|
|
38
40
|
import { trackedSourceOracle } from './owned-freeze-conflict.js';
|
|
39
|
-
import { thinkingForChild, runPhaseChild, runWithEmphasisRetry, prependHint, USER_CANCELLED } from './child-runner.js';
|
|
41
|
+
import { thinkingForChild, runPhaseChild, runWithEmphasisRetry, prependHint, USER_CANCELLED, CommandTimeoutError, isFatalChildCause } from './child-runner.js';
|
|
40
42
|
import { runResearchWorker, researchWorkerCacheHeading } from './research-worker.js';
|
|
41
43
|
import { SessionUI } from '../remote/bridge.js';
|
|
42
44
|
import { isYoloMode, yoloPickAutoAnswer } from './yolo.js';
|
|
@@ -85,14 +87,12 @@ export function replaceToolingWithVerified(research, verifiedCommands) {
|
|
|
85
87
|
}
|
|
86
88
|
// ─── Phase functions ─────────────────────────────────────────────────────────
|
|
87
89
|
// Authoritative directive that travels with the refine orientation block. Refine
|
|
88
|
-
//
|
|
89
|
-
// no signal the
|
|
90
|
-
// ("
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
// the deps). Handing refine the manifest/config CONTENT up front, with this
|
|
95
|
-
// reframe, fixes it at the origin (A/B: 1/5 → 5/5 preserve, 5/5 end-to-end).
|
|
90
|
+
// is PHASE_ORDER[0] and research is [1], so on a "scaffold the project" title
|
|
91
|
+
// refine has no signal that the manifest already exists. It can then author
|
|
92
|
+
// greenfield strip-constraints ("X is the only dependency", "exactly N scripts")
|
|
93
|
+
// which compose obeys — and the implementer rewrites the manifest from scratch,
|
|
94
|
+
// dropping every dependency and script already in it. Handing refine the
|
|
95
|
+
// manifest/config CONTENT up front, with this reframe, fixes it at the origin.
|
|
96
96
|
const REFINE_PRESERVE_DIRECTIVE = 'EXISTING FILES ON DISK — AUTHORITATIVE (overrides any "scaffold / create / set '
|
|
97
97
|
+ 'up / initialize / from scratch / only / exactly / minimal" wording in the task '
|
|
98
98
|
+ 'below): the files shown in the PROJECT ORIENTATION block ALREADY EXIST. When '
|
|
@@ -146,14 +146,13 @@ export async function phaseContractsBlock(deps) {
|
|
|
146
146
|
}
|
|
147
147
|
/**
|
|
148
148
|
* The carried-context blocks a GENERATIVE phase (refine, compose) receives: the
|
|
149
|
-
* cross-slice contracts plus the carried cross-cutting requirements
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
* /task is byte-identical to before.
|
|
149
|
+
* cross-slice contracts plus the carried cross-cutting requirements
|
|
150
|
+
* (`.pi-tasks/requirements.md`, written at plan time). The verbatim requirement
|
|
151
|
+
* quotes travel INTO every task's spec generation, so a mandated methodology
|
|
152
|
+
* ("a test lands in the same change as each new route") reaches the task's
|
|
153
|
+
* GOAL/CONSTRAINTS and its VERIFY. Content travels; a pointer back to the spec
|
|
154
|
+
* doc does not. Both blocks are '' outside a /task-auto run, so a bare /task
|
|
155
|
+
* sees no change.
|
|
157
156
|
*/
|
|
158
157
|
export async function phaseCarriedBlocks(deps) {
|
|
159
158
|
const contracts = await phaseContractsBlock(deps);
|
|
@@ -162,13 +161,13 @@ export async function phaseCarriedBlocks(deps) {
|
|
|
162
161
|
return [contracts, requirements, owned].filter(b => b.length > 0).join('\n');
|
|
163
162
|
}
|
|
164
163
|
/**
|
|
165
|
-
* The owned (task-mapped) requirements for THIS task
|
|
164
|
+
* The owned (task-mapped) requirements for THIS task: matched by
|
|
166
165
|
* the plan title the coverage map keyed them to, which is the task's stored
|
|
167
166
|
* `raw prompt` section verbatim. Empty outside /task-auto runs, for spliced
|
|
168
|
-
* repair tasks, and when the plan recorded no mapping — all of which
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
167
|
+
* repair tasks, and when the plan recorded no mapping — all of which make this a
|
|
168
|
+
* no-op. This is the BELT (a prompt block, into refine and compose);
|
|
169
|
+
* `appendOwnedConstraints` on the final spec is the BRACES. The belt is a request
|
|
170
|
+
* to the model and can be ignored; the braces are a host-side append and cannot.
|
|
172
171
|
*/
|
|
173
172
|
async function ownedForThisTask(deps) {
|
|
174
173
|
try {
|
|
@@ -196,17 +195,18 @@ function repoSourceOracle(cwd) {
|
|
|
196
195
|
});
|
|
197
196
|
}
|
|
198
197
|
/**
|
|
199
|
-
* DETACH
|
|
198
|
+
* DETACH — an owned requirement this task cannot satisfy, because a
|
|
200
199
|
* category freeze in the very spec that carries it covers the only file that
|
|
201
200
|
* could, stops being this task's obligation and is released to whichever later
|
|
202
201
|
* task writes that file.
|
|
203
202
|
*
|
|
204
203
|
* Runs at the LAST spec-producing step, where the pair first exists: the stamped
|
|
205
204
|
* bullet is written one statement earlier by `appendOwnedConstraints`, and a
|
|
206
|
-
* critique-time probe
|
|
207
|
-
* never edits prose and never asks a model —
|
|
208
|
-
*
|
|
209
|
-
*
|
|
205
|
+
* critique-time probe would find nothing because the stamp does not exist yet.
|
|
206
|
+
* It never edits prose and never asks a model — a model asked to remove a
|
|
207
|
+
* contradiction can satisfy the request by DELETING the authoritative clause,
|
|
208
|
+
* which is not satisfaction of the requirement. The quote stays in the ledger
|
|
209
|
+
* throughout; only its owner changes.
|
|
210
210
|
*/
|
|
211
211
|
export async function resolveOwnedFreezeForThisTask(deps, spec) {
|
|
212
212
|
const ledger = await readOwnedRequirements(deps.cwd).catch(() => []);
|
|
@@ -230,16 +230,16 @@ export async function resolveOwnedFreezeForThisTask(deps, spec) {
|
|
|
230
230
|
return res.spec;
|
|
231
231
|
}
|
|
232
232
|
/**
|
|
233
|
-
* CLAIM
|
|
233
|
+
* CLAIM — the other half. A requirement detached by an earlier task
|
|
234
234
|
* becomes THIS task's own when its refined prompt says it writes the frozen
|
|
235
235
|
* file. Run before compose builds its carried blocks, so the claimed obligation
|
|
236
236
|
* rides the same belt every owned requirement does and the braces stamp it onto
|
|
237
237
|
* this spec.
|
|
238
238
|
*
|
|
239
|
-
* The claimant is the only party that knows
|
|
240
|
-
* bare plan titles, and
|
|
241
|
-
*
|
|
242
|
-
*
|
|
239
|
+
* The claimant is the only party that knows. At detach time the later tasks are
|
|
240
|
+
* bare plan titles, and a plan title names a slice of behaviour rather than a
|
|
241
|
+
* file. By its own compose a task has a REFINED prompt, which does say which
|
|
242
|
+
* files it will write — and that is what `writeIntent` reads.
|
|
243
243
|
*/
|
|
244
244
|
export async function claimOwnedFreezeForThisTask(deps, refined) {
|
|
245
245
|
const ledger = await readOwnedRequirements(deps.cwd).catch(() => []);
|
|
@@ -259,24 +259,23 @@ export const phaseRefine = async (deps, raw, planContext) => {
|
|
|
259
259
|
const contracts = await phaseCarriedBlocks(deps);
|
|
260
260
|
// Imperative tool directives the user wrote into the RAW prompt ("via web
|
|
261
261
|
// search", "fetch <url>"). Refine paraphrases the task and a weak model drops
|
|
262
|
-
// these some of the time
|
|
263
|
-
//
|
|
262
|
+
// these some of the time, and a directive that vanishes at refine is gone from
|
|
263
|
+
// every later phase. Hand them to refine as a MUST-PRESERVE block (belt) and
|
|
264
264
|
// re-check the output below (lever). Empty on an ordinary prompt → refine unchanged.
|
|
265
265
|
const directives = extractUserDirectives(raw);
|
|
266
266
|
const directivesBlock = preserveDirectivesBlock(directives);
|
|
267
267
|
const refined = await runPhaseChild(deps, 'refine', 'read', REFINE_PROMPT(raw, planContext, existingFiles, contracts, directivesBlock),
|
|
268
268
|
// refine's deliverable is a 4-section text rewrite that never strictly
|
|
269
|
-
// needs a successful read
|
|
270
|
-
// existing codebase the model over-
|
|
271
|
-
//
|
|
272
|
-
//
|
|
273
|
-
//
|
|
274
|
-
// from the title + design doc alone.
|
|
269
|
+
// needs a successful read: it is producible from the title and the design
|
|
270
|
+
// doc alone. Against a large existing codebase the model can over-explore
|
|
271
|
+
// instead — re-reading source hunting for the implementation — and burn the
|
|
272
|
+
// loop budget. Degrade to a no-tools final attempt rather than hard-failing
|
|
273
|
+
// the whole run.
|
|
275
274
|
{ degradeOnExhaustion: true, verb: 'restart' });
|
|
276
275
|
// Shape check, REPORTED not enforced. Refine's four sections are what
|
|
277
276
|
// extractCapsSection, scopedToolingGoal, deriveTitle and extractEnrichTargets
|
|
278
|
-
// each look for, and all four fail SILENTLY when one is missing
|
|
279
|
-
//
|
|
277
|
+
// each look for, and all four fail SILENTLY when one is missing, so without
|
|
278
|
+
// this line the loss leaves no trace. Deliberately not a retry or a throw: refine's
|
|
280
279
|
// output is usable prose even when a heading is gone (the four consumers
|
|
281
280
|
// degrade, they do not break), and a run must not die over a heading. This
|
|
282
281
|
// puts the miss in the debug log where an audit can find it.
|
|
@@ -302,7 +301,16 @@ export async function phaseVerifyTooling(deps, research) {
|
|
|
302
301
|
try {
|
|
303
302
|
verifyOutput = await runPhaseChild(deps, 'verify-tooling', 'read,bash', VERIFY_TOOLING_PROMPT(toolingList));
|
|
304
303
|
}
|
|
305
|
-
catch {
|
|
304
|
+
catch (e) {
|
|
305
|
+
if (isFatalChildCause(e))
|
|
306
|
+
throw e;
|
|
307
|
+
// The fallback ships the tooling list UNVERIFIED, which is the right
|
|
308
|
+
// degrade for a child that merely failed. A hung command is different: it
|
|
309
|
+
// cost the ceiling on every strike and says the SPEC named something
|
|
310
|
+
// unbounded, so it is the one cause worth a trail line rather than silence.
|
|
311
|
+
if (e instanceof CommandTimeoutError) {
|
|
312
|
+
deps.logDebug?.(`verify-tooling: ${e.message} — shipping the list unverified`);
|
|
313
|
+
}
|
|
306
314
|
return replaceToolingWithVerified(research, commands);
|
|
307
315
|
}
|
|
308
316
|
const parsed = parseVerifyToolingOutput(verifyOutput);
|
|
@@ -316,10 +324,10 @@ export async function phaseVerifyTooling(deps, research) {
|
|
|
316
324
|
* The worker channels the APIS research worker is given.
|
|
317
325
|
*
|
|
318
326
|
* `pi-worker-search` + `pi-worker-fetch` ride along only when the configured
|
|
319
|
-
* engine is usable
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
327
|
+
* engine is usable. `searchConfigured` decides: exa and ddg are keyless and
|
|
328
|
+
* always usable, brave is usable only with its key. A keyless tool that errors
|
|
329
|
+
* on every call is something a weak model burns calls on; a tool the child was
|
|
330
|
+
* never handed is a channel it cannot use at all, however the prompt is worded.
|
|
323
331
|
*
|
|
324
332
|
* Both halves of "given a channel" — the tools string and the `-e` path — come
|
|
325
333
|
* from the same rows, so they cannot disagree.
|
|
@@ -335,10 +343,10 @@ export function apisWorkerChannels() {
|
|
|
335
343
|
* ddg) always are; only brave needs its API key.
|
|
336
344
|
*/
|
|
337
345
|
export function searchConfigured(getEnv = k => process.env[k], provider = getConfig().searchProvider) {
|
|
338
|
-
//
|
|
339
|
-
//
|
|
340
|
-
//
|
|
341
|
-
//
|
|
346
|
+
// Goes through `searchProviderKey`, the same lookup `search()` itself uses.
|
|
347
|
+
// Re-stating brave's env pair here would make two statements of one fact, and
|
|
348
|
+
// this is the one that decides whether the APIS worker is handed the search
|
|
349
|
+
// tool at all.
|
|
342
350
|
return searchProviderKey(provider, getEnv) !== null;
|
|
343
351
|
}
|
|
344
352
|
/** Extra prompt block for the APIS worker when search is available — trigger-framed
|
|
@@ -353,9 +361,9 @@ export const RESEARCH_SEARCH_HINT = '\n\nLIVE WEB — use pi-worker-search for e
|
|
|
353
361
|
* In-process guards loaded into the TOOLING worker only: block a re-read of any
|
|
354
362
|
* file already read, and block any byte-identical grep/find/ls repeat, feeding
|
|
355
363
|
* the model "you already have this, answer now" instead of letting it re-run.
|
|
356
|
-
* TOOLING
|
|
357
|
-
*
|
|
358
|
-
* See single-read-guard.ts.
|
|
364
|
+
* TOOLING's job is to name verification commands, so it has no reason to read a
|
|
365
|
+
* file twice or repeat a search byte for byte — which is what makes both rules
|
|
366
|
+
* safe to arm HERE and nowhere else. See single-read-guard.ts.
|
|
359
367
|
*/
|
|
360
368
|
export const SINGLE_READ_EXTENSION_PATH = fileURLToPath(new URL('../workers/single-read-extension.js', import.meta.url));
|
|
361
369
|
/**
|
|
@@ -363,15 +371,13 @@ export const SINGLE_READ_EXTENSION_PATH = fileURLToPath(new URL('../workers/sing
|
|
|
363
371
|
* cares about — never the per-file edit list. Big refined prompts embed a long
|
|
364
372
|
* bulleted "fix these files" checklist *inside* the GOAL block; handing that to
|
|
365
373
|
* a weak local model drags it into reading/grepping source it doesn't need and
|
|
366
|
-
* it loops
|
|
374
|
+
* it loops.
|
|
367
375
|
* So scope TOOLING's view to the GOAL prose, truncated at the first bullet.
|
|
368
376
|
*
|
|
369
377
|
* Fallbacks, in order: no bare `GOAL` header (free-form refined) → the whole
|
|
370
378
|
* refined unchanged; a GOAL block with no bullets → the full GOAL block. The
|
|
371
379
|
* GOAL boundary is the next bare ALL-CAPS header (CONSTRAINTS, KNOWN-UNKNOWNS,
|
|
372
|
-
* …) or end of text.
|
|
373
|
-
* bullet-heavy failure case drops 3319→329 chars with zero source-file
|
|
374
|
-
* mentions; the rest are unchanged or only lightly trimmed.
|
|
380
|
+
* …) or end of text.
|
|
375
381
|
*/
|
|
376
382
|
export function scopedToolingGoal(refined) {
|
|
377
383
|
const m = /^GOAL[ \t]*\n([\s\S]*?)(?=\n[A-Z][A-Z][A-Z -]*[ \t]*\n|$(?![\s\S]))/m.exec(refined);
|
|
@@ -400,8 +406,8 @@ async function manifestDependencyNames(cwd) {
|
|
|
400
406
|
/**
|
|
401
407
|
* Prepended to worker:apis's prompt on the ONE retry the zero-retrieval gate triggers. It
|
|
402
408
|
* names the exact failure (a section written with no retrieval) so the correction is concrete,
|
|
403
|
-
* and bounds the retrieval to the symbols about to be listed — a broad "read everything"
|
|
404
|
-
* would trade
|
|
409
|
+
* and bounds the retrieval to the symbols about to be listed — a broad "read everything"
|
|
410
|
+
* here would trade a memory-written section for a read runaway.
|
|
405
411
|
*/
|
|
406
412
|
const APIS_ZERO_RETRIEVAL_PREAMBLE = 'STOP. Your previous attempt at this task wrote a complete APIS section without calling a '
|
|
407
413
|
+ 'single retrieval tool — so every signature, type, and command in it was recalled from '
|
|
@@ -412,12 +418,11 @@ const APIS_ZERO_RETRIEVAL_PREAMBLE = 'STOP. Your previous attempt at this task w
|
|
|
412
418
|
+ 'list — no more, no less; do not read the whole tree.';
|
|
413
419
|
/**
|
|
414
420
|
* Prepended to worker:context's prompt on the ONE retry the silent-retry gate triggers. The
|
|
415
|
-
* previous attempt produced ZERO bullets
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
*
|
|
419
|
-
*
|
|
420
|
-
* bullet. It does NOT loosen the sourced-bullet invariant — it explicitly repeats that
|
|
421
|
+
* previous attempt produced ZERO bullets, which `classifyContextSilence`
|
|
422
|
+
* (context-silence.ts) has already judged a genuine loss rather than an honest empty
|
|
423
|
+
* answer. So this names that failure and steers away from the two shapes that cause it:
|
|
424
|
+
* the repeated-grep thrash that trips the loop-killer, and emitting anything that is not
|
|
425
|
+
* a bullet. It does NOT loosen the sourced-bullet invariant — it explicitly repeats that
|
|
421
426
|
* external-API semantics stay open questions unless quoted.
|
|
422
427
|
*/
|
|
423
428
|
const CONTEXT_SILENT_RETRY_PREAMBLE = 'STOP. Your previous attempt at this task produced ZERO usable bullets — either it thrashed '
|
|
@@ -448,15 +453,12 @@ export async function phaseResearch(deps, refined) {
|
|
|
448
453
|
// repo; purely additive (nothing is blocked) so it can only remove a
|
|
449
454
|
// redundant read, never hide a file.
|
|
450
455
|
//
|
|
451
|
-
// Applied to FILES and APIS only — NOT CONTEXT/TOOLING
|
|
452
|
-
//
|
|
453
|
-
//
|
|
454
|
-
//
|
|
455
|
-
//
|
|
456
|
-
//
|
|
457
|
-
// reads ~0 files regardless, so the block was pure prefill and made it slower
|
|
458
|
-
// in 5/5 reps; TOOLING is already scoped + single-read-guarded and saw no
|
|
459
|
-
// benefit. So orientation only goes where reads actually happen.
|
|
456
|
+
// Applied to FILES and APIS only — NOT CONTEXT/TOOLING, and the split is by
|
|
457
|
+
// whether the worker reads at all. FILES and APIS explore by reading, so
|
|
458
|
+
// pre-supplying the core replaces reads they would otherwise make. CONTEXT
|
|
459
|
+
// works from the inventory and grep, and TOOLING is scoped to the GOAL prose
|
|
460
|
+
// and single-read-guarded, so for those two the block is pure prefill with no
|
|
461
|
+
// read to displace. Orientation only goes where reads actually happen.
|
|
460
462
|
const orientationPaths = getConfig().orientation && inventoryRaw.length > 0 ?
|
|
461
463
|
inventoryRaw.split('\n').filter(l => l.trim().length > 0)
|
|
462
464
|
: [];
|
|
@@ -476,25 +478,20 @@ export async function phaseResearch(deps, refined) {
|
|
|
476
478
|
// Judged against the EXTERNAL CONTEXT this run actually gathered — the same string
|
|
477
479
|
// the worker is handed below — and the manifest's dependency names.
|
|
478
480
|
const manifestPackages = await manifestDependencyNames(deps.cwd);
|
|
479
|
-
//
|
|
480
|
-
//
|
|
481
|
-
//
|
|
482
|
-
//
|
|
483
|
-
//
|
|
484
|
-
//
|
|
485
|
-
//
|
|
486
|
-
//
|
|
487
|
-
// nexttask 5B fan-out bounds. All four read their env ONCE per research
|
|
488
|
-
// phase, so every worker in a run sees the same policy and a harness cannot
|
|
489
|
-
// half-apply an arm. CAP, SCALE and carry-forward are null/false in the
|
|
490
|
-
// shipped configuration; the progress deadline shipped ON (nexttask 9).
|
|
481
|
+
// The spec-cited-URL lever from ./spec-urls.ts is built and unit-tested but is
|
|
482
|
+
// NOT WIRED HERE: pointing the worker at a page it should have read did not
|
|
483
|
+
// change what it produced, so the block would be prefill on every APIS prompt
|
|
484
|
+
// for nothing.
|
|
485
|
+
// Research fan-out bounds, read from the environment ONCE per research phase,
|
|
486
|
+
// so every worker in a run sees the same policy and a harness cannot half-apply
|
|
487
|
+
// one. In the shipped configuration the budget knobs are unset and the progress
|
|
488
|
+
// deadline is on.
|
|
491
489
|
const leverEnv = snapshotLeverEnv();
|
|
492
490
|
const fanoutBudget = projectDocsBudget(leverEnv);
|
|
493
491
|
const progressCeilingMs = workerProgressCeilingMs(leverEnv);
|
|
494
|
-
// Which deadline policy was in force
|
|
495
|
-
//
|
|
496
|
-
//
|
|
497
|
-
// not say which policy it ran under cannot be compared with one that does.
|
|
492
|
+
// Which deadline policy was in force decides what every worker timing below
|
|
493
|
+
// means, and the two policies are not comparable. Logging it is what makes a
|
|
494
|
+
// trail readable after the fact.
|
|
498
495
|
deps.logDebug?.(progressCeilingMs === null ?
|
|
499
496
|
'phase:research: worker deadline = fixed elapsed cap (progress deadline DISABLED)'
|
|
500
497
|
: `phase:research: worker deadline = no-progress, ceiling ${progressCeilingMs}ms`);
|
|
@@ -512,10 +509,9 @@ export async function phaseResearch(deps, refined) {
|
|
|
512
509
|
// wall-clock-relative (queueing shows up in waitMs).
|
|
513
510
|
//
|
|
514
511
|
// Restarted attempts get their OWN row. Without one the widget contradicts
|
|
515
|
-
// itself:
|
|
516
|
-
//
|
|
517
|
-
//
|
|
518
|
-
// gap, so naming it is what closes the widget.
|
|
512
|
+
// itself: waitMs and workMs describe only the FINAL attempt while the phase
|
|
513
|
+
// clock counts every attempt, so the phase total exceeds its longest member by
|
|
514
|
+
// the time the discarded attempts took. Naming that gap is what reconciles them.
|
|
519
515
|
const recordWorker = (label, p) => p.then(r => {
|
|
520
516
|
deps.recordSubStep?.(`${label} wait`, r.waitMs);
|
|
521
517
|
deps.recordSubStep?.(`${label} work`, r.workMs);
|
|
@@ -524,33 +520,15 @@ export async function phaseResearch(deps, refined) {
|
|
|
524
520
|
}
|
|
525
521
|
return r;
|
|
526
522
|
});
|
|
527
|
-
// Run the four workers ONE AT A TIME.
|
|
528
|
-
//
|
|
529
|
-
//
|
|
530
|
-
//
|
|
531
|
-
//
|
|
532
|
-
//
|
|
533
|
-
//
|
|
534
|
-
// each other ~4x (context worker measured 27s solo vs 128s under load),
|
|
535
|
-
// so summed-but-fast (~100s) beats max-of-slowed (~130s).
|
|
536
|
-
//
|
|
537
|
-
// KNOWN-OPEN, AND THIS IS THE HONEST STATE OF IT. That A/B was run when
|
|
538
|
-
// every worker carried Qwen3's `/no_think` prompt suffix, so "thinking OFF"
|
|
539
|
-
// was assumed and sequential followed. The suffix has since been measured
|
|
540
|
-
// INERT — with server thinking on and `/no_think` still in the prompt,
|
|
541
|
-
// Qwen3.8 emitted a median 17k-char trace anyway (n=25) — and it has been
|
|
542
|
-
// removed in favour of the `research` reasoning group (config/reasoning.ts).
|
|
543
|
-
// So the arm this default was chosen under may never have been the arm that
|
|
544
|
-
// ran, and the group's level is now a user-visible setting rather than a
|
|
523
|
+
// Run the four workers ONE AT A TIME by default. Which order wins depends on
|
|
524
|
+
// the backend: concurrent streams share one local GPU and slow each other
|
|
525
|
+
// down, so the sum of four fast workers can beat the max of four slowed ones,
|
|
526
|
+
// while a backend that genuinely serves parallel streams has no such tradeoff.
|
|
527
|
+
// `parallelResearchWorkers` is the opt-in for those backends. The worker's
|
|
528
|
+
// reasoning level (config/reasoning.ts `research` group) changes decode length
|
|
529
|
+
// and so changes the answer too, which is why this is a config knob and not a
|
|
545
530
|
// constant.
|
|
546
531
|
//
|
|
547
|
-
// The default stays SEQUENTIAL because that is the measured-safe arm on a
|
|
548
|
-
// single-GPU box and because flipping a shipped default on an invalidated
|
|
549
|
-
// premise would be replacing one unmeasured claim with another. The
|
|
550
|
-
// parallel x reasoning-level interaction is unmeasured; re-run the A/B
|
|
551
|
-
// before changing this, and treat `parallelResearchWorkers` as the opt-in
|
|
552
|
-
// for backends that genuinely serve parallel streams.
|
|
553
|
-
//
|
|
554
532
|
// Result order (files, apis, context, tooling) is preserved for assembly.
|
|
555
533
|
// Resolved once: `searchConfigured()` reads the environment, and the tools
|
|
556
534
|
// string and the `-e` paths must be derived from the SAME answer.
|
|
@@ -568,46 +546,38 @@ export async function phaseResearch(deps, refined) {
|
|
|
568
546
|
// Read-heavy: gets the orientation core (see note above). Search/fetch
|
|
569
547
|
// ride along only when a Brave key exists — see SEARCH_EXTENSION_PATH.
|
|
570
548
|
// FILES' finished map rides along when available (serial default), so
|
|
571
|
-
// the worker doesn't re-derive where-things-live
|
|
572
|
-
// queries the FILES worker just answered
|
|
573
|
-
// duplicate `.`-decodes per task through the serial bottleneck).
|
|
549
|
+
// the worker doesn't re-derive where-things-live through project-docs
|
|
550
|
+
// queries the FILES worker just answered.
|
|
574
551
|
prompt: prior => orientation.block
|
|
575
552
|
+ promptHeader
|
|
576
553
|
+ RESEARCH_APIS_PROMPT(refined, prior.find(s => s.name === 'FILES')?.text || undefined)
|
|
577
554
|
+ (searchConfigured() ? RESEARCH_SEARCH_HINT : '')
|
|
578
|
-
//
|
|
579
|
-
//
|
|
580
|
-
//
|
|
581
|
-
// to the worker as a broken tool.
|
|
555
|
+
// Empty unless PI_TASK_PROJECT_DOCS_BUDGET is set. The tool-side
|
|
556
|
+
// half lives in pi-worker-docs.ts; a budget enforced without being
|
|
557
|
+
// announced would just read to the worker as a broken tool.
|
|
582
558
|
+ (fanoutBudget === null ? '' : projectDocsBudgetNotice(fanoutBudget)),
|
|
583
559
|
// The tools string and the `-e` paths are ONE fact — which worker
|
|
584
|
-
// channels this research worker is given — and
|
|
560
|
+
// channels this research worker is given — and would otherwise be two literals
|
|
585
561
|
// kept in step by eye. `channelSet` derives both from the same rows.
|
|
586
562
|
tools: `read,grep,find,ls,${apisChannels.tools}`,
|
|
587
563
|
fanoutBounded: true,
|
|
588
564
|
extensions: apisChannels.extensions,
|
|
589
|
-
// ZERO-RETRIEVAL GATE
|
|
590
|
-
//
|
|
591
|
-
//
|
|
592
|
-
//
|
|
593
|
-
//
|
|
594
|
-
//
|
|
595
|
-
//
|
|
596
|
-
//
|
|
597
|
-
//
|
|
598
|
-
//
|
|
599
|
-
// from the near-runaway 37-read tail.
|
|
565
|
+
// ZERO-RETRIEVAL GATE. worker:apis can emit a complete, plausible APIS
|
|
566
|
+
// section having made ZERO retrieval tool calls — the whole thing recalled
|
|
567
|
+
// from memory. RESEARCH_APIS_PROMPT already instructs tool use, so another
|
|
568
|
+
// instruction is not the answer; this is a deterministic gate instead.
|
|
569
|
+
// `groundingRetrievalCount === 0` on a NON-EMPTY section is ungrounded by
|
|
570
|
+
// construction, with no semantic judgement needed. The forced-retrieval
|
|
571
|
+
// retry recovers a grounded section rather than silencing the worker (the
|
|
572
|
+
// original is kept if the retry still retrieves nothing, so the entry count
|
|
573
|
+
// cannot collapse), and it bounds itself — "look up the symbols you will
|
|
574
|
+
// list — no more" — away from a read runaway.
|
|
600
575
|
//
|
|
601
|
-
//
|
|
602
|
-
//
|
|
603
|
-
//
|
|
604
|
-
//
|
|
605
|
-
//
|
|
606
|
-
// established: the gate is correct BY CONSTRUCTION; on the 3 firings observed it
|
|
607
|
-
// recovered a grounded section every time; and it did NO harm (ungrounded-symbol rate
|
|
608
|
-
// went DOWN not up, no entry collapse, no runaway, cost +4-6%). It is wired as a
|
|
609
|
-
// harmless safety net, NOT a proven-effective lever — do not cite it as a measured win
|
|
610
|
-
// (nexxtasks.txt "ZERO-RETRIEVAL GATE ... ABSTAIN"). A powered A/B is STILL OPEN.
|
|
576
|
+
// A SAFETY NET, NOT A DEMONSTRATED WIN. The failure it catches is
|
|
577
|
+
// intermittent, and nothing here establishes how often it fires or what it
|
|
578
|
+
// is worth. What the code does establish is that it cannot make things
|
|
579
|
+
// worse: it only ever replaces a zero-retrieval section with a retrieving
|
|
580
|
+
// one.
|
|
611
581
|
zeroRetrievalRetry: APIS_ZERO_RETRIEVAL_PREAMBLE
|
|
612
582
|
},
|
|
613
583
|
{
|
|
@@ -619,30 +589,26 @@ export async function phaseResearch(deps, refined) {
|
|
|
619
589
|
// spawning long enumeration loops whose output then inflates
|
|
620
590
|
// prefill on every subsequent round.
|
|
621
591
|
//
|
|
622
|
-
//
|
|
623
|
-
//
|
|
624
|
-
//
|
|
625
|
-
//
|
|
626
|
-
//
|
|
627
|
-
// APIS' own answers are the ones F-2 shows are type-only and unverified.
|
|
592
|
+
// ISOLATED on purpose: this worker is NOT given the APIS worker's output.
|
|
593
|
+
// It keeps `read,grep` and is forbidden — by prompt and by the post-check
|
|
594
|
+
// below — from asserting external-API behaviour it cannot see. Handing it
|
|
595
|
+
// the APIS section would widen what it may assert without making any of it
|
|
596
|
+
// checkable here.
|
|
628
597
|
tools: 'read,grep',
|
|
629
|
-
// SILENT-RETRY GATE.
|
|
630
|
-
//
|
|
631
|
-
//
|
|
632
|
-
//
|
|
633
|
-
//
|
|
634
|
-
// retry once, keep the retry only if it emits bullets. See context-silence.ts.
|
|
598
|
+
// SILENT-RETRY GATE. This worker can come back with zero bullets. The two
|
|
599
|
+
// causes `classifyContextSilence` recognises — a loop-degrade banner, and a
|
|
600
|
+
// hallucinated non-bullet fragment — are both dropped sections, not honest
|
|
601
|
+
// empty answers, so retry once and keep the retry only if it emits bullets.
|
|
602
|
+
// See context-silence.ts.
|
|
635
603
|
retryIfSilent: CONTEXT_SILENT_RETRY_PREAMBLE,
|
|
636
|
-
// BRACES for the LIVE-DATA RULE
|
|
637
|
-
// `
|
|
638
|
-
//
|
|
639
|
-
//
|
|
640
|
-
//
|
|
641
|
-
//
|
|
642
|
-
//
|
|
643
|
-
//
|
|
644
|
-
// persisted — so it cannot reach compose as fact. Demotion, not deletion: the
|
|
645
|
-
// bullet count is preserved, because a silenced worker is a different
|
|
604
|
+
// BRACES for the LIVE-DATA RULE (the belt is the prompt). This worker has
|
|
605
|
+
// `read,grep` only, so it cannot have read a doc — yet it can write one
|
|
606
|
+
// bullet that fuses a fact it DID read from the manifest with an external-API
|
|
607
|
+
// claim it did not, under a single "per the docs" attribution. Fused that
|
|
608
|
+
// way the whole bullet reads as sourced and can become a hard CONSTRAINT.
|
|
609
|
+
// A flagged bullet is demoted to an OPEN QUESTION here — before the section
|
|
610
|
+
// is persisted — so it cannot reach compose as fact. Demotion, not deletion:
|
|
611
|
+
// the bullet count is preserved, because a silenced worker is a different
|
|
646
612
|
// regression.
|
|
647
613
|
postProcess: text => {
|
|
648
614
|
const r = demoteUnsourcedAttributions(text, externalContext, manifestPackages);
|
|
@@ -684,10 +650,10 @@ export async function phaseResearch(deps, refined) {
|
|
|
684
650
|
taskId: deps.taskId,
|
|
685
651
|
signal: deps.signal,
|
|
686
652
|
spawn: deps.spawn,
|
|
687
|
-
// ONE CELL PER WORKER
|
|
688
|
-
//
|
|
689
|
-
//
|
|
690
|
-
//
|
|
653
|
+
// ONE CELL PER WORKER. The four are the same job over four
|
|
654
|
+
// questions, so one shared `research` cell is the tempting shape —
|
|
655
|
+
// but the four cells do not ship identical, so sharing one would
|
|
656
|
+
// silently change three of them. See config/reasoning.ts.
|
|
691
657
|
thinkingFor: thinkingForChild,
|
|
692
658
|
logDebug: deps.logDebug,
|
|
693
659
|
onChildOutput: deps.onChildOutput,
|
|
@@ -699,7 +665,7 @@ export async function phaseResearch(deps, refined) {
|
|
|
699
665
|
}, prior);
|
|
700
666
|
const sections = [];
|
|
701
667
|
if (!getConfig().parallelResearchWorkers) {
|
|
702
|
-
// Default: ONE AT A TIME (see the
|
|
668
|
+
// Default: ONE AT A TIME (see the note above the worker specs) — a fatal
|
|
703
669
|
// failure throws before later workers run, and each worker can see the
|
|
704
670
|
// finished sections before it (APIS builds on the FILES map).
|
|
705
671
|
for (const spec of workerSpecs) {
|
|
@@ -711,8 +677,8 @@ export async function phaseResearch(deps, refined) {
|
|
|
711
677
|
// worker runs to its own outcome first, so one fatal failure cannot
|
|
712
678
|
// orphan the others' output — their sections persist for the resume
|
|
713
679
|
// before the failure is thrown. Assembly order stays the spec order
|
|
714
|
-
// regardless of completion order. No prior sections exist here, so
|
|
715
|
-
//
|
|
680
|
+
// regardless of completion order. No prior sections exist here, so prompt
|
|
681
|
+
// builders get none — APIS runs without the FILES map it gets when serial.
|
|
716
682
|
const settled = await Promise.allSettled(workerSpecs.map(spec => drive(spec, [])));
|
|
717
683
|
for (const s of settled) {
|
|
718
684
|
if (s.status === 'rejected')
|
|
@@ -784,7 +750,7 @@ export async function phaseAutoAnswer(deps, refined, research, question) {
|
|
|
784
750
|
text = await runPhaseChild(deps, 'grill-auto', 'read', prependHint(GRILL_AUTO_FORMAT_HINT, basePrompt));
|
|
785
751
|
}
|
|
786
752
|
let parsed = parseAutoAnswer(text);
|
|
787
|
-
// Anti-synthesis guard
|
|
753
|
+
// Anti-synthesis guard: the auto-answer invented
|
|
788
754
|
// `Bun.mkdirSync` while research's APIS section carried the correct list,
|
|
789
755
|
// and the invention was promoted into requirements + VERIFY. Deterministic
|
|
790
756
|
// verbatim-substring check: an API-shaped identifier in the answer that is
|
|
@@ -804,7 +770,9 @@ export async function phaseAutoAnswer(deps, refined, research, question) {
|
|
|
804
770
|
if (autoAnswerHasTag(text2))
|
|
805
771
|
reasked = parseAutoAnswer(text2);
|
|
806
772
|
}
|
|
807
|
-
catch {
|
|
773
|
+
catch (e) {
|
|
774
|
+
if (isFatalChildCause(e))
|
|
775
|
+
throw e;
|
|
808
776
|
reasked = null;
|
|
809
777
|
}
|
|
810
778
|
if (reasked === null
|
|
@@ -859,8 +827,8 @@ export async function phaseGrill(deps, ctx, widgetState, refined, research) {
|
|
|
859
827
|
const ui = new SessionUI(ctx);
|
|
860
828
|
// ONE record, two renderings (task/qa-transcript.ts): `forRecord()` is what
|
|
861
829
|
// compose and critique are handed, `forGenerator()` is what the next grill-gen
|
|
862
|
-
// call sees. The
|
|
863
|
-
//
|
|
830
|
+
// call sees. The two differ only in provenance suffixes, which is why they can
|
|
831
|
+
// drift apart unnoticed.
|
|
864
832
|
const transcript = new QaTranscript(GRILL_QA_POLICY);
|
|
865
833
|
const askedQuestions = []; // plain text of each question, for the dup backstop
|
|
866
834
|
// Deterministic backstop against a model that ignores "never re-ask": a
|
|
@@ -953,8 +921,6 @@ export async function phaseGrill(deps, ctx, widgetState, refined, research) {
|
|
|
953
921
|
* the same place. The task file's `## refined prompt` is deliberately left as
|
|
954
922
|
* refine wrote it; the drop is recorded on the `## gates` trail with both source
|
|
955
923
|
* lines quoted, so the decision stays auditable after the fact.
|
|
956
|
-
*
|
|
957
|
-
* STEP 0 `scripts/refuted-constraint-baserate.ts`; A/B-1 `…-ab.ts` (PASS).
|
|
958
924
|
*/
|
|
959
925
|
export async function dropRefutedConstraints(deps, refined, research) {
|
|
960
926
|
const refuted = applyRefutations(refined, research);
|
|
@@ -1019,17 +985,15 @@ export async function phaseCritique(deps, spec, refined, qa, planContext, resear
|
|
|
1019
985
|
* An additional deterministic defect block, forced into the rewrite exactly
|
|
1020
986
|
* like the probes below and overriding a CLEAN triage the same way.
|
|
1021
987
|
*
|
|
1022
|
-
*
|
|
1023
|
-
*
|
|
1024
|
-
*
|
|
1025
|
-
* rather than through a hand-copied replica of it, or the two arms differ by
|
|
1026
|
-
* more than the probe. Undefined in production.
|
|
988
|
+
* The seam exists so a candidate probe can be exercised through the SHIPPED
|
|
989
|
+
* critique path rather than through a hand-copied replica of it — otherwise a
|
|
990
|
+
* comparison differs by more than the probe. Undefined in production.
|
|
1027
991
|
*/
|
|
1028
992
|
extraDefects) {
|
|
1029
993
|
// Fast triage before the expensive full rewrite. The rewrite regenerates
|
|
1030
|
-
// the entire spec from scratch
|
|
1031
|
-
//
|
|
1032
|
-
//
|
|
994
|
+
// the entire spec from scratch, which makes it the most expensive step in the
|
|
995
|
+
// pipeline. Most compose drafts are already good, so we first ask a cheap,
|
|
996
|
+
// short-output triage pass whether a rewrite is even needed.
|
|
1033
997
|
//
|
|
1034
998
|
// We only short-circuit when the draft already has a runnable VERIFY block
|
|
1035
999
|
// (parseVerifyBlock !== null): the final handoff gate rejects specs without
|
|
@@ -1041,12 +1005,12 @@ extraDefects) {
|
|
|
1041
1005
|
// model does not self-discover reliably, each forced into the rewrite and each
|
|
1042
1006
|
// overriding a CLEAN triage. They live as rows in CRITIQUE_PROBES
|
|
1043
1007
|
// (critique-probes.ts) so the override and the merge below are DERIVED from
|
|
1044
|
-
// the table rather than retyped — a probe
|
|
1008
|
+
// the table rather than retyped — a probe would otherwise be listed by hand in three
|
|
1045
1009
|
// places, and forgetting the override term shipped the very defect it was
|
|
1046
1010
|
// added to catch.
|
|
1047
1011
|
//
|
|
1048
1012
|
// The contract registry is read here rather than inside the table because the
|
|
1049
|
-
// critique PROMPT needs it too
|
|
1013
|
+
// critique PROMPT needs it too: threading the design's pinned
|
|
1050
1014
|
// interface facts into the rewrite lets it RECONCILE a synthesized wiring
|
|
1051
1015
|
// specific against the facts it must reproduce — the generation-side
|
|
1052
1016
|
// complement of the verify-side boundary check.
|
|
@@ -1066,12 +1030,14 @@ extraDefects) {
|
|
|
1066
1030
|
let verdict;
|
|
1067
1031
|
try {
|
|
1068
1032
|
// No tools: triage judges only the spec/refined/qa text it is given.
|
|
1069
|
-
// Granting `read`
|
|
1070
|
-
//
|
|
1071
|
-
//
|
|
1033
|
+
// Granting `read` lets it wander the repo to "verify" findings, which
|
|
1034
|
+
// costs as much as the rewrite this pass exists to avoid. The judgement
|
|
1035
|
+
// needs no file access.
|
|
1072
1036
|
verdict = await runPhaseChild(deps, 'critique-triage', '', CRITIQUE_TRIAGE_PROMPT(spec, refined, qa, contractsBlock));
|
|
1073
1037
|
}
|
|
1074
|
-
catch {
|
|
1038
|
+
catch (e) {
|
|
1039
|
+
if (isFatalChildCause(e))
|
|
1040
|
+
throw e;
|
|
1075
1041
|
verdict = null;
|
|
1076
1042
|
}
|
|
1077
1043
|
deps.recordSubStep?.('triage', Date.now() - tTriage);
|
|
@@ -1142,10 +1108,9 @@ export async function critiqueWithFallback(d, p) {
|
|
|
1142
1108
|
// so returning that same draft would persist a VERIFY-less spec the
|
|
1143
1109
|
// handoff gate rejects and resume can't heal. Compose now enforces a
|
|
1144
1110
|
// parseable VERIFY, so this should hold; keep the guard so a regression
|
|
1145
|
-
// fails the run cleanly instead of shipping a broken spec.
|
|
1146
|
-
//
|
|
1147
|
-
//
|
|
1148
|
-
// — deliver it rather than fail the run. The guard costs time, never work.)
|
|
1111
|
+
// fails the run cleanly instead of shipping a broken spec. A draft that
|
|
1112
|
+
// carries the SAME defect the rewrite failed to fix is still delivered —
|
|
1113
|
+
// it is the validated-shape fallback, and failing the run costs more.
|
|
1149
1114
|
if (parseVerifyBlock(p.spec) === null)
|
|
1150
1115
|
throw err;
|
|
1151
1116
|
p.ctx.ui.notify(msg === 'verify_grep_theater' ?
|
|
@@ -1159,8 +1124,8 @@ export async function critiqueWithFallback(d, p) {
|
|
|
1159
1124
|
* REFINE — restate the raw prompt as a bounded 4-section spec, then subtractively
|
|
1160
1125
|
* strike any phantom runtime specifier (`bun:sql`) it carried up verbatim from the
|
|
1161
1126
|
* spec doc, BEFORE it flows to research/grill/compose. An appended correction alone
|
|
1162
|
-
* loses: the affirmative survives into the composed GOAL and on to the
|
|
1163
|
-
*
|
|
1127
|
+
* loses: the affirmative survives into the composed GOAL and on to the
|
|
1128
|
+
* implementer, because compose re-leaks it. Rewriting the source so compose has nothing to
|
|
1164
1129
|
* contradict is the fix. Silent + no-op when nothing is wrong or the runtime's types
|
|
1165
1130
|
* aren't installed.
|
|
1166
1131
|
*/
|
|
@@ -1213,16 +1178,16 @@ export async function composePhase(d, p) {
|
|
|
1213
1178
|
* CRITIQUE — the last spec-producing step, and the two host-side corrections that
|
|
1214
1179
|
* must run after it in THIS ORDER.
|
|
1215
1180
|
*
|
|
1216
|
-
* BRACES
|
|
1217
|
-
* CONSTRAINTS bullet. The belt block upstream is obeyed
|
|
1181
|
+
* BRACES: append any owned design obligation the spec still omits as a
|
|
1182
|
+
* CONSTRAINTS bullet. The belt block upstream is obeyed only sometimes; a host-side
|
|
1218
1183
|
* append is obeyed by construction. Idempotent — quotes the spec already carries
|
|
1219
1184
|
* (belt-obeying reps) are skipped.
|
|
1220
1185
|
*
|
|
1221
1186
|
* Then DETACH: an owned obligation whose only file this spec also FREEZES is
|
|
1222
1187
|
* unsatisfiable here, so it moves to the pending task that writes that file rather
|
|
1223
1188
|
* than shipping a requirement no one can meet. It MUST run after the append, because
|
|
1224
|
-
* the append is what writes the stamp the detach reads
|
|
1225
|
-
*
|
|
1189
|
+
* the append is what writes the stamp the detach reads, so a critique-time probe
|
|
1190
|
+
* would find nothing.
|
|
1226
1191
|
*/
|
|
1227
1192
|
export async function critiquePhase(d, p) {
|
|
1228
1193
|
const spec = await critiqueWithFallback(d, p);
|
|
@@ -1239,10 +1204,9 @@ export async function critiquePhase(d, p) {
|
|
|
1239
1204
|
* The pipeline, as a table with no bodies.
|
|
1240
1205
|
*
|
|
1241
1206
|
* Every row's `run` is a named exported function, so the COMPOSITION inside a
|
|
1242
|
-
* step
|
|
1243
|
-
*
|
|
1244
|
-
*
|
|
1245
|
-
* they run in is now asserted by driving the row rather than retyped in a test.
|
|
1207
|
+
* step is drivable directly instead of only through a whole TaskRunner run. That
|
|
1208
|
+
* matters because a step's parts can each be correct while the order they run in
|
|
1209
|
+
* is wrong — see `runPhaseRow`, which is the surface that pins the order.
|
|
1246
1210
|
*/
|
|
1247
1211
|
export const PHASES = [
|
|
1248
1212
|
{
|
|
@@ -1279,50 +1243,30 @@ export async function runPhaseRow(row, deps, pc) {
|
|
|
1279
1243
|
export async function replayPhaseCarry(row, deps, pc) {
|
|
1280
1244
|
await row.carry?.(deps, pc);
|
|
1281
1245
|
}
|
|
1282
|
-
// INTEGRATION-DEPTH APPEND
|
|
1283
|
-
// deterministically append a known-runnable integration command to the VERIFY block
|
|
1284
|
-
// whenever a task's ACCEPTANCE claims runtime behaviour — is REFUTED at STEP 0 and was
|
|
1285
|
-
// NOT built. Nothing below is wired; this is the record.
|
|
1246
|
+
// INTEGRATION-DEPTH APPEND — considered for this site, NOT built.
|
|
1286
1247
|
//
|
|
1287
|
-
// The
|
|
1288
|
-
//
|
|
1289
|
-
//
|
|
1290
|
-
// product — mx5 7/41, IAR1 3/10, godot-engine 2/20, runner 0/2, total 12/73 (16.4%).
|
|
1291
|
-
// That total OVERSTATES the truth: godot's two hits only match because the block greps
|
|
1292
|
-
// a URL out of CLAUDE.md, and IAR1's TASK_0006 curls a GitHub tarball to check a hash,
|
|
1293
|
-
// so genuine product integration is ~9/73 (~12%). The addressable class — runtime claim
|
|
1294
|
-
// in ACCEPTANCE, a boot command available with provenance, static-only VERIFY anyway —
|
|
1295
|
-
// is 29/73 (39.7%), clearing the task's 25% kill condition, but 27 of those 29 are mx5.
|
|
1248
|
+
// The idea: whenever a task's ACCEPTANCE claims runtime behaviour, deterministically
|
|
1249
|
+
// append a known-runnable integration command to its VERIFY block. Most VERIFY blocks
|
|
1250
|
+
// never boot or touch the integrated product, so the gap is real.
|
|
1296
1251
|
//
|
|
1297
|
-
// What kills
|
|
1298
|
-
//
|
|
1299
|
-
//
|
|
1300
|
-
//
|
|
1301
|
-
//
|
|
1302
|
-
//
|
|
1303
|
-
// until the 15-minute command watchdog and then FAILs. Every command that DOES
|
|
1304
|
-
// terminate (`bun run build` exit 0) fails the metric.
|
|
1305
|
-
// godot `godot --headless --quit` (0.8s, exit 0) and the real GUT runner (1.7s,
|
|
1306
|
-
// exit 0) are both appendable — and neither matches the metric, which is
|
|
1307
|
-
// web-shaped (curl/localhost/PORT=/run dev/http://). Nothing appendable can
|
|
1308
|
-
// move the registered metric on a non-web stack, so the two-stack A/B the
|
|
1309
|
-
// task requires is unsatisfiable by construction, not by sample size.
|
|
1310
|
-
// IAR1 no candidate at all: cmake is absent from this box (the N5 finding).
|
|
1311
|
-
// R4 forbids swapping the metric after seeing results, so a broadened "boots the real
|
|
1312
|
-
// product" metric is a separate pre-registered experiment, not a rescue of this one.
|
|
1252
|
+
// What kills it is the input, not the premise. The append needs a command that is all
|
|
1253
|
+
// four of: provenance-bearing, proven runnable, TERMINATING, and integration-shaped.
|
|
1254
|
+
// That intersection tends to be empty. A dev server matches the shape and never
|
|
1255
|
+
// terminates — appending it hangs the verify child until the command watchdog and then
|
|
1256
|
+
// FAILs. Everything that does terminate (a build, a headless one-shot) is not
|
|
1257
|
+
// integration-shaped. And on a non-web stack nothing appendable is web-shaped at all.
|
|
1313
1258
|
//
|
|
1314
|
-
// The deeper
|
|
1315
|
-
//
|
|
1316
|
-
//
|
|
1317
|
-
//
|
|
1318
|
-
//
|
|
1319
|
-
//
|
|
1320
|
-
// That machinery already exists in ONE place that owns ports, seeding and teardown: the
|
|
1321
|
-
// final gate's render check. The mx5-class defect belongs there (nexttask TASK 6), not
|
|
1322
|
-
// in per-task VERIFY blocks.
|
|
1259
|
+
// The deeper point: on a web stack, integration is not a COMMAND. An integrated VERIFY
|
|
1260
|
+
// block is a whole task-specific procedure — pick a free port, export the database URL,
|
|
1261
|
+
// boot, seed, log in, assert some endpoints, tear down. A host-side append cannot
|
|
1262
|
+
// synthesize that from provenance, because a launch contract records script NAMES and
|
|
1263
|
+
// nothing else: no port, no health URL. Synthesizing it from the task's own
|
|
1264
|
+
// `## verified tooling` section is fabrication.
|
|
1323
1265
|
//
|
|
1324
|
-
//
|
|
1325
|
-
//
|
|
1266
|
+
// That machinery already exists in ONE place that owns ports, seeding and teardown: the
|
|
1267
|
+
// final gate's render check. This class of defect belongs there, not in per-task VERIFY
|
|
1268
|
+
// blocks. Do NOT wire an append here without a command source that satisfies all four
|
|
1269
|
+
// properties at once.
|
|
1326
1270
|
/** Dispatch a row's declared post-commit effect. Rows with none do nothing. */
|
|
1327
1271
|
export async function postCommitPhase(phase, deps, pc, out) {
|
|
1328
1272
|
await phase.postCommit?.(deps, pc, out);
|