@mjasnikovs/pi-task 0.18.15 → 0.18.17
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/README.md +2 -2
- package/dist/task/accept-debt.d.ts +28 -1
- package/dist/task/accept-debt.js +61 -3
- package/dist/task/auto-io.d.ts +4 -2
- package/dist/task/auto-io.js +6 -3
- package/dist/task/auto-orchestrator.d.ts +1 -0
- package/dist/task/auto-orchestrator.js +135 -19
- package/dist/task/auto-prompts.d.ts +5 -5
- package/dist/task/auto-prompts.js +9 -2
- package/dist/task/contracts.d.ts +8 -0
- package/dist/task/contracts.js +4 -2
- package/dist/task/decompose-fidelity.d.ts +47 -0
- package/dist/task/decompose-fidelity.js +132 -0
- package/dist/task/final-gate-fix.d.ts +22 -3
- package/dist/task/final-gate-fix.js +72 -7
- package/dist/task/final-gate.d.ts +48 -1
- package/dist/task/final-gate.js +182 -34
- package/dist/task/gate-deps.d.ts +7 -0
- package/dist/task/gate-deps.js +37 -1
- package/dist/task/launch-contract.d.ts +36 -1
- package/dist/task/launch-contract.js +83 -2
- package/dist/task/phases.d.ts +13 -1
- package/dist/task/phases.js +50 -11
- package/dist/task/prompts.js +2 -0
- package/dist/task/render-check.d.ts +42 -0
- package/dist/task/render-check.js +186 -0
- package/dist/task/requirements.d.ts +88 -0
- package/dist/task/requirements.js +334 -0
- package/dist/task/verify-reconcile.d.ts +36 -0
- package/dist/task/verify-reconcile.js +203 -0
- package/dist/task/write-guard.d.ts +52 -0
- package/dist/task/write-guard.js +112 -0
- package/package.json +1 -1
- package/dist/task/_ab.d.ts +0 -1
- package/dist/task/_ab.js +0 -68
- package/dist/task/task-file.d.ts +0 -14
- package/dist/task/task-file.js +0 -15
- package/dist/think-test/cli.d.ts +0 -1
- package/dist/think-test/cli.js +0 -98
- package/dist/think-test/client.d.ts +0 -26
- package/dist/think-test/client.js +0 -37
- package/dist/think-test/compressor.d.ts +0 -5
- package/dist/think-test/compressor.js +0 -25
- package/dist/think-test/judge.d.ts +0 -4
- package/dist/think-test/judge.js +0 -11
- package/dist/think-test/score.d.ts +0 -8
- package/dist/think-test/score.js +0 -22
- package/dist/think-test/serialize.d.ts +0 -19
- package/dist/think-test/serialize.js +0 -41
- package/dist/think-test/transcript.d.ts +0 -7
- package/dist/think-test/transcript.js +0 -41
- package/dist/think-test/transform.d.ts +0 -6
- package/dist/think-test/transform.js +0 -24
- package/dist/think-test/types.d.ts +0 -45
- package/dist/think-test/types.js +0 -1
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* decompose-fidelity — verbatim fidelity of plan derivations (mx5 run 11, goal B).
|
|
3
|
+
*
|
|
4
|
+
* The failure this closes: the design's §12 milestone lines 2 and 4 end in
|
|
5
|
+
* "guards + tests" / "contact + tests"; the decomposed titles carried everything
|
|
6
|
+
* BUT the "+ tests" suffix. A title is ALL a per-task pipeline ever sees, so a
|
|
7
|
+
* silently dropped constraint fragment vanishes from the whole run — the dropped
|
|
8
|
+
* tests were exactly the instrument that would have caught the shipped 404 bug.
|
|
9
|
+
* Decompose paraphrases freely and NOTHING compared a title to the spec line it
|
|
10
|
+
* derives from.
|
|
11
|
+
*
|
|
12
|
+
* Mechanism (contracts.ts pattern, applied to decompose itself): the decompose
|
|
13
|
+
* prompt asks each task line to cite its origin as a trailing
|
|
14
|
+
* `[source: "<verbatim spec line>"]`. The host then:
|
|
15
|
+
* 1. GROUNDS the quote — a citation that is not a (whitespace/case-normalised)
|
|
16
|
+
* substring of the source doc is fabricated and is stripped, never trusted;
|
|
17
|
+
* 2. deterministically detects DROPPED ADDITIVE FRAGMENTS: the `+`-joined
|
|
18
|
+
* trailing constraints of the cited line ("… + tests") whose words are
|
|
19
|
+
* absent from the title;
|
|
20
|
+
* 3. RE-ATTACHES the missing fragments to the title verbatim.
|
|
21
|
+
*
|
|
22
|
+
* Scope is deliberately the additive-suffix class (`+`-joined fragments): those
|
|
23
|
+
* are constraints by construction, so re-attachment can never inject noise that
|
|
24
|
+
* the cited line doesn't demand — worst case is redundancy with what the title
|
|
25
|
+
* already says, never fabrication. Whole-line paraphrase drift is NOT judged here
|
|
26
|
+
* (a title is a paraphrase by design); requirement-level coverage owns that.
|
|
27
|
+
* No similarity thresholds anywhere: grounding is exact normalised substring,
|
|
28
|
+
* presence is exact word membership (with a singular/plural `s` allowance).
|
|
29
|
+
*/
|
|
30
|
+
import { normalise } from './contracts.js';
|
|
31
|
+
/** Trailing `[source: "…"]` clause a decompose line may carry (prompt asks for it last). */
|
|
32
|
+
const SOURCE_RE = /\s*\[source:\s*"(.+)"\s*\]\s*$/i;
|
|
33
|
+
/** Split a decompose title into its base and its GROUNDED source citation.
|
|
34
|
+
* An absent clause yields no source; a fabricated (ungrounded) one is stripped
|
|
35
|
+
* and dropped — exactly like keepGroundedContracts rejects a paraphrased quote. */
|
|
36
|
+
export function extractTitleSource(title, sourceDoc) {
|
|
37
|
+
const m = SOURCE_RE.exec(title);
|
|
38
|
+
if (!m)
|
|
39
|
+
return { base: title.trim() };
|
|
40
|
+
const base = title.slice(0, m.index).trim();
|
|
41
|
+
const quote = m[1].trim();
|
|
42
|
+
if (quote.length === 0 || !normalise(sourceDoc).includes(normalise(quote))) {
|
|
43
|
+
return { base };
|
|
44
|
+
}
|
|
45
|
+
return { base, source: quote };
|
|
46
|
+
}
|
|
47
|
+
/** Word tokens for presence checks: alphanumeric runs, lowercased. */
|
|
48
|
+
function words(s) {
|
|
49
|
+
return s.toLowerCase().match(/[a-z0-9]+/g) ?? [];
|
|
50
|
+
}
|
|
51
|
+
/** Is every word of `fragment` present in `titleWords`? A bare trailing `s`
|
|
52
|
+
* difference (test/tests) does not count as absence — a rule, not a threshold. */
|
|
53
|
+
function fragmentPresent(fragment, titleWords) {
|
|
54
|
+
return words(fragment).every(w => {
|
|
55
|
+
if (titleWords.has(w))
|
|
56
|
+
return true;
|
|
57
|
+
if (w.endsWith('s') && titleWords.has(w.slice(0, -1)))
|
|
58
|
+
return true;
|
|
59
|
+
return titleWords.has(w + 's');
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The `+`-joined trailing constraint fragments of `sourceLine` whose words are
|
|
64
|
+
* absent from `title`. "2. **Auth** — sessions, login/logout/me, guards + tests."
|
|
65
|
+
* yields the fragment "tests"; a title that never mentions tests gets it back.
|
|
66
|
+
* Fragments before the first `+` are the task's body — a title paraphrases those
|
|
67
|
+
* freely and they are never judged here. A `+`-part is further split on commas
|
|
68
|
+
* ("+ Tailwind v4 tokens, nav, router" is three constraints), so a title missing
|
|
69
|
+
* one of them gets ONLY that one restored, not the whole phrase (measured live:
|
|
70
|
+
* whole-phrase restoration re-attached text the title already carried).
|
|
71
|
+
*/
|
|
72
|
+
export function findDroppedPlusFragments(sourceLine, title) {
|
|
73
|
+
const parts = sourceLine.split('+');
|
|
74
|
+
if (parts.length < 2)
|
|
75
|
+
return [];
|
|
76
|
+
const titleWords = new Set(words(title));
|
|
77
|
+
const missing = [];
|
|
78
|
+
for (const raw of parts.slice(1)) {
|
|
79
|
+
for (const sub of raw.split(',')) {
|
|
80
|
+
// A fragment runs to the next `+`/comma; strip trailing sentence
|
|
81
|
+
// punctuation and markdown emphasis so "tests.**" compares as "tests".
|
|
82
|
+
const fragment = sub
|
|
83
|
+
.replace(/[*_`]/g, '')
|
|
84
|
+
.replace(/[.,;:!?)\]]+\s*$/, '')
|
|
85
|
+
.trim();
|
|
86
|
+
if (fragment.length === 0)
|
|
87
|
+
continue;
|
|
88
|
+
if (words(fragment).length === 0)
|
|
89
|
+
continue;
|
|
90
|
+
if (!fragmentPresent(fragment, titleWords))
|
|
91
|
+
missing.push(fragment);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return missing;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Reconcile decompose output against the source doc: ground each citation, strip
|
|
98
|
+
* the clause (its job ends here), and re-attach any dropped `+`-fragments to the
|
|
99
|
+
* title verbatim so downstream refine/compose — which see ONLY the title — get
|
|
100
|
+
* the constraint back. Titles without a citation pass through unchanged, so a
|
|
101
|
+
* model that never cites degrades to exactly the old behavior.
|
|
102
|
+
*/
|
|
103
|
+
export function reconcileTitleSources(titles, sourceDoc) {
|
|
104
|
+
const out = [];
|
|
105
|
+
const restored = [];
|
|
106
|
+
let sourced = 0;
|
|
107
|
+
for (let i = 0; i < titles.length; i++) {
|
|
108
|
+
const { base, source } = extractTitleSource(titles[i], sourceDoc);
|
|
109
|
+
if (source === undefined) {
|
|
110
|
+
out.push(base);
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
sourced++;
|
|
114
|
+
const missing = findDroppedPlusFragments(source, base);
|
|
115
|
+
if (missing.length === 0) {
|
|
116
|
+
out.push(base);
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
restored.push({ index: i, fragments: missing, source });
|
|
120
|
+
out.push(`${base} — MUST also cover (restored from its spec line): ${missing.join(', ')}`);
|
|
121
|
+
}
|
|
122
|
+
return { titles: out, restored, sourced };
|
|
123
|
+
}
|
|
124
|
+
/** The decompose-prompt rule that makes titles citable (the belt half; the host
|
|
125
|
+
* grounding + restoration above is the lever). Kept here so prompt and parser
|
|
126
|
+
* can't drift apart. */
|
|
127
|
+
export const DECOMPOSE_SOURCE_RULE = '- When a task derives from a specific line of the feature/spec (a milestone, a'
|
|
128
|
+
+ ' bullet, a requirement sentence), END that task\'s line with [source: "<that'
|
|
129
|
+
+ ' line copied VERBATIM>"]. Copy exactly — a paraphrased or invented quote is'
|
|
130
|
+
+ ' discarded host-side. Put the [source: …] clause after any [decisions: …]'
|
|
131
|
+
+ ' clause. When the cited line carries additive constraints ("+ tests",'
|
|
132
|
+
+ ' "+ docs"), those are PART of the task — keep them in the title itself.';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type TreeChangeSummary } from './write-guard.js';
|
|
1
2
|
/** Same bounded-fix contract as lint-fix: edit in place, bash exists to RUN the
|
|
2
3
|
* failing command (and the project's own tooling), not to mutate git state. */
|
|
3
4
|
export declare const FINAL_FIX_TOOLS = "read,edit,bash";
|
|
@@ -79,13 +80,31 @@ export interface FinalFixDeps {
|
|
|
79
80
|
/** Labels of every currently-discoverable gate command (static + integration),
|
|
80
81
|
* for the shrink guard. Pure discovery — nothing is executed. */
|
|
81
82
|
discoverLabels: (cwd: string) => string[];
|
|
82
|
-
/** Discard the fix child's working-tree edits (
|
|
83
|
+
/** Discard the fix child's working-tree edits (guard trips only). Absent
|
|
83
84
|
* → the violation is still rejected, edits are left for inspection. */
|
|
84
85
|
discard?: (cwd: string) => Promise<void>;
|
|
86
|
+
/** The fix child's tree changes (`git status --porcelain` shape) — diff capture
|
|
87
|
+
* for the log and the deletion guard's input. The tree was clean before the
|
|
88
|
+
* child ran (every task committed), so status IS the child's work. */
|
|
89
|
+
treeChanges?: () => Promise<TreeChangeSummary>;
|
|
90
|
+
/** The union of every task spec's frozen (Do-NOT-modify) paths — the whole-run
|
|
91
|
+
* write-deny set, since this child works across all slices at once. */
|
|
92
|
+
frozenPaths?: () => Promise<string[]>;
|
|
93
|
+
/** Restore the given frozen paths to HEAD; returns the files actually reverted
|
|
94
|
+
* (same mechanical deny the enforce pass carries — see frozen-path-guard.ts). */
|
|
95
|
+
revertFrozen?: (paths: string[]) => Promise<string[]>;
|
|
96
|
+
/** Deterministic probe scan over the child's ADDED lines (probe-gaming, F6):
|
|
97
|
+
* a fix written to game a check rather than meet it rejects the attempt —
|
|
98
|
+
* run 11's autofix replaced the typed client with a hand-written contract
|
|
99
|
+
* copy to green the lint. Findings are verbatim offending lines. */
|
|
100
|
+
probeScan?: () => Promise<string[]>;
|
|
101
|
+
/** Write a timestamped line to the gate debug log (guard events). */
|
|
102
|
+
log?: (msg: string) => void;
|
|
85
103
|
}
|
|
86
104
|
/**
|
|
87
|
-
* Run one bounded final-gate fix attempt: snapshot discovery → child →
|
|
88
|
-
*
|
|
105
|
+
* Run one bounded final-gate fix attempt: snapshot discovery → child → write-guard
|
|
106
|
+
* stack (diff capture → frozen-path revert → deletion guard → shrink guard → probe
|
|
107
|
+
* scan) → gate re-run. Never throws for an outcome; only a user cancel inside
|
|
89
108
|
* runChild propagates (the caller's USER_CANCELLED path handles it).
|
|
90
109
|
*/
|
|
91
110
|
export declare function runFinalGateAutofix(deps: FinalFixDeps): Promise<FinalFixResult>;
|
|
@@ -25,8 +25,26 @@
|
|
|
25
25
|
* the child runs; any previously-discovered command that is no longer
|
|
26
26
|
* discoverable afterwards rejects the attempt and discards its edits. A fix may
|
|
27
27
|
* change what a command DOES, never make it disappear.
|
|
28
|
+
*
|
|
29
|
+
* WRITE-GUARD STACK (mx5 run 11): this child was added after the run-8 guard
|
|
30
|
+
* generation and inherited none of them — it ran `rm` on a sibling task's
|
|
31
|
+
* verified deliverable to satisfy a recorded debt claim and hand-copied a pinned
|
|
32
|
+
* contract to green the lint, with free bash and no trace. Every attempt now
|
|
33
|
+
* runs, deterministically and in order: frozen-path revert (when a freeze set is
|
|
34
|
+
* wired — see below) → deletion guard (a tracked file deleted without relocation
|
|
35
|
+
* rejects the attempt) → shrink guard (above) → probe-gaming scan over the added
|
|
36
|
+
* lines (a fix that SAYS it games a check rejects the attempt). Diff capture for
|
|
37
|
+
* every write-capable gate child lives at the gate-deps seam, keyed on the
|
|
38
|
+
* child's TOOLS, so the next write-capable kind cannot run invisibly either.
|
|
39
|
+
*
|
|
40
|
+
* The frozen-path deny is implemented but NOT wired by gate-deps: per-task
|
|
41
|
+
* frozen fences are task-SCOPED (they fence a task off a sibling's territory),
|
|
42
|
+
* and the measured union over the run-11 specs would have reverted the one
|
|
43
|
+
* legitimate whole-repo fix that run needed (migrate.ts — frozen by its own
|
|
44
|
+
* producing task). It activates only when a run-GLOBAL freeze source exists.
|
|
28
45
|
*/
|
|
29
46
|
import { USER_CANCELLED } from './child-runner.js';
|
|
47
|
+
import { findForbiddenDeletions } from './write-guard.js';
|
|
30
48
|
/** Same bounded-fix contract as lint-fix: edit in place, bash exists to RUN the
|
|
31
49
|
* failing command (and the project's own tooling), not to mutate git state. */
|
|
32
50
|
export const FINAL_FIX_TOOLS = 'read,edit,bash';
|
|
@@ -100,6 +118,10 @@ export function buildFinalFixPrompt(failReason) {
|
|
|
100
118
|
' command pass. Relocating or scoping a file the runner was never meant',
|
|
101
119
|
' to pick up (per the project’s own config) is a legitimate fix;',
|
|
102
120
|
' deleting it or marking it skipped is not.',
|
|
121
|
+
' - Do NOT delete tracked files at all. Every tracked file is a completed',
|
|
122
|
+
' task’s committed deliverable; a deletion is detected and the whole fix',
|
|
123
|
+
' is rejected. A legitimate relocation keeps the file (same file name)',
|
|
124
|
+
' elsewhere in the tree.',
|
|
103
125
|
' - Do NOT remove or rename the project’s own commands (its test/build/',
|
|
104
126
|
' lint scripts or targets). Making the gate unable to find the command',
|
|
105
127
|
' is detected and the whole fix is rejected.',
|
|
@@ -135,8 +157,9 @@ export function parseFinalFixMarker(text) {
|
|
|
135
157
|
return { blocked: false, note: last[2].trim() || undefined };
|
|
136
158
|
}
|
|
137
159
|
/**
|
|
138
|
-
* Run one bounded final-gate fix attempt: snapshot discovery → child →
|
|
139
|
-
*
|
|
160
|
+
* Run one bounded final-gate fix attempt: snapshot discovery → child → write-guard
|
|
161
|
+
* stack (diff capture → frozen-path revert → deletion guard → shrink guard → probe
|
|
162
|
+
* scan) → gate re-run. Never throws for an outcome; only a user cancel inside
|
|
140
163
|
* runChild propagates (the caller's USER_CANCELLED path handles it).
|
|
141
164
|
*/
|
|
142
165
|
export async function runFinalGateAutofix(deps) {
|
|
@@ -151,6 +174,38 @@ export async function runFinalGateAutofix(deps) {
|
|
|
151
174
|
throw err;
|
|
152
175
|
return { ok: false, reason: `fix child failed: ${msg}` };
|
|
153
176
|
}
|
|
177
|
+
const rejected = (what) => ({
|
|
178
|
+
ok: false,
|
|
179
|
+
reason: `${what} — edits ${deps.discard ? 'discarded' : 'REJECTED but left in the tree (no discard available)'}`
|
|
180
|
+
});
|
|
181
|
+
// (Diff capture — what the pass changed, durably — happens at the gate-deps
|
|
182
|
+
// seam for every write-capable child; here only the guards act on it.)
|
|
183
|
+
// FROZEN-PATH WRITE-DENY: undo the child's edits to any path a task spec
|
|
184
|
+
// froze, before anything downstream can act on them — same mechanical deny
|
|
185
|
+
// the enforce pass carries (prompt framing is A/B-proven insufficient).
|
|
186
|
+
// Non-fatal: the rest of the fix survives, only the frozen edits are undone.
|
|
187
|
+
if (deps.frozenPaths && deps.revertFrozen) {
|
|
188
|
+
const frozen = await deps.frozenPaths();
|
|
189
|
+
if (frozen.length > 0) {
|
|
190
|
+
const reverted = await deps.revertFrozen(frozen);
|
|
191
|
+
if (reverted.length > 0) {
|
|
192
|
+
deps.log?.(`final-fix FROZEN-PATH GUARD — reverted spec-frozen file(s) the fix pass modified: ${reverted.join(', ')}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// DELETION GUARD (post-revert state): a tracked file the pass deleted without
|
|
197
|
+
// relocating it is a committed deliverable destroyed — reject the attempt.
|
|
198
|
+
if (deps.treeChanges) {
|
|
199
|
+
const gone = findForbiddenDeletions(await deps.treeChanges());
|
|
200
|
+
if (gone.length > 0) {
|
|
201
|
+
if (deps.discard)
|
|
202
|
+
await deps.discard(deps.cwd);
|
|
203
|
+
const r = rejected(`fix pass DELETED tracked file(s) (${gone.join(', ')}) — a completed task's `
|
|
204
|
+
+ `committed deliverable is not the fix child's to remove`);
|
|
205
|
+
deps.log?.(`final-fix DELETION GUARD — ${r.reason}`);
|
|
206
|
+
return r;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
154
209
|
// SHRINK GUARD: every gate command discoverable before the fix must still be
|
|
155
210
|
// discoverable after it. A vanished command means the child "fixed" the gate
|
|
156
211
|
// by removing the check — reject and (when possible) discard the edits.
|
|
@@ -159,11 +214,21 @@ export async function runFinalGateAutofix(deps) {
|
|
|
159
214
|
if (vanished.length > 0) {
|
|
160
215
|
if (deps.discard)
|
|
161
216
|
await deps.discard(deps.cwd);
|
|
162
|
-
return {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
217
|
+
return rejected(`fix pass removed the gate's own command(s) (${vanished.join(', ')})`);
|
|
218
|
+
}
|
|
219
|
+
// PROBE SCAN (F6): added lines whose stated purpose is to make a check pass
|
|
220
|
+
// rather than meet the requirement reject the attempt — there is no verify
|
|
221
|
+
// child downstream of this pass to judge the finding, and the probe is
|
|
222
|
+
// FP-measured at 1 true hit in 50,735 added lines on the real corpus.
|
|
223
|
+
if (deps.probeScan) {
|
|
224
|
+
const findings = await deps.probeScan();
|
|
225
|
+
if (findings.length > 0) {
|
|
226
|
+
if (deps.discard)
|
|
227
|
+
await deps.discard(deps.cwd);
|
|
228
|
+
const r = rejected(`fix pass added CHECK-GAMING code (${findings.slice(0, 2).join('; ').slice(0, 300)})`);
|
|
229
|
+
deps.log?.(`final-fix PROBE-GAMING GUARD — ${r.reason}`);
|
|
230
|
+
return r;
|
|
231
|
+
}
|
|
167
232
|
}
|
|
168
233
|
const marker = parseFinalFixMarker(text);
|
|
169
234
|
if (marker.blocked) {
|
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
import { type HealthCommand } from './repo-health-check.js';
|
|
2
2
|
import { type AcceptDebt } from './accept-debt.js';
|
|
3
|
+
import { type RenderOutcome } from './render-check.js';
|
|
3
4
|
export interface FinalGateOutcome {
|
|
4
5
|
/** true → statics and every runnable integration command passed (or nothing to run). */
|
|
5
6
|
ok: boolean;
|
|
6
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* On a fail: the exact command, its exit code, and the tail of its output — the
|
|
9
|
+
* MECHANICAL failure only. The accept-debt note is deliberately NOT folded in
|
|
10
|
+
* here (mx5 run 11): this string seeds the final-gate AUTOFIX child's prompt,
|
|
11
|
+
* and a debt included there is read as an instruction — the run-11 fix child
|
|
12
|
+
* `rm`'d a sibling task's verified deliverable to satisfy a recorded claim. The
|
|
13
|
+
* child cannot act on text it never receives; debts travel in `debtNote`.
|
|
14
|
+
*/
|
|
7
15
|
reason: string;
|
|
16
|
+
/**
|
|
17
|
+
* Human-facing suffix listing the still-open accepted-defect claims (see
|
|
18
|
+
* buildAcceptDebtNote) — for the picker question and the trail, NEVER for the
|
|
19
|
+
* autofix seed. Absent when nothing is open.
|
|
20
|
+
*/
|
|
21
|
+
debtNote?: string;
|
|
8
22
|
/**
|
|
9
23
|
* ACCEPT-despite-verify-FAIL debts still open at run end (mx5 run 4 B3 / run 8
|
|
10
24
|
* TASK_0012): tasks the user blessed as-is despite a verify-FAIL that a
|
|
@@ -33,6 +47,9 @@ export declare function discoverLockfileChecks(cwd: string): HealthCommand[];
|
|
|
33
47
|
export declare function discoverBootCommand(cwd: string): HealthCommand | null;
|
|
34
48
|
type BootOutcome = {
|
|
35
49
|
outcome: 'skip' | 'pass';
|
|
50
|
+
/** Set when the render check could not OBSERVE the served page (no browser,
|
|
51
|
+
* undeterminable port) — surfaced by the gate as an UNOBSERVED warning. */
|
|
52
|
+
renderNote?: string;
|
|
36
53
|
} | {
|
|
37
54
|
outcome: 'fail';
|
|
38
55
|
detail: string;
|
|
@@ -60,6 +77,20 @@ export interface BootDeps {
|
|
|
60
77
|
* real socket; the default probes ss/lsof + pgid.
|
|
61
78
|
*/
|
|
62
79
|
groupHasListener?: (pgid: number) => boolean;
|
|
80
|
+
/**
|
|
81
|
+
* The (lowest) TCP port a listener owned by process group `pgid` is bound to,
|
|
82
|
+
* or null when it cannot be determined. Feeds the render check's URL; injected
|
|
83
|
+
* for tests, default probes ss/lsof + pgid.
|
|
84
|
+
*/
|
|
85
|
+
groupListeningPort?: (pgid: number) => number | null;
|
|
86
|
+
/**
|
|
87
|
+
* Load the served page once in a headless browser and judge the RENDERED DOM
|
|
88
|
+
* (mx5 runs 8/11: curl cannot execute JS, so a blank-mount app passed every
|
|
89
|
+
* gate). Runs only for a served app, against the live listener, before the
|
|
90
|
+
* boot child is killed. Absent → the boot check behaves exactly as before;
|
|
91
|
+
* the gate wires runRenderCheck by default for served apps.
|
|
92
|
+
*/
|
|
93
|
+
renderProbe?: (url: string) => RenderOutcome;
|
|
63
94
|
}
|
|
64
95
|
/**
|
|
65
96
|
* Does the finished run stand up a listening HTTP server? Deterministic, from the
|
|
@@ -101,6 +132,22 @@ export declare function runBootCheck(cwd: string, [bin, args]: HealthCommand, gr
|
|
|
101
132
|
* gaming the gate, not fixing the defect.
|
|
102
133
|
*/
|
|
103
134
|
export declare function discoverGateCommandLabels(cwd: string): string[];
|
|
135
|
+
/**
|
|
136
|
+
* A non-zero exit whose output shows the EXTERNAL INFRASTRUCTURE a launch script
|
|
137
|
+
* talks to is absent HERE — a database/daemon that is not running or not
|
|
138
|
+
* installed — rather than a fault in the script itself. Applied ONLY to
|
|
139
|
+
* launch-contract scripts (a migrate/seed against no DB is an environment gap on
|
|
140
|
+
* this box; the same wording in a `test` run is a real failure the suite must own).
|
|
141
|
+
*/
|
|
142
|
+
export declare const INFRA_GAP_OUTPUT_RE: RegExp;
|
|
143
|
+
/**
|
|
144
|
+
* The task whose commit INTRODUCED `rel` (oldest `--diff-filter=A` commit whose
|
|
145
|
+
* subject carries the pi-task `(TASK_nnnn)` suffix — both the task snapshot and the
|
|
146
|
+
* ENFORCE commit shapes match). Null when the file predates the run, was never
|
|
147
|
+
* committed, git is unavailable, or the adding commit is not a task commit — every
|
|
148
|
+
* unknown degrades to "no conflict claim".
|
|
149
|
+
*/
|
|
150
|
+
export declare function taskThatIntroduced(cwd: string, rel: string): string | null;
|
|
104
151
|
/**
|
|
105
152
|
* Run the final gate: static analysis first, then the lockfile consistency
|
|
106
153
|
* checks, then the discovered integration commands, then one boot exercise of
|