@codyswann/lisa 3.33.5 → 3.33.6
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/all/copy-overwrite/scripts/check-state-classification.mjs +18 -4
- package/all/copy-overwrite/scripts/lisa-gates.mjs +47 -46
- package/all/copy-overwrite/scripts/lisa-run-gates.mjs +3 -2
- package/dist/configs/eslint/base.d.ts +21 -0
- package/dist/configs/eslint/base.d.ts.map +1 -1
- package/dist/configs/eslint/base.js +78 -2
- package/dist/configs/eslint/base.js.map +1 -1
- package/dist/configs/eslint/cdk.d.ts.map +1 -1
- package/dist/configs/eslint/cdk.js +5 -1
- package/dist/configs/eslint/cdk.js.map +1 -1
- package/dist/configs/eslint/expo.d.ts.map +1 -1
- package/dist/configs/eslint/expo.js +5 -1
- package/dist/configs/eslint/expo.js.map +1 -1
- package/dist/configs/eslint/harper-fabric.d.ts.map +1 -1
- package/dist/configs/eslint/harper-fabric.js +6 -1
- package/dist/configs/eslint/harper-fabric.js.map +1 -1
- package/dist/configs/eslint/nestjs.d.ts.map +1 -1
- package/dist/configs/eslint/nestjs.js +5 -1
- package/dist/configs/eslint/nestjs.js.map +1 -1
- package/dist/configs/eslint/phaser.d.ts.map +1 -1
- package/dist/configs/eslint/phaser.js +6 -1
- package/dist/configs/eslint/phaser.js.map +1 -1
- package/dist/configs/eslint/typescript.d.ts +2 -2
- package/dist/configs/eslint/typescript.d.ts.map +1 -1
- package/dist/configs/eslint/typescript.js +6 -2
- package/dist/configs/eslint/typescript.js.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +11 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +29 -28
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/expo/copy-overwrite/scripts/bdd/baseline.mjs +11 -4
- package/expo/copy-overwrite/scripts/bdd/discover.mjs +12 -6
- package/expo/copy-overwrite/scripts/bdd/waivers.mjs +7 -4
- package/expo/copy-overwrite/scripts/bdd-matrix.mjs +1 -0
- package/expo/copy-overwrite/scripts/check-bdd-coverage.mjs +26 -17
- package/expo/copy-overwrite/scripts/check-e2e-coverage.mjs +12 -8
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/scripts/check-conflict-markers.mjs +1 -1
- package/scripts/check-required-check-promotions.mjs +8 -4
- package/scripts/detect-stale-workflow-inputs.mjs +1 -3
- package/scripts/fix-namespace-test-assertions.mjs +1 -1
- package/scripts/generate-agy-plugin-artifacts.mjs +12 -7
- package/scripts/generate-codex-plugin-artifacts.mjs +14 -9
- package/scripts/generate-copilot-plugin-artifacts.mjs +1 -1
- package/scripts/generate-cursor-plugin-artifacts.mjs +2 -2
- package/scripts/generate-upstream-evidence-manifest.mjs +1 -1
- package/scripts/lisa-assert-eas-profile.mjs +3 -3
- package/scripts/plugin-parity-drift.mjs +29 -13
- package/scripts/plugin-routing-validate.mjs +8 -2
- package/scripts/update-node-version.ts +7 -3
- package/scripts/verify-health-agentic-built.mjs +27 -20
- package/scripts/verify-health-consumer-built.mjs +7 -3
- package/scripts/verify-health-deterministic-built.mjs +24 -19
- package/typescript/copy-overwrite/eslint.ignore.config.json +0 -2
- package/typescript/copy-overwrite/scripts/check-nightly-e2e-health.mjs +9 -4
- package/typescript/copy-overwrite/scripts/lisa-mutation.mjs +1 -3
|
@@ -17,6 +17,14 @@ import {
|
|
|
17
17
|
import { tmpdir } from "node:os";
|
|
18
18
|
import path from "node:path";
|
|
19
19
|
|
|
20
|
+
// Literals named once — each was repeated enough times that a typo in one
|
|
21
|
+
// copy would diverge silently.
|
|
22
|
+
const TEMPLATES_MANAGED = "templates.managed";
|
|
23
|
+
const AGENTIC_CI_SKIP_LINT = "agentic.ci.skip.lint";
|
|
24
|
+
const ESLINT_CONFIG_TS = "eslint.config.ts";
|
|
25
|
+
const AGENTIC_INTENTIONAL_DRIFT = "agentic.intentional-drift";
|
|
26
|
+
const HARPER_APP = "harper-app";
|
|
27
|
+
|
|
20
28
|
let assertions = 0;
|
|
21
29
|
const check = (condition, message) => {
|
|
22
30
|
assertions += 1;
|
|
@@ -241,8 +249,7 @@ function artifactEvaluator(request, signal) {
|
|
|
241
249
|
const mutationDisabled =
|
|
242
250
|
request.config.quality.mutation.gate.enabled === false;
|
|
243
251
|
const managedDrift = request.deterministicFindings.find(
|
|
244
|
-
finding =>
|
|
245
|
-
finding.check === "templates.managed" && finding.status === "fail"
|
|
252
|
+
finding => finding.check === TEMPLATES_MANAGED && finding.status === "fail"
|
|
246
253
|
);
|
|
247
254
|
|
|
248
255
|
if (mutationDisabled) {
|
|
@@ -268,19 +275,19 @@ function artifactEvaluator(request, signal) {
|
|
|
268
275
|
!/\b(?:reason|justification)\b/iu.test(workflow.content)
|
|
269
276
|
) {
|
|
270
277
|
judgments.push({
|
|
271
|
-
check:
|
|
278
|
+
check: AGENTIC_CI_SKIP_LINT,
|
|
272
279
|
reason: `${workflow.path} skips lint without a recorded justification.`,
|
|
273
280
|
});
|
|
274
281
|
}
|
|
275
282
|
}
|
|
276
283
|
if (
|
|
277
|
-
managedDrift?.reason.includes(
|
|
284
|
+
managedDrift?.reason.includes(ESLINT_CONFIG_TS) === true &&
|
|
278
285
|
/\b(?:reason|justification)\b/iu.test(override?.content ?? "") &&
|
|
279
286
|
managedArtifact?.content.includes("no-explicit-any") === true &&
|
|
280
287
|
/["']off["']/u.test(managedArtifact.content)
|
|
281
288
|
) {
|
|
282
289
|
judgments.push({
|
|
283
|
-
check:
|
|
290
|
+
check: AGENTIC_INTENTIONAL_DRIFT,
|
|
284
291
|
reason:
|
|
285
292
|
"The bounded managed ESLint drift disables no-explicit-any despite the recorded temporary justification.",
|
|
286
293
|
});
|
|
@@ -316,13 +323,13 @@ try {
|
|
|
316
323
|
2
|
|
317
324
|
)}\n`
|
|
318
325
|
);
|
|
319
|
-
await mkdir(path.join(project,
|
|
326
|
+
await mkdir(path.join(project, HARPER_APP), { recursive: true });
|
|
320
327
|
await writeFile(
|
|
321
|
-
path.join(project,
|
|
328
|
+
path.join(project, HARPER_APP, "config.yaml"),
|
|
322
329
|
"graphqlSchema: ./schema.graphql\njsResource: true\nstatic: ./web\n"
|
|
323
330
|
);
|
|
324
331
|
await writeFile(
|
|
325
|
-
path.join(project,
|
|
332
|
+
path.join(project, HARPER_APP, "schema.graphql"),
|
|
326
333
|
"type Query { health: Boolean! }\n"
|
|
327
334
|
);
|
|
328
335
|
git("init", "--initial-branch=main");
|
|
@@ -525,7 +532,7 @@ try {
|
|
|
525
532
|
check(
|
|
526
533
|
unreasonedSkip.findings.some(
|
|
527
534
|
finding =>
|
|
528
|
-
finding.check ===
|
|
535
|
+
finding.check === AGENTIC_CI_SKIP_LINT &&
|
|
529
536
|
finding.reason.includes("ci.yml")
|
|
530
537
|
),
|
|
531
538
|
"unreasoned skipped job produces a named warning"
|
|
@@ -545,22 +552,22 @@ try {
|
|
|
545
552
|
);
|
|
546
553
|
check(
|
|
547
554
|
!reasonedSkip.findings.some(
|
|
548
|
-
finding => finding.check ===
|
|
555
|
+
finding => finding.check === AGENTIC_CI_SKIP_LINT
|
|
549
556
|
),
|
|
550
557
|
"recorded skip justification clears the job warning"
|
|
551
558
|
);
|
|
552
559
|
printStateDump("skipped-job-reason-clears", {
|
|
553
560
|
undocumented: unreasonedSkip.findings
|
|
554
|
-
.filter(finding => finding.check ===
|
|
561
|
+
.filter(finding => finding.check === AGENTIC_CI_SKIP_LINT)
|
|
555
562
|
.map(findingState),
|
|
556
563
|
documented: reasonedSkip.findings
|
|
557
|
-
.filter(finding => finding.check ===
|
|
564
|
+
.filter(finding => finding.check === AGENTIC_CI_SKIP_LINT)
|
|
558
565
|
.map(findingState),
|
|
559
566
|
});
|
|
560
567
|
console.log("[EVIDENCE: state-dump: skipped-job-reason-clears]");
|
|
561
568
|
await writeFile(ciPath, ciOriginal);
|
|
562
569
|
|
|
563
|
-
const managedEslintPath = path.join(project,
|
|
570
|
+
const managedEslintPath = path.join(project, ESLINT_CONFIG_TS);
|
|
564
571
|
const managedEslintOriginal = await readFile(managedEslintPath);
|
|
565
572
|
const managedJustification =
|
|
566
573
|
'// justification: temporary vendor migration\nexport default [{ rules: { "@typescript-eslint/no-explicit-any": "off" } }];\n';
|
|
@@ -599,7 +606,7 @@ try {
|
|
|
599
606
|
);
|
|
600
607
|
equal(
|
|
601
608
|
observedManagedArtifacts.map(artifact => artifact?.path),
|
|
602
|
-
[
|
|
609
|
+
[ESLINT_CONFIG_TS, ESLINT_CONFIG_TS],
|
|
603
610
|
"both drift judgments inspect the bounded managed ESLint artifact"
|
|
604
611
|
);
|
|
605
612
|
equal(
|
|
@@ -613,18 +620,18 @@ try {
|
|
|
613
620
|
check(
|
|
614
621
|
benignDrift.findings.some(
|
|
615
622
|
finding =>
|
|
616
|
-
finding.check ===
|
|
623
|
+
finding.check === TEMPLATES_MANAGED && finding.status === "fail"
|
|
617
624
|
),
|
|
618
625
|
"benign agentic judgment cannot erase deterministic managed drift"
|
|
619
626
|
);
|
|
620
627
|
check(
|
|
621
628
|
!benignDrift.findings.some(
|
|
622
|
-
finding => finding.check ===
|
|
629
|
+
finding => finding.check === AGENTIC_INTENTIONAL_DRIFT
|
|
623
630
|
),
|
|
624
631
|
"benign managed content produces no drift judgment"
|
|
625
632
|
);
|
|
626
633
|
const suspiciousDriftWarning = suspiciousDrift.findings.find(
|
|
627
|
-
finding => finding.check ===
|
|
634
|
+
finding => finding.check === AGENTIC_INTENTIONAL_DRIFT
|
|
628
635
|
);
|
|
629
636
|
equal(
|
|
630
637
|
suspiciousDriftWarning?.status,
|
|
@@ -643,7 +650,7 @@ try {
|
|
|
643
650
|
.update(benignManagedContent)
|
|
644
651
|
.digest("hex"),
|
|
645
652
|
warnings: benignDrift.findings
|
|
646
|
-
.filter(finding => finding.check ===
|
|
653
|
+
.filter(finding => finding.check === AGENTIC_INTENTIONAL_DRIFT)
|
|
647
654
|
.map(findingState),
|
|
648
655
|
},
|
|
649
656
|
suspicious: {
|
|
@@ -651,7 +658,7 @@ try {
|
|
|
651
658
|
.update(suspiciousManagedContent)
|
|
652
659
|
.digest("hex"),
|
|
653
660
|
warnings: suspiciousDrift.findings
|
|
654
|
-
.filter(finding => finding.check ===
|
|
661
|
+
.filter(finding => finding.check === AGENTIC_INTENTIONAL_DRIFT)
|
|
655
662
|
.map(findingState),
|
|
656
663
|
},
|
|
657
664
|
});
|
|
@@ -678,7 +685,7 @@ try {
|
|
|
678
685
|
name: "malformed",
|
|
679
686
|
evaluator: async () => ({
|
|
680
687
|
status: "completed",
|
|
681
|
-
judgments: [{ check:
|
|
688
|
+
judgments: [{ check: TEMPLATES_MANAGED, reason: "collision" }],
|
|
682
689
|
}),
|
|
683
690
|
timeoutMs: 1_000,
|
|
684
691
|
},
|
|
@@ -14,6 +14,10 @@ import {
|
|
|
14
14
|
import { tmpdir } from "node:os";
|
|
15
15
|
import path from "node:path";
|
|
16
16
|
|
|
17
|
+
// Literals named once — each was repeated enough times that a typo in one
|
|
18
|
+
// copy would diverge silently.
|
|
19
|
+
const LATEST_JSON = "latest.json";
|
|
20
|
+
|
|
17
21
|
let assertions = 0;
|
|
18
22
|
const check = (condition, message) => {
|
|
19
23
|
assertions += 1;
|
|
@@ -64,7 +68,7 @@ function runCli(project, argv, input) {
|
|
|
64
68
|
|
|
65
69
|
/** Return whether the canonical result exists without throwing on absence. */
|
|
66
70
|
async function resultExists(project) {
|
|
67
|
-
return lstat(path.join(project, ".lisa", "health",
|
|
71
|
+
return lstat(path.join(project, ".lisa", "health", LATEST_JSON))
|
|
68
72
|
.then(() => true)
|
|
69
73
|
.catch(() => false);
|
|
70
74
|
}
|
|
@@ -91,14 +95,14 @@ async function prepare(project) {
|
|
|
91
95
|
|
|
92
96
|
/** Validate one final CLI result against its exact persisted representation. */
|
|
93
97
|
async function validateFinal(project, stdout, expectedMode) {
|
|
94
|
-
const resultPath = path.join(project, ".lisa", "health",
|
|
98
|
+
const resultPath = path.join(project, ".lisa", "health", LATEST_JSON);
|
|
95
99
|
const persisted = await readFile(resultPath, "utf8");
|
|
96
100
|
equal(stdout, persisted, `${expectedMode} stdout equals persisted bytes`);
|
|
97
101
|
const result = JSON.parse(stdout);
|
|
98
102
|
equal(result.mode, expectedMode, `final result is ${expectedMode}`);
|
|
99
103
|
equal(
|
|
100
104
|
(await readdir(path.dirname(resultPath))).sort(),
|
|
101
|
-
[
|
|
105
|
+
[LATEST_JSON],
|
|
102
106
|
"one final result remains with no temporary or lock artifact"
|
|
103
107
|
);
|
|
104
108
|
return result;
|
|
@@ -18,6 +18,14 @@ import {
|
|
|
18
18
|
import { tmpdir } from "node:os";
|
|
19
19
|
import path from "node:path";
|
|
20
20
|
|
|
21
|
+
// Literals named once — each was repeated enough times that a typo in one
|
|
22
|
+
// copy would diverge silently.
|
|
23
|
+
const PACKAGE_JSON = "package.json";
|
|
24
|
+
const LISA_CONFIG_JSON = ".lisa.config.json";
|
|
25
|
+
const HARPER_APP = "harper-app";
|
|
26
|
+
const TEMPLATES_MANAGED = "templates.managed";
|
|
27
|
+
const PRETTIERIGNORE = ".prettierignore";
|
|
28
|
+
|
|
21
29
|
let assertions = 0;
|
|
22
30
|
const check = (condition, message) => {
|
|
23
31
|
assertions += 1;
|
|
@@ -149,7 +157,7 @@ try {
|
|
|
149
157
|
await mkdir(isolatedBin, { recursive: true });
|
|
150
158
|
await symlink(gitExecutable, path.join(isolatedBin, "git"));
|
|
151
159
|
await writeFile(
|
|
152
|
-
path.join(project,
|
|
160
|
+
path.join(project, PACKAGE_JSON),
|
|
153
161
|
`${JSON.stringify(
|
|
154
162
|
{
|
|
155
163
|
name: "deterministic-health-fixture",
|
|
@@ -161,7 +169,7 @@ try {
|
|
|
161
169
|
)}\n`
|
|
162
170
|
);
|
|
163
171
|
await writeFile(
|
|
164
|
-
path.join(project,
|
|
172
|
+
path.join(project, LISA_CONFIG_JSON),
|
|
165
173
|
`${JSON.stringify(
|
|
166
174
|
{
|
|
167
175
|
tracker: "github",
|
|
@@ -172,13 +180,13 @@ try {
|
|
|
172
180
|
2
|
|
173
181
|
)}\n`
|
|
174
182
|
);
|
|
175
|
-
await mkdir(path.join(project,
|
|
183
|
+
await mkdir(path.join(project, HARPER_APP), { recursive: true });
|
|
176
184
|
await writeFile(
|
|
177
|
-
path.join(project,
|
|
185
|
+
path.join(project, HARPER_APP, "config.yaml"),
|
|
178
186
|
"graphqlSchema: ./schema.graphql\njsResource: true\nstatic: ./web\n"
|
|
179
187
|
);
|
|
180
188
|
await writeFile(
|
|
181
|
-
path.join(project,
|
|
189
|
+
path.join(project, HARPER_APP, "schema.graphql"),
|
|
182
190
|
"type Query { health: Boolean! }\n"
|
|
183
191
|
);
|
|
184
192
|
git("init", "--initial-branch=main");
|
|
@@ -220,7 +228,7 @@ try {
|
|
|
220
228
|
}
|
|
221
229
|
);
|
|
222
230
|
const version = JSON.parse(
|
|
223
|
-
await readFile(path.join(root,
|
|
231
|
+
await readFile(path.join(root, PACKAGE_JSON), "utf8")
|
|
224
232
|
).version;
|
|
225
233
|
await writeFile(
|
|
226
234
|
path.join(project, ".claude", ".lisa-plugins-synced"),
|
|
@@ -256,13 +264,12 @@ try {
|
|
|
256
264
|
equal(clean.summary.counts.fail, 0, "clean fixture has zero failures");
|
|
257
265
|
equal(clean.summary.verdict, "in band", "clean fixture is in band");
|
|
258
266
|
equal(
|
|
259
|
-
clean.findings.find(finding => finding.check ===
|
|
260
|
-
.status,
|
|
267
|
+
clean.findings.find(finding => finding.check === TEMPLATES_MANAGED).status,
|
|
261
268
|
"pass",
|
|
262
269
|
"the real TypeScript plus Harper child template stack composes cleanly"
|
|
263
270
|
);
|
|
264
271
|
check(
|
|
265
|
-
(await readFile(path.join(project,
|
|
272
|
+
(await readFile(path.join(project, PRETTIERIGNORE), "utf8")).includes(
|
|
266
273
|
"AI GUARDRAILS HARPER-FABRIC"
|
|
267
274
|
),
|
|
268
275
|
"the real child copy-contents block survives its parent overwrite"
|
|
@@ -298,14 +305,14 @@ try {
|
|
|
298
305
|
);
|
|
299
306
|
await writeFile(callerPath, callerOriginal);
|
|
300
307
|
|
|
301
|
-
const prettierPath = path.join(project,
|
|
308
|
+
const prettierPath = path.join(project, PRETTIERIGNORE);
|
|
302
309
|
const prettierOriginal = await readFile(prettierPath);
|
|
303
310
|
await writeFile(path.join(project, ".lisaignore"), ".prettierignore\n");
|
|
304
311
|
await writeFile(prettierPath, "project-owned while ignored\n");
|
|
305
312
|
const ignoredTemplate = await assertPureCollection(health, options);
|
|
306
313
|
equal(
|
|
307
314
|
ignoredTemplate.findings.find(
|
|
308
|
-
finding => finding.check ===
|
|
315
|
+
finding => finding.check === TEMPLATES_MANAGED
|
|
309
316
|
).status,
|
|
310
317
|
"pass",
|
|
311
318
|
"ignored templates are outside Lisa ownership"
|
|
@@ -337,9 +344,8 @@ try {
|
|
|
337
344
|
await writeFile(learningsPath, customLearnings);
|
|
338
345
|
const learningsOwned = await assertPureCollection(health, options);
|
|
339
346
|
equal(
|
|
340
|
-
learningsOwned.findings.find(
|
|
341
|
-
|
|
342
|
-
).status,
|
|
347
|
+
learningsOwned.findings.find(finding => finding.check === TEMPLATES_MANAGED)
|
|
348
|
+
.status,
|
|
343
349
|
"pass",
|
|
344
350
|
"project learnings remain host-owned after their initial seed"
|
|
345
351
|
);
|
|
@@ -396,8 +402,7 @@ try {
|
|
|
396
402
|
);
|
|
397
403
|
const drift = await assertPureCollection(health, options);
|
|
398
404
|
const managedDrift = drift.findings.filter(
|
|
399
|
-
finding =>
|
|
400
|
-
finding.check === "templates.managed" && finding.status === "fail"
|
|
405
|
+
finding => finding.check === TEMPLATES_MANAGED && finding.status === "fail"
|
|
401
406
|
);
|
|
402
407
|
equal(
|
|
403
408
|
managedDrift.length,
|
|
@@ -422,7 +427,7 @@ try {
|
|
|
422
427
|
console.log("[EVIDENCE: clean-project-in-band]");
|
|
423
428
|
console.log("[EVIDENCE: managed-file-restoration-in-band]");
|
|
424
429
|
|
|
425
|
-
const configPath = path.join(project,
|
|
430
|
+
const configPath = path.join(project, LISA_CONFIG_JSON);
|
|
426
431
|
const config = JSON.parse(await readFile(configPath, "utf8"));
|
|
427
432
|
delete config.github.repo;
|
|
428
433
|
await writeFile(configPath, `${JSON.stringify(config, null, 2)}\n`);
|
|
@@ -458,10 +463,10 @@ try {
|
|
|
458
463
|
const unsafeProject = path.join(workspace, "unsafe-host");
|
|
459
464
|
await mkdir(unsafeProject, { recursive: true });
|
|
460
465
|
await writeFile(
|
|
461
|
-
path.join(unsafeProject,
|
|
466
|
+
path.join(unsafeProject, LISA_CONFIG_JSON),
|
|
462
467
|
'{"tracker":"github","harness":"codex"}\n'
|
|
463
468
|
);
|
|
464
|
-
execFileSync("mkfifo", [path.join(unsafeProject,
|
|
469
|
+
execFileSync("mkfifo", [path.join(unsafeProject, PACKAGE_JSON)]);
|
|
465
470
|
const unsafeStarted = Date.now();
|
|
466
471
|
const unsafe = await health.runDeterministicHealth(unsafeProject, {
|
|
467
472
|
lisaRoot: root,
|
|
@@ -426,7 +426,9 @@ function validateMatch(match, where) {
|
|
|
426
426
|
try {
|
|
427
427
|
// No `g` flag, ever: a sticky lastIndex makes repeated .test() calls
|
|
428
428
|
// return alternating answers, which reads as an intermittent gate.
|
|
429
|
-
|
|
429
|
+
// Compiling IS the assertion — an invalid pattern throws right here — so
|
|
430
|
+
// the result is deliberately unused.
|
|
431
|
+
const _compiled = new RegExp(pattern);
|
|
430
432
|
} catch (error) {
|
|
431
433
|
throw new GateConfigError(
|
|
432
434
|
`${where}: \`match.pattern\` does not compile: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -1550,6 +1552,9 @@ function sleep(ms) {
|
|
|
1550
1552
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
1551
1553
|
}
|
|
1552
1554
|
|
|
1555
|
+
/** GitHub's remaining-quota response header, read from three call sites. */
|
|
1556
|
+
const RATELIMIT_REMAINING_HEADER = "x-ratelimit-remaining";
|
|
1557
|
+
|
|
1553
1558
|
/**
|
|
1554
1559
|
* How long to wait before retrying a throttled response, bounded.
|
|
1555
1560
|
*
|
|
@@ -1563,7 +1568,7 @@ export function retryDelayMs(response, attempt, maxSeconds) {
|
|
|
1563
1568
|
if (Number.isFinite(retryAfter) && retryAfter > 0) {
|
|
1564
1569
|
return Math.min(retryAfter, maxSeconds) * 1000;
|
|
1565
1570
|
}
|
|
1566
|
-
const remaining = response.headers?.get?.(
|
|
1571
|
+
const remaining = response.headers?.get?.(RATELIMIT_REMAINING_HEADER);
|
|
1567
1572
|
const reset = Number(response.headers?.get?.("x-ratelimit-reset"));
|
|
1568
1573
|
if (remaining === "0" && Number.isFinite(reset)) {
|
|
1569
1574
|
const seconds = Math.max(0, reset - Math.floor(Date.now() / 1000));
|
|
@@ -1613,7 +1618,7 @@ export async function apiGet(api, path, wait = sleep) {
|
|
|
1613
1618
|
// 401/403 without rate-limit headers is an auth problem: retrying cannot
|
|
1614
1619
|
// fix a token that is not allowed to read run history, so fail immediately
|
|
1615
1620
|
// with a message that names the fix.
|
|
1616
|
-
const remaining = response.headers?.get?.(
|
|
1621
|
+
const remaining = response.headers?.get?.(RATELIMIT_REMAINING_HEADER);
|
|
1617
1622
|
const throttled =
|
|
1618
1623
|
response.status === 429 || (response.status === 403 && remaining === "0");
|
|
1619
1624
|
if ((response.status === 401 || response.status === 403) && !throttled) {
|
|
@@ -1782,7 +1787,7 @@ export async function apiWrite(api, method, path, payload, wait = sleep) {
|
|
|
1782
1787
|
continue;
|
|
1783
1788
|
}
|
|
1784
1789
|
if (response.ok) return await response.json();
|
|
1785
|
-
const remaining = response.headers?.get?.(
|
|
1790
|
+
const remaining = response.headers?.get?.(RATELIMIT_REMAINING_HEADER);
|
|
1786
1791
|
const throttled =
|
|
1787
1792
|
response.status === 429 || (response.status === 403 && remaining === "0");
|
|
1788
1793
|
if ((response.status === 401 || response.status === 403) && !throttled) {
|
|
@@ -120,9 +120,7 @@ try {
|
|
|
120
120
|
|
|
121
121
|
if (changed.length === 0) {
|
|
122
122
|
console.log(
|
|
123
|
-
|
|
124
|
-
since +
|
|
125
|
-
". Nothing to mutate."
|
|
123
|
+
`⚪ Mutation gate: no changed source files vs ${since}. Nothing to mutate.`
|
|
126
124
|
);
|
|
127
125
|
process.exit(0);
|
|
128
126
|
}
|