@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
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* decompose-fidelity — verbatim fidelity of plan derivations
|
|
2
|
+
* decompose-fidelity — verbatim fidelity of plan derivations.
|
|
3
3
|
*
|
|
4
|
-
* The failure this closes:
|
|
5
|
-
* "guards + tests"
|
|
4
|
+
* The failure this closes: a design's milestone line ends in an additive
|
|
5
|
+
* constraint — "… guards + tests" — and the decomposed title carries everything
|
|
6
6
|
* BUT the "+ tests" suffix. A title is ALL a per-task pipeline ever sees, so a
|
|
7
|
-
* silently dropped
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* derives from.
|
|
7
|
+
* silently dropped fragment vanishes from the whole run, and the dropped thing is
|
|
8
|
+
* disproportionately the instrument that would have caught the bug. Decompose
|
|
9
|
+
* paraphrases freely, and without this nothing compares a title to the spec line
|
|
10
|
+
* it derives from.
|
|
11
11
|
*
|
|
12
12
|
* Mechanism (contracts.ts pattern, applied to decompose itself): the decompose
|
|
13
13
|
* prompt asks each task line to cite its origin as a trailing
|
|
@@ -20,9 +20,11 @@
|
|
|
20
20
|
* 3. RE-ATTACHES the missing fragments to the title verbatim.
|
|
21
21
|
*
|
|
22
22
|
* Scope is deliberately the additive-suffix class (`+`-joined fragments): those
|
|
23
|
-
* are constraints by construction, so re-attachment can never inject noise
|
|
24
|
-
*
|
|
25
|
-
* already says, never fabrication.
|
|
23
|
+
* are constraints by construction, so re-attachment can never inject noise the
|
|
24
|
+
* cited line does not demand — worst case is redundancy with what the title
|
|
25
|
+
* already says, never fabrication. In practice not even that: a title that
|
|
26
|
+
* already carries the fragment restores nothing, and the singular/plural
|
|
27
|
+
* allowance means "a test" counts as covering "tests". Whole-line paraphrase drift is NOT judged here
|
|
26
28
|
* (a title is a paraphrase by design); requirement-level coverage owns that.
|
|
27
29
|
* No similarity thresholds anywhere: grounding is exact normalised substring,
|
|
28
30
|
* presence is exact word membership (with a singular/plural `s` allowance).
|
|
@@ -45,17 +47,15 @@ const SOURCE_RE = /^\[source:\s*"([\s\S]*)"\s*\]$/i;
|
|
|
45
47
|
*
|
|
46
48
|
* BACKTICKS ARE THE SAME CLASS and were the larger half. A code span renders as
|
|
47
49
|
* bare text, so `3. **Invites** — create/validate/redeem, \`/join/:token\` page.`
|
|
48
|
-
* comes back as `Invites — create/validate/redeem, /join/:token page.`
|
|
49
|
-
*
|
|
50
|
-
* 107/216 grounded with backticks kept, 216/216 with them dropped.
|
|
50
|
+
* comes back as `Invites — create/validate/redeem, /join/:token page.` Screening
|
|
51
|
+
* every spec line in its RENDERED form is what makes those quotes match at all.
|
|
51
52
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* CEILING real spec
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* check: CEILING raw 216/216, CEILING rendered 216/216, FLOOR 0/216.
|
|
53
|
+
* The two directions this has to hold in, both run:
|
|
54
|
+
* FLOOR a real spec line with ONE content word altered must NOT be grounded —
|
|
55
|
+
* changing `sessions` to `tokens`, or `redeem` to `revoke`, drops it.
|
|
56
|
+
* CEILING a real spec line quoted without its markup MUST be grounded — both the
|
|
57
|
+
* `2. **Auth** —` numbering-and-bold case and the backticked
|
|
58
|
+
* `` `/join/:token` `` case still match.
|
|
59
59
|
*/
|
|
60
60
|
function demark(s) {
|
|
61
61
|
return s
|
|
@@ -69,10 +69,13 @@ function demark(s) {
|
|
|
69
69
|
* Undo the backslash-escaping a model applies to a quote it is putting INSIDE a
|
|
70
70
|
* double-quoted clause. `[source: "… \`import { sql } from \\"bun\\"\` gotcha …"]`
|
|
71
71
|
* is a faithful copy of a line the document stores with plain quotes; the
|
|
72
|
-
* backslashes are an artefact of the delimiter, not content
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
72
|
+
* backslashes are an artefact of the delimiter, not content, so without this an
|
|
73
|
+
* otherwise-faithful quote fails to match for that reason alone.
|
|
74
|
+
*
|
|
75
|
+
* Only `\"` is undone — no other escape sequence is interpreted, so this cannot
|
|
76
|
+
* rewrite a quote into something the document happens to contain. Confirmed both
|
|
77
|
+
* ways: the escaped-quote citation grounds, and a citation carrying a literal
|
|
78
|
+
* `\n` does not.
|
|
76
79
|
*/
|
|
77
80
|
function unescapeQuotes(s) {
|
|
78
81
|
return s.replace(/\\"/g, '"');
|
|
@@ -80,15 +83,17 @@ function unescapeQuotes(s) {
|
|
|
80
83
|
/**
|
|
81
84
|
* Split a decompose title into its base and its GROUNDED source citations.
|
|
82
85
|
*
|
|
83
|
-
* PLURAL, because the model emits plural
|
|
84
|
-
* citation and a
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
* which of course
|
|
89
|
-
* fabricated one
|
|
90
|
-
*
|
|
91
|
-
* matching plus the `$` anchor
|
|
86
|
+
* PLURAL, because the model emits plural: the prompt asks for one trailing
|
|
87
|
+
* citation and a real share of titles carry more than one.
|
|
88
|
+
*
|
|
89
|
+
* A single anchored pattern cannot read them. Run on `[source: "A"] [source: "B"]`,
|
|
90
|
+
* `\[source:\s*"(.+)"\]$` captures the superstring `A"] [source: "B` — from the
|
|
91
|
+
* FIRST clause to the LAST quote — which is of course not in the document, so two
|
|
92
|
+
* real citations become one fabricated one and both are discarded. Making the
|
|
93
|
+
* quantifier LAZY changes nothing: `(.+?)` against the same input captures the
|
|
94
|
+
* identical superstring, because leftmost-first matching plus the `$` anchor
|
|
95
|
+
* expands it across the later clauses just the same. Peeling from the end with
|
|
96
|
+
* lastIndexOf is what actually works — confirmed, both citations come back.
|
|
92
97
|
*
|
|
93
98
|
* An absent clause yields no sources; a fabricated (ungrounded) one is dropped
|
|
94
99
|
* — exactly like keepGroundedContracts rejects a paraphrased quote.
|
|
@@ -2,18 +2,15 @@
|
|
|
2
2
|
* decompose-granularity — the deterministic FLOOR on how finely /task-auto cuts
|
|
3
3
|
* a feature into tasks.
|
|
4
4
|
*
|
|
5
|
-
* The failure this closes
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* never sees the fork; and the answer decides the whole plan. Live A/B, run 18's
|
|
12
|
-
* transcript with ONLY that line swapped (n=8/arm): coarse mean 11.4 titles vs
|
|
13
|
-
* fine mean 28.6, 63.5/64 pairwise wins, p<0.001.
|
|
5
|
+
* The failure this closes: the SAME design doc, from the SAME base commit, with a
|
|
6
|
+
* byte-identical planning path, plans several times coarser or finer depending on
|
|
7
|
+
* ONE line of clarify text. /task-auto's clarify head asks a plan-shape question
|
|
8
|
+
* first ("one task per milestone, or split smaller?"), the answer-side triage
|
|
9
|
+
* auto-resolves it and stamps it "already settled by the spec", so the user never
|
|
10
|
+
* sees the fork — and that answer decides the whole plan.
|
|
14
11
|
*
|
|
15
|
-
* The spec does NOT settle it.
|
|
16
|
-
*
|
|
12
|
+
* The spec does NOT settle it. A section titled "Build order (milestones)" is an
|
|
13
|
+
* ORDER, not a task breakdown. So the plan's granularity, the single
|
|
17
14
|
* highest-leverage decision in a run (each title is handed to its own pipeline
|
|
18
15
|
* that researches and specs it alone), was being decided by a coin flip nobody
|
|
19
16
|
* could see, review, or reproduce.
|
|
@@ -25,10 +22,10 @@
|
|
|
25
22
|
*
|
|
26
23
|
* floor = ceil(ownable requirements / MAX_REQUIREMENTS_PER_TASK)
|
|
27
24
|
*
|
|
28
|
-
* MAX_REQUIREMENTS_PER_TASK = 2
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
25
|
+
* MAX_REQUIREMENTS_PER_TASK = 2 sits deliberately between the two shapes: a plan
|
|
26
|
+
* cut fine enough to work carries roughly one ownable requirement per task, and a
|
|
27
|
+
* collapsed one bundles several. A ceiling of 2 rejects the collapse without
|
|
28
|
+
* demanding the finest possible plan.
|
|
32
29
|
*
|
|
33
30
|
* Spec-shape-agnostic: the only inputs are two integers. A CLI, a library, a
|
|
34
31
|
* refactor, a docs job all flow through the same arithmetic, and a feature with
|
|
@@ -37,7 +34,7 @@
|
|
|
37
34
|
*/
|
|
38
35
|
/**
|
|
39
36
|
* The most distinct grounded requirements one task may carry before the plan is
|
|
40
|
-
* judged too coarse. See the module docstring for the
|
|
37
|
+
* judged too coarse. See the module docstring for where the number comes from.
|
|
41
38
|
*/
|
|
42
39
|
export declare const MAX_REQUIREMENTS_PER_TASK = 2;
|
|
43
40
|
/**
|
|
@@ -47,14 +44,14 @@ export declare const MAX_REQUIREMENTS_PER_TASK = 2;
|
|
|
47
44
|
* Also zero below MIN_REQUIREMENTS_FOR_PLAN_SHAPE, for the reason that constant
|
|
48
45
|
* already documents: under a handful of requirements the plan is one or two tasks
|
|
49
46
|
* either way, and the requirement COUNT at that scale is an artifact of extraction
|
|
50
|
-
* granularity rather than real breadth.
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
47
|
+
* granularity rather than real breadth. A one-line feature request — "add a
|
|
48
|
+
* --version flag that prints the version and exits 0" — extracts three ownable
|
|
49
|
+
* requirements (the flag, the print, the exit code) for what is unambiguously one
|
|
50
|
+
* task, and an ungated floor would demand two. The same cut governs both checks
|
|
51
|
+
* because it is the same judgement.
|
|
52
|
+
*
|
|
53
|
+
* Run: the floor is 0 for 0-4 ownable requirements, then ceil(n/2) — 5 gives 3,
|
|
54
|
+
* 10 gives 5, 21 gives 11.
|
|
58
55
|
*/
|
|
59
56
|
export declare function granularityFloor(ownable: number): number;
|
|
60
57
|
/** Is this plan too coarse for the requirements it has to carry? */
|
|
@@ -76,25 +73,31 @@ export declare function planShapeIsHostsToAnswer(ownable: number): boolean;
|
|
|
76
73
|
/**
|
|
77
74
|
* Does this clarify question decide how finely the feature is CUT into tasks?
|
|
78
75
|
*
|
|
79
|
-
* Deterministic and narrow on purpose
|
|
80
|
-
* answering for itself
|
|
81
|
-
*
|
|
82
|
-
*
|
|
76
|
+
* Deterministic and narrow on purpose: it must fire on the fork the triage keeps
|
|
77
|
+
* answering for itself and stay off ordinary scope questions, because an
|
|
78
|
+
* over-eager classifier would replace a real user decision with the host's.
|
|
79
|
+
* Matched against the plain-text question.
|
|
80
|
+
*
|
|
81
|
+
* BOTH halves must hold — a breakdown phrase AND a plan-unit noun — and the unit
|
|
82
|
+
* list is SINGULAR except for tasks. Measured across the units it names:
|
|
83
|
+
* milestone / section / step / phase / task / tasks fire
|
|
84
|
+
* milestones / sections / steps / phases do NOT
|
|
85
|
+
* So "one task per milestone, or split smaller?" fires, while the same fork
|
|
86
|
+
* phrased "follow the milestones as-is, or split more granularly?" does not —
|
|
87
|
+
* the breakdown half matches, the plural unit does not.
|
|
83
88
|
*/
|
|
84
89
|
export declare function isPlanShapeQuestion(question: string): boolean;
|
|
85
90
|
/**
|
|
86
91
|
* BELT — the host's own answer to that fork, recorded in the clarify transcript in
|
|
87
92
|
* place of the triage's.
|
|
88
93
|
*
|
|
89
|
-
* WHY A CLARIFICATION AND NOT A DECOMPOSE RULE.
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* intact, the identical directive held 20–39 titles across 16 reps. The channel is
|
|
97
|
-
* part of the lever, not a detail.
|
|
94
|
+
* WHY A CLARIFICATION AND NOT A DECOMPOSE RULE. The identical directive behaves
|
|
95
|
+
* very differently depending on where it lands. As a RULES line REPLACING "prefer
|
|
96
|
+
* a handful of substantial tasks", it removes the collapse but takes the
|
|
97
|
+
* counterweight with it, and plan size runs away — far enough that a decompose
|
|
98
|
+
* child can exhaust its context window and kill the planning phase outright. In
|
|
99
|
+
* the CLARIFICATIONS block, with that counterweight left intact, the same words
|
|
100
|
+
* land as one input among several. The channel is part of the lever, not a detail.
|
|
98
101
|
*
|
|
99
102
|
* Deliberately count-free: the spec-derived floor stays host-side, where it is
|
|
100
103
|
* enforced silently and cannot be chased.
|
|
@@ -105,6 +108,6 @@ export declare const PLAN_SHAPE_ANSWER: string;
|
|
|
105
108
|
* BRACES — the reprompt when the returned plan lands under the floor. Also
|
|
106
109
|
* countless, for the reason above: it asks for a SPLIT of the plan in hand rather
|
|
107
110
|
* than a fresh roll (a regeneration is a new stochastic draw over the whole plan
|
|
108
|
-
* and can drop an area the current one covers
|
|
111
|
+
* and can drop an area the current one covers).
|
|
109
112
|
*/
|
|
110
113
|
export declare function granularitySplitHint(titles: number, ownable: number): string;
|
|
@@ -2,18 +2,15 @@
|
|
|
2
2
|
* decompose-granularity — the deterministic FLOOR on how finely /task-auto cuts
|
|
3
3
|
* a feature into tasks.
|
|
4
4
|
*
|
|
5
|
-
* The failure this closes
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* never sees the fork; and the answer decides the whole plan. Live A/B, run 18's
|
|
12
|
-
* transcript with ONLY that line swapped (n=8/arm): coarse mean 11.4 titles vs
|
|
13
|
-
* fine mean 28.6, 63.5/64 pairwise wins, p<0.001.
|
|
5
|
+
* The failure this closes: the SAME design doc, from the SAME base commit, with a
|
|
6
|
+
* byte-identical planning path, plans several times coarser or finer depending on
|
|
7
|
+
* ONE line of clarify text. /task-auto's clarify head asks a plan-shape question
|
|
8
|
+
* first ("one task per milestone, or split smaller?"), the answer-side triage
|
|
9
|
+
* auto-resolves it and stamps it "already settled by the spec", so the user never
|
|
10
|
+
* sees the fork — and that answer decides the whole plan.
|
|
14
11
|
*
|
|
15
|
-
* The spec does NOT settle it.
|
|
16
|
-
*
|
|
12
|
+
* The spec does NOT settle it. A section titled "Build order (milestones)" is an
|
|
13
|
+
* ORDER, not a task breakdown. So the plan's granularity, the single
|
|
17
14
|
* highest-leverage decision in a run (each title is handed to its own pipeline
|
|
18
15
|
* that researches and specs it alone), was being decided by a coin flip nobody
|
|
19
16
|
* could see, review, or reproduce.
|
|
@@ -25,10 +22,10 @@
|
|
|
25
22
|
*
|
|
26
23
|
* floor = ceil(ownable requirements / MAX_REQUIREMENTS_PER_TASK)
|
|
27
24
|
*
|
|
28
|
-
* MAX_REQUIREMENTS_PER_TASK = 2
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
25
|
+
* MAX_REQUIREMENTS_PER_TASK = 2 sits deliberately between the two shapes: a plan
|
|
26
|
+
* cut fine enough to work carries roughly one ownable requirement per task, and a
|
|
27
|
+
* collapsed one bundles several. A ceiling of 2 rejects the collapse without
|
|
28
|
+
* demanding the finest possible plan.
|
|
32
29
|
*
|
|
33
30
|
* Spec-shape-agnostic: the only inputs are two integers. A CLI, a library, a
|
|
34
31
|
* refactor, a docs job all flow through the same arithmetic, and a feature with
|
|
@@ -37,7 +34,7 @@
|
|
|
37
34
|
*/
|
|
38
35
|
/**
|
|
39
36
|
* The most distinct grounded requirements one task may carry before the plan is
|
|
40
|
-
* judged too coarse. See the module docstring for the
|
|
37
|
+
* judged too coarse. See the module docstring for where the number comes from.
|
|
41
38
|
*/
|
|
42
39
|
export const MAX_REQUIREMENTS_PER_TASK = 2;
|
|
43
40
|
/**
|
|
@@ -47,14 +44,14 @@ export const MAX_REQUIREMENTS_PER_TASK = 2;
|
|
|
47
44
|
* Also zero below MIN_REQUIREMENTS_FOR_PLAN_SHAPE, for the reason that constant
|
|
48
45
|
* already documents: under a handful of requirements the plan is one or two tasks
|
|
49
46
|
* either way, and the requirement COUNT at that scale is an artifact of extraction
|
|
50
|
-
* granularity rather than real breadth.
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
47
|
+
* granularity rather than real breadth. A one-line feature request — "add a
|
|
48
|
+
* --version flag that prints the version and exits 0" — extracts three ownable
|
|
49
|
+
* requirements (the flag, the print, the exit code) for what is unambiguously one
|
|
50
|
+
* task, and an ungated floor would demand two. The same cut governs both checks
|
|
51
|
+
* because it is the same judgement.
|
|
52
|
+
*
|
|
53
|
+
* Run: the floor is 0 for 0-4 ownable requirements, then ceil(n/2) — 5 gives 3,
|
|
54
|
+
* 10 gives 5, 21 gives 11.
|
|
58
55
|
*/
|
|
59
56
|
export function granularityFloor(ownable) {
|
|
60
57
|
if (ownable < MIN_REQUIREMENTS_FOR_PLAN_SHAPE)
|
|
@@ -84,10 +81,18 @@ export function planShapeIsHostsToAnswer(ownable) {
|
|
|
84
81
|
/**
|
|
85
82
|
* Does this clarify question decide how finely the feature is CUT into tasks?
|
|
86
83
|
*
|
|
87
|
-
* Deterministic and narrow on purpose
|
|
88
|
-
* answering for itself
|
|
89
|
-
*
|
|
90
|
-
*
|
|
84
|
+
* Deterministic and narrow on purpose: it must fire on the fork the triage keeps
|
|
85
|
+
* answering for itself and stay off ordinary scope questions, because an
|
|
86
|
+
* over-eager classifier would replace a real user decision with the host's.
|
|
87
|
+
* Matched against the plain-text question.
|
|
88
|
+
*
|
|
89
|
+
* BOTH halves must hold — a breakdown phrase AND a plan-unit noun — and the unit
|
|
90
|
+
* list is SINGULAR except for tasks. Measured across the units it names:
|
|
91
|
+
* milestone / section / step / phase / task / tasks fire
|
|
92
|
+
* milestones / sections / steps / phases do NOT
|
|
93
|
+
* So "one task per milestone, or split smaller?" fires, while the same fork
|
|
94
|
+
* phrased "follow the milestones as-is, or split more granularly?" does not —
|
|
95
|
+
* the breakdown half matches, the plural unit does not.
|
|
91
96
|
*/
|
|
92
97
|
export function isPlanShapeQuestion(question) {
|
|
93
98
|
const q = question.toLowerCase();
|
|
@@ -102,15 +107,13 @@ export function isPlanShapeQuestion(question) {
|
|
|
102
107
|
* BELT — the host's own answer to that fork, recorded in the clarify transcript in
|
|
103
108
|
* place of the triage's.
|
|
104
109
|
*
|
|
105
|
-
* WHY A CLARIFICATION AND NOT A DECOMPOSE RULE.
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
* intact, the identical directive held 20–39 titles across 16 reps. The channel is
|
|
113
|
-
* part of the lever, not a detail.
|
|
110
|
+
* WHY A CLARIFICATION AND NOT A DECOMPOSE RULE. The identical directive behaves
|
|
111
|
+
* very differently depending on where it lands. As a RULES line REPLACING "prefer
|
|
112
|
+
* a handful of substantial tasks", it removes the collapse but takes the
|
|
113
|
+
* counterweight with it, and plan size runs away — far enough that a decompose
|
|
114
|
+
* child can exhaust its context window and kill the planning phase outright. In
|
|
115
|
+
* the CLARIFICATIONS block, with that counterweight left intact, the same words
|
|
116
|
+
* land as one input among several. The channel is part of the lever, not a detail.
|
|
114
117
|
*
|
|
115
118
|
* Deliberately count-free: the spec-derived floor stays host-side, where it is
|
|
116
119
|
* enforced silently and cannot be chased.
|
|
@@ -125,7 +128,7 @@ export const PLAN_SHAPE_ANSWER = 'subdivide into smaller per-deliverable tasks
|
|
|
125
128
|
* BRACES — the reprompt when the returned plan lands under the floor. Also
|
|
126
129
|
* countless, for the reason above: it asks for a SPLIT of the plan in hand rather
|
|
127
130
|
* than a fresh roll (a regeneration is a new stochastic draw over the whole plan
|
|
128
|
-
* and can drop an area the current one covers
|
|
131
|
+
* and can drop an area the current one covers).
|
|
129
132
|
*/
|
|
130
133
|
export function granularitySplitHint(titles, ownable) {
|
|
131
134
|
return (`[SYSTEM NOTE: your plan of ${titles} task(s) is too coarse for the`
|
|
@@ -12,15 +12,18 @@ export type DeepRenderOutcome = {
|
|
|
12
12
|
export interface LoginCredentials {
|
|
13
13
|
identifier: string;
|
|
14
14
|
password: string;
|
|
15
|
-
/** Key
|
|
15
|
+
/** Key NAMES only. The values are read from the project's own dotenv and typed
|
|
16
|
+
* into the page; neither ever reaches a log line, a skip note or a failure
|
|
17
|
+
* detail — those quote the key names and the request paths only. */
|
|
16
18
|
identifierKey: string;
|
|
17
19
|
passwordKey: string;
|
|
18
20
|
}
|
|
19
21
|
/**
|
|
20
|
-
* Parse a dotenv-style file into a plain record. Deliberately minimal
|
|
21
|
-
* `export ` prefix,
|
|
22
|
-
*
|
|
23
|
-
*
|
|
22
|
+
* Parse a dotenv-style file into a plain record. Deliberately minimal — KEY=VALUE,
|
|
23
|
+
* an optional `export ` prefix, `#` comments, and matching quotes that preserve
|
|
24
|
+
* inner spaces while an unquoted value drops a trailing ` #` comment. This reads
|
|
25
|
+
* the same file the app's own runtime reads, and anything it cannot parse simply
|
|
26
|
+
* yields no credentials, which is a SKIP rather than a failure.
|
|
24
27
|
*/
|
|
25
28
|
export declare function parseEnvFile(text: string): Record<string, string>;
|
|
26
29
|
/** The variables the booted app itself sees: its dotenv files, overlaid by the real
|
|
@@ -37,7 +40,7 @@ export declare function findLoginCredentials(vars: Record<string, string>): Logi
|
|
|
37
40
|
* The LOCAL port the project's own client was built to call, when its dotenv pins
|
|
38
41
|
* one (`APP_URL=http://localhost:3000`, `VITE_API_URL=…`), else null.
|
|
39
42
|
*
|
|
40
|
-
* Why the boot check wants it
|
|
43
|
+
* Why the boot check wants it: a bundler
|
|
41
44
|
* bakes that base URL into the client at BUILD time, so a client served on the
|
|
42
45
|
* gate's freshly-reserved private port calls an origin nothing is listening on. The
|
|
43
46
|
* app is then unusable for reasons that have nothing to do with the code, and the
|
|
@@ -45,7 +48,7 @@ export declare function findLoginCredentials(vars: Record<string, string>): Logi
|
|
|
45
48
|
* origin and never reaches the server we booted. Serving on the app's own declared
|
|
46
49
|
* port makes the session same-origin and the evidence real.
|
|
47
50
|
*
|
|
48
|
-
* This deliberately narrows the private-port ownership evidence
|
|
51
|
+
* This deliberately narrows the private-port ownership evidence, so it
|
|
49
52
|
* only applies when the port is LOCAL, DECLARED by the project itself, and CURRENTLY
|
|
50
53
|
* FREE — the caller checks freeness and falls back to a reserved port otherwise.
|
|
51
54
|
*/
|
|
@@ -117,18 +120,23 @@ export declare function deriveLegacyFacts(log: SessionRequest[]): Pick<DeepSessi
|
|
|
117
120
|
* Judge a recorded session. The ONE thing that may FAIL is a session the SERVER
|
|
118
121
|
* authenticated (2xx on the sign-in request) whose client then could not use it:
|
|
119
122
|
*
|
|
120
|
-
* - never left the wall → the
|
|
123
|
+
* - never left the wall → the signature exactly;
|
|
121
124
|
* - data calls attempted, none 2xx → the same class one page deeper;
|
|
122
|
-
* - post-sign-in page renders blank → the
|
|
125
|
+
* - post-sign-in page renders blank → the class behind the wall.
|
|
123
126
|
*
|
|
124
127
|
* Everything else is an environment or shape gap and SKIPs. Note what is NOT a
|
|
125
128
|
* failure: zero data calls attempted after sign-in. A server-rendered app that
|
|
126
129
|
* redirects to a fresh document legitimately issues no XHR at all, so the missing
|
|
127
|
-
* half is reported UNOBSERVED in the detail instead.
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
130
|
+
* half is reported UNOBSERVED in the detail instead.
|
|
131
|
+
*
|
|
132
|
+
* The data assertion is deliberately POST-AUTH and EXCLUDES the sign-in request.
|
|
133
|
+
* A plain "at least one same-origin 2xx during the session" would be satisfied by
|
|
134
|
+
* the probe's own login POST and nothing else — a broken build passes it.
|
|
135
|
+
*
|
|
136
|
+
* Run across every branch: only those three FAIL. No wall PASSes; no credentials,
|
|
137
|
+
* an undriveable form, no sign-in request, a server that REJECTED the credentials,
|
|
138
|
+
* and a client pinned to a foreign origin all SKIP; and zero post-auth data calls
|
|
139
|
+
* PASSes with the gap noted.
|
|
132
140
|
*/
|
|
133
141
|
export declare function judgeDeepSession(f: DeepSessionFacts): DeepRenderOutcome;
|
|
134
142
|
/** Whole-session wall-clock cap, including browser launch (I4). */
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* deep-render-check — sign in on the booted app and prove the AUTHENTICATED half
|
|
3
|
-
* of it is alive
|
|
3
|
+
* of it is alive.
|
|
4
4
|
*
|
|
5
5
|
* The failure class this closes: the shallow render check (render-check.ts) loads
|
|
6
|
-
* ONE url and judges the rendered DOM.
|
|
6
|
+
* ONE url and judges the rendered DOM. An app can satisfy it completely while
|
|
7
7
|
* being unusable — GET / redirects to /login, the login page renders fully, and
|
|
8
|
-
* that is the whole check.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
8
|
+
* that is the whole check.
|
|
9
|
+
*
|
|
10
|
+
* Behind that wall lives the DEAD CLIENT CALL. A typed RPC client whose method
|
|
11
|
+
* names are proxied (hono's `$get`/`$post`, say) turns a wrong-but-plausible
|
|
12
|
+
* spelling into just another path segment: the call returns a request BUILDER and
|
|
13
|
+
* never issues a request. Login POSTs 200 and sets the session cookie, the
|
|
14
|
+
* follow-up data call is never made at all, and the app bounces back to the wall
|
|
15
|
+
* forever. The dead spellings sit in the same files as correct ones, which is the
|
|
16
|
+
* signature of code no runtime ever executed — and everything static stays green:
|
|
17
|
+
* the suite passes, tsc is clean, and both endpoints answer 200 to curl.
|
|
17
18
|
*
|
|
18
19
|
* The generic instrument is a NETWORK FACT: after a real sign-in, did the client
|
|
19
20
|
* actually leave the wall, and did its data calls actually reach the server. No
|
|
@@ -24,8 +25,8 @@
|
|
|
24
25
|
*
|
|
25
26
|
* SCOPE HONESTY: this is WEB-ONLY. It runs only behind detectsServedApp() and does
|
|
26
27
|
* nothing for C++, Godot, CLI or library projects, which are most of the fleet. It
|
|
27
|
-
* is here because the class is the most expensive one observed
|
|
28
|
-
*
|
|
28
|
+
* is here because the class is the most expensive one observed: a blank page, or
|
|
29
|
+
* a login that does not work, ends a run outright.
|
|
29
30
|
*
|
|
30
31
|
* Mechanism, dependency-free: the same discovered Chrome-family binary the shallow
|
|
31
32
|
* check uses, driven over the DevTools protocol through the `ws` dependency the
|
|
@@ -47,7 +48,9 @@ import { findHeadlessBrowser, judgeRenderedDom } from './render-check.js';
|
|
|
47
48
|
const IDENTIFIER_SUFFIXES = ['PHONE', 'EMAIL', 'USERNAME', 'USER', 'LOGIN', 'IDENTIFIER'];
|
|
48
49
|
const PASSWORD_SUFFIXES = ['PASSWORD', 'PASSWD', 'PASS'];
|
|
49
50
|
/** Prefixes whose `_PASSWORD` belongs to infrastructure, not to an app account.
|
|
50
|
-
* `DB_USER`/`DB_PASSWORD` pair perfectly and would otherwise be tried as a login.
|
|
51
|
+
* `DB_USER`/`DB_PASSWORD` pair perfectly and would otherwise be tried as a login.
|
|
52
|
+
* Confirmed: that pair alone yields no credentials, and so does POSTGRES_*, while
|
|
53
|
+
* an ADMIN pair in the same file is chosen over both. */
|
|
51
54
|
const INFRA_PREFIX_RE = /^(DATABASE|DB|POSTGRES|POSTGRESQL|PG|MYSQL|MARIADB|MONGO|MONGODB|REDIS|RABBIT|RABBITMQ|AMQP|KAFKA|SMTP|IMAP|MAIL|MAILER|S3|MINIO|AWS|GCP|AZURE|DOCKER|REGISTRY|NPM|GITHUB|GITLAB|PROXY|LDAP|VAULT|GRAFANA|SENTRY)$/i;
|
|
52
55
|
/** Prefixes that name a seeded APP account, tried before any other pair. */
|
|
53
56
|
const ACCOUNT_PREFIX_ORDER = ['ADMIN', 'TEST', 'E2E', 'SEED', 'DEV', 'DEFAULT', 'USER', 'LOGIN'];
|
|
@@ -65,10 +68,11 @@ function splitKey(key, suffixes) {
|
|
|
65
68
|
return null;
|
|
66
69
|
}
|
|
67
70
|
/**
|
|
68
|
-
* Parse a dotenv-style file into a plain record. Deliberately minimal
|
|
69
|
-
* `export ` prefix,
|
|
70
|
-
*
|
|
71
|
-
*
|
|
71
|
+
* Parse a dotenv-style file into a plain record. Deliberately minimal — KEY=VALUE,
|
|
72
|
+
* an optional `export ` prefix, `#` comments, and matching quotes that preserve
|
|
73
|
+
* inner spaces while an unquoted value drops a trailing ` #` comment. This reads
|
|
74
|
+
* the same file the app's own runtime reads, and anything it cannot parse simply
|
|
75
|
+
* yields no credentials, which is a SKIP rather than a failure.
|
|
72
76
|
*/
|
|
73
77
|
export function parseEnvFile(text) {
|
|
74
78
|
const out = {};
|
|
@@ -166,7 +170,7 @@ export function findLoginCredentials(vars) {
|
|
|
166
170
|
* The LOCAL port the project's own client was built to call, when its dotenv pins
|
|
167
171
|
* one (`APP_URL=http://localhost:3000`, `VITE_API_URL=…`), else null.
|
|
168
172
|
*
|
|
169
|
-
* Why the boot check wants it
|
|
173
|
+
* Why the boot check wants it: a bundler
|
|
170
174
|
* bakes that base URL into the client at BUILD time, so a client served on the
|
|
171
175
|
* gate's freshly-reserved private port calls an origin nothing is listening on. The
|
|
172
176
|
* app is then unusable for reasons that have nothing to do with the code, and the
|
|
@@ -174,7 +178,7 @@ export function findLoginCredentials(vars) {
|
|
|
174
178
|
* origin and never reaches the server we booted. Serving on the app's own declared
|
|
175
179
|
* port makes the session same-origin and the evidence real.
|
|
176
180
|
*
|
|
177
|
-
* This deliberately narrows the private-port ownership evidence
|
|
181
|
+
* This deliberately narrows the private-port ownership evidence, so it
|
|
178
182
|
* only applies when the port is LOCAL, DECLARED by the project itself, and CURRENTLY
|
|
179
183
|
* FREE — the caller checks freeness and falls back to a reserved port otherwise.
|
|
180
184
|
*/
|
|
@@ -219,18 +223,23 @@ const MISSING_ROUTE_STATUS = new Set([404, 405, 501]);
|
|
|
219
223
|
* Judge a recorded session. The ONE thing that may FAIL is a session the SERVER
|
|
220
224
|
* authenticated (2xx on the sign-in request) whose client then could not use it:
|
|
221
225
|
*
|
|
222
|
-
* - never left the wall → the
|
|
226
|
+
* - never left the wall → the signature exactly;
|
|
223
227
|
* - data calls attempted, none 2xx → the same class one page deeper;
|
|
224
|
-
* - post-sign-in page renders blank → the
|
|
228
|
+
* - post-sign-in page renders blank → the class behind the wall.
|
|
225
229
|
*
|
|
226
230
|
* Everything else is an environment or shape gap and SKIPs. Note what is NOT a
|
|
227
231
|
* failure: zero data calls attempted after sign-in. A server-rendered app that
|
|
228
232
|
* redirects to a fresh document legitimately issues no XHR at all, so the missing
|
|
229
|
-
* half is reported UNOBSERVED in the detail instead.
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
233
|
+
* half is reported UNOBSERVED in the detail instead.
|
|
234
|
+
*
|
|
235
|
+
* The data assertion is deliberately POST-AUTH and EXCLUDES the sign-in request.
|
|
236
|
+
* A plain "at least one same-origin 2xx during the session" would be satisfied by
|
|
237
|
+
* the probe's own login POST and nothing else — a broken build passes it.
|
|
238
|
+
*
|
|
239
|
+
* Run across every branch: only those three FAIL. No wall PASSes; no credentials,
|
|
240
|
+
* an undriveable form, no sign-in request, a server that REJECTED the credentials,
|
|
241
|
+
* and a client pinned to a foreign origin all SKIP; and zero post-auth data calls
|
|
242
|
+
* PASSes with the gap noted.
|
|
234
243
|
*/
|
|
235
244
|
export function judgeDeepSession(f) {
|
|
236
245
|
if (!f.landingHadAuthWall) {
|
|
@@ -753,9 +762,9 @@ export async function driveSession(cdp, { url, credentials, judge, quietMs }) {
|
|
|
753
762
|
lastActivity = Date.now();
|
|
754
763
|
await settle(() => lastActivity, POST_SUBMIT_CAP_MS, quietMs);
|
|
755
764
|
// The sign-in request: the first same-origin non-GET issued by the submit. Its
|
|
756
|
-
// own 2xx is the precondition for judging anything, and it is
|
|
757
|
-
// data evidence
|
|
758
|
-
// exactly this request and nothing else
|
|
765
|
+
// own 2xx is the precondition for judging anything, and it is EXCLUDED from the
|
|
766
|
+
// data evidence — a broken build satisfies "at least one same-origin 2xx" with
|
|
767
|
+
// exactly this request and nothing else.
|
|
759
768
|
const after = new Map([...requests].filter(([, r]) => r.at >= submitMark));
|
|
760
769
|
let authId = null;
|
|
761
770
|
for (const [id, r] of after) {
|
|
@@ -770,7 +779,7 @@ export async function driveSession(cdp, { url, credentials, judge, quietMs }) {
|
|
|
770
779
|
const domJudgment = judgeRenderedDom(now?.html ?? '');
|
|
771
780
|
const leftAuthWall = !(now?.hasPassword ?? false) || (now?.pathname ?? '') !== before.pathname;
|
|
772
781
|
// Exercise the authenticated app once. A sign-in page that ends on a success
|
|
773
|
-
// card
|
|
782
|
+
// card can issue NOTHING after the login POST, so the authenticated
|
|
774
783
|
// data path is never observed at all and every request-shaped fact below is a
|
|
775
784
|
// fact about the login form. Re-entering the landing URL with the session cookie
|
|
776
785
|
// is the cheapest way to make the app fetch its own data. Deliberately gated on
|