@mjasnikovs/pi-task 0.38.28 → 0.38.30
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/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 +22 -16
- package/dist/shared/command-watchdog.js +28 -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 +178 -162
- 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 +46 -51
- package/dist/task/child-runner.js +48 -49
- 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 +25 -7
- package/dist/task/context-usage.js +21 -6
- 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 +6 -7
- 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 +37 -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-thinking.d.ts +33 -31
- package/dist/task/implementation-thinking.js +5 -6
- package/dist/task/implementation-turn.d.ts +34 -31
- package/dist/task/implementation-turn.js +29 -27
- 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 +9 -8
- package/dist/task/loop-detector.js +16 -12
- 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 +62 -64
- 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 +180 -248
- 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 +33 -36
- package/dist/task/research-worker.js +39 -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 +12 -12
- package/dist/workers/focused-extractor.js +16 -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 +86 -54
- package/dist/workers/pi-worker-core.js +112 -112
- 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 +23 -10
- 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 +25 -28
- package/dist/workers/single-read-guard.js +32 -32
- 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 +43 -53
- package/dist/workers/worker-profiles.js +30 -38
- package/package.json +10 -8
|
@@ -1,31 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* batch-test-task — ban the whole-project "write all the tests" task when the
|
|
3
|
-
* DECISIONS channel mandates tests-in-the-same-change
|
|
3
|
+
* DECISIONS channel mandates tests-in-the-same-change.
|
|
4
4
|
*
|
|
5
|
-
* The failure this closes:
|
|
5
|
+
* The failure this closes: a plan carrying one enormous title like "Write
|
|
6
|
+
* component and page tests — with screenshot baselines for all components and
|
|
7
|
+
* pages", which cannot converge, while the decision carried ON THAT TITLE says
|
|
8
|
+
* the opposite — that a test lands in the same change as each new route or
|
|
9
|
+
* component, and testing is not batched to the end of a milestone.
|
|
6
10
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
11
|
+
* Decompose did not invent the shape; it mirrors a spec whose own milestone
|
|
12
|
+
* structure induces it. So the conflict is SPEC-INTERNAL — the spec's structure
|
|
13
|
+
* against the spec's own cadence rule — and the decisions channel OVERRIDES the
|
|
14
|
+
* spec doc by definition, the same precedence the task titles already state.
|
|
15
|
+
* Resolve toward the decision; never ask the user.
|
|
9
16
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* TITLE said the opposite:
|
|
13
|
-
*
|
|
14
|
-
* "a test lands *as fast as possible* — in the same change — as each new route
|
|
15
|
-
* or React component/page. No route or component is considered done until its
|
|
16
|
-
* test exists and passes. Don't batch testing to the end of a milestone."
|
|
17
|
-
*
|
|
18
|
-
* Decompose did not invent the shape: the spec's own §10/§12 structure induced it,
|
|
19
|
-
* and decompose mirrors the spec. So the conflict is SPEC-INTERNAL (the spec's
|
|
20
|
-
* milestone shape vs the spec's own cadence rule), and the decisions channel
|
|
21
|
-
* OVERRIDES the spec doc by definition — the same precedence the task titles
|
|
22
|
-
* already state. Resolve toward the decision; never ask the user.
|
|
23
|
-
*
|
|
24
|
-
* The mechanism is a deterministic post-decompose rewrite (applied on EVERY
|
|
25
|
-
* decompose output, like fidelity reconciliation), plus a conditional prompt rule
|
|
17
|
+
* The mechanism is a deterministic post-decompose rewrite, applied on every
|
|
18
|
+
* decompose output like fidelity reconciliation, plus a conditional prompt rule
|
|
26
19
|
* as the belt. Only the batch-EVERYTHING shape is banned — coverage is never
|
|
27
|
-
* nuked
|
|
28
|
-
*
|
|
20
|
+
* nuked. Which of the two outcomes fires is decided by `groundedCoverage`, not by
|
|
21
|
+
* wording, and holding the title fixed while changing only the requirement
|
|
22
|
+
* switches it:
|
|
29
23
|
*
|
|
30
24
|
* • the batch title grounds NO requirement that survives its removal ⇒ every
|
|
31
25
|
* requirement it touched is owned by some other task, the per-change cadence
|
|
@@ -41,8 +35,12 @@
|
|
|
41
35
|
import { groundedCoverage } from './coverage-loop.js';
|
|
42
36
|
/**
|
|
43
37
|
* Sentences that MANDATE tests landing with the change they cover. Deliberately
|
|
44
|
-
* narrow: a spec that merely REQUIRES tests
|
|
45
|
-
*
|
|
38
|
+
* narrow: a spec that merely REQUIRES tests does not ban a batch task — only an
|
|
39
|
+
* explicit cadence or anti-batch directive does. Run: "every route has tests"
|
|
40
|
+
* does NOT mandate, while "a test lands in the same change as each new route",
|
|
41
|
+
* "never batch tests" and "a route is not considered done until its test exists"
|
|
42
|
+
* all do. That last alternative needs the literal word "not" — a sentence phrased
|
|
43
|
+
* "NO route is considered done until…" does not match it on its own.
|
|
46
44
|
*/
|
|
47
45
|
const SAME_CHANGE_RE = /\bin the same (?:change|commit|pr|patch|diff|task|step)\b|\b(?:do ?n['’]?t|do not|never|no)\s+(?:batch|defer|postpone|save|leave)\b|\bnot\b[^.]{0,60}\bdone until\b[^.]{0,60}\btest/i;
|
|
48
46
|
/** Any mention of testing — the mandate must be ABOUT tests, not about docs. */
|
|
@@ -50,11 +48,12 @@ const TEST_WORD_RE = /\btests?\b|\btesting\b|\btest-first\b/i;
|
|
|
50
48
|
/**
|
|
51
49
|
* Does the decisions/spec text mandate tests-in-the-same-change?
|
|
52
50
|
*
|
|
53
|
-
* Scans sentence by sentence and requires BOTH signals in the SAME sentence, so
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
51
|
+
* Scans sentence by sentence and requires BOTH signals in the SAME sentence, so a
|
|
52
|
+
* testing section that happens to sit near an unrelated "don't defer" line cannot
|
|
53
|
+
* trigger the ban — confirmed, "Don't defer the docs. Every route has tests."
|
|
54
|
+
* returns false. `decisions` is checked first and alone is sufficient; the spec is
|
|
55
|
+
* scanned too, and a mandate found only there is enough, because a cadence rule is
|
|
56
|
+
* often stated in the doc body and only echoed into the decisions channel.
|
|
58
57
|
*/
|
|
59
58
|
export function mandatesTestsInSameChange(decisions, spec = '') {
|
|
60
59
|
for (const text of [decisions, spec]) {
|
|
@@ -70,13 +69,13 @@ export function mandatesTestsInSameChange(decisions, spec = '') {
|
|
|
70
69
|
const DECISIONS_CLAUSE_RE = /\s*\[decisions:/i;
|
|
71
70
|
/**
|
|
72
71
|
* Where decompose's trailing metadata starts. `[source: …]` is included because
|
|
73
|
-
* reconcileTitleSources only strips a WELL-FORMED trailing citation
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* title reads the citation's words as the task's own
|
|
77
|
-
* each new route or React component/page"
|
|
78
|
-
*
|
|
79
|
-
*
|
|
72
|
+
* reconcileTitleSources only strips a WELL-FORMED trailing citation. Confirmed by
|
|
73
|
+
* running it: `[source: "…"]` is stripped, while `[source: "…" [10. Testing]]`
|
|
74
|
+
* comes back untouched, leaking the QUOTED SPEC LINE into the title. Judging scope
|
|
75
|
+
* on such a title reads the citation's words as the task's own, so a cadence quote
|
|
76
|
+
* about "each new route or React component/page" makes a properly scoped "Write
|
|
77
|
+
* route/API tests for auth" look like a batch task. A citation is provenance,
|
|
78
|
+
* never scope.
|
|
80
79
|
*/
|
|
81
80
|
const CLAUSE_START_RE = /\s*\[(?:source|decisions)\s*:/i;
|
|
82
81
|
/** Split a title into the part decompose authored, and the `[decisions: …]` tail
|
|
@@ -99,10 +98,10 @@ function head(body) {
|
|
|
99
98
|
* scope. Measured live: the model frequently appends its citation as a bare
|
|
100
99
|
* quote with no `[source: …]` wrapper ("Write auth route tests — … — "…a test
|
|
101
100
|
* lands as fast as possible — in the same change — as each new route or React
|
|
102
|
-
* component/page.""), and that borrowed "each"
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
101
|
+
* component/page.""), and that borrowed "each" makes a correctly scoped per-area
|
|
102
|
+
* test task read as a batch task. Trading a possible miss — a batch title whose
|
|
103
|
+
* only quantifier sits inside a quote — for never deleting a properly scoped test
|
|
104
|
+
* task: the false positive is far the more expensive error.
|
|
106
105
|
*/
|
|
107
106
|
function stripQuotedSpans(s) {
|
|
108
107
|
return s.replace(/"[^"]*"/g, ' ').replace(/[“][^”]*[”]/g, ' ');
|
|
@@ -127,19 +126,19 @@ const MIN_ECHO_CHARS = 40;
|
|
|
127
126
|
/**
|
|
128
127
|
* Drop detail segments that are VERBATIM spec text.
|
|
129
128
|
*
|
|
130
|
-
* Third variant of the same failure, and the one the syntactic defenses miss:
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
* repeated it inside a `[source: "…"]` clause:
|
|
129
|
+
* Third variant of the same failure, and the one the syntactic defenses miss: the
|
|
130
|
+
* model appends its citation as BARE PROSE — no quotes, no `[source: …]` wrapper —
|
|
131
|
+
* and may then repeat it inside a `[source: "…"]` clause:
|
|
134
132
|
*
|
|
135
133
|
* "Implement Login page with phone/password form and tests — **Client/UI:**
|
|
136
134
|
* Playwright `1.61.1` React component tests … — every component/page test
|
|
137
135
|
* captures a screenshot committed as a baseline. [source: "…"]"
|
|
138
136
|
*
|
|
139
137
|
* `stripQuotedSpans` sees no quotes and `splitDecisions` cuts only at the clause,
|
|
140
|
-
* so the borrowed "every component/page"
|
|
141
|
-
* scope
|
|
142
|
-
* deletion this module exists to avoid.
|
|
138
|
+
* so the borrowed "every component/page" survives as if it were the task's own
|
|
139
|
+
* scope and a correctly per-change-scoped Login task is DROPPED — the exact
|
|
140
|
+
* deletion this module exists to avoid. Demonstrated by running that title both
|
|
141
|
+
* ways: WITHOUT the spec it is flagged as a batch task, WITH the spec it is kept.
|
|
143
142
|
*
|
|
144
143
|
* The general rule the two earlier guards were reaching for: text the title shares
|
|
145
144
|
* verbatim with the spec is provenance, whoever failed to mark it as such. So the
|
|
@@ -175,12 +174,13 @@ const TEST_INFRA_RE = /\b(?:harness|infrastructure|infra|runner|config|configura
|
|
|
175
174
|
* WHOLE-PROJECT scope: a universal quantifier that governs a PROJECT-LEVEL target
|
|
176
175
|
* ("all components and pages", "every route"), not merely any noun.
|
|
177
176
|
*
|
|
178
|
-
* Both halves are load-bearing
|
|
177
|
+
* Both halves are load-bearing:
|
|
179
178
|
* - "full"/"complete" are excluded — they routinely scope a single area
|
|
180
179
|
* ("full login flow");
|
|
181
|
-
* - the quantifier must reach a project-level plural within
|
|
182
|
-
* "Test PartCard component — ALL badge combinations…"
|
|
183
|
-
* that
|
|
180
|
+
* - the quantifier must reach a project-level plural within a short span, so
|
|
181
|
+
* "Test PartCard component — ALL badge combinations…" stays a one-component
|
|
182
|
+
* task. Confirmed: that title is NOT flagged, while "…for all components and
|
|
183
|
+
* pages" is.
|
|
184
184
|
*/
|
|
185
185
|
const WHOLE_SCOPE_RE = /\b(?:all|every|each|entire|whole|comprehensive)\b[\w\s,/-]{0,20}?\b(?:components?|pages?|routes?|endpoints?|screens?|views?|modules?|layers?|files?|features?|app|application|project|codebase|repo|repository|system|surface)\b|\bacross the (?:app|application|project|codebase|repo|repository)\b|\bend[- ]to[- ]end coverage\b/i;
|
|
186
186
|
/**
|
|
@@ -218,9 +218,11 @@ const TEST_COMMAND_RE = /\b(?:bun test|npm (?:run )?test|yarn test|pnpm (?:run )
|
|
|
218
218
|
* The spec's own coverage source — the command whose report scopes the sweep.
|
|
219
219
|
*
|
|
220
220
|
* Only backticked spans are considered, so the result is a command the spec
|
|
221
|
-
* actually writes down rather than a phrase inferred from prose
|
|
222
|
-
*
|
|
223
|
-
*
|
|
221
|
+
* actually writes down rather than a phrase inferred from prose: a plain-prose
|
|
222
|
+
* "bun test" is ignored and falls through to the generic phrase. A span carrying a
|
|
223
|
+
* coverage flag wins over a plain test run — a spec naming both `bun test` and
|
|
224
|
+
* `bun test --coverage` yields the latter. The fallback keeps the sweep title
|
|
225
|
+
* well-formed when the spec names no command at all.
|
|
224
226
|
*/
|
|
225
227
|
export function coverageSourceFromSpec(spec) {
|
|
226
228
|
const spans = [...spec.matchAll(/`([^`\n]+)`/g)].map(m => m[1].trim());
|
|
@@ -233,9 +235,9 @@ export function coverageSourceFromSpec(spec) {
|
|
|
233
235
|
* carries NO ownership signal here. Without this scrub the bare token "test"
|
|
234
236
|
* connects a screenshot-baseline requirement to "Write auth route tests", and the
|
|
235
237
|
* orphan check goes blind. (Scrubbed locally rather than added to
|
|
236
|
-
* COVERAGE_STOPWORDS: those govern the
|
|
238
|
+
* COVERAGE_STOPWORDS: those govern the monotonic adoption guard,
|
|
237
239
|
* where "test" IS a discriminating noun for a plan that has no testing task at
|
|
238
|
-
* all.) Token-level, not regex — `
|
|
240
|
+
* all.) Token-level, not regex — `myapp_test` must scrub to `myapp`.
|
|
239
241
|
*/
|
|
240
242
|
const GENERIC_TEST_TOKENS = new Set([
|
|
241
243
|
'test',
|
|
@@ -327,15 +329,20 @@ export function buildSweepTitle(orphaned, coverageSource) {
|
|
|
327
329
|
* Rewrite a decomposed plan so it carries no whole-project batch test task when
|
|
328
330
|
* the decisions mandate tests-in-the-same-change.
|
|
329
331
|
*
|
|
330
|
-
* No mandate, or no batch title ⇒ the plan is returned untouched
|
|
331
|
-
* every non-cadence run
|
|
332
|
+
* No mandate, or no batch title ⇒ the plan is returned untouched, with no actions,
|
|
333
|
+
* so every non-cadence run is unaffected. Both identity paths run as described.
|
|
332
334
|
*
|
|
333
335
|
* With a mandate, ALL batch titles are removed at once before coverage is
|
|
334
336
|
* re-measured — otherwise two batch tasks would each mask the other's orphans and
|
|
335
337
|
* both would look droppable. The orphaned set is then whatever grounded coverage
|
|
336
338
|
* the removal costs; it is non-empty only when no other task's title claims that
|
|
337
|
-
* requirement, and it becomes the sweep's scope. At most ONE sweep is emitted
|
|
338
|
-
* the first batch title's position, so plan order is preserved
|
|
339
|
+
* requirement, and it becomes the sweep's scope. At most ONE sweep is emitted, in
|
|
340
|
+
* the first batch title's position, so plan order is preserved.
|
|
341
|
+
*
|
|
342
|
+
* Run on the SAME batch title twice, changing only the requirement list: when
|
|
343
|
+
* another task grounds the requirement the title is DROPPED, and when the batch
|
|
344
|
+
* title is its only owner it is SCOPED into a sweep naming that quote and the
|
|
345
|
+
* spec's own coverage command. Any `[decisions: …]` tail rides onto the sweep.
|
|
339
346
|
*/
|
|
340
347
|
export function rewriteBatchTestPlan(titles, decisions, spec, requirementQuotes, isCrossCutting) {
|
|
341
348
|
if (!mandatesTestsInSameChange(decisions, spec))
|
|
@@ -3,9 +3,9 @@ import { type DeepRenderOutcome } from './deep-render-check.js';
|
|
|
3
3
|
import type { HealthCommand } from './repo-health-check.js';
|
|
4
4
|
/**
|
|
5
5
|
* Why this script is NOT a launch of the shipped app, or null when it plausibly
|
|
6
|
-
* is one
|
|
6
|
+
* is one.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* A boot command can resolve to `bun run dev`, whose body is
|
|
9
9
|
* `docker compose -f docker-compose.dev.yml up -d && until docker compose … pg_isready
|
|
10
10
|
* … && concurrently "bun run dev:css" "bun run dev:js" "bun run --watch
|
|
11
11
|
* src/server/index.ts"`. The gate sandbox has no docker, so the chain died at 127 and
|
|
@@ -17,15 +17,22 @@ import type { HealthCommand } from './repo-health-check.js';
|
|
|
17
17
|
* producing an unfalsifiable skip.
|
|
18
18
|
*
|
|
19
19
|
* CONSERVATIVE AND LEXICAL BY CONSTRUCTION. Only two shapes are rejected, both
|
|
20
|
-
* decidable from the script text alone
|
|
20
|
+
* decidable from the script text alone, and both run against every case named
|
|
21
|
+
* below:
|
|
21
22
|
* 1. the chain OPENS with container orchestration (docker/podman/nerdctl … up|start|run);
|
|
22
23
|
* 2. the whole body is a multiplexer (concurrently/npm-run-all/run-p/run-s/turbo)
|
|
23
24
|
* whose every child is an ASSET watcher in watch mode (tailwind/tsc/esbuild/…),
|
|
24
25
|
* i.e. nothing in it can ever listen.
|
|
25
|
-
* Anything else — `vite`, `next dev`, `node dist/index.js`, `nodemon`, `bun
|
|
26
|
-
* src/index.ts`, and any multiplexer with one non-asset child — is accepted
|
|
27
|
-
* unchanged.
|
|
28
|
-
*
|
|
26
|
+
* Anything else — `vite`, `next dev`, `node dist/index.js`, `nodemon`, `bun run
|
|
27
|
+
* --watch src/index.ts`, and any multiplexer with one non-asset child — is accepted
|
|
28
|
+
* unchanged. All of those were run and accepted; so was a bare
|
|
29
|
+
* `tailwindcss … --watch`, which is only rejected INSIDE a multiplexer. A chain
|
|
30
|
+
* opening `docker compose … up` is rejected even when a real launch follows it,
|
|
31
|
+
* while `bun run docker-compose.dev.yml` is accepted, since the verb must be a
|
|
32
|
+
* bare token.
|
|
33
|
+
*
|
|
34
|
+
* Deciding whether a watcher actually SERVES is not attempted here; that is exactly
|
|
35
|
+
* what the static serve-entry check is for.
|
|
29
36
|
*/
|
|
30
37
|
export declare function nonLaunchScriptReason(body: string, scripts?: Record<string, string>): string | null;
|
|
31
38
|
/**
|
|
@@ -33,7 +40,7 @@ export declare function nonLaunchScriptReason(body: string, scripts?: Record<str
|
|
|
33
40
|
* else `dev`; Makefile `run`). null means the project has nothing to boot —
|
|
34
41
|
* the boot check degrades to nothing-to-run.
|
|
35
42
|
*
|
|
36
|
-
* A script that is not a LAUNCH at all (nonLaunchScriptReason —
|
|
43
|
+
* A script that is not a LAUNCH at all (nonLaunchScriptReason — an
|
|
37
44
|
* `docker compose up` orchestrator) is rejected here and falls through to the
|
|
38
45
|
* next candidate, then to null. Discovering nothing is strictly better than
|
|
39
46
|
* discovering something unfalsifiable: an env-gap skip of an orchestration script
|
|
@@ -42,7 +49,7 @@ export declare function nonLaunchScriptReason(body: string, scripts?: Record<str
|
|
|
42
49
|
export declare function discoverBootCommand(cwd: string): HealthCommand | null;
|
|
43
50
|
/**
|
|
44
51
|
* The launch script that EXISTS but was rejected as not-a-launch, if any. Without
|
|
45
|
-
* this the rejection would trade
|
|
52
|
+
* this the rejection would trade an unfalsifiable skip for pure silence: no
|
|
46
53
|
* boot command means bootSkipVerdict has no label to name, and a project whose test
|
|
47
54
|
* suite ran still reports `observed > 0`, so unobservedVerdict stays quiet too. A
|
|
48
55
|
* served app whose only declared launch script cannot start it was not observed to
|
|
@@ -60,7 +67,7 @@ type BootOutcome = {
|
|
|
60
67
|
* by the gate as an UNOBSERVED warning. */
|
|
61
68
|
renderNote?: string;
|
|
62
69
|
/** skip only: the boot command never spawned (ENOENT) — feeds the
|
|
63
|
-
* full-blindness guard
|
|
70
|
+
* full-blindness guard, unlike a 127 where the runner ran. */
|
|
64
71
|
spawnFailed?: boolean;
|
|
65
72
|
} | {
|
|
66
73
|
outcome: 'fail';
|
|
@@ -82,7 +89,7 @@ export interface BootDeps {
|
|
|
82
89
|
reap?: (pid: number) => boolean;
|
|
83
90
|
/**
|
|
84
91
|
* Does process group `pgid` currently own a LISTENing TCP socket? Drives the
|
|
85
|
-
* served-app boot check
|
|
92
|
+
* served-app boot check: a watcher (`dev` = tailwind/bundler
|
|
86
93
|
* --watch) stays alive forever without ever listening, so "still alive after the
|
|
87
94
|
* grace window = PASS" blessed a project that cannot serve a single request.
|
|
88
95
|
* Injected so the listener requirement is deterministically testable without a
|
|
@@ -97,15 +104,15 @@ export interface BootDeps {
|
|
|
97
104
|
groupListeningPort?: (pgid: number) => number | null;
|
|
98
105
|
/**
|
|
99
106
|
* Load the served page once in a headless browser and judge the RENDERED DOM
|
|
100
|
-
* (
|
|
107
|
+
* (curl cannot execute JS, so a blank-mount app passes every
|
|
101
108
|
* gate). Runs only for a served app, against the live listener, before the
|
|
102
109
|
* boot child is killed. Absent → the boot check behaves exactly as before;
|
|
103
110
|
* the gate wires runRenderCheck by default for served apps.
|
|
104
111
|
*/
|
|
105
112
|
renderProbe?: (url: string) => RenderOutcome;
|
|
106
113
|
/**
|
|
107
|
-
* SIGN IN on the served page and judge the AUTHENTICATED half of the app
|
|
108
|
-
*
|
|
114
|
+
* SIGN IN on the served page and judge the AUTHENTICATED half of the app.
|
|
115
|
+
* Runs only after `renderProbe` PASSED — the shallow blank-page rule
|
|
109
116
|
* keeps its own RED/GREEN-proven verdict and is never shadowed by this one.
|
|
110
117
|
* Absent → the boot check behaves exactly as before; the gate wires
|
|
111
118
|
* runDeepRenderCheck by default for served apps. May only FAIL when the SERVER
|
|
@@ -152,7 +159,7 @@ export interface BootDeps {
|
|
|
152
159
|
spawnBoot?: (bin: string, args: string[], opts: BootSpawnOptions) => BootChild;
|
|
153
160
|
/**
|
|
154
161
|
* Tear down the child's whole process group. Injected with `spawnBoot`, because
|
|
155
|
-
* a fake child has no group to kill and a real `process.kill(
|
|
162
|
+
* a fake child has no group to kill and a real `process.kill(pid)` against a
|
|
156
163
|
* fake pid would signal something else entirely.
|
|
157
164
|
*/
|
|
158
165
|
killGroup?: (pid: number, signal: NodeJS.Signals) => void;
|
|
@@ -196,11 +203,14 @@ export declare function parseSsListeners(stdout: string): Array<{
|
|
|
196
203
|
port: number;
|
|
197
204
|
}>;
|
|
198
205
|
/**
|
|
199
|
-
* `netstat -tlnp` rows → {pid, port}
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
206
|
+
* `netstat -tlnp` rows → {pid, port}. Three parsers exist because no single
|
|
207
|
+
* enumerator is present everywhere — a box may ship netstat and no ss, or ss and
|
|
208
|
+
* no netstat — and without SOME enumerator the served-app check can never observe
|
|
209
|
+
* a listener and fails unfalsifiably.
|
|
210
|
+
*
|
|
211
|
+
* The pid rides in the trailing "PID/Program name" column ("1234/bun"); rows the
|
|
212
|
+
* kernel will not attribute to us print "-" there and are skipped. Both run as
|
|
213
|
+
* described.
|
|
204
214
|
*/
|
|
205
215
|
export declare function parseNetstatListeners(stdout: string): Array<{
|
|
206
216
|
pid: number;
|
|
@@ -214,13 +224,14 @@ export declare function parseLsofListeners(stdout: string): Array<{
|
|
|
214
224
|
export declare function canEnumerateListeners(): boolean;
|
|
215
225
|
/**
|
|
216
226
|
* A free TCP port on the loopback interface, or null if one cannot be reserved.
|
|
217
|
-
* The boot check hands this to the child as PORT so that a successful HTTP
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
227
|
+
* The boot check hands this to the child as PORT so that a successful HTTP request
|
|
228
|
+
* to it is OWNERSHIP evidence: nobody else knows the number, whereas an orphaned
|
|
229
|
+
* server left by an earlier check still answers on a conventional port and would
|
|
230
|
+
* pass a check the app had not earned.
|
|
221
231
|
*/
|
|
222
232
|
export declare function pickFreePort(): Promise<number | null>;
|
|
223
|
-
/** Can we bind 127.0.0.1:`port` right now?
|
|
233
|
+
/** Can we bind 127.0.0.1:`port` right now? Free ⇒ the boot child can have it.
|
|
234
|
+
* Run: true for a just-reserved port, false while anything holds it. */
|
|
224
235
|
export declare function isPortFree(port: number): Promise<boolean>;
|
|
225
236
|
/**
|
|
226
237
|
* The project's own declared local port, but only if nothing is holding it — the
|
|
@@ -236,8 +247,11 @@ export declare function defaultFindPortHolder(port: number): {
|
|
|
236
247
|
command: string;
|
|
237
248
|
} | null;
|
|
238
249
|
/**
|
|
239
|
-
* Exercise the start command ONCE.
|
|
240
|
-
*
|
|
250
|
+
* Exercise the start command ONCE. All four outcomes below were run against real
|
|
251
|
+
* child processes in throwaway projects.
|
|
252
|
+
*
|
|
253
|
+
* For a CLI project (`expectServer` false) the command's own fate within the grace
|
|
254
|
+
* window decides:
|
|
241
255
|
*
|
|
242
256
|
* - non-zero exit (or signal death) before the window closes → FAIL, output tail;
|
|
243
257
|
* - exit 0 before the window closes → PASS (a CLI-style "run" that finished);
|
|
@@ -247,22 +261,21 @@ export declare function defaultFindPortHolder(port: number): {
|
|
|
247
261
|
* For a SERVED app (`expectServer` true — the spec/plan promised an HTTP server) mere
|
|
248
262
|
* survival is not enough: a watcher (`dev` = tailwind/bundler --watch) stays alive
|
|
249
263
|
* forever without ever listening, and a type-only entrypoint exits 0 in <1s having
|
|
250
|
-
* served nothing
|
|
264
|
+
* served nothing. The boot then
|
|
251
265
|
* PASSes only once a LISTENing socket owned by our process group is observed; if the
|
|
252
266
|
* command exits, or the grace window closes, with no listener ever seen → FAIL naming
|
|
253
267
|
* that a listening server was expected.
|
|
254
268
|
*
|
|
255
|
-
* OBSERVABILITY is a precondition of that FAIL
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
*
|
|
260
|
-
* recorded failed. Two defences, in order:
|
|
269
|
+
* OBSERVABILITY is a precondition of that FAIL. The listener requirement needs
|
|
270
|
+
* pgid-attributed socket enumeration; win32 has none, and neither does a Linux
|
|
271
|
+
* image shipping no ss, netstat or lsof. Without a defence the check would emit
|
|
272
|
+
* "never opened a listening socket" against an app that demonstrably serves, and
|
|
273
|
+
* no amount of fixing could falsify it. Two defences, in order:
|
|
261
274
|
*
|
|
262
275
|
* - the child is spawned with a freshly reserved, otherwise-unused PORT, and an
|
|
263
276
|
* HTTP answer on THAT port proves a listener regardless of tooling. The private
|
|
264
277
|
* port is what makes the HTTP probe trustworthy: an orphaned server from an
|
|
265
|
-
* earlier check answers on
|
|
278
|
+
* earlier check answers on:3000, but nobody else knows this number.
|
|
266
279
|
* - if nothing can enumerate listeners AND the assigned port never answered, the
|
|
267
280
|
* served-app requirement is unobservable here, so `expectServer` collapses to
|
|
268
281
|
* the survival rule and the PASS is stamped UNOBSERVED. An app that ignores PORT
|
|
@@ -270,8 +283,10 @@ export declare function defaultFindPortHolder(port: number): {
|
|
|
270
283
|
* not an app defect, and it may not be reported as one.
|
|
271
284
|
*
|
|
272
285
|
* A child that EXITS non-zero still FAILs in every environment: "the process died"
|
|
273
|
-
* needs no socket probe
|
|
274
|
-
*
|
|
286
|
+
* needs no socket probe. Confirmed — a start script exiting 3 comes back as
|
|
287
|
+
* `exited 3` with the output tail attached, with no listener question asked. That
|
|
288
|
+
* is what keeps a crashed app reportable even where a hot-reloading runtime would
|
|
289
|
+
* otherwise hold the process open.
|
|
275
290
|
*
|
|
276
291
|
* Env-gap contract as everywhere: spawn error (ENOENT) or a command-not-found
|
|
277
292
|
* inside the chain (exit 127, or the runner's own wording where the platform
|
|
@@ -283,9 +298,9 @@ export declare function runBootCheck(cwd: string, [bin, args]: HealthCommand, gr
|
|
|
283
298
|
}): Promise<BootOutcome>;
|
|
284
299
|
/**
|
|
285
300
|
* The SAME third verdict, at the door unobservedVerdict cannot reach: the boot
|
|
286
|
-
* check specifically
|
|
301
|
+
* check specifically.
|
|
287
302
|
*
|
|
288
|
-
*
|
|
303
|
+
* A run can ship an app with no HTTP server behind a converged final gate. Its
|
|
289
304
|
* `src/server/index.ts` ends at `export {app}` — no `Bun.serve`, no
|
|
290
305
|
* `export default app`, no `start` script — so `bun run src/server/index.ts` exits
|
|
291
306
|
* 0 immediately and the product cannot be started at all. The gate's boot command
|
|
@@ -294,26 +309,27 @@ export declare function runBootCheck(cwd: string, [bin, args]: HealthCommand, gr
|
|
|
294
309
|
* contribute nothing to `dynObserved`, and `bun run test`, `test:ct`, `build`,
|
|
295
310
|
* `lint`, `seed` and `migrate` all ran — so `dynObserved > 0`, the full-skip
|
|
296
311
|
* blindness guard (observabilityGapFailure) stayed correctly quiet, and the trail
|
|
297
|
-
*
|
|
312
|
+
* report then reads `final-gate: autofix converged — statics + … passed`, with
|
|
313
|
+
* every task green.
|
|
298
314
|
*
|
|
299
315
|
* The defect is that "the app was never observed to boot" and "the app booted
|
|
300
|
-
* fine" produced BYTE-IDENTICAL gate output. That is the class
|
|
316
|
+
* fine" produced BYTE-IDENTICAL gate output. That is the class the verdict check
|
|
301
317
|
* exists to kill one layer up: absence of evidence rendered in the shape of
|
|
302
318
|
* evidence. So a discovered-but-skipped boot now names itself, and — unlike every
|
|
303
319
|
* other skip — it CANNOT be cancelled by observations from other commands.
|
|
304
|
-
* Component tests are the trap here, not the alibi:
|
|
320
|
+
* Component tests are the trap here, not the alibi: a suite of green Playwright
|
|
305
321
|
* CT tests, and CT mounts components in a browser without ever assembling or
|
|
306
322
|
* starting the server.
|
|
307
323
|
*
|
|
308
324
|
* DECIDED, do not silently re-open:
|
|
309
325
|
* - NOT a FAIL. A boot skip on a docker-less box is a genuine environment gap, and
|
|
310
|
-
* failing it re-creates
|
|
326
|
+
* failing it re-creates the unfalsifiable-FAIL mistake pointing the other
|
|
311
327
|
* way. UNOBSERVED blocks nothing while being loud and durable (the caller records
|
|
312
328
|
* it as final-gate debt the next run re-surfaces), and it keeps "boot never ran"
|
|
313
329
|
* out of the autofix child's seed — a child cannot fix a missing docker, so the
|
|
314
330
|
* highest-probability response would be to FABRICATE a bootable command, the
|
|
315
331
|
* class that refuted the `## verified tooling` harvest.
|
|
316
|
-
* - BOTH skip flavours count.
|
|
332
|
+
* - BOTH skip flavours count. A skip can carry `spawnFailed: false` (127 inside
|
|
317
333
|
* the script chain, not an ENOENT on the runner), so keying off spawnFailed would
|
|
318
334
|
* have missed the actual defect.
|
|
319
335
|
* - SERVED APPS ONLY. `expectServer === false` (a CLI/library project) is fenced off
|