@quikit/quikpilot-runner 8.1.0 → 8.2.0

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 CHANGED
@@ -1,27 +1,27 @@
1
- # @quikit/quikpilot-runner
2
-
3
- QuikPilot's CI runner. Invoked automatically by the `.github/workflows/quikpilot.yml` file QuikPilot
4
- installs in an onboarded repository — it fetches the run's work packet, runs your setup/lint/test
5
- commands, reports results to QuikTest, enforces the denied-path guardrail, commits, pushes, and
6
- reports back to QuikTrack.
7
-
8
- This package is not meant to be installed or run by hand. It exists so a fix to QuikPilot's runner
9
- logic ships as a new package version rather than a new pull request into every onboarded repository
10
- — the workflow file itself lives in your repository (QuikIT cannot update it directly), so it stays a
11
- thin, ~25-line launcher that invokes an exact, pinned version of this package via `npx`.
12
-
13
- It carries no secrets and needs none of your credentials: it authenticates to QuikTrack and to GitHub
14
- using short-lived tokens exchanged at runtime, never a value baked into the workflow file or this
15
- package.
16
-
17
- ## Versioning and support
18
-
19
- Every workflow file pins an **exact** version of this package (`npx --yes
20
- @quikit/quikpilot-runner@<version>`, never a range or `latest`) — a repository never picks up a new
21
- release on its own. Older published versions are not removed from npm and keep working as long as a
22
- repository's workflow file keeps pinning them; upgrading to a newer version only happens through a new
23
- pull request into that repository (QuikTrack's "re-bootstrap" flow), never silently.
24
-
25
- Releases follow [SemVer](https://semver.org/): a major version bump means the workflow file's own
26
- shape changed (inputs, permissions) and requires a new pull request regardless of this package's
27
- version; minor/patch releases are runner-logic fixes safe to pick up on the next re-bootstrap.
1
+ # @quikit/quikpilot-runner
2
+
3
+ QuikPilot's CI runner. Invoked automatically by the `.github/workflows/quikpilot.yml` file QuikPilot
4
+ installs in an onboarded repository — it fetches the run's work packet, runs your setup/lint/test
5
+ commands, reports results to QuikTest, enforces the denied-path guardrail, commits, pushes, and
6
+ reports back to QuikTrack.
7
+
8
+ This package is not meant to be installed or run by hand. It exists so a fix to QuikPilot's runner
9
+ logic ships as a new package version rather than a new pull request into every onboarded repository
10
+ — the workflow file itself lives in your repository (QuikIT cannot update it directly), so it stays a
11
+ thin, ~25-line launcher that invokes an exact, pinned version of this package via `npx`.
12
+
13
+ It carries no secrets and needs none of your credentials: it authenticates to QuikTrack and to GitHub
14
+ using short-lived tokens exchanged at runtime, never a value baked into the workflow file or this
15
+ package.
16
+
17
+ ## Versioning and support
18
+
19
+ Every workflow file pins an **exact** version of this package (`npx --yes
20
+ @quikit/quikpilot-runner@<version>`, never a range or `latest`) — a repository never picks up a new
21
+ release on its own. Older published versions are not removed from npm and keep working as long as a
22
+ repository's workflow file keeps pinning them; upgrading to a newer version only happens through a new
23
+ pull request into that repository (QuikTrack's "re-bootstrap" flow), never silently.
24
+
25
+ Releases follow [SemVer](https://semver.org/): a major version bump means the workflow file's own
26
+ shape changed (inputs, permissions) and requires a new pull request regardless of this package's
27
+ version; minor/patch releases are runner-logic fixes safe to pick up on the next re-bootstrap.
package/dist/index.js CHANGED
@@ -254,6 +254,7 @@ var FILE_TOO_LARGE_CODE = "CODEGEN_FILE_TOO_LARGE";
254
254
  var CONTEXT_TOO_LARGE_CODE = "CODEGEN_CONTEXT_TOO_LARGE";
255
255
  var OUTPUT_TOO_LARGE_CODE = "CODEGEN_OUTPUT_TOO_LARGE";
256
256
  var NOT_RETRIED_CODES = /* @__PURE__ */ new Set([FILE_TOO_LARGE_CODE, CONTEXT_TOO_LARGE_CODE, OUTPUT_TOO_LARGE_CODE]);
257
+ var JUDGED_BY_TOO_LARGE_CODE = "CODEGEN_JUDGED_BY_TOO_LARGE";
257
258
  var SUSPECT_PLACEHOLDER_RE = /rest(?: of the)? (?:file|code) unchanged|remainder unchanged|\/\/\s*\.\.\.\s*(?:rest|remaining)/i;
258
259
  var SUSPECT_LENGTH_DROP_RATIO = 0.6;
259
260
  var SUSPECT_REMOVED_LINE_RATIO = 0.3;
@@ -313,7 +314,32 @@ function looksLikeTruncatedRewrite(target, currentContent, newContent) {
313
314
  return null;
314
315
  }
315
316
  var CONTRACT_VERSION = "test-targets-1";
316
- async function runCodegen(gateway, targets, workspaceListing, requiredTests, deniedPaths) {
317
+ function buildJudgedByPool(requiredTests, targets, skippedCases) {
318
+ const claimedIds = /* @__PURE__ */ new Set();
319
+ for (const t of targets) {
320
+ for (const id of t.automationIds ?? []) claimedIds.add(id);
321
+ }
322
+ const skippedIds = new Set(skippedCases.map((s) => s.automationId));
323
+ const pool = [];
324
+ for (const tc of requiredTests) {
325
+ if (!claimedIds.has(tc.automationId) || skippedIds.has(tc.automationId)) continue;
326
+ if (!tc.given || !tc.when || !tc.then) continue;
327
+ pool.push({ automationId: tc.automationId, title: tc.title, given: tc.given, when: tc.when, then: tc.then });
328
+ }
329
+ return pool;
330
+ }
331
+ function narrowJudgedByForTarget(pool, targets, codeTargetPath) {
332
+ const narrowedIds = /* @__PURE__ */ new Set();
333
+ for (const t of targets) {
334
+ if (!t.automationIds?.length || !t.contextPaths?.includes(codeTargetPath)) continue;
335
+ for (const id of t.automationIds) narrowedIds.add(id);
336
+ }
337
+ return pool.filter((c) => narrowedIds.has(c.automationId));
338
+ }
339
+ function toWireJudgedBy(pool) {
340
+ return pool.map(({ automationId: _automationId, ...rest }) => rest);
341
+ }
342
+ async function runCodegen(gateway, targets, workspaceListing, requiredTests, deniedPaths, judgedByPool, warnings) {
317
343
  const results = [];
318
344
  const listing = new Set(workspaceListing);
319
345
  for (const target of targets) {
@@ -346,8 +372,10 @@ async function runCodegen(gateway, targets, workspaceListing, requiredTests, den
346
372
  if (target.automationIds && target.automationIds.length > 0) {
347
373
  const wanted = new Set(target.automationIds);
348
374
  contextData.requiredTests = requiredTests.filter((tc) => wanted.has(tc.automationId));
375
+ } else if (judgedByPool.length > 0) {
376
+ contextData.judgedBy = toWireJudgedBy(judgedByPool);
349
377
  }
350
- const res = await fetchWithRetry(`${gateway.baseUrl}/ai/execute`, {
378
+ const callCodegen = () => fetchWithRetry(`${gateway.baseUrl}/ai/execute`, {
351
379
  method: "POST",
352
380
  headers: { "content-type": "application/json", "x-run-token": gateway.token },
353
381
  body: JSON.stringify({
@@ -358,15 +386,36 @@ async function runCodegen(gateway, targets, workspaceListing, requiredTests, den
358
386
  contextData
359
387
  })
360
388
  });
389
+ let res = await callCodegen();
361
390
  if (!res.ok) {
362
391
  throw new Error(`Codegen call failed for ${target.path}: ${res.status} ${res.statusText}`);
363
392
  }
364
- const envelope = await res.json();
393
+ let envelope = await res.json();
365
394
  checkHardFailure(envelope, "pilot.codegen");
395
+ if (envelope?.errorCode === JUDGED_BY_TOO_LARGE_CODE && contextData.judgedBy) {
396
+ const before = contextData.judgedBy.length;
397
+ const narrowed = narrowJudgedByForTarget(judgedByPool, targets, target.path);
398
+ if (narrowed.length > 0) {
399
+ contextData.judgedBy = toWireJudgedBy(narrowed);
400
+ } else {
401
+ delete contextData.judgedBy;
402
+ }
403
+ warnings.push(`judgedBy narrowed for ${target.path}: ${before} \u2192 ${narrowed.length} cases`);
404
+ res = await callCodegen();
405
+ if (!res.ok) {
406
+ throw new Error(`Codegen call failed for ${target.path}: ${res.status} ${res.statusText}`);
407
+ }
408
+ envelope = await res.json();
409
+ checkHardFailure(envelope, "pilot.codegen");
410
+ }
366
411
  if (typeof envelope?.errorCode === "string" && NOT_RETRIED_CODES.has(envelope.errorCode)) {
367
412
  const detail = envelope.error ? `: ${envelope.error}` : "";
368
413
  throw new Error(`Codegen refused ${target.path}: ${envelope.errorCode} (not retried)${detail}`);
369
414
  }
415
+ if (envelope?.errorCode === JUDGED_BY_TOO_LARGE_CODE) {
416
+ const detail = envelope.error ? `: ${envelope.error}` : "";
417
+ throw new Error(`Codegen refused ${target.path}: ${envelope.errorCode} (after narrowing)${detail}`);
418
+ }
370
419
  const body = unwrapExecute(envelope, "pilot.codegen");
371
420
  if (body.outcome !== "GENERATED" || typeof body.newContent !== "string") {
372
421
  throw new Error(
@@ -807,16 +856,21 @@ function findJUnitReport(cwd = process.cwd()) {
807
856
  function buildCiUrl(serverUrl, repository, githubRunId) {
808
857
  return `${serverUrl}/${repository}/actions/runs/${githubRunId}`;
809
858
  }
859
+ function describeUnmatchedAutomationIds(unmatched) {
860
+ if (unmatched.length === 0) return null;
861
+ const named = unmatched.map((u) => `${u.automationId} (\xD7${u.count})`).join(", ");
862
+ return `${unmatched.length} generated test result(s) did not match any test case: ${named} \u2014 check the automationId format.`;
863
+ }
810
864
  async function reportToQuikTest(params) {
811
865
  const { resultsUrl, runToken, githubServerUrl, githubRepository, githubRunId, cwd } = params;
812
866
  if (!resultsUrl) {
813
867
  console.log("packet.quikTest is null \u2014 this run has no QuikTest run to report into.");
814
- return;
868
+ return null;
815
869
  }
816
870
  const report = findJUnitReport(cwd);
817
871
  if (!report) {
818
872
  console.warn("::warning::QuikPilot found no JUnit report \u2014 no results reported to QuikTest.");
819
- return;
873
+ return null;
820
874
  }
821
875
  try {
822
876
  console.log(`reporting ${report}`);
@@ -833,8 +887,16 @@ async function reportToQuikTest(params) {
833
887
  throw new Error(`QuikTest report POST failed: ${res.status} ${res.statusText}`);
834
888
  }
835
889
  (0, import_node_fs4.rmSync)(report, { force: true });
890
+ let unmatched = [];
891
+ try {
892
+ const json = await res.json();
893
+ unmatched = json.data?.unmatched ?? [];
894
+ } catch {
895
+ }
896
+ return { unmatched };
836
897
  } catch (err) {
837
898
  console.warn(`::warning::QuikPilot failed to report results to QuikTest: ${err instanceof Error ? err.message : String(err)}`);
899
+ return null;
838
900
  }
839
901
  }
840
902
 
@@ -844,6 +906,12 @@ var TESTCASE_RE = /<testcase\b([^>]*?)(?:\/>|>([\s\S]*?)<\/testcase>)/g;
844
906
  var NAME_ATTR_RE = /\bname="([^"]*)"/;
845
907
  var CLASSNAME_ATTR_RE = /\bclassname="([^"]*)"/;
846
908
  var FAILURE_CHILD_RE = /<failure\b|<error\b/;
909
+ var TESTSUITE_OPEN_RE = /<testsuite\b([^>]*?)>/g;
910
+ var FILE_ATTR_RE = /\bfile="([^"]*)"/;
911
+ var QP_TOKEN_BRACKET_RE = /\[(QP-[A-Z][A-Z0-9]*-\d+-\d+)\]/;
912
+ function normalizeSlashes(path) {
913
+ return path.replace(/\\/g, "/");
914
+ }
847
915
  var FAILURE_TAG_RE = /<(?:failure|error)\b([^>]*?)(?:\/>|>([\s\S]*?)<\/(?:failure|error)>)/;
848
916
  var FAILURE_MESSAGE_ATTR_RE = /\bmessage="([^"]*)"/;
849
917
  var MAX_FAILURE_TEXT = 500;
@@ -862,6 +930,14 @@ function extractFailureText(testcaseBody) {
862
930
  function parseJUnitOutcomes(xml) {
863
931
  const outcomes = /* @__PURE__ */ new Map();
864
932
  const failureText = /* @__PURE__ */ new Map();
933
+ const discoveredFiles = /* @__PURE__ */ new Set();
934
+ const discoveredAutomationIds = /* @__PURE__ */ new Set();
935
+ TESTSUITE_OPEN_RE.lastIndex = 0;
936
+ let suiteMatch;
937
+ while (suiteMatch = TESTSUITE_OPEN_RE.exec(xml)) {
938
+ const file = FILE_ATTR_RE.exec(suiteMatch[1])?.[1];
939
+ if (file) discoveredFiles.add(normalizeSlashes(file));
940
+ }
865
941
  let match;
866
942
  TESTCASE_RE.lastIndex = 0;
867
943
  while (match = TESTCASE_RE.exec(xml)) {
@@ -876,8 +952,13 @@ function parseJUnitOutcomes(xml) {
876
952
  const text = extractFailureText(body);
877
953
  if (text) failureText.set(id, text);
878
954
  }
955
+ const file = FILE_ATTR_RE.exec(attrs)?.[1];
956
+ if (file) discoveredFiles.add(normalizeSlashes(file));
957
+ if (classname) discoveredFiles.add(normalizeSlashes(classname));
958
+ const bracket = QP_TOKEN_BRACKET_RE.exec(name)?.[1];
959
+ if (bracket) discoveredAutomationIds.add(bracket);
879
960
  }
880
- return { outcomes, failureText };
961
+ return { outcomes, failureText, discoveredFiles, discoveredAutomationIds };
881
962
  }
882
963
  function readJUnitOutcomes(cwd) {
883
964
  const report = findJUnitReport(cwd);
@@ -891,12 +972,24 @@ function readJUnitOutcomes(cwd) {
891
972
  function captureTestSnapshot(command, cwd = process.cwd()) {
892
973
  const outcome = runTestCommand(command);
893
974
  const parsed = readJUnitOutcomes(cwd);
894
- return { outcome, results: parsed?.outcomes ?? null, failureText: parsed?.failureText };
975
+ return {
976
+ outcome,
977
+ results: parsed?.outcomes ?? null,
978
+ failureText: parsed?.failureText,
979
+ discoveredFiles: parsed?.discoveredFiles ?? null,
980
+ discoveredAutomationIds: parsed?.discoveredAutomationIds ?? null
981
+ };
895
982
  }
896
983
  async function captureBaselineSnapshot(command, cwd = process.cwd()) {
897
984
  const outcome = await runTestCommandAsync(command);
898
985
  const parsed = readJUnitOutcomes(cwd);
899
- return { outcome, results: parsed?.outcomes ?? null, failureText: parsed?.failureText };
986
+ return {
987
+ outcome,
988
+ results: parsed?.outcomes ?? null,
989
+ failureText: parsed?.failureText,
990
+ discoveredFiles: parsed?.discoveredFiles ?? null,
991
+ discoveredAutomationIds: parsed?.discoveredAutomationIds ?? null
992
+ };
900
993
  }
901
994
  function checkForRegressions(baseline, after) {
902
995
  if (!baseline.results || !after.results) {
@@ -1058,7 +1151,7 @@ function validateTarget(target, workspaceRoot, workspaceListing, deniedPaths) {
1058
1151
  );
1059
1152
  }
1060
1153
  }
1061
- async function runTargeting(gateway, design, workspaceRoot, workspaceListing, requiredTests, deniedPaths) {
1154
+ async function runTargeting(gateway, design, workspaceRoot, workspaceListing, requiredTests, deniedPaths, testDiscovery) {
1062
1155
  const contextData = {
1063
1156
  // NESTED, NOT FLATTENED — a second vocabulary for the design shape is exactly what
1064
1157
  // QUIKTR-1034 cost.
@@ -1073,6 +1166,7 @@ async function runTargeting(gateway, design, workspaceRoot, workspaceListing, re
1073
1166
  if (deniedPaths.length > 0) {
1074
1167
  contextData.deniedPaths = deniedPaths;
1075
1168
  }
1169
+ contextData.testDiscovery = testDiscovery;
1076
1170
  const res = await fetchWithRetry(`${gateway.baseUrl}/ai/execute`, {
1077
1171
  method: "POST",
1078
1172
  headers: { "content-type": "application/json", "x-run-token": gateway.token },
@@ -1107,6 +1201,47 @@ async function runTargeting(gateway, design, workspaceRoot, workspaceListing, re
1107
1201
  };
1108
1202
  }
1109
1203
 
1204
+ // src/testPlacementCheck.ts
1205
+ function isDiscovered(targetPath, discoveredFiles) {
1206
+ const normalized = targetPath.replace(/\\/g, "/");
1207
+ for (const candidate of discoveredFiles) {
1208
+ if (candidate === normalized) return true;
1209
+ if (candidate.endsWith(normalized) || normalized.endsWith(candidate)) return true;
1210
+ }
1211
+ return false;
1212
+ }
1213
+ function checkTestPlacement(targets, discoveredFiles) {
1214
+ if (!discoveredFiles || discoveredFiles.size === 0) return { blocked: false, violations: [] };
1215
+ const violations = [];
1216
+ for (const target of targets) {
1217
+ if (target.kind !== "EXISTING") continue;
1218
+ if (!target.automationIds || target.automationIds.length === 0) continue;
1219
+ if (!isDiscovered(target.path, discoveredFiles)) {
1220
+ violations.push({ file: target.path, automationIds: target.automationIds });
1221
+ }
1222
+ }
1223
+ return { blocked: violations.length > 0, violations };
1224
+ }
1225
+ function describeTestPlacementViolations(check) {
1226
+ return check.violations.map(
1227
+ (v) => `${v.file} claims test case(s) ${v.automationIds.join(", ")} but the repository's own test runner never discovered this file`
1228
+ ).join("; ");
1229
+ }
1230
+ function checkAutomationIdCoverage(targets, discoveredAutomationIds) {
1231
+ if (discoveredAutomationIds === null || discoveredAutomationIds === void 0) {
1232
+ return { blocked: false, missing: [] };
1233
+ }
1234
+ const claimed = /* @__PURE__ */ new Set();
1235
+ for (const target of targets) {
1236
+ for (const id of target.automationIds ?? []) claimed.add(id);
1237
+ }
1238
+ const missing = [...claimed].filter((id) => !discoveredAutomationIds.has(id));
1239
+ return { blocked: missing.length > 0, missing };
1240
+ }
1241
+ function describeAutomationCoverageViolations(check) {
1242
+ return `test case(s) ${check.missing.join(", ")} have no matching test discovered in the test run \u2014 generated, but never executed`;
1243
+ }
1244
+
1110
1245
  // src/tokenExchange.ts
1111
1246
  async function exchangeForRunToken(tokenUrl, oidcToken) {
1112
1247
  const res = await fetch(tokenUrl, {
@@ -1142,7 +1277,8 @@ async function run(env2) {
1142
1277
  packet.workspaceRoot,
1143
1278
  workspaceListing,
1144
1279
  packet.requiredTests,
1145
- packet.guardrails.deniedPaths
1280
+ packet.guardrails.deniedPaths,
1281
+ packet.testDiscovery
1146
1282
  );
1147
1283
  if (targeting.outcome === "NO_TARGET") {
1148
1284
  writePhase0Marker(env2.runId);
@@ -1173,6 +1309,11 @@ async function run(env2) {
1173
1309
  );
1174
1310
  }
1175
1311
  runCommand(packet.commands.setup, "Setup");
1312
+ const judgedByPool = buildJudgedByPool(
1313
+ packet.requiredTests,
1314
+ targeting.targets,
1315
+ targeting.skippedCases ?? []
1316
+ );
1176
1317
  const [baseline, results] = await Promise.all([
1177
1318
  captureBaselineSnapshot(packet.commands.test),
1178
1319
  runCodegen(
@@ -1180,7 +1321,9 @@ async function run(env2) {
1180
1321
  targeting.targets,
1181
1322
  workspaceListing,
1182
1323
  packet.requiredTests,
1183
- packet.guardrails.deniedPaths
1324
+ packet.guardrails.deniedPaths,
1325
+ judgedByPool,
1326
+ warnings
1184
1327
  )
1185
1328
  ]);
1186
1329
  const depCheck = checkImportDependencies(
@@ -1199,6 +1342,12 @@ async function run(env2) {
1199
1342
  `QuikPilot's generated code exceeds the approved design \u2014 ${describeScopeViolations(scopeCheck)}`
1200
1343
  );
1201
1344
  }
1345
+ const placementCheck = checkTestPlacement(targeting.targets, baseline.discoveredFiles);
1346
+ if (placementCheck.blocked) {
1347
+ throw new Error(
1348
+ `QuikPilot's generated tests are not where the test runner will find them \u2014 ${describeTestPlacementViolations(placementCheck)}`
1349
+ );
1350
+ }
1202
1351
  flushCodegenResults(results);
1203
1352
  try {
1204
1353
  runCommand(packet.commands.format, "Format");
@@ -1213,6 +1362,12 @@ async function run(env2) {
1213
1362
  `QuikPilot's generated code introduced test failures \u2014 ${describeRegressions(check)}`
1214
1363
  );
1215
1364
  }
1365
+ const coverageCheck = checkAutomationIdCoverage(targeting.targets, after.discoveredAutomationIds);
1366
+ if (coverageCheck.blocked) {
1367
+ throw new Error(
1368
+ `QuikPilot's generated tests were not executed \u2014 ${describeAutomationCoverageViolations(coverageCheck)}`
1369
+ );
1370
+ }
1216
1371
  }
1217
1372
  } catch (err) {
1218
1373
  hardFailure = true;
@@ -1222,13 +1377,18 @@ async function run(env2) {
1222
1377
  console.error("No run token \u2014 the OIDC exchange failed before QuikTrack could be reached.");
1223
1378
  return { hardFailure: true };
1224
1379
  }
1225
- await reportToQuikTest({
1380
+ const quikTestReport = await reportToQuikTest({
1226
1381
  resultsUrl: packet?.quikTest?.resultsUrl,
1227
1382
  runToken,
1228
1383
  githubServerUrl: env2.githubServerUrl,
1229
1384
  githubRepository: env2.githubRepository,
1230
1385
  githubRunId: env2.githubRunId
1231
1386
  });
1387
+ const unmatchedWarning = quikTestReport ? describeUnmatchedAutomationIds(quikTestReport.unmatched) : null;
1388
+ if (unmatchedWarning) {
1389
+ warnings.push(unmatchedWarning);
1390
+ console.warn(`QuikPilot ingest warning (not blocking): ${unmatchedWarning}`);
1391
+ }
1232
1392
  if (!hardFailure && packet) {
1233
1393
  try {
1234
1394
  checkGuardrail(packet.guardrails.deniedPaths);
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/env.ts", "../src/quiktrackError.ts", "../src/callback.ts", "../src/commands.ts", "../src/git.ts", "../src/commit.ts", "../src/codegen.ts", "../src/envelope.ts", "../src/retryFetch.ts", "../src/dependencyCheck.ts", "../src/guardrail.ts", "../src/installationToken.ts", "../src/oidc.ts", "../src/overlapCheck.ts", "../src/packet.ts", "../src/phase0.ts", "../src/quiktest.ts", "../src/regressionCheck.ts", "../src/scopeCheck.ts", "../src/targeting.ts", "../src/deniedPaths.ts", "../src/tokenExchange.ts", "../src/run.ts", "../src/readinessCheck.ts", "../src/index.ts"],
4
- "sourcesContent": ["/** The `workflow_dispatch` inputs QuikTrack's `dispatch.ts` sends, unchanged by QUIKTR-572 \u2014 the\n * generated workflow file still passes them through as job-level env vars under these exact\n * names. QUIKTR-805: `runToken`/`RUN_TOKEN` (a bearer, visible in the Actions UI as a dispatch\n * input) was replaced with `tokenUrl`/`TOKEN_URL` \u2014 the runner now exchanges a GitHub OIDC ID\n * token there for a run token at runtime; see `oidc.ts` and `tokenExchange.ts`. QUIKTR-804 adds\n * `installationTokenUrl`/`INSTALLATION_TOKEN_URL` \u2014 the run token is exchanged there for a\n * repo-scoped GitHub push credential; see `installationToken.ts`. */\nexport interface PilotRunEnv {\n mode: \"run\";\n runId: string;\n callbackUrl: string;\n packetUrl: string;\n tokenUrl: string;\n installationTokenUrl: string;\n /** GitHub Actions built-ins, read directly from `process.env` rather than threaded through here\n * individually. */\n githubRunId: string;\n githubServerUrl: string;\n githubRepository: string;\n}\n\n/**\n * QUIKTR-1084 \u2014 the readiness dry-run branch. Deliberately carries none of `PilotRunEnv`'s\n * fields: no packet fetch, no OIDC/run-token exchange, no design/codegen/commit/push. It only\n * needs the two commands to run and where to report the result.\n *\n * `readinessToken`/`READINESS_TOKEN` travels as a plain dispatch input, unlike the pilot-run\n * token \u2014 deliberately. QUIKTR-805 stopped doing that for the run token because a leaked one\n * could spend money through the LLM gateway; this token can only POST a\n * `{ junitFound, junitPath }` result for the one `QtPilotConfig` it was minted for (see\n * `readiness-dispatch.ts`), which is the same blast radius the pre-805 run token had. Splitting\n * out a second OIDC-exchange endpoint to protect a credential this narrow isn't worth the new\n * surface.\n */\nexport interface ReadinessCheckEnv {\n mode: \"readiness_check\";\n readinessToken: string;\n readinessCallbackUrl: string;\n setupCmd: string;\n testCmd: string;\n githubRunId: string;\n githubServerUrl: string;\n githubRepository: string;\n}\n\nexport type RunnerEnv = PilotRunEnv | ReadinessCheckEnv;\n\nexport function required(name: string, value: string | undefined): string {\n if (!value) {\n throw new Error(`Missing required environment variable: ${name}`);\n }\n return value;\n}\n\nexport function readRunnerEnv(env: NodeJS.ProcessEnv = process.env): RunnerEnv {\n const githubRunId = required(\"GITHUB_RUN_ID\", env.GITHUB_RUN_ID);\n const githubServerUrl = env.GITHUB_SERVER_URL ?? \"https://github.com\";\n const githubRepository = required(\"GITHUB_REPOSITORY\", env.GITHUB_REPOSITORY);\n\n if (env.MODE === \"readiness_check\") {\n return {\n mode: \"readiness_check\",\n readinessToken: required(\"READINESS_TOKEN\", env.READINESS_TOKEN),\n readinessCallbackUrl: required(\"READINESS_CALLBACK_URL\", env.READINESS_CALLBACK_URL),\n setupCmd: env.SETUP_CMD ?? \"\",\n testCmd: required(\"TEST_CMD\", env.TEST_CMD),\n githubRunId,\n githubServerUrl,\n githubRepository,\n };\n }\n\n return {\n mode: \"run\",\n runId: required(\"RUN_ID\", env.RUN_ID),\n callbackUrl: required(\"CALLBACK_URL\", env.CALLBACK_URL),\n packetUrl: required(\"PACKET_URL\", env.PACKET_URL),\n tokenUrl: required(\"TOKEN_URL\", env.TOKEN_URL),\n installationTokenUrl: required(\"INSTALLATION_TOKEN_URL\", env.INSTALLATION_TOKEN_URL),\n githubRunId,\n githubServerUrl,\n githubRepository,\n };\n}\n", "/**\n * QUIKTR-1080 \u2014 QuikTrack's internal pilot routes return a stable `reason_code` in the body on\n * every `pilotError()`-shaped failure (401/403/409/429); the generic 500 catch-all has none, and a\n * non-2xx response isn't guaranteed to be JSON at all (a proxy/gateway error can produce a\n * non-JSON body). Best effort: falls back to bare status/statusText when `reason_code` is absent\n * or the body doesn't parse \u2014 never throws itself.\n *\n * Unrelated to envelope.ts's `errorCode` \u2014 that's the AI Runtime's own, separate `/ai/execute`\n * contract. Two different services, two different field names; not to be conflated.\n */\nexport async function describeQuikTrackFailure(res: Response): Promise<string> {\n try {\n const body = await res.json();\n if (body && typeof body === \"object\" && typeof (body as Record<string, unknown>).reason_code === \"string\") {\n return `${res.status} ${res.statusText} (${(body as Record<string, unknown>).reason_code})`;\n }\n } catch {\n // not JSON, no json() method at all, or already consumed \u2014 fall back below\n }\n return `${res.status} ${res.statusText}`;\n}\n", "import { describeQuikTrackFailure } from \"./quiktrackError\";\n\nexport type RunStatus = \"completed\" | \"failed\";\n\n/** Always fires, regardless of what failed upstream \u2014 a run that fails silently is worse than one\n * that fails loudly. `branch` is omitted entirely (not sent as null/empty) when no push happened,\n * matching the original `jq ... | with_entries(select(.value != null and .value != \"\"))`. Same\n * treatment for `warnings` (QUIKTR-1064) \u2014 non-fatal findings like a targeting overlap, omitted\n * when there are none rather than sent as an empty array. */\nexport async function reportBack(params: {\n callbackUrl: string;\n runToken: string;\n status: RunStatus;\n branch?: string;\n warnings?: string[];\n}): Promise<void> {\n const { callbackUrl, runToken, status, branch, warnings } = params;\n const body: Record<string, unknown> = { status };\n if (branch) body.branch = branch;\n if (warnings && warnings.length > 0) body.warnings = warnings;\n const res = await fetch(callbackUrl, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${runToken}`, \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n throw new Error(`Report back to QuikTrack failed: ${await describeQuikTrackFailure(res)}`);\n }\n}\n", "import { execSync, spawn } from \"node:child_process\";\n\n/** Runs a packet-supplied command through bash \u2014 same interpreter GitHub's own `run:` steps used,\n * so a command written against that shell (e.g. `set -o pipefail`-reliant) behaves the same way.\n * A null/empty command is a no-op, matching the original `[ -n \"$CMD\" ]` guard. */\nexport function runCommand(command: string | null, label: string): void {\n if (!command) return;\n try {\n execSync(command, { shell: \"/bin/bash\", stdio: \"inherit\" });\n } catch (err) {\n throw new Error(`${label} failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n}\n\nexport type TestOutcome = \"success\" | \"failure\";\n\n/** The Test step alone is soft \u2014 a failing suite must not hide the rest of the run (guardrail,\n * commit, push) from happening, and must not flip the final callback to `failed`. QuikTest owns\n * per-test outcomes; this is only ever logged, never reported. QUIKTR-1036: this is still correct\n * for a NO_TARGET run (nothing was generated, so there's nothing to regress against) \u2014 a\n * codegen'd run's Test step is decided by regressionCheck.ts instead, using the async twin below. */\nexport function runTestCommand(command: string | null): TestOutcome {\n if (!command) return \"success\";\n try {\n execSync(command, { shell: \"/bin/bash\", stdio: \"inherit\" });\n return \"success\";\n } catch {\n return \"failure\";\n }\n}\n\n/** Same contract as `runTestCommand`, but non-blocking: `execSync` blocks the event loop, which\n * would serialize the baseline test run behind (or in front of) codegen's network-bound calls\n * instead of letting them overlap. QUIKTR-1036 \u2014 the baseline run is the only caller today. */\nexport function runTestCommandAsync(command: string | null): Promise<TestOutcome> {\n if (!command) return Promise.resolve(\"success\");\n return new Promise((resolve) => {\n const child = spawn(command, { shell: \"/bin/bash\", stdio: \"inherit\" });\n child.on(\"exit\", (code) => resolve(code === 0 ? \"success\" : \"failure\"));\n child.on(\"error\", () => resolve(\"failure\"));\n });\n}\n", "import { execFileSync } from \"node:child_process\";\n\n/** Thin wrapper around `execFileSync` \u2014 args passed as an array, never through a shell, so a\n * branch name or guardrail pattern can never be interpreted as shell syntax. `extraEnv` layers\n * on top of the inherited environment; every existing call site is unaffected since it defaults\n * to empty. */\nfunction git(args: string[], extraEnv: NodeJS.ProcessEnv = {}): string {\n return execFileSync(\"git\", args, {\n encoding: \"utf8\",\n env: { ...process.env, ...extraEnv },\n }).trim();\n}\n\nexport function currentBranch(): string {\n return git([\"rev-parse\", \"--abbrev-ref\", \"HEAD\"]);\n}\n\n/** Only fetches + checks out when the packet names a target branch different from the one the\n * workflow_dispatch already put us on \u2014 dispatch always runs against the default branch (the\n * only place `workflow_dispatch` can find the file), but the PR base may differ. */\nexport function checkoutTargetBranch(targetBranch: string | null): void {\n if (!targetBranch || targetBranch === currentBranch()) return;\n git([\"fetch\", \"origin\", targetBranch]);\n git([\"checkout\", targetBranch]);\n}\n\nexport function addAll(): void {\n git([\"add\", \"-A\"]);\n}\n\n/** `:(glob)` pathspec \u2014 same semantics `**` needs that a hand-rolled glob-to-regex would risk\n * getting wrong. */\nexport function diffCachedNamesMatching(pattern: string): string[] {\n const out = git([\"diff\", \"--cached\", \"--name-only\", \"--\", `:(glob)${pattern}`]);\n return out ? out.split(\"\\n\").filter(Boolean) : [];\n}\n\n/** Tracked files under `pathspec`, relative to cwd \u2014 same cwd every other export here already\n * assumes is the checkout root, so a caller can feed these straight to readFileSync/writeFileSync\n * with no translation. QUIKTR-1035 \u2014 `pathspec` is always concrete; \"null means repo root\" is\n * targeting.ts's workspaceRoot concept, not a generic git one. */\nexport function listFiles(pathspec: string): string[] {\n const out = git([\"ls-files\", \"--\", pathspec]);\n return out ? out.split(\"\\n\").filter(Boolean) : [];\n}\n\nexport function hasStagedChanges(): boolean {\n try {\n execFileSync(\"git\", [\"diff\", \"--cached\", \"--quiet\"]);\n return false;\n } catch {\n return true;\n }\n}\n\nexport function configureCommitIdentity(): void {\n git([\"config\", \"user.name\", \"quikpilot[bot]\"]);\n git([\"config\", \"user.email\", \"quikpilot@users.noreply.github.com\"]);\n}\n\nexport function checkoutNewBranch(branch: string): void {\n git([\"checkout\", \"-b\", branch]);\n}\n\nexport function commit(message: string): void {\n git([\"commit\", \"-m\", message]);\n}\n\n/**\n * Push, authenticated with a repo-scoped GitHub installation token (QUIKTR-804, D16) rather than\n * whatever ambient credential checkout configured. `x-access-token:<token>` Basic-auth, GitHub's\n * documented scheme for installation tokens over HTTPS git.\n *\n * Carried via `GIT_CONFIG_COUNT`/`GIT_CONFIG_KEY_0`/`GIT_CONFIG_VALUE_0` env vars rather than a\n * `-c http.extraheader=...` argv flag or a `.git/config` write: env vars are not visible to `ps`,\n * argv is \u2014 the same class of exposure `packet.ts`'s own header comment already avoids for this\n * runner's other credential. Scoped to this one invocation only; never persisted.\n *\n * QUIKTR-943 rehearsal, 7.0.1 \u2014 the key MUST be `http.https://github.com/.extraheader`\n * (URL-scoped), not the unscoped `http.extraheader`. `actions/checkout` persists its own\n * credential under the URL-scoped key, pointing at the job's ambient token (contents: read since\n * QUIKTR-804 dropped it). Git prefers the more specific URL-scoped key, so an unscoped header here\n * silently loses to checkout's read-only one \u2014 the push then fails with \"denied to\n * github-actions[bot]\" even though this token itself has write access and the exchange succeeded.\n *\n * QUIKTR-943 rehearsal, 7.0.2 \u2014 url-scoping alone re-broke the push a second way:\n * `http.<url>.extraheader` is multi-valued (git appends, it doesn't replace), so checkout's\n * `.git/config` entry and this call's env-var entry are BOTH sent, and GitHub 400s with\n * `Duplicate header: \"Authorization\"`. `--unset-all` clears checkout's entry from `.git/config`\n * first, so our env-var header (scoped to this one invocation, never written to disk) is the only\n * one on the wire. Tolerates the key already being absent (exit 5) \u2014 nothing to clear is not a\n * failure, and a workflow that ever runs with `persist-credentials: false` shouldn't crash here.\n */\nfunction clearCheckoutExtraHeader(): void {\n try {\n git([\"config\", \"--unset-all\", \"http.https://github.com/.extraheader\"]);\n } catch (err: unknown) {\n const status = (err as { status?: number }).status;\n if (status !== 5) throw err;\n }\n}\n\nexport function push(branch: string, installationToken: string): void {\n clearCheckoutExtraHeader();\n const basicAuth = Buffer.from(`x-access-token:${installationToken}`).toString(\"base64\");\n git([\"push\", \"--set-upstream\", \"origin\", branch], {\n GIT_CONFIG_COUNT: \"1\",\n GIT_CONFIG_KEY_0: \"http.https://github.com/.extraheader\",\n GIT_CONFIG_VALUE_0: `AUTHORIZATION: basic ${basicAuth}`,\n });\n}\n", "import {\n checkoutNewBranch,\n commit,\n configureCommitIdentity,\n hasStagedChanges,\n push,\n} from \"./git\";\n\nexport interface CommitResult {\n changed: boolean;\n branch?: string;\n}\n\n/**\n * QUIKTR-1067 \u2014 \"QuikPilot Phase 0 skeleton\" used to be hardcoded for every commit, including one\n * carrying a real generated fix (PR #19) \u2014 indistinguishable from the genuinely-empty NO_TARGET\n * marker commit without opening the diff, and git history is permanent. `targeted: false` is the\n * one case that message is still accurate for. `issueKey`/`issueTitle` null with `targeted: true`\n * is defensive only \u2014 dispatch never reaches commit before Gate 1, which always attaches an issue.\n */\nexport function buildCommitMessage(\n runId: string,\n targeted: boolean,\n issueKey: string | null,\n issueTitle: string | null,\n): string {\n if (!targeted) return `QuikPilot Phase 0 skeleton (run ${runId})`;\n if (issueKey && issueTitle) return `${issueKey}: ${issueTitle}\\n\\nQuikPilot run ${runId}`;\n return `QuikPilot generated changes (run ${runId})`;\n}\n\n/** Runs regardless of the Test step's outcome \u2014 a failing suite must not hide the generated diff\n * from a reviewer (the whole reason Test alone is a soft failure). Only reached when Setup, Lint,\n * and the guardrail check all passed. The branch name comes from the packet, not `runId`: QuikTrack\n * already computed and stored it, and two sources for one value will eventually disagree.\n * `installationToken` (QUIKTR-804) is the repo-scoped GitHub credential the push authenticates\n * with \u2014 see git.ts's `push` for why. */\nexport function commitAndPush(\n branch: string | null,\n runId: string,\n installationToken: string,\n targeted: boolean,\n issueKey: string | null,\n issueTitle: string | null,\n): CommitResult {\n if (!hasStagedChanges()) return { changed: false };\n if (!branch) {\n throw new Error(\"packet carried no branch name\");\n }\n configureCommitIdentity();\n checkoutNewBranch(branch);\n commit(buildCommitMessage(runId, targeted, issueKey, issueTitle));\n push(branch, installationToken);\n return { changed: true, branch };\n}\n", "import { readFileSync, writeFileSync, mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { checkHardFailure, unwrapExecute } from \"./envelope\";\nimport type { PilotPacket } from \"./packet\";\nimport { fetchWithRetry } from \"./retryFetch\";\nimport type { PilotTarget } from \"./targeting\";\n\n/**\n * QUIKTR-823 \u2014 one `/ai/execute` call per file, proven working against a real request this\n * morning (Suyash): `x-run-token` header carrying the packet's `gateway.token`, full file content\n * in and out. Never a patch \u2014 a failed apply would cost a whole extra call against a tight budget,\n * and a patch that can't apply is exactly the kind of failure this loop can't safely paper over.\n *\n * QUIKTR-1035 \u2014 `targets` (with per-target `planStepsImplemented`) replaces the old\n * `targetPaths: string[]` plus a single `design`-derived `planSteps` shared across every file.\n * Merging targeting's per-target steps back into one shared list would destroy the reason they're\n * per-target: the route file and the service file need different instructions.\n *\n * \u2500\u2500 ALL-OR-NOTHING \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * The first failed or REFUSED file throws, and `run.ts`'s existing hard-failure handling takes it\n * from there: no branch, no pull request. A pull request is a claim the work is done; a\n * partially-applied change compiles sometimes, passes tests sometimes, and looks complete either\n * way. Already decided twice elsewhere for the same reason \u2014 Gate 1's spec commit is one\n * transaction, and `create_issue` with `testCases` is explicitly all-or-nothing. Retrying the\n * failed file instead of discarding the rest is the better long-run answer and belongs with\n * self-heal (Phase 3, unscoped) \u2014 not silently attempted here.\n *\n * `CODEGEN_FILE_TOO_LARGE` and `CODEGEN_CONTEXT_TOO_LARGE` are the AI Runtime's own distinct error\n * codes, checked on their side before dispatch \u2014 retrying hits the identical wall every time, so\n * both are deliberately not retried, same as every other failure here.\n *\n * \u2500\u2500 CONTEXT CONTRACT (contextPaths \u2192 contextContents) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * pilot.targeting now names, per target, which other files pilot.codegen should read\n * (`target.contextPaths`) \u2014 replacing the old `siblingContent` guess (nearest file by directory),\n * which only ever ran for NEW_FILE targets and was never more than a stated assumption about this\n * repo's own layout. `contextContents: [{ path, content }]` is now sent for EXISTING targets too,\n * not just NEW_FILE. Empty/absent contextPaths means empty contextContents \u2014 no fallback.\n * `workspaceListing` still goes out for NEW_FILE only, unchanged.\n *\n * \u2500\u2500 BUFFERED WRITES (QUIKTR-1035) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * `runCodegen` no longer writes anything \u2014 it collects `{targetPath, newContent}` in memory and\n * `flushCodegenResults` writes them all, only once every call has succeeded. Two independent\n * reasons: it makes all-or-nothing literally true for the working tree, not just the pull request\n * (today a failure on file 3 leaves files 1-2 already written even though the throw stops the\n * commit); and it lets the test baseline run against an untouched tree while codegen's network-\n * bound calls are still in flight (QUIKTR-1036 is what actually wires that concurrency up \u2014 this\n * only makes it possible).\n */\nconst FILE_TOO_LARGE_CODE = \"CODEGEN_FILE_TOO_LARGE\";\nconst CONTEXT_TOO_LARGE_CODE = \"CODEGEN_CONTEXT_TOO_LARGE\";\n/** \u00A716.7 \u2014 the AI Runtime's OWN output-cap guard telling us directly, distinct from\n * `looksLikeTruncatedRewrite` below (this file's interim heuristic guess at the same problem). */\nconst OUTPUT_TOO_LARGE_CODE = \"CODEGEN_OUTPUT_TOO_LARGE\";\nconst NOT_RETRIED_CODES = new Set([FILE_TOO_LARGE_CODE, CONTEXT_TOO_LARGE_CODE, OUTPUT_TOO_LARGE_CODE]);\n\n/**\n * \u00A716.7 \u2014 interim runner-side guard, live under \u00A715 today (not gated on self-heal or on the AI\n * Runtime's own `CODEGEN_OUTPUT_TOO_LARGE` check, which isn't deployed yet). Codegen's output is\n * capped around 8,192 tokens; `CODEGEN_FILE_TOO_LARGE` only checks the ~200k-char *input*, so a\n * rewrite of a file well under that can still get truncated on the way out. The dangerous case is\n * a retry that comes back as valid, `success: true` JSON with the file quietly abbreviated \u2014\n * codegen's contract is that anything missing from `newContent` is deleted, so that reads as a\n * clean success while silently destroying code. \u00A716.7 names this exact heuristic as QuikTrack's\n * own stopgap until the real guard (a pre-dispatch prediction plus a finish-reason check) ships on\n * the runtime side.\n */\nconst SUSPECT_PLACEHOLDER_RE =\n /rest(?: of the)? (?:file|code) unchanged|remainder unchanged|\\/\\/\\s*\\.\\.\\.\\s*(?:rest|remaining)/i;\n/** Below 60% of its original length, an EXISTING rewrite is suspect rather than a real edit \u2014 a\n * targeted fix (planStepsImplemented) trims, it doesn't gut a file to a stub. Raised from 0.5 to\n * 0.6 after the AI Runtime's 2026-09-24 incident: a real pilot-chat.ts rewrite came back 38,500 ->\n * 22,585 chars (58.67% remaining) with success: true and no placeholder text \u2014 the old 0.5 ratio\n * only fires below 50% remaining, so that exact silent deletion sailed through undetected. */\nconst SUSPECT_LENGTH_DROP_RATIO = 0.6;\n/** A drop in character count can hide behind reformatting (fewer, longer lines) \u2014 this catches\n * the opposite failure: a rewrite that removes a large share of *lines* without a matching drop\n * in characters. 30% is a deliberately conservative starting point, not a calibrated number \u2014 no\n * incident has been observed on this signal alone yet. Tighten once real call metrics exist. */\nconst SUSPECT_REMOVED_LINE_RATIO = 0.3;\n/** Below this many lines, the multiset diff's \"changed line looks like removed+added\" blind spot\n * makes the ratio check unreliable \u2014 skip it rather than false-positive on small/single-line files. */\nconst MIN_LINES_FOR_REMOVED_LINE_CHECK = 10;\n/** Exported symbols removed silently are exactly the \"code vanishes, response still looks valid\"\n * failure mode \u2014 TS/JS only, since this parses no grammar beyond an `export` declaration. */\nconst JS_TS_EXTENSION_RE = /\\.(?:ts|tsx|js|jsx|mjs|cjs)$/;\nconst EXPORTED_SYMBOL_RE =\n /^export\\s+(?:default\\s+)?(?:async\\s+)?(?:function\\*?|class|const|let|var|interface|type|enum)\\s+([A-Za-z_$][\\w$]*)/gm;\n\n/** Language-neutral, line-based multiset diff \u2014 not an LCS/AST diff. Counts lines present in\n * `currentContent` with no matching occurrence left in `newContent`; good enough to flag \"lines\n * vanished\" without claiming to be a minimal diff. */\nfunction countRemovedLines(currentContent: string, newContent: string): number {\n const remaining = new Map<string, number>();\n for (const line of newContent.split(\"\\n\")) {\n remaining.set(line, (remaining.get(line) ?? 0) + 1);\n }\n let removed = 0;\n for (const line of currentContent.split(\"\\n\")) {\n const count = remaining.get(line) ?? 0;\n if (count > 0) {\n remaining.set(line, count - 1);\n } else {\n removed++;\n }\n }\n return removed;\n}\n\nfunction extractExportedSymbols(content: string): Set<string> {\n const symbols = new Set<string>();\n for (const match of content.matchAll(EXPORTED_SYMBOL_RE)) {\n symbols.add(match[1]);\n }\n return symbols;\n}\n\n/** Symbols removed by the rewrite that the plan text never names \u2014 a naive substring check, not a\n * reference-tracking one: it undercounts (a symbol renamed to match a plan word would slip past)\n * rather than overcounts, which is the right side to err on for a hard-failing guard. */\nfunction removedUnexplainedSymbols(targetPath: string, planText: string, currentContent: string, newContent: string): string[] {\n if (!JS_TS_EXTENSION_RE.test(targetPath)) return [];\n const before = extractExportedSymbols(currentContent);\n const after = extractExportedSymbols(newContent);\n const lowerPlan = planText.toLowerCase();\n return [...before].filter((symbol) => !after.has(symbol) && !lowerPlan.includes(symbol.toLowerCase()));\n}\n\nfunction looksLikeTruncatedRewrite(target: PilotTarget, currentContent: string, newContent: string): string | null {\n if (SUSPECT_PLACEHOLDER_RE.test(newContent)) {\n return \"contains placeholder text suggesting an abbreviated rewrite\";\n }\n if (currentContent.length > 0 && newContent.length < currentContent.length * SUSPECT_LENGTH_DROP_RATIO) {\n return `sharp length drop (${currentContent.length} -> ${newContent.length} chars)`;\n }\n\n // A multiset line diff can't tell \"line changed\" from \"line removed\" \u2014 on a short/single-line\n // file, one edited line reads as 100% removed. Require a real line count before trusting it.\n const currentLineCount = currentContent.length > 0 ? currentContent.split(\"\\n\").length : 0;\n if (currentLineCount >= MIN_LINES_FOR_REMOVED_LINE_CHECK) {\n const removedLines = countRemovedLines(currentContent, newContent);\n if (removedLines > currentLineCount * SUSPECT_REMOVED_LINE_RATIO) {\n const pct = ((removedLines / currentLineCount) * 100).toFixed(0);\n return `removed ${removedLines} of ${currentLineCount} lines (${pct}%) without a matching drop in character count`;\n }\n }\n\n const planText = target.planStepsImplemented.join(\" \");\n const unexplainedSymbols = removedUnexplainedSymbols(target.path, planText, currentContent, newContent);\n if (unexplainedSymbols.length > 0) {\n return `removed exported symbol(s) the plan steps don't mention: ${unexplainedSymbols.join(\", \")}`;\n }\n\n return null;\n}\n\n/** QUIKTR-1083 (\u00A715.6) \u2014 sent on every codegen call, same reasoning as targeting.ts's own constant. */\nconst CONTRACT_VERSION = \"test-targets-1\";\n\n/** The shape at `envelope.structuredJson` for `pilot.codegen` \u2014 NOT the envelope itself. A\n * refusal's reason is `refusalReason`; the envelope has no `code`/`message` fields (those were\n * never real \u2014 see envelope.ts). */\ninterface CodegenResult {\n outcome?: \"GENERATED\" | \"REFUSED\";\n newContent?: string;\n summary?: string;\n refusalReason?: string;\n}\n\nexport interface CodegenFileResult {\n targetPath: string;\n newContent: string;\n}\n\n/**\n * Run codegen for exactly the targets named, in order, stopping at the first failure. Throws\n * rather than returning a partial result \u2014 see the ALL-OR-NOTHING note above; a caller that wants\n * to know how far it got before failing should catch and inspect the message, not branch on a\n * return value that implies partial success is a valid state. Writes nothing \u2014 call\n * `flushCodegenResults` with the return value once this resolves.\n */\nexport async function runCodegen(\n gateway: PilotPacket[\"gateway\"],\n targets: PilotTarget[],\n workspaceListing: string[],\n requiredTests: PilotPacket[\"requiredTests\"],\n deniedPaths: string[],\n): Promise<CodegenFileResult[]> {\n const results: CodegenFileResult[] = [];\n const listing = new Set(workspaceListing);\n\n for (const target of targets) {\n const isNewFile = target.kind === \"NEW_FILE\";\n const currentContent = isNewFile ? \"\" : readFileSync(target.path, \"utf8\");\n\n // targeting names its own context needs per target \u2014 an invented contextPath is the same\n // class of bug as an invented EXISTING target (targeting.ts's validateTarget): fail loudly\n // rather than silently sending less context than the model asked for.\n const contextPaths = target.contextPaths ?? [];\n for (const contextPath of contextPaths) {\n if (!listing.has(contextPath)) {\n throw new Error(\n `pilot.codegen contextPaths named a file not found in the checkout: ${contextPath} (target ${target.path})`,\n );\n }\n }\n const contextContents = contextPaths.map((path) => ({ path, content: readFileSync(path, \"utf8\") }));\n\n const contextData: Record<string, unknown> = {\n targetPath: target.path,\n currentContent,\n planSteps: target.planStepsImplemented,\n kind: target.kind,\n contextContents,\n // QUIKTR-1083 (\u00A715.6) \u2014 required on every call on the versioned path.\n contractVersion: CONTRACT_VERSION,\n };\n if (isNewFile) {\n // Bounds WHAT EXISTS \u2014 stops an invented import like hooks/useGroups \u2014 only meaningful for\n // a file that doesn't exist yet to compare against.\n contextData.workspaceListing = workspaceListing;\n }\n if (deniedPaths.length > 0) {\n contextData.deniedPaths = deniedPaths;\n }\n // QUIKTR-1083 (\u00A715.4) \u2014 only for a test target (one targeting named automationIds for), and\n // only that target's own subset \u2014 never the full list, and never for a code target at all.\n if (target.automationIds && target.automationIds.length > 0) {\n const wanted = new Set(target.automationIds);\n contextData.requiredTests = requiredTests.filter((tc) => wanted.has(tc.automationId));\n }\n\n // QUIKTR-1069 \u2014 retries a transport-level failure only (502/503/504, a dropped connection);\n // a real refusal always arrives as a 200 with the refusal inside the envelope, below.\n const res = await fetchWithRetry(`${gateway.baseUrl}/ai/execute`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"x-run-token\": gateway.token },\n body: JSON.stringify({\n appId: \"quiktrack\",\n useCase: \"pilot.codegen\",\n expectedOutputType: \"json\",\n userPrompt: \"\",\n contextData,\n }),\n });\n\n if (!res.ok) {\n throw new Error(`Codegen call failed for ${target.path}: ${res.status} ${res.statusText}`);\n }\n\n // /ai/execute wraps every result in an envelope \u2014 the use-case result lives at\n // structuredJson, and a failure can arrive as success:false in an HTTP 200 (see envelope.ts).\n // CODEGEN_FILE_TOO_LARGE / CODEGEN_CONTEXT_TOO_LARGE are checked on the RAW envelope, before\n // unwrapping: they arrive as a failure (success:false), so unwrapping first would throw the\n // generic envelope error and lose the not-retried distinction this check exists to preserve.\n const envelope: any = await res.json();\n // QUIKTR-1083 \u2014 SEMANTIC_MISMATCH/CONTRACT_REJECTED, same \"raw envelope, before unwrap\" point\n // as the CODEGEN_* check right below.\n checkHardFailure(envelope, \"pilot.codegen\");\n if (typeof envelope?.errorCode === \"string\" && NOT_RETRIED_CODES.has(envelope.errorCode)) {\n const detail = envelope.error ? `: ${envelope.error}` : \"\";\n throw new Error(`Codegen refused ${target.path}: ${envelope.errorCode} (not retried)${detail}`);\n }\n\n const body = unwrapExecute<CodegenResult>(envelope, \"pilot.codegen\");\n\n if (body.outcome !== \"GENERATED\" || typeof body.newContent !== \"string\") {\n throw new Error(\n `Codegen refused ${target.path}${body.refusalReason ? `: ${body.refusalReason}` : \"\"}`,\n );\n }\n\n if (!isNewFile) {\n const suspectReason = looksLikeTruncatedRewrite(target, currentContent, body.newContent);\n if (suspectReason) {\n throw new Error(\n `Codegen output for ${target.path} looks like a truncated/abbreviated rewrite (${suspectReason}) ` +\n `\u2014 refusing to apply it. Interim guard per \u00A716.7; the AI Runtime's own output-cap check is not live yet.`,\n );\n }\n }\n\n // AI Runtime, 2026-09-24 \u2014 one structured line per call, to build the input/output/removed-line\n // distribution SUSPECT_LENGTH_DROP_RATIO and SUSPECT_REMOVED_LINE_RATIO were guessed without.\n // Not itself a safety check \u2014 plain data collection for calibrating the two guards above.\n console.log(\n JSON.stringify({\n event: \"codegen.metrics\",\n targetPath: target.path,\n kind: target.kind,\n inputLength: currentContent.length,\n outputLength: body.newContent.length,\n removedLines: isNewFile ? null : countRemovedLines(currentContent, body.newContent),\n }),\n );\n\n results.push({ targetPath: target.path, newContent: body.newContent });\n }\n\n return results;\n}\n\n/** Writes every result to disk. Only ever call this after every `runCodegen` call succeeded \u2014\n * see the buffered-writes note above. Creates the parent directory first: a NEW_FILE target can\n * legitimately name a directory that doesn't exist yet (e.g. a repo's first hooks/ file). */\nexport function flushCodegenResults(results: CodegenFileResult[]): void {\n for (const { targetPath, newContent } of results) {\n mkdirSync(dirname(targetPath), { recursive: true });\n writeFileSync(targetPath, newContent);\n }\n}\n", "/**\n * QUIKTR-1046 \u2014 `/ai/execute` wraps every use-case result in an envelope; the use-case's own result\n * lives at `envelope.structuredJson`, not at the top level. Both `targeting.ts` and `codegen.ts`\n * read the raw response directly and have never worked against a real reply \u2014 this is the one\n * place that unwraps it, so there is exactly one place to get it right.\n *\n * A failed call can arrive as `success: false` in an HTTP 200 body \u2014 `res.ok` alone is not enough.\n * Observed live 2026-09-18/19/21, including a real RUN_CREDENTIAL_SCOPE refusal shaped exactly\n * like this.\n */\n/**\n * QUIKTR-1083 (\u00A715 of the spec-phase contract) \u2014 two hard-failure codes the AI Runtime raises on\n * the versioned `pilot.targeting`/`pilot.codegen` path, neither ever retried: `SEMANTIC_MISMATCH`\n * (the JSON shape was valid, a rule failed \u2014 e.g. a generated test file missing its\n * `[<automationId>]` marker) and `CONTRACT_REJECTED` (the request itself was refused \u2014 an unknown\n * or removed `contextData` key, or an unrecognised `contractVersion`). Both carry the explanation\n * in `envelope.error`.\n *\n * Checked on the RAW envelope, before `unwrapExecute` \u2014 same reason codegen.ts's existing\n * `CODEGEN_FILE_TOO_LARGE`/`CODEGEN_CONTEXT_TOO_LARGE` check already runs there: unwrapping first\n * would throw `unwrapExecute`'s generic `success:false` error and lose the distinction. No custom\n * error class \u2014 `run.ts`'s top-level catch already prints any thrown error's message, and\n * `fetchWithRetry` never retries a 200 response regardless of body, so \"print the violation list\"\n * and \"never retried\" both already hold once this throws a message that names the code and detail.\n */\nconst HARD_FAILURE_CODES = new Set([\"SEMANTIC_MISMATCH\", \"CONTRACT_REJECTED\"]);\n\nexport function checkHardFailure(envelope: any, useCase: string): void {\n const code = envelope?.errorCode;\n if (typeof code === \"string\" && HARD_FAILURE_CODES.has(code)) {\n const detail = envelope.error ?? envelope.normalizedText ?? \"no detail\";\n throw new Error(`${useCase} failed (${code}, not retried): ${detail}`);\n }\n}\n\nexport function unwrapExecute<T>(envelope: any, useCase: string): T {\n if (envelope?.success === false) {\n throw new Error(\n `${useCase} failed: ${envelope.errorCode ?? \"UNKNOWN\"} \u2014 ` +\n `${envelope.error ?? envelope.normalizedText ?? \"no message\"}`,\n );\n }\n if (!envelope?.structuredJson || typeof envelope.structuredJson !== \"object\") {\n throw new Error(`${useCase} returned no structuredJson: ${JSON.stringify(envelope)}`);\n }\n return envelope.structuredJson as T;\n}\n", "/**\n * QUIKTR-1069 \u2014 a gateway timeout in front of the AI Runtime is not a refusal: the demo rehearsal\n * hit a 504 from a devtunnel/load balancer, not the runtime, and the same call succeeded on retry.\n * Retries ONLY transport-level signals \u2014 HTTP 502/503/504, or a thrown network error\n * (ECONNRESET/ETIMEDOUT) \u2014 twice, with a short fixed backoff. Every other failure (a real refusal,\n * CODEGEN_FILE_TOO_LARGE, success:false+errorCode, any 4xx) arrives as a normal HTTP 200 with the\n * refusal inside the envelope body, or a genuine non-transient 4xx \u2014 neither ever matches this\n * function's retry condition, so nothing here needs to special-case them.\n *\n * Spend: a retried call the runtime actually completed has been paid for twice. maxRunUsd already\n * caps the run (enforced at the gateway, per packet.ts's own comment), so this fails safe \u2014 the\n * worst case is hitting the budget wall slightly sooner, never an uncapped spend.\n */\nconst RETRYABLE_STATUS_CODES = new Set([502, 503, 504]);\nconst RETRYABLE_NETWORK_ERROR_CODES = new Set([\"ECONNRESET\", \"ETIMEDOUT\"]);\n\nfunction isRetryableNetworkError(err: unknown): boolean {\n const code =\n (err as { cause?: { code?: string } } | undefined)?.cause?.code ??\n (err as { code?: string } | undefined)?.code;\n return typeof code === \"string\" && RETRYABLE_NETWORK_ERROR_CODES.has(code);\n}\n\nexport async function fetchWithRetry(\n url: string,\n init: RequestInit,\n { retries = 2, backoffMs = 250 }: { retries?: number; backoffMs?: number } = {},\n): Promise<Response> {\n for (let attempt = 0; ; attempt++) {\n try {\n const res = await fetch(url, init);\n if (RETRYABLE_STATUS_CODES.has(res.status) && attempt < retries) {\n await new Promise((r) => setTimeout(r, backoffMs));\n continue;\n }\n return res;\n } catch (err) {\n if (isRetryableNetworkError(err) && attempt < retries) {\n await new Promise((r) => setTimeout(r, backoffMs));\n continue;\n }\n throw err;\n }\n }\n}\n", "import { readFileSync } from \"node:fs\";\nimport { resolve, join } from \"node:path\";\nimport type { CodegenFileResult } from \"./codegen\";\n\n/**\n * QUIKTR-1045 \u2014 codegen importing a package the repository doesn't have currently fails safely\n * (setup already ran, so the package genuinely isn't installed, and the regression check catches\n * the resulting test failure) but with the WRONG diagnosis: it reads as \"the generated logic is\n * broken\" when the real problem is a fabricated import. This names that failure correctly instead.\n *\n * Only a minimal regex import-scanner \u2014 not a real JS/TS parser. Same reasoning\n * `regressionCheck.ts` already states for its own hand-rolled JUnit scanner: this package is\n * dependency-free on purpose (published outside the monorepo, bundled into a single CLI file with\n * no externals \u2014 see build.mjs), so a real parser is off the table, not merely unused.\n *\n * Explicitly scoped to JS/TS: it only acts when a `package.json` is found. A repo in another\n * language has none, `readDeclaredDependencies` returns null, and the check no-ops \u2014 this is what\n * keeps it from looking like a general \"detect the repo's language\" mechanism, which it isn't.\n */\nexport interface DependencyViolation {\n file: string;\n packages: string[];\n}\n\nexport interface DependencyCheck {\n blocked: boolean;\n violations: DependencyViolation[];\n}\n\nconst SCANNABLE_EXTENSIONS = [\".ts\", \".tsx\", \".js\", \".jsx\", \".mjs\", \".cjs\", \".mts\", \".cts\"];\n\n// import ... from \"x\" / import \"x\" / export ... from \"x\" / require(\"x\") / import(\"x\")\nconst IMPORT_RE = /(?:\\bimport\\b[^'\"]*?\\bfrom\\s*|\\bimport\\s*\\(\\s*|\\bexport\\b[^'\"]*?\\bfrom\\s*|\\brequire\\s*\\(\\s*|\\bimport\\s+)(['\"])([^'\"]+)\\1/g;\n\n// Not exhaustive \u2014 same \"minimal, not exhaustive\" treatment regressionCheck.ts's own scanner uses.\nconst NODE_BUILTINS = new Set([\n \"assert\", \"buffer\", \"child_process\", \"cluster\", \"crypto\", \"dgram\", \"dns\", \"domain\", \"events\",\n \"fs\", \"http\", \"http2\", \"https\", \"net\", \"os\", \"path\", \"perf_hooks\", \"process\", \"punycode\",\n \"querystring\", \"readline\", \"repl\", \"stream\", \"string_decoder\", \"sys\", \"timers\", \"tls\", \"tty\",\n \"url\", \"util\", \"v8\", \"vm\", \"worker_threads\", \"zlib\", \"inspector\", \"async_hooks\",\n]);\n\n// QUIKTR-1063 \u2014 the two path-alias conventions common enough to assume even\n// when a repo's tsconfig can't be read or parsed: \"@/...\" (QuikTrack,\n// QuikChat, and most of this monorepo's own apps) and \"~/...\". Without this,\n// \"@/lib/x\" was parsed as the scoped package \"@/lib\" \u2014 a real package.json\n// entry it could never actually match \u2014 and every aliased import in a repo\n// using either convention was reported as an invented dependency.\n//\n// QUIKTR-1068 \u2014 this is now a FLOOR, not the whole answer: `resolveAliasPrefixes`\n// below adds whatever a real tsconfig.json/jsconfig.json actually declares in\n// `compilerOptions.paths`, for repos using some other convention entirely.\n// Always unioned in regardless of what a config says, so a repo with no\n// config (or an unparseable one) keeps exactly today's behavior.\nconst DEFAULT_ALIAS_PREFIXES = [\"@/\", \"~/\"];\n\nfunction packageNameFromSpecifier(specifier: string, aliasPrefixes: string[] = DEFAULT_ALIAS_PREFIXES): string | null {\n if (specifier.startsWith(\".\") || specifier.startsWith(\"/\")) return null; // relative/absolute\n if (specifier.startsWith(\"node:\")) return null; // explicit builtin\n if (aliasPrefixes.some((prefix) => specifier.startsWith(prefix))) return null; // path alias\n const segments = specifier.split(\"/\");\n const name = specifier.startsWith(\"@\") ? segments.slice(0, 2).join(\"/\") : segments[0];\n if (NODE_BUILTINS.has(name)) return null;\n return name;\n}\n\nfunction scanImports(source: string, aliasPrefixes: string[] = DEFAULT_ALIAS_PREFIXES): string[] {\n const found = new Set<string>();\n let match: RegExpExecArray | null;\n IMPORT_RE.lastIndex = 0;\n while ((match = IMPORT_RE.exec(source))) {\n const name = packageNameFromSpecifier(match[2], aliasPrefixes);\n if (name) found.add(name);\n }\n return [...found];\n}\n\n/** Pure \u2014 no fs, trivially unit-testable. `declaredDependencies === null` means \"couldn't tell\n * what this repo declares\" (no package.json, or unparseable) \u2014 the check no-ops rather than\n * blocking on a question it can't actually answer. `aliasPrefixes` defaults to the floor above;\n * callers with a real tsconfig read (see `resolveAliasPrefixes`) pass the fuller list. */\nexport function checkImportDependencies(\n results: CodegenFileResult[],\n declaredDependencies: Set<string> | null,\n aliasPrefixes: string[] = DEFAULT_ALIAS_PREFIXES,\n): DependencyCheck {\n if (!declaredDependencies) return { blocked: false, violations: [] };\n\n const violations: DependencyViolation[] = [];\n for (const { targetPath, newContent } of results) {\n if (!SCANNABLE_EXTENSIONS.some((ext) => targetPath.endsWith(ext))) continue;\n const invented = scanImports(newContent, aliasPrefixes).filter((pkg) => !declaredDependencies.has(pkg));\n if (invented.length > 0) violations.push({ file: targetPath, packages: invented });\n }\n return { blocked: violations.length > 0, violations };\n}\n\ninterface PackageJson {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n}\n\nfunction dependencyNames(pkg: PackageJson): Set<string> {\n // devDependencies included deliberately \u2014 a generated test file may legitimately import one.\n return new Set([\n ...Object.keys(pkg.dependencies ?? {}),\n ...Object.keys(pkg.devDependencies ?? {}),\n ...Object.keys(pkg.peerDependencies ?? {}),\n ]);\n}\n\n/**\n * Reads the target repo's declared dependencies. Checks `results` FIRST for a generated\n * `package.json` \u2014 codegen may have legitimately added the very dependency it's about to import,\n * and reading the pre-generation file on disk would false-flag that. Falls back to the on-disk\n * file, and to `null` (\u2192 the check no-ops) when neither exists or parses.\n */\nexport function readDeclaredDependencies(\n results: CodegenFileResult[],\n workspaceRoot: string | null,\n): Set<string> | null {\n const packageJsonPath = join(resolve(workspaceRoot ?? \".\"), \"package.json\");\n const generated = results.find((r) => resolve(r.targetPath) === packageJsonPath);\n\n let raw: string | null;\n if (generated) {\n raw = generated.newContent;\n } else {\n try {\n raw = readFileSync(packageJsonPath, \"utf8\");\n } catch {\n raw = null;\n }\n }\n if (raw === null) return null;\n\n try {\n return dependencyNames(JSON.parse(raw) as PackageJson);\n } catch {\n return null;\n }\n}\n\n/**\n * QUIKTR-1068 \u2014 strips line and block comments plus trailing commas from a JSON(C) string, best\n * effort. Not a real JSONC parser: a character scanner rather than a regex replace (a regex would\n * corrupt a string VALUE containing `//`, e.g. a URL), but anything it can't cleanly handle just\n * fails `JSON.parse` afterward \u2014 `resolveAliasPrefixes` below treats that the same as no config at\n * all and falls back to the floor. Never throws itself.\n */\nfunction stripJsonComments(text: string): string {\n let out = \"\";\n let inString = false;\n let inLineComment = false;\n let inBlockComment = false;\n for (let i = 0; i < text.length; i++) {\n const c = text[i];\n const next = text[i + 1];\n if (inLineComment) {\n if (c === \"\\n\") {\n inLineComment = false;\n out += c;\n }\n continue;\n }\n if (inBlockComment) {\n if (c === \"*\" && next === \"/\") {\n inBlockComment = false;\n i++;\n }\n continue;\n }\n if (inString) {\n out += c;\n if (c === \"\\\\\") {\n out += next;\n i++;\n continue;\n }\n if (c === '\"') inString = false;\n continue;\n }\n if (c === '\"') {\n inString = true;\n out += c;\n continue;\n }\n if (c === \"/\" && next === \"/\") {\n inLineComment = true;\n i++;\n continue;\n }\n if (c === \"/\" && next === \"*\") {\n inBlockComment = true;\n i++;\n continue;\n }\n out += c;\n }\n return out.replace(/,(\\s*[}\\]])/g, \"$1\");\n}\n\ninterface TsOrJsConfig {\n compilerOptions?: { paths?: Record<string, unknown> };\n}\n\n/**\n * QUIKTR-1068 \u2014 `DEFAULT_ALIAS_PREFIXES` is a floor, not the whole answer: a repo may declare its\n * own alias conventions in `compilerOptions.paths`. Tries `tsconfig.json` then `jsconfig.json` at\n * the workspace root (same results-first-then-disk precedence as `readDeclaredDependencies` \u2014 a\n * generated config this run legitimately wrote should win over a stale on-disk one), unions any\n * `paths` keys (wildcard stripped: `\"@/*\"` \u2192 `\"@/\"`) with the floor, and dedupes. Never throws and\n * never returns fewer than the floor \u2014 an unreadable or malformed config is exactly the same as no\n * config, not a reason to block a run that could otherwise pass.\n *\n * Does NOT follow `extends` \u2014 only the root config's own `paths`, same \"minimal, not exhaustive\"\n * boundary this file already draws elsewhere (see the module docblock).\n */\nexport function resolveAliasPrefixes(\n results: CodegenFileResult[],\n workspaceRoot: string | null,\n): string[] {\n const root = resolve(workspaceRoot ?? \".\");\n\n for (const filename of [\"tsconfig.json\", \"jsconfig.json\"]) {\n const configPath = join(root, filename);\n const generated = results.find((r) => resolve(r.targetPath) === configPath);\n\n let raw: string | null;\n if (generated) {\n raw = generated.newContent;\n } else {\n try {\n raw = readFileSync(configPath, \"utf8\");\n } catch {\n raw = null;\n }\n }\n if (raw === null) continue;\n\n try {\n const parsed = JSON.parse(stripJsonComments(raw)) as TsOrJsConfig;\n const paths = parsed.compilerOptions?.paths;\n const fromConfig =\n paths && typeof paths === \"object\"\n ? Object.keys(paths).map((k) => (k.endsWith(\"*\") ? k.slice(0, -1) : k))\n : [];\n return [...new Set([...DEFAULT_ALIAS_PREFIXES, ...fromConfig])];\n } catch {\n continue; // malformed \u2014 try the next config file, or fall through to the floor\n }\n }\n\n return DEFAULT_ALIAS_PREFIXES;\n}\n\n/** Regressions and new failures named separately elsewhere in this package for the same reason\n * this exists at all: conflating diagnoses wastes someone's morning. */\nexport function describeDependencyViolations(check: DependencyCheck): string {\n return check.violations\n .map((v) => `${v.file} imports ${v.packages.join(\", \")}, not a dependency of this repository`)\n .join(\"; \");\n}\n", "import { addAll, diffCachedNamesMatching } from \"./git\";\n\n/** Stages everything, then refuses to proceed if any staged file matches a denied-path glob.\n * Public and inspectable on purpose (Suyash, 2026-09-10): moving this into a published package\n * doesn't hide the enforcement \u2014 it's the same check, just no longer duplicated per customer repo. */\nexport function checkGuardrail(deniedPaths: string[]): void {\n addAll();\n const violations = deniedPaths.flatMap((pattern) => diffCachedNamesMatching(pattern));\n if (violations.length > 0) {\n throw new Error(`QuikPilot touched denied paths:\\n${violations.join(\"\\n\")}`);\n }\n}\n", "import { describeQuikTrackFailure } from \"./quiktrackError\";\n\ninterface InstallationTokenResponse {\n success: boolean;\n data: { token: string; expiresAt: string };\n}\n\n/** Exchange the QuikPilot run token for a repo-scoped GitHub installation token (QUIKTR-804) \u2014\n * mirrors `tokenExchange.ts`'s `exchangeForRunToken` shape: bearer auth, `{success,data}`\n * envelope, same error-message style. */\nexport async function exchangeForInstallationToken(\n installationTokenUrl: string,\n runToken: string,\n): Promise<string> {\n const res = await fetch(installationTokenUrl, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${runToken}` },\n });\n if (!res.ok) {\n throw new Error(`Exchange installation token failed: ${await describeQuikTrackFailure(res)}`);\n }\n const body = (await res.json()) as InstallationTokenResponse;\n if (body.success !== true) {\n throw new Error(\"Exchange installation token failed: response did not carry success:true\");\n }\n return body.data.token;\n}\n", "import { required } from \"./env\";\n\n/** Must equal `apps/quiktrack/lib/services/github/oidc.ts`'s own copy of this literal \u2014 that app\n * verifies the token this package requests. Duplicated because this package is published outside\n * the monorepo and cannot import from the app; same reasoning `packet.ts`'s header gives for\n * duplicating `PilotPacket`'s shape. */\nconst QUIKPILOT_OIDC_AUDIENCE = \"quiktrack-quikpilot\";\n\ninterface OidcTokenResponse {\n value: string;\n}\n\n/** Request a GitHub Actions OIDC ID token \u2014 the runner's proof of identity, exchanged at\n * `TOKEN_URL` for a QuikPilot run token (QUIKTR-805). `ACTIONS_ID_TOKEN_REQUEST_URL` and\n * `ACTIONS_ID_TOKEN_REQUEST_TOKEN` are ambient GitHub Actions env vars, present only because the\n * generated workflow declares `permissions: id-token: write` \u2014 no dispatch input carries them. */\nexport async function fetchGithubOidcToken(\n env: NodeJS.ProcessEnv = process.env,\n): Promise<string> {\n const requestUrl = required(\n \"ACTIONS_ID_TOKEN_REQUEST_URL\",\n env.ACTIONS_ID_TOKEN_REQUEST_URL,\n );\n const requestToken = required(\n \"ACTIONS_ID_TOKEN_REQUEST_TOKEN\",\n env.ACTIONS_ID_TOKEN_REQUEST_TOKEN,\n );\n const separator = requestUrl.includes(\"?\") ? \"&\" : \"?\";\n const url = `${requestUrl}${separator}audience=${encodeURIComponent(QUIKPILOT_OIDC_AUDIENCE)}`;\n const res = await fetch(url, {\n headers: { Authorization: `Bearer ${requestToken}` },\n });\n if (!res.ok) {\n throw new Error(`Fetch GitHub OIDC token failed: ${res.status} ${res.statusText}`);\n }\n const body = (await res.json()) as OidcTokenResponse;\n if (!body.value) {\n throw new Error(\"GitHub OIDC token response carried no value\");\n }\n return body.value;\n}\n", "import type { PilotTarget } from \"./targeting\";\n\n/**\n * QUIKTR-1064 \u2014 QUIKSP-3's first live run implemented \"reject negative amounts\" twice: once in\n * src/server.js against raw input, once in src/validation.js against parsed minor units. Targeting\n * split the work across two files and gave each its own planStepsImplemented describing the same\n * rule; codegen faithfully built both. Per-target steps are meant to be DISJOINT (QUIKTR-1035) \u2014\n * nothing checked that they are.\n *\n * The real fix is `pilot.targeting`'s prompt \u2014 an AI Runtime change, not this package's. This is\n * the cheap half the ticket assigns here: a non-blocking warning, not semantic analysis. A\n * significant-word overlap between two steps in DIFFERENT targets is treated as the same rule\n * described twice. Same-target steps are never compared \u2014 one file legitimately implementing\n * several related steps is normal and not what this looks for.\n */\nexport interface OverlapWarning {\n targetA: string;\n stepA: string;\n targetB: string;\n stepB: string;\n /** QUIKTR-1081 \u2014 \"identical\" (the exact same instruction, modulo case/whitespace) is blocking;\n * \"similar\" (the existing Jaccard-threshold match, reworded but not the same text) stays a\n * warning. Two legitimate halves of one change never share the literal same instruction. */\n severity: \"identical\" | \"similar\";\n}\n\n// QUIKTR-1081 \u2014 a path-convention heuristic, not a real \"is this a test\" signal: nothing in this\n// package (or apps/quiktrack/lib/services/pilot) tags a PilotTarget as covering a test today. A\n// behaviour appearing in both a file and its test is correct, so a pair is exempt from this check\n// entirely \u2014 not merely from blocking \u2014 whenever either side looks like a test file.\nconst TEST_PATH_RE = /(\\.(test|spec)\\.[jt]sx?$)|(^|\\/)(__tests__|tests?)\\//i;\n\nexport function isTestTarget(path: string): boolean {\n return TEST_PATH_RE.test(path);\n}\n\nconst STOPWORDS = new Set([\n \"a\", \"an\", \"the\", \"is\", \"are\", \"was\", \"were\", \"be\", \"been\", \"being\",\n \"of\", \"to\", \"in\", \"on\", \"for\", \"with\", \"at\", \"by\", \"from\", \"as\",\n \"and\", \"or\", \"not\", \"no\", \"nor\",\n \"this\", \"that\", \"these\", \"those\", \"it\", \"its\",\n \"cannot\", \"can't\", \"should\", \"must\", \"may\", \"will\", \"shall\",\n \"when\", \"if\", \"than\", \"then\", \"so\", \"do\", \"does\", \"did\",\n]);\n\n// Ignore words this short too \u2014 they add noise to the overlap without carrying meaning (\"id\",\n// \"an\", two-letter fragments from punctuation stripping).\nconst MIN_WORD_LENGTH = 3;\n\nfunction significantWords(step: string): Set<string> {\n return new Set(\n step\n .toLowerCase()\n .replace(/[^a-z0-9\\s]/g, \" \")\n .split(/\\s+/)\n .filter((w) => w.length >= MIN_WORD_LENGTH && !STOPWORDS.has(w)),\n );\n}\n\nfunction jaccard(a: Set<string>, b: Set<string>): number {\n if (a.size === 0 || b.size === 0) return 0;\n let intersection = 0;\n for (const w of a) if (b.has(w)) intersection++;\n const union = a.size + b.size - intersection;\n return intersection / union;\n}\n\n// QUIKTR-1081 \u2014 stricter than significantWords' normalization (which drops stopwords/short words\n// entirely): this only ignores case and incidental whitespace, so \"identical\" means the actual\n// same instruction, not merely \"shares enough meaningful words.\"\nfunction normalizedStep(step: string): string {\n return step.trim().toLowerCase().replace(/\\s+/g, \" \");\n}\n\n// Cheap and deliberately generous \u2014 a false positive here costs a reviewer one glance at a warning\n// line; a false negative is exactly the bug this exists to catch.\nconst OVERLAP_THRESHOLD = 0.5;\n\n/** Every cross-target pair of plan steps whose significant words overlap enough to plausibly be the\n * same rule described twice. Steps within the same target are never compared. */\nexport function findOverlappingSteps(targets: PilotTarget[]): OverlapWarning[] {\n const items = targets.flatMap((target) =>\n target.planStepsImplemented.map((step) => ({\n target: target.path,\n step,\n words: significantWords(step),\n })),\n );\n\n const warnings: OverlapWarning[] = [];\n for (let i = 0; i < items.length; i++) {\n for (let j = i + 1; j < items.length; j++) {\n if (items[i].target === items[j].target) continue;\n if (isTestTarget(items[i].target) || isTestTarget(items[j].target)) continue;\n if (jaccard(items[i].words, items[j].words) >= OVERLAP_THRESHOLD) {\n warnings.push({\n targetA: items[i].target,\n stepA: items[i].step,\n targetB: items[j].target,\n stepB: items[j].step,\n severity: normalizedStep(items[i].step) === normalizedStep(items[j].step) ? \"identical\" : \"similar\",\n });\n }\n }\n }\n return warnings;\n}\n\nexport function describeOverlapWarnings(warnings: OverlapWarning[]): string[] {\n return warnings.map(\n (w) =>\n `${w.targetA} and ${w.targetB} both implement what looks like the same rule \u2014 \"${w.stepA}\" / \"${w.stepB}\". Check these aren't two independent implementations of the same behavior.`,\n );\n}\n", "import { describeQuikTrackFailure } from \"./quiktrackError\";\n\n/** Mirrors `apps/quiktrack/lib/services/pilot/packet.ts`'s `PilotPacket` shape. Duplicated rather\n * than imported \u2014 this package is published outside the monorepo and cannot depend on the app. */\nexport interface PilotPacket {\n runId: string;\n issueKey: string | null;\n /** QUIKTR-1067 \u2014 same nullability as issueKey, for the same reason: the commit message needs\n * both to say what actually changed instead of the hardcoded \"Phase 0 skeleton\" placeholder. */\n issueTitle: string | null;\n branch: string | null;\n targetBranch: string | null;\n /** QUIKTR-1033 \u2014 the subtree targeting (QUIKTR-1035) lists files under. Null means the\n * repository root, as null \u2014 never normalised to \".\". */\n workspaceRoot: string | null;\n commands: {\n setup: string | null;\n test: string | null;\n e2e: string | null;\n lint: string | null;\n /** QUIKTR-1045 \u2014 run after codegen flushes, before lint. Soft failure. */\n format: string | null;\n };\n guardrails: {\n deniedPaths: string[];\n maxHealIterations: number;\n maxWallClockMinutes: number;\n // No maxRunUsd \u2014 it travels as a claim on gateway.token instead (QUIKTR-823).\n };\n /** Where to call for AI codegen, and the credential that authorizes it. */\n gateway: {\n baseUrl: string;\n token: string;\n };\n /** The pilot.design technical design, as context for codegen. No file paths \u2014 see the app's\n * spec-contract.ts. Null only in theory (dispatch requires a design to already exist). */\n design: {\n rootCause: string;\n approach: string;\n /** Mirrors `apps/quiktrack/lib/services/pilot/spec-contract.ts`'s `PilotApiChange`. */\n apiChanges: { surface: string; change: string; reason: string }[];\n riskLevel: \"LOW\" | \"MEDIUM\" | \"HIGH\";\n riskRationale: string;\n } | null;\n quikTest: { testRunId: string; resultsUrl: string } | null;\n /** QUIKTR-1065 \u2014 the approved test cases codegen still owes real test code for. Sent to\n * pilot.targeting so it can propose a test-file target naming which cases it covers; today\n * nothing reads this field yet (the AI Runtime side isn't built), so it always arrives as `[]`\n * or is silently unused once wired up here. */\n requiredTests: {\n automationId: string;\n title: string;\n covers: string[];\n given: string | null;\n when: string | null;\n then: string | null;\n }[];\n}\n\ninterface PacketResponse {\n success: boolean;\n data: PilotPacket;\n}\n\n/** GET the run's work packet. Bearer auth via the run token, matching the header curl sent on\n * stdin (`--config -`) so it never showed up in `ps` \u2014 an HTTP client's header option is already\n * invisible to `ps`, so no equivalent trick is needed here. */\nexport async function fetchPacket(\n packetUrl: string,\n runToken: string,\n githubRunId: string,\n): Promise<PilotPacket> {\n const url = `${packetUrl}?githubRunId=${encodeURIComponent(githubRunId)}`;\n const res = await fetch(url, {\n headers: { Authorization: `Bearer ${runToken}` },\n });\n if (!res.ok) {\n throw new Error(`Fetch work packet failed: ${await describeQuikTrackFailure(res)}`);\n }\n const body = (await res.json()) as PacketResponse;\n if (body.success !== true) {\n throw new Error(\"Fetch work packet failed: response did not carry success:true\");\n }\n return body.data;\n}\n", "import { appendFileSync, mkdirSync } from \"node:fs\";\n\n/** Phase 0 has no agent. This proves the loop end to end without touching real source, which would\n * risk breaking the build for a reason nobody would connect back to QuikPilot. Verbatim carry-over\n * from the inlined workflow \u2014 real codegen is separate, not-yet-built work. */\nexport function writePhase0Marker(runId: string): void {\n mkdirSync(\".quikpilot\", { recursive: true });\n appendFileSync(\".quikpilot/phase0-marker.txt\", `QuikPilot Phase 0 skeleton marker for run ${runId}\\n`);\n}\n", "import { readdirSync, rmSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nconst SKIP_DIRS = new Set([\"node_modules\", \".git\"]);\n\nfunction walkForJUnitByName(dir: string): string | null {\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return null;\n }\n for (const entry of entries) {\n if (SKIP_DIRS.has(entry)) continue;\n const full = join(dir, entry);\n let stat;\n try {\n stat = statSync(full);\n } catch {\n continue;\n }\n if (stat.isDirectory()) {\n const found = walkForJUnitByName(full);\n if (found) return found;\n } else if (/^junit.*\\.xml$/.test(entry)) {\n return full;\n }\n }\n return null;\n}\n\nfunction firstXmlIn(dir: string, namePattern: RegExp): string | null {\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return null;\n }\n const match = entries.find((e) => namePattern.test(e));\n return match ? join(dir, match) : null;\n}\n\n/** QtPilotConfig has no column for the report path, so this is a convention over a short list of\n * common locations rather than a configurable setting. A project that writes its report elsewhere\n * reports nothing and finds out from the log \u2014 a missing artefact must not fail the run. Checked\n * in the same priority the original `find` clause listed them, though exact traversal order was\n * never guaranteed there either. */\nexport function findJUnitReport(cwd = process.cwd()): string | null {\n return (\n walkForJUnitByName(cwd) ??\n firstXmlIn(join(cwd, \"test-results\"), /\\.xml$/) ??\n firstXmlIn(join(cwd, \"reports\"), /^junit.*\\.xml$/) ??\n firstXmlIn(join(cwd, \"target\", \"surefire-reports\"), /\\.xml$/)\n );\n}\n\nfunction buildCiUrl(serverUrl: string, repository: string, githubRunId: string): string {\n return `${serverUrl}/${repository}/actions/runs/${githubRunId}`;\n}\n\n/** Best-effort \u2014 every branch here is designed to never throw, matching the bash step's own\n * `if: always()` + internally tolerant logic (null resultsUrl and \"no report found\" are both the\n * common path in Phase 0, not edge cases \u2014 D19). Deletes the report after a successful POST so the\n * guardrail's `git add -A` never commits a CI artefact into the customer's pull request. */\nexport async function reportToQuikTest(params: {\n resultsUrl: string | null | undefined;\n runToken: string;\n githubServerUrl: string;\n githubRepository: string;\n githubRunId: string;\n cwd?: string;\n}): Promise<void> {\n const { resultsUrl, runToken, githubServerUrl, githubRepository, githubRunId, cwd } = params;\n if (!resultsUrl) {\n console.log(\"packet.quikTest is null \u2014 this run has no QuikTest run to report into.\");\n return;\n }\n const report = findJUnitReport(cwd);\n if (!report) {\n console.warn(\"::warning::QuikPilot found no JUnit report \u2014 no results reported to QuikTest.\");\n return;\n }\n try {\n console.log(`reporting ${report}`);\n const ciUrl = buildCiUrl(githubServerUrl, githubRepository, githubRunId);\n const { readFileSync } = await import(\"node:fs\");\n const body = readFileSync(report);\n // QUIKTR-1082 \u2014 this runner is the only caller QuikPilot controls; requesting \"bracket\"\n // explicitly here changes nothing for any other QuikTest customer's own ingestion.\n const url = `${resultsUrl}?ciUrl=${encodeURIComponent(ciUrl)}&automationIdFormat=bracket`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${runToken}`, \"Content-Type\": \"text/xml\" },\n body,\n });\n if (!res.ok) {\n throw new Error(`QuikTest report POST failed: ${res.status} ${res.statusText}`);\n }\n rmSync(report, { force: true });\n } catch (err) {\n console.warn(`::warning::QuikPilot failed to report results to QuikTest: ${err instanceof Error ? err.message : String(err)}`);\n }\n}\n", "import { readFileSync } from \"node:fs\";\nimport { runTestCommand, runTestCommandAsync, type TestOutcome } from \"./commands\";\nimport { findJUnitReport } from \"./quiktest\";\n\n/**\n * QUIKTR-1036 \u2014 once codegen writes real code, a failing test after it probably means the\n * generated code (or a generated test) is wrong. Blocking unconditionally would break any repo\n * with pre-existing failures, so a run captures a \"before\" snapshot (the baseline, run against the\n * untouched tree) and an \"after\" snapshot (post-codegen), and diffs them per test:\n * passed before, fails now -> regression, block\n * absent before, fails now -> new failure, block (codegen writing test files makes this the\n * common case, not an edge case \u2014 a different diagnosis from a\n * regression, so it's reported separately)\n * failed before, fails now -> not ours, stays soft (the case the soft-fail existed for)\n *\n * Only a minimal <testcase> scanner \u2014 not a full XML parser like\n * apps/quiktrack/lib/test/resultParser.ts, which extracts failure messages/stack traces across\n * multiple formats for QuikTest's ingest API and can't be imported here anyway (this package is\n * published outside the monorepo \u2014 same reason packet.ts duplicates its types instead of sharing\n * them). classname::name (or bare name with no classname) is an internal-only identity, used only\n * to match a test between two local runs \u2014 it never needs to match QuikTest's own configurable\n * automationIdFormat.\n */\nexport interface TestSnapshot {\n outcome: TestOutcome;\n /** testId -> passed. null when no JUnit report was found or it couldn't be parsed \u2014 the\n * fallback used when either snapshot lacks this is to stay soft, same as today, since blocking\n * with no way to name what broke would contradict the whole point of the classification. */\n results: Map<string, boolean> | null;\n /**\n * QUIKTR-1029 self-heal prerequisite 1 (Suyash, 2026-09-22 \u2014 \"buildable now and useful on its\n * own: today a regression blocks the push without saying why the test failed\"). testId -> a\n * bounded failure message, only for tests that failed IN THIS SNAPSHOT. Deliberately a second,\n * optional map rather than widening `results`'s value type: `checkForRegressions`'s diffing\n * logic (and every existing test constructing a `TestSnapshot` fixture directly) stays untouched\n * \u2014 this is additive context, not a new signal the diff itself reasons about.\n */\n failureText?: Map<string, string>;\n}\n\nconst TESTCASE_RE = /<testcase\\b([^>]*?)(?:\\/>|>([\\s\\S]*?)<\\/testcase>)/g;\nconst NAME_ATTR_RE = /\\bname=\"([^\"]*)\"/;\nconst CLASSNAME_ATTR_RE = /\\bclassname=\"([^\"]*)\"/;\nconst FAILURE_CHILD_RE = /<failure\\b|<error\\b/;\n\n/** The `<failure>`/`<error>` child itself, within one `<testcase>`'s already-isolated body. */\nconst FAILURE_TAG_RE = /<(?:failure|error)\\b([^>]*?)(?:\\/>|>([\\s\\S]*?)<\\/(?:failure|error)>)/;\nconst FAILURE_MESSAGE_ATTR_RE = /\\bmessage=\"([^\"]*)\"/;\n\n/** Console/PR-message budget, not a data-integrity bound \u2014 this is display text, never re-parsed. */\nconst MAX_FAILURE_TEXT = 500;\n\n/** The five entities the JUnit writers in real use (Vitest, Jest, pytest, go-junit-report) all\n * produce \u2014 not a general XML-unescape, same \"minimal scanner, not a parser\" posture as the rest\n * of this file. Literal `&quot;`/`&amp;` reaching a console log or a PR body reads as broken. */\nfunction unescapeXmlEntities(s: string): string {\n return s.replace(/&lt;/g, \"<\").replace(/&gt;/g, \">\").replace(/&quot;/g, '\"').replace(/&apos;/g, \"'\").replace(/&amp;/g, \"&\");\n}\n\n/** `message=\"...\"` when present (short, what every framework puts the assertion diff in);\n * otherwise the tag's own body text (stack trace), truncated \u2014 never both, never neither if\n * either exists. `null` when the testcase body has no `<failure>`/`<error>` at all, or the tag\n * carries no text either way (both attrs and body empty \u2014 seen from at least one Go harness). */\nfunction extractFailureText(testcaseBody: string): string | null {\n const tag = FAILURE_TAG_RE.exec(testcaseBody);\n if (!tag) return null;\n const [, attrs = \"\", inner = \"\"] = tag;\n const raw = (FAILURE_MESSAGE_ATTR_RE.exec(attrs)?.[1] ?? inner).trim();\n if (!raw) return null;\n const text = unescapeXmlEntities(raw);\n return text.length > MAX_FAILURE_TEXT ? `${text.slice(0, MAX_FAILURE_TEXT)}\u2026` : text;\n}\n\ninterface JUnitParseResult {\n outcomes: Map<string, boolean>;\n failureText: Map<string, string>;\n}\n\nfunction parseJUnitOutcomes(xml: string): JUnitParseResult {\n const outcomes = new Map<string, boolean>();\n const failureText = new Map<string, string>();\n let match: RegExpExecArray | null;\n TESTCASE_RE.lastIndex = 0;\n while ((match = TESTCASE_RE.exec(xml))) {\n const [, attrs, body = \"\"] = match;\n const name = NAME_ATTR_RE.exec(attrs)?.[1];\n if (!name) continue;\n const classname = CLASSNAME_ATTR_RE.exec(attrs)?.[1];\n const id = classname ? `${classname}::${name}` : name;\n const failed = FAILURE_CHILD_RE.test(body);\n outcomes.set(id, !failed);\n if (failed) {\n const text = extractFailureText(body);\n if (text) failureText.set(id, text);\n }\n }\n return { outcomes, failureText };\n}\n\nfunction readJUnitOutcomes(cwd: string): JUnitParseResult | null {\n const report = findJUnitReport(cwd);\n if (!report) return null;\n try {\n return parseJUnitOutcomes(readFileSync(report, \"utf8\"));\n } catch {\n return null;\n }\n}\n\nexport function captureTestSnapshot(command: string | null, cwd = process.cwd()): TestSnapshot {\n const outcome = runTestCommand(command);\n const parsed = readJUnitOutcomes(cwd);\n return { outcome, results: parsed?.outcomes ?? null, failureText: parsed?.failureText };\n}\n\nexport async function captureBaselineSnapshot(\n command: string | null,\n cwd = process.cwd(),\n): Promise<TestSnapshot> {\n const outcome = await runTestCommandAsync(command);\n const parsed = readJUnitOutcomes(cwd);\n return { outcome, results: parsed?.outcomes ?? null, failureText: parsed?.failureText };\n}\n\nexport interface RegressionCheck {\n blocked: boolean;\n regressions: string[];\n newFailures: string[];\n preExisting: string[];\n /** testId -> bounded failure text, for whichever `regressions`/`newFailures` entries had one in\n * the AFTER snapshot (the failure that actually blocks the push \u2014 the baseline's own failure\n * text, if any, is irrelevant here). Always present, possibly empty \u2014 never omitted, so a\n * caller never has to guard its absence the way `results` itself still requires. */\n failureText: Map<string, string>;\n}\n\nexport function checkForRegressions(baseline: TestSnapshot, after: TestSnapshot): RegressionCheck {\n if (!baseline.results || !after.results) {\n return { blocked: false, regressions: [], newFailures: [], preExisting: [], failureText: new Map() };\n }\n\n const regressions: string[] = [];\n const newFailures: string[] = [];\n const preExisting: string[] = [];\n const failureText = new Map<string, string>();\n const afterFailureText = after.failureText;\n\n for (const [testId, passed] of after.results) {\n if (passed) continue;\n const before = baseline.results.get(testId);\n if (before === true) {\n regressions.push(testId);\n const text = afterFailureText?.get(testId);\n if (text) failureText.set(testId, text);\n } else if (before === false) {\n preExisting.push(testId);\n } else {\n newFailures.push(testId);\n const text = afterFailureText?.get(testId);\n if (text) failureText.set(testId, text);\n }\n }\n\n return { blocked: regressions.length > 0 || newFailures.length > 0, regressions, newFailures, preExisting, failureText };\n}\n\n/** Regressions and new failures named separately \u2014 conflating them is the thing that wastes\n * someone's morning (they're different diagnoses: one means the generated code broke something\n * that worked, the other means a generated test doesn't pass yet). Pre-existing failures are\n * noted, not hidden, so the message doesn't read as if they were silently dropped.\n *\n * QUIKTR-1029 self-heal prerequisite 1 \u2014 each named test now carries its failure text inline\n * when one was captured, so a run that blocks says WHY, not only WHAT. */\nexport function describeRegressions(check: RegressionCheck): string {\n const withText = (id: string) => {\n const text = check.failureText.get(id);\n return text ? `${id} (${text})` : id;\n };\n const parts: string[] = [];\n if (check.regressions.length > 0) {\n parts.push(\n `${check.regressions.length} regression(s) (passed before, now fail): ${check.regressions.map(withText).join(\", \")}`,\n );\n }\n if (check.newFailures.length > 0) {\n parts.push(\n `${check.newFailures.length} new failure(s) (did not exist before): ${check.newFailures.map(withText).join(\", \")}`,\n );\n }\n if (check.preExisting.length > 0) {\n parts.push(`${check.preExisting.length} pre-existing failure(s), unrelated to this change, not blocking`);\n }\n return parts.join(\"; \");\n}\n", "import { readFileSync } from \"node:fs\";\nimport type { CodegenFileResult } from \"./codegen\";\nimport type { PilotTarget } from \"./targeting\";\n\n/**\n * QUIKTR-1081 \u2014 QUIKSPL-5's PR #22 fixed the reported bug in src/validation.js and also silently\n * added an undeclared PUT endpoint to src/server.js that returned success while updating nothing.\n * Tests passed, the dependency check passed, and nothing compared what codegen actually added\n * against the design's own declared `apiChanges` \u2014 because nothing did.\n *\n * Same \"minimal, not exhaustive\" standard as dependencyCheck.ts's import scanner and\n * regressionCheck.ts's JUnit scanner, for the same reason: this package is dependency-free,\n * bundled into a single CLI file with no externals, published outside the monorepo, and the\n * target repository is arbitrary \u2014 no real per-framework route parser is on the table. This is a\n * same-line METHOD+PATH text heuristic, a tripwire against the ticket's own incident (method and\n * path both named on the documenting comment's line), not a route parser for every framework a\n * customer repo might use. It will not catch a Next.js-style `export function PUT(...)` whose path\n * comes from file location rather than an in-file string \u2014 ROUTE_EXPORT_RE below covers that one\n * export shape specifically, matched by method presence alone since it has no in-file path to\n * compare.\n *\n * \"Exported symbols\" (the ticket's own words) is deliberately narrowed to route-handler-shaped\n * exports here, not any new exported symbol: an arbitrary new exported helper is routine,\n * legitimate refactoring, and checking every export against free-text `apiChanges` would produce\n * exactly the kind of false-positive noise this package's checks otherwise avoid.\n */\nexport interface ScopeViolation {\n file: string;\n method: string;\n path: string;\n}\n\nexport interface ScopeCheck {\n blocked: boolean;\n violations: ScopeViolation[];\n}\n\ninterface RouteMention {\n method: string;\n path: string;\n}\n\nconst ROUTE_METHOD_RE = /\\b(GET|POST|PUT|PATCH|DELETE)\\b/i;\nconst ROUTE_PATH_RE = /\\/[A-Za-z0-9_\\-{}[\\]]+(?:\\/[A-Za-z0-9_\\-:{}[\\]]+)+/;\nconst ROUTE_EXPORT_RE = /\\bexport\\s+(?:async\\s+)?function\\s+(GET|POST|PUT|PATCH|DELETE)\\s*\\(/;\n\n/** No in-file path \u2014 a Next.js-style route handler's path comes from where the file lives, not a\n * string in it. Matched against `apiChanges` by method presence alone (see `surfaceCovers`). */\nconst NO_PATH = \"(this file's route)\";\n\nfunction detectMentions(text: string): RouteMention[] {\n const found: RouteMention[] = [];\n for (const line of text.split(\"\\n\")) {\n const methodMatch = ROUTE_METHOD_RE.exec(line);\n const pathMatch = ROUTE_PATH_RE.exec(line);\n if (methodMatch && pathMatch) {\n found.push({ method: methodMatch[1].toUpperCase(), path: pathMatch[0] });\n }\n const exportMatch = ROUTE_EXPORT_RE.exec(line);\n if (exportMatch) {\n found.push({ method: exportMatch[1].toUpperCase(), path: NO_PATH });\n }\n }\n return found;\n}\n\n/** `:id`, `{id}`, `[id]` all become `*` so a declared surface and a detected mention compare equal\n * regardless of the exact param name either side happens to use. */\nfunction normalizePath(path: string): string {\n return path.replace(/:[A-Za-z0-9_]+|\\{[^}]+\\}|\\[[^\\]]+\\]/g, \"*\");\n}\n\nfunction surfaceCovers(surface: string, mention: RouteMention): boolean {\n if (!new RegExp(`\\\\b${mention.method}\\\\b`, \"i\").test(surface)) return false;\n if (mention.path === NO_PATH) return true; // method presence is all a route-export mention has\n const declaredPath = normalizePath(surface);\n const mentionPath = normalizePath(mention.path);\n return declaredPath.includes(mentionPath) || mentionPath.includes(declaredPath);\n}\n\n/** Lines present in `after` but not in `before` \u2014 a set difference, not a positional diff (code\n * can shift line numbers around an addition). Good enough to separate \"genuinely new this run\"\n * from \"was already there\" without a real diff algorithm, same spirit as this package's other\n * scanners. */\nfunction addedLines(before: string, after: string): string {\n const beforeLines = new Set(before.split(\"\\n\"));\n return after\n .split(\"\\n\")\n .filter((line) => !beforeLines.has(line))\n .join(\"\\n\");\n}\n\nexport function checkApiScope(\n results: CodegenFileResult[],\n targets: PilotTarget[],\n apiChanges: { surface: string; change: string; reason: string }[],\n): ScopeCheck {\n const targetsByPath = new Map(targets.map((t) => [t.path, t]));\n const violations: ScopeViolation[] = [];\n\n for (const { targetPath, newContent } of results) {\n const target = targetsByPath.get(targetPath);\n const isNewFile = target?.kind === \"NEW_FILE\";\n\n let scanned: string;\n if (isNewFile) {\n scanned = newContent;\n } else {\n let currentContent: string;\n try {\n currentContent = readFileSync(targetPath, \"utf8\");\n } catch {\n currentContent = \"\";\n }\n scanned = addedLines(currentContent, newContent);\n }\n\n for (const mention of detectMentions(scanned)) {\n if (!apiChanges.some((c) => surfaceCovers(c.surface, mention))) {\n violations.push({ file: targetPath, method: mention.method, path: mention.path });\n }\n }\n }\n\n return { blocked: violations.length > 0, violations };\n}\n\nexport function describeScopeViolations(check: ScopeCheck): string {\n return check.violations\n .map((v) => `${v.file} adds ${v.method} ${v.path}, not declared in the design's API changes`)\n .join(\"; \");\n}\n", "import { resolve, relative, isAbsolute } from \"node:path\";\nimport { matchesDeniedPath } from \"./deniedPaths\";\nimport { listFiles } from \"./git\";\nimport { checkHardFailure, unwrapExecute } from \"./envelope\";\nimport type { PilotPacket } from \"./packet\";\nimport { fetchWithRetry } from \"./retryFetch\";\n\n/**\n * QUIKTR-1035 \u2014 `pilot.targeting`: turns the design plus a file listing into real per-file\n * instructions, replacing codegen.ts's old planStepsFromDesign entirely. Proven live by the AI\n * Runtime against a real 624-file QuikChat listing before this was wired in.\n *\n * QUIKTR-1083 (\u00A715) \u2014 the versioned test-target contract. `contractVersion: \"test-targets-1\"` is\n * sent unconditionally: per \u00A715.6 the unversioned path is only \"exactly today's behaviour\" for a\n * caller that never asks for the new shape, and this runner always wants it once it ships.\n */\nconst CONTRACT_VERSION = \"test-targets-1\";\n\nexport type TargetKind = \"EXISTING\" | \"NEW_FILE\";\n\nexport interface PilotTarget {\n path: string;\n kind: TargetKind;\n planStepsImplemented: string[];\n // Context contract change \u2014 pilot.targeting now names, per target, which other files\n // pilot.codegen should read before writing this one (\"to write this file, read these\").\n // codegen.ts validates and reads these; absent/empty means no context, no fallback.\n contextPaths?: string[];\n /** \u00A715.3 \u2014 present only on a test target: the automation IDs (not database ids \u2014 see\n * \u00A715.3's own naming rationale) this target's generated file must cover. codegen.ts forwards\n * only the matching `requiredTests` subset for a target carrying this. */\n automationIds?: string[];\n}\n\n/** \u00A715.3 amendment 1 \u2014 a case with no behaviour (given/when/then all null) is named here instead\n * of silently dropped; the model has no discretion over which cases land here vs. in a target's\n * `automationIds` (completeness is enforced on the runtime side). Informational on this side \u2014\n * folded into `run.ts`'s `warnings`, never blocking. */\nexport interface SkippedCase {\n automationId: string;\n reason: \"NO_BEHAVIOUR\";\n}\n\nexport type TargetingResult =\n | { outcome: \"TARGETED\"; targets: PilotTarget[]; skippedCases: SkippedCase[] }\n | { outcome: \"NO_TARGET\"; reason: string | null };\n\ninterface TargetingResponse {\n outcome?: \"TARGETED\" | \"NO_TARGET\";\n targets?: {\n path: string;\n kind: string;\n planStepsImplemented: string[];\n contextPaths?: string[];\n automationIds?: string[];\n }[];\n skippedCases?: SkippedCase[];\n noTargetReason?: string;\n}\n\n/**\n * Tracked files under the packet's workspace root, or the whole checkout when it's null\n * (QUIKTR-1033) \u2014 never normalised to \".\" at the packet layer itself, only here where a concrete\n * pathspec is actually needed. An unscoped listing on a large monorepo is ~210k tokens, which fits\n * one provider and breaks the fallback chain \u2014 see workspaceRoot's own doc comment on PilotPacket.\n */\nexport function listWorkspaceFiles(workspaceRoot: string | null): string[] {\n return listFiles(workspaceRoot ?? \".\");\n}\n\n/**\n * VALIDATION IS OURS \u2014 the AI Runtime's schema doesn't guarantee a path is actually safe to write.\n * An EXISTING target must already be in the checkout; a NEW_FILE target must resolve inside the\n * workspace root. Either failure throws \u2014 a dropped target is a plan half-executed, and run.ts's\n * existing top-level try/catch already turns this into the same hard failure any other pre-setup\n * step gets.\n */\nfunction validateTarget(\n target: { path: string; kind: string },\n workspaceRoot: string | null,\n workspaceListing: Set<string>,\n deniedPaths: string[],\n): void {\n // QUIKTR-1083 (\u00A715.3) \u2014 layer 2 of three: checked here, before any codegen spend, regardless of\n // kind. Layer 1 (the runtime's own targeting validator) should already exclude a denied path;\n // this does not trust that and re-checks independently.\n const denied = matchesDeniedPath(target.path, deniedPaths);\n if (denied) {\n throw new Error(\n `pilot.targeting proposed a target matching a denied path (${denied}): ${target.path}`,\n );\n }\n if (target.kind !== \"EXISTING\" && target.kind !== \"NEW_FILE\") {\n throw new Error(`pilot.targeting returned an unknown kind \"${target.kind}\" for ${target.path}`);\n }\n if (target.kind === \"EXISTING\") {\n if (!workspaceListing.has(target.path)) {\n throw new Error(\n `pilot.targeting named an EXISTING file not found in the checkout: ${target.path}`,\n );\n }\n return;\n }\n const root = resolve(workspaceRoot ?? \".\");\n const rel = relative(root, resolve(target.path));\n if (rel.startsWith(\"..\") || isAbsolute(rel)) {\n throw new Error(\n `pilot.targeting named a NEW_FILE path that escapes the workspace root: ${target.path}`,\n );\n }\n}\n\nexport async function runTargeting(\n gateway: PilotPacket[\"gateway\"],\n design: PilotPacket[\"design\"],\n workspaceRoot: string | null,\n workspaceListing: string[],\n requiredTests: PilotPacket[\"requiredTests\"],\n deniedPaths: string[],\n): Promise<TargetingResult> {\n // QUIKTR-1069 \u2014 retries a transport-level failure only (502/503/504, a dropped connection); a\n // real refusal always arrives as a 200 with the refusal inside the envelope, below.\n const contextData: Record<string, unknown> = {\n // NESTED, NOT FLATTENED \u2014 a second vocabulary for the design shape is exactly what\n // QUIKTR-1034 cost.\n workspaceListing,\n design,\n // QUIKTR-1065/1083 \u2014 requiredTests carried through so targeting can propose a test-file\n // target naming which cases it covers (\u00A715.1's Case shape, unchanged).\n requiredTests,\n // QUIKTR-1083 (\u00A715.6) \u2014 required on the versioned path.\n contractVersion: CONTRACT_VERSION,\n };\n // QUIKTR-1083 (\u00A715.3) \u2014 optional on the wire; omitted rather than sent empty, matching\n // codegen.ts's identical treatment.\n if (deniedPaths.length > 0) {\n contextData.deniedPaths = deniedPaths;\n }\n\n const res = await fetchWithRetry(`${gateway.baseUrl}/ai/execute`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"x-run-token\": gateway.token },\n body: JSON.stringify({\n appId: \"quiktrack\",\n useCase: \"pilot.targeting\",\n expectedOutputType: \"json\",\n userPrompt: \"\",\n contextData,\n }),\n });\n\n if (!res.ok) {\n throw new Error(`Targeting call failed: ${res.status} ${res.statusText}`);\n }\n\n // /ai/execute wraps every result in an envelope \u2014 the use-case result lives at\n // structuredJson, and a failure can arrive as success:false in an HTTP 200 (see envelope.ts).\n // QUIKTR-1083 \u2014 SEMANTIC_MISMATCH/CONTRACT_REJECTED are checked on the raw envelope, before\n // unwrapping, same reason codegen.ts's pre-existing CODEGEN_* checks do: unwrapping first would\n // throw unwrapExecute's generic success:false error and lose the distinction.\n const envelope = await res.json();\n checkHardFailure(envelope, \"pilot.targeting\");\n const body = unwrapExecute<TargetingResponse>(envelope, \"pilot.targeting\");\n\n if (body.outcome === \"NO_TARGET\") {\n return { outcome: \"NO_TARGET\", reason: body.noTargetReason ?? null };\n }\n if (body.outcome !== \"TARGETED\" || !Array.isArray(body.targets)) {\n throw new Error(`pilot.targeting returned an unexpected shape: ${JSON.stringify(body)}`);\n }\n\n const listing = new Set(workspaceListing);\n for (const target of body.targets) {\n validateTarget(target, workspaceRoot, listing, deniedPaths);\n }\n\n return {\n outcome: \"TARGETED\",\n targets: body.targets as PilotTarget[],\n skippedCases: body.skippedCases ?? [],\n };\n}\n", "/**\n * QUIKTR-1083 (\u00A715.3) \u2014 layer 2 of the three denied-path layers the contract describes: after\n * `pilot.targeting` responds, every proposed target's path is checked against `deniedPaths` here,\n * before any codegen spend. (Layer 1 is the AI Runtime's own targeting validator; layer 3 is\n * `guardrail.ts`'s post-commit check on the actually-staged diff.)\n *\n * Hand-rolled rather than a `minimatch`/`picomatch` dependency: this package is published\n * publicly and carries no secrets or heavy deps on purpose (see workflow-template.ts's own\n * docblock), and the denied-path patterns in real use (a dotfile glob under a double-star prefix,\n * a workflows directory suffixed with a double star, a bare lockfile name under a double-star\n * prefix) never need brace expansion, character classes, or `?` \u2014 only a double star (any depth,\n * including none) and a single star (anything but a path separator). A dependency for two glob\n * tokens is not worth the weight.\n */\nfunction globToRegExp(pattern: string): RegExp {\n const escaped = pattern\n .split(\"\")\n .map((c) => (/[.+^${}()|[\\]\\\\]/.test(c) ? `\\\\${c}` : c))\n .join(\"\");\n // Order matters: the more specific `**/` token first, so the generic `**`/`*` passes below\n // don't consume it first and lose the \"zero directories is also a match\" behaviour every\n // default pattern (`**/*.env*`, `**/package-lock.json`, ...) actually depends on \u2014 a repo-root\n // `.env` must match `**/*.env*` exactly as a nested one does, the same way `.gitignore`'s own\n // `**/` prefix works.\n const withGlobs = escaped\n .replace(/\\*\\*\\//g, \" SLASH \")\n .replace(/\\*\\*/g, \" STAR \")\n .replace(/\\*/g, \"[^/]*\")\n .replace(/ SLASH /g, \"(?:.*/)?\")\n .replace(/ STAR /g, \".*\");\n return new RegExp(`^${withGlobs}$`);\n}\n\n/** The first pattern `path` matches, or `null`. `path` is repo-relative, matching how every\n * `deniedPaths` entry and every target's `path` are already written elsewhere in this package. */\nexport function matchesDeniedPath(path: string, patterns: string[]): string | null {\n for (const pattern of patterns) {\n if (globToRegExp(pattern).test(path)) return pattern;\n }\n return null;\n}\n", "import { describeQuikTrackFailure } from \"./quiktrackError\";\n\ninterface TokenExchangeResponse {\n success: boolean;\n data: { runToken: string; expiresAt: string };\n}\n\n/** Exchange a GitHub OIDC ID token for a QuikPilot run token (QUIKTR-805) \u2014 mirrors `packet.ts`'s\n * `fetchPacket` shape: bearer auth, `{success,data}` envelope, same error-message style. */\nexport async function exchangeForRunToken(tokenUrl: string, oidcToken: string): Promise<string> {\n const res = await fetch(tokenUrl, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${oidcToken}` },\n });\n if (!res.ok) {\n throw new Error(`Exchange run token failed: ${await describeQuikTrackFailure(res)}`);\n }\n const body = (await res.json()) as TokenExchangeResponse;\n if (body.success !== true) {\n throw new Error(\"Exchange run token failed: response did not carry success:true\");\n }\n return body.data.runToken;\n}\n", "import { reportBack } from \"./callback\";\nimport { runCommand, runTestCommand } from \"./commands\";\nimport { commitAndPush } from \"./commit\";\nimport { flushCodegenResults, runCodegen } from \"./codegen\";\nimport {\n checkImportDependencies,\n describeDependencyViolations,\n readDeclaredDependencies,\n resolveAliasPrefixes,\n} from \"./dependencyCheck\";\nimport type { PilotRunEnv } from \"./env\";\nimport { checkGuardrail } from \"./guardrail\";\nimport { checkoutTargetBranch } from \"./git\";\nimport { exchangeForInstallationToken } from \"./installationToken\";\nimport { fetchGithubOidcToken } from \"./oidc\";\nimport { describeOverlapWarnings, findOverlappingSteps } from \"./overlapCheck\";\nimport { fetchPacket, type PilotPacket } from \"./packet\";\nimport { writePhase0Marker } from \"./phase0\";\nimport { reportToQuikTest } from \"./quiktest\";\nimport { captureBaselineSnapshot, captureTestSnapshot, checkForRegressions, describeRegressions } from \"./regressionCheck\";\nimport { checkApiScope, describeScopeViolations } from \"./scopeCheck\";\nimport { listWorkspaceFiles, runTargeting } from \"./targeting\";\nimport { exchangeForRunToken } from \"./tokenExchange\";\n\n/**\n * QUIKTR-572 \u2014 the run sequence, preserving the original inlined workflow's error semantics exactly:\n * Fetch packet / Checkout branch / Setup / Lint / Guardrail are hard failures that skip everything\n * remaining except the QuikTest report and the final callback (both ran under `if: always()`\n * before). Test alone is soft \u2014 its failure never blocks Guardrail/Commit/Push and never flips the\n * final callback to `failed` (QuikTest owns per-test outcomes; captured here only for the log).\n *\n * QUIKTR-1045 \u2014 Format is soft, same reasoning as Test: a formatting hiccup must not block a\n * correct fix. Caught locally at its own call site (not a new commands.ts function) and logged;\n * never sets hardFailure, never blocks the Lint/regression-check/Guardrail/Commit/Push that follow.\n *\n * QUIKTR-805 \u2014 the very first thing the run does is exchange a GitHub OIDC ID token for a run\n * token (no QuikPilot credential exists before this). It is folded into the same top-level try as\n * every other hard failure, with one deliberate exception: if THIS step fails, there is no run\n * token to report failure with either, so reportToQuikTest/reportBack are skipped rather than\n * called with nothing to authenticate \u2014 the job's own log is the only record, and the run's\n * existing DISPATCHING-expiry sweep is what notices it (same accepted fallback dispatch.ts's own\n * docblock documents for its \"RESIDUAL WINDOW\" crash case).\n *\n * QUIKTR-804 \u2014 immediately before pushing, the run token (already in hand by this point) is\n * exchanged for a repo-scoped GitHub installation token, which authenticates the push itself\n * instead of the ambient `github.token`. Folded into the EXISTING Guardrail/Commit/Push try block\n * below rather than given its own \u2014 a failure here is just another commit/push hard failure, with\n * no new edge case: unlike the OIDC exchange above, the run token already exists, so\n * reportToQuikTest/reportBack fire normally either way.\n */\n/** Caller narrows `RunnerEnv` to `PilotRunEnv` first \u2014 `index.ts` branches on `mode` before either\n * this or `readinessCheck.ts`'s `runReadinessCheck` is invoked. No default parameter: the old\n * `readRunnerEnv()` default returned this shape unconditionally, which is no longer true now\n * that `RunnerEnv` is a union (QUIKTR-1084). */\nexport async function run(env: PilotRunEnv): Promise<{ hardFailure: boolean }> {\n let hardFailure = false;\n let packet: PilotPacket | undefined;\n let branch: string | undefined;\n let runToken: string | undefined;\n let warnings: string[] = [];\n // QUIKTR-1067 \u2014 hoisted out of the try block's TARGETED branch: commitAndPush\n // needs it later, outside that scope, to build a real commit message instead\n // of the \"Phase 0 skeleton\" placeholder. Defaults false \u2014 correct for\n // NO_TARGET and for any early hard failure, both of which skip commitAndPush\n // or must fall back to the marker message anyway.\n let targeted = false;\n\n try {\n runToken = await exchangeForRunToken(env.tokenUrl, await fetchGithubOidcToken());\n packet = await fetchPacket(env.packetUrl, runToken, env.githubRunId);\n checkoutTargetBranch(packet.targetBranch);\n\n const workspaceListing = listWorkspaceFiles(packet.workspaceRoot);\n const targeting = await runTargeting(\n packet.gateway,\n packet.design,\n packet.workspaceRoot,\n workspaceListing,\n packet.requiredTests,\n packet.guardrails.deniedPaths,\n );\n if (targeting.outcome === \"NO_TARGET\") {\n // Nothing to write \u2014 a marker commit is more honest than an empty one. Nothing was\n // generated, so there's nothing to regress against \u2014 Test stays soft, unchanged.\n writePhase0Marker(env.runId);\n runCommand(packet.commands.setup, \"Setup\");\n runCommand(packet.commands.lint, \"Lint\");\n runTestCommand(packet.commands.test);\n } else {\n targeted = true;\n // QUIKTR-1083 (\u00A715.3) \u2014 informational, never blocking: a case with no given/when/then has\n // nothing to test, and the runtime already enforces every requiredTests case lands in\n // exactly one of a target's automationIds or here, never both, never neither. Folded into\n // the same warnings array the overlap-check below already populates and reportBack sends.\n if (targeting.skippedCases?.length) {\n for (const skipped of targeting.skippedCases) {\n const w = `Test case ${skipped.automationId} has no given/when/then \u2014 skipped, no test was written for it.`;\n warnings.push(w);\n console.warn(`QuikPilot targeting warning (not blocking): ${w}`);\n }\n }\n // QUIKTR-1064 \u2014 cheap: two targets whose planStepsImplemented describe the same rule (the\n // real fix is pilot.targeting's prompt, an AI Runtime change, not this package's \u2014 see\n // overlapCheck.ts). QUIKTR-1081 \u2014 a literal identical instruction now blocks outright: two\n // legitimate halves of one change never share the exact same instruction, and PR #23 merged\n // 28 seconds after opening on exactly this signal. A near-identical, reworded pair stays a\n // non-blocking warning, logged and reported back, same as before.\n const overlaps = findOverlappingSteps(targeting.targets);\n const blockingOverlaps = overlaps.filter((o) => o.severity === \"identical\");\n const softOverlaps = overlaps.filter((o) => o.severity === \"similar\");\n if (softOverlaps.length > 0) {\n warnings = describeOverlapWarnings(softOverlaps);\n for (const w of warnings) {\n console.warn(`QuikPilot targeting warning (not blocking): ${w}`);\n }\n }\n if (blockingOverlaps.length > 0) {\n throw new Error(\n `QuikPilot's generated plan gives two files identical instructions \u2014 ${describeOverlapWarnings(blockingOverlaps).join(\"; \")}`,\n );\n }\n\n // QUIKTR-1036 \u2014 Setup moves here (was after codegen/flush): the baseline test needs\n // dependencies installed, but has to run against the PRE-codegen tree. Installing\n // dependencies doesn't depend on which application source files exist, so this is safe, and\n // running Setup a second time later would undercut \"the baseline costs almost no wall-clock.\"\n runCommand(packet.commands.setup, \"Setup\");\n\n // Baseline runs concurrently with codegen's network-bound calls \u2014 codegen writes nothing\n // until flushCodegenResults, so there's nothing for the baseline to race against.\n const [baseline, results] = await Promise.all([\n captureBaselineSnapshot(packet.commands.test),\n runCodegen(\n packet.gateway,\n targeting.targets,\n workspaceListing,\n packet.requiredTests,\n packet.guardrails.deniedPaths,\n ),\n ]);\n\n // QUIKTR-1045 \u2014 checked on the in-memory results, BEFORE anything is\n // written: an invented import is never written to disk at all, matching\n // the same all-or-nothing treatment every other codegen failure already\n // gets here. Hard failure \u2014 a generation that imports a package this\n // repository doesn't have can't be trusted.\n const depCheck = checkImportDependencies(\n results,\n readDeclaredDependencies(results, packet.workspaceRoot),\n resolveAliasPrefixes(results, packet.workspaceRoot),\n );\n if (depCheck.blocked) {\n throw new Error(\n `QuikPilot's generated code imports packages this repository doesn't have \u2014 ${describeDependencyViolations(depCheck)}`,\n );\n }\n\n // QUIKTR-1081 \u2014 QUIKSPL-5's PR #22: codegen added an undeclared PUT endpoint alongside the\n // fix nobody asked for. Checked here for the same reason as the dependency check above \u2014\n // in-memory, before anything is written \u2014 against the design's own declared apiChanges.\n const scopeCheck = checkApiScope(results, targeting.targets, packet.design?.apiChanges ?? []);\n if (scopeCheck.blocked) {\n throw new Error(\n `QuikPilot's generated code exceeds the approved design \u2014 ${describeScopeViolations(scopeCheck)}`,\n );\n }\n\n flushCodegenResults(results);\n try {\n runCommand(packet.commands.format, \"Format\");\n } catch (err) {\n // QUIKTR-1045 \u2014 soft, like Test: see the file docblock.\n console.error(`Format failed (not blocking): ${err instanceof Error ? err.message : String(err)}`);\n }\n runCommand(packet.commands.lint, \"Lint\");\n\n const after = captureTestSnapshot(packet.commands.test);\n const check = checkForRegressions(baseline, after);\n if (check.blocked) {\n throw new Error(\n `QuikPilot's generated code introduced test failures \u2014 ${describeRegressions(check)}`,\n );\n }\n }\n } catch (err) {\n hardFailure = true;\n console.error(err instanceof Error ? err.message : String(err));\n }\n\n if (!runToken) {\n console.error(\"No run token \u2014 the OIDC exchange failed before QuikTrack could be reached.\");\n return { hardFailure: true };\n }\n\n await reportToQuikTest({\n resultsUrl: packet?.quikTest?.resultsUrl,\n runToken,\n githubServerUrl: env.githubServerUrl,\n githubRepository: env.githubRepository,\n githubRunId: env.githubRunId,\n });\n\n if (!hardFailure && packet) {\n try {\n checkGuardrail(packet.guardrails.deniedPaths);\n const installationToken = await exchangeForInstallationToken(\n env.installationTokenUrl,\n runToken,\n );\n const result = commitAndPush(\n packet.branch,\n env.runId,\n installationToken,\n targeted,\n packet.issueKey,\n packet.issueTitle,\n );\n branch = result.branch;\n } catch (err) {\n hardFailure = true;\n console.error(err instanceof Error ? err.message : String(err));\n }\n }\n\n await reportBack({\n callbackUrl: env.callbackUrl,\n runToken,\n status: hardFailure ? \"failed\" : \"completed\",\n branch,\n warnings,\n });\n\n return { hardFailure };\n}\n", "import type { ReadinessCheckEnv } from \"./env\";\nimport { runCommand, runTestCommand } from \"./commands\";\nimport { findJUnitReport } from \"./quiktest\";\nimport { describeQuikTrackFailure } from \"./quiktrackError\";\n\n/**\n * QUIKTR-1084 \u2014 readiness's \"later session\": actually run the customer's `setupCmd`/`testCmd` and\n * report whether the run produced a JUnit report the pilot-run path (`quiktest.ts`) will ever\n * find. Checked out onto the default branch already by the workflow's own `actions/checkout` step\n * \u2014 no packet, no design, no codegen, no commit, no push.\n *\n * Both command failures are soft here, deliberately unlike `run.ts`'s hard-fails-on-Setup: a\n * repo's setup or test suite failing is not what this check is FOR \u2014 it exists purely to answer\n * \"if a real run happened, would QuikTest hear about it,\" which only needs the report to exist,\n * not the tests to pass.\n */\nexport interface ReadinessCheckResult {\n setupOk: boolean;\n testOk: boolean;\n junitFound: boolean;\n junitPath: string | null;\n}\n\nexport async function runReadinessCheck(env: ReadinessCheckEnv): Promise<void> {\n let setupOk = true;\n try {\n runCommand(env.setupCmd || null, \"Setup\");\n } catch (err) {\n setupOk = false;\n console.error(err instanceof Error ? err.message : String(err));\n }\n\n const testOutcome = runTestCommand(env.testCmd);\n const testOk = testOutcome === \"success\";\n\n const junitPath = findJUnitReport();\n const result: ReadinessCheckResult = {\n setupOk,\n testOk,\n junitFound: junitPath !== null,\n junitPath,\n };\n\n try {\n const res = await fetch(env.readinessCallbackUrl, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${env.readinessToken}`, \"Content-Type\": \"application/json\" },\n body: JSON.stringify(result),\n });\n if (!res.ok) {\n throw new Error(`Readiness callback POST failed: ${await describeQuikTrackFailure(res)}`);\n }\n } catch (err) {\n // Same \"never throws\" posture as reportToQuikTest/reportBack \u2014 the job's own log is the\n // fallback record if even this fails. The expiry sweep readiness.ts will need (mirroring\n // dispatch.ts's DISPATCHING-expiry sweep) is what notices a dry run stuck in RUNNING.\n console.warn(\n `::warning::QuikPilot readiness check failed to report its result: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n}\n", "import { readRunnerEnv } from \"./env\";\nimport { run } from \"./run\";\nimport { runReadinessCheck } from \"./readinessCheck\";\n\nconst env = readRunnerEnv();\n\n// QUIKTR-1084 \u2014 narrows the RunnerEnv union before either branch runs; run()/runReadinessCheck()\n// each take only their own variant, not the union, so this `if` is what makes that safe.\nconst task =\n env.mode === \"readiness_check\"\n ? runReadinessCheck(env).then(() => ({ hardFailure: false }))\n : run(env);\n\ntask\n .then(({ hardFailure }) => {\n process.exitCode = hardFailure ? 1 : 0;\n })\n .catch((err) => {\n // reportBack/the readiness callback itself throwing is the one failure mode neither branch can\n // recover from internally \u2014 still exit non-zero so the raw Actions UI shows the run as failed.\n console.error(err instanceof Error ? err.message : String(err));\n process.exitCode = 1;\n });\n"],
5
- "mappings": "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",
3
+ "sources": ["../src/env.ts", "../src/quiktrackError.ts", "../src/callback.ts", "../src/commands.ts", "../src/git.ts", "../src/commit.ts", "../src/codegen.ts", "../src/envelope.ts", "../src/retryFetch.ts", "../src/dependencyCheck.ts", "../src/guardrail.ts", "../src/installationToken.ts", "../src/oidc.ts", "../src/overlapCheck.ts", "../src/packet.ts", "../src/phase0.ts", "../src/quiktest.ts", "../src/regressionCheck.ts", "../src/scopeCheck.ts", "../src/targeting.ts", "../src/deniedPaths.ts", "../src/testPlacementCheck.ts", "../src/tokenExchange.ts", "../src/run.ts", "../src/readinessCheck.ts", "../src/index.ts"],
4
+ "sourcesContent": ["/** The `workflow_dispatch` inputs QuikTrack's `dispatch.ts` sends, unchanged by QUIKTR-572 \u2014 the\r\n * generated workflow file still passes them through as job-level env vars under these exact\r\n * names. QUIKTR-805: `runToken`/`RUN_TOKEN` (a bearer, visible in the Actions UI as a dispatch\r\n * input) was replaced with `tokenUrl`/`TOKEN_URL` \u2014 the runner now exchanges a GitHub OIDC ID\r\n * token there for a run token at runtime; see `oidc.ts` and `tokenExchange.ts`. QUIKTR-804 adds\r\n * `installationTokenUrl`/`INSTALLATION_TOKEN_URL` \u2014 the run token is exchanged there for a\r\n * repo-scoped GitHub push credential; see `installationToken.ts`. */\r\nexport interface PilotRunEnv {\r\n mode: \"run\";\r\n runId: string;\r\n callbackUrl: string;\r\n packetUrl: string;\r\n tokenUrl: string;\r\n installationTokenUrl: string;\r\n /** GitHub Actions built-ins, read directly from `process.env` rather than threaded through here\r\n * individually. */\r\n githubRunId: string;\r\n githubServerUrl: string;\r\n githubRepository: string;\r\n}\r\n\r\n/**\r\n * QUIKTR-1084 \u2014 the readiness dry-run branch. Deliberately carries none of `PilotRunEnv`'s\r\n * fields: no packet fetch, no OIDC/run-token exchange, no design/codegen/commit/push. It only\r\n * needs the two commands to run and where to report the result.\r\n *\r\n * `readinessToken`/`READINESS_TOKEN` travels as a plain dispatch input, unlike the pilot-run\r\n * token \u2014 deliberately. QUIKTR-805 stopped doing that for the run token because a leaked one\r\n * could spend money through the LLM gateway; this token can only POST a\r\n * `{ junitFound, junitPath }` result for the one `QtPilotConfig` it was minted for (see\r\n * `readiness-dispatch.ts`), which is the same blast radius the pre-805 run token had. Splitting\r\n * out a second OIDC-exchange endpoint to protect a credential this narrow isn't worth the new\r\n * surface.\r\n */\r\nexport interface ReadinessCheckEnv {\r\n mode: \"readiness_check\";\r\n readinessToken: string;\r\n readinessCallbackUrl: string;\r\n setupCmd: string;\r\n testCmd: string;\r\n githubRunId: string;\r\n githubServerUrl: string;\r\n githubRepository: string;\r\n}\r\n\r\nexport type RunnerEnv = PilotRunEnv | ReadinessCheckEnv;\r\n\r\nexport function required(name: string, value: string | undefined): string {\r\n if (!value) {\r\n throw new Error(`Missing required environment variable: ${name}`);\r\n }\r\n return value;\r\n}\r\n\r\nexport function readRunnerEnv(env: NodeJS.ProcessEnv = process.env): RunnerEnv {\r\n const githubRunId = required(\"GITHUB_RUN_ID\", env.GITHUB_RUN_ID);\r\n const githubServerUrl = env.GITHUB_SERVER_URL ?? \"https://github.com\";\r\n const githubRepository = required(\"GITHUB_REPOSITORY\", env.GITHUB_REPOSITORY);\r\n\r\n if (env.MODE === \"readiness_check\") {\r\n return {\r\n mode: \"readiness_check\",\r\n readinessToken: required(\"READINESS_TOKEN\", env.READINESS_TOKEN),\r\n readinessCallbackUrl: required(\"READINESS_CALLBACK_URL\", env.READINESS_CALLBACK_URL),\r\n setupCmd: env.SETUP_CMD ?? \"\",\r\n testCmd: required(\"TEST_CMD\", env.TEST_CMD),\r\n githubRunId,\r\n githubServerUrl,\r\n githubRepository,\r\n };\r\n }\r\n\r\n return {\r\n mode: \"run\",\r\n runId: required(\"RUN_ID\", env.RUN_ID),\r\n callbackUrl: required(\"CALLBACK_URL\", env.CALLBACK_URL),\r\n packetUrl: required(\"PACKET_URL\", env.PACKET_URL),\r\n tokenUrl: required(\"TOKEN_URL\", env.TOKEN_URL),\r\n installationTokenUrl: required(\"INSTALLATION_TOKEN_URL\", env.INSTALLATION_TOKEN_URL),\r\n githubRunId,\r\n githubServerUrl,\r\n githubRepository,\r\n };\r\n}\r\n", "/**\r\n * QUIKTR-1080 \u2014 QuikTrack's internal pilot routes return a stable `reason_code` in the body on\r\n * every `pilotError()`-shaped failure (401/403/409/429); the generic 500 catch-all has none, and a\r\n * non-2xx response isn't guaranteed to be JSON at all (a proxy/gateway error can produce a\r\n * non-JSON body). Best effort: falls back to bare status/statusText when `reason_code` is absent\r\n * or the body doesn't parse \u2014 never throws itself.\r\n *\r\n * Unrelated to envelope.ts's `errorCode` \u2014 that's the AI Runtime's own, separate `/ai/execute`\r\n * contract. Two different services, two different field names; not to be conflated.\r\n */\r\nexport async function describeQuikTrackFailure(res: Response): Promise<string> {\r\n try {\r\n const body = await res.json();\r\n if (body && typeof body === \"object\" && typeof (body as Record<string, unknown>).reason_code === \"string\") {\r\n return `${res.status} ${res.statusText} (${(body as Record<string, unknown>).reason_code})`;\r\n }\r\n } catch {\r\n // not JSON, no json() method at all, or already consumed \u2014 fall back below\r\n }\r\n return `${res.status} ${res.statusText}`;\r\n}\r\n", "import { describeQuikTrackFailure } from \"./quiktrackError\";\r\n\r\nexport type RunStatus = \"completed\" | \"failed\";\r\n\r\n/** Always fires, regardless of what failed upstream \u2014 a run that fails silently is worse than one\r\n * that fails loudly. `branch` is omitted entirely (not sent as null/empty) when no push happened,\r\n * matching the original `jq ... | with_entries(select(.value != null and .value != \"\"))`. Same\r\n * treatment for `warnings` (QUIKTR-1064) \u2014 non-fatal findings like a targeting overlap, omitted\r\n * when there are none rather than sent as an empty array. */\r\nexport async function reportBack(params: {\r\n callbackUrl: string;\r\n runToken: string;\r\n status: RunStatus;\r\n branch?: string;\r\n warnings?: string[];\r\n}): Promise<void> {\r\n const { callbackUrl, runToken, status, branch, warnings } = params;\r\n const body: Record<string, unknown> = { status };\r\n if (branch) body.branch = branch;\r\n if (warnings && warnings.length > 0) body.warnings = warnings;\r\n const res = await fetch(callbackUrl, {\r\n method: \"POST\",\r\n headers: { Authorization: `Bearer ${runToken}`, \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify(body),\r\n });\r\n if (!res.ok) {\r\n throw new Error(`Report back to QuikTrack failed: ${await describeQuikTrackFailure(res)}`);\r\n }\r\n}\r\n", "import { execSync, spawn } from \"node:child_process\";\r\n\r\n/** Runs a packet-supplied command through bash \u2014 same interpreter GitHub's own `run:` steps used,\r\n * so a command written against that shell (e.g. `set -o pipefail`-reliant) behaves the same way.\r\n * A null/empty command is a no-op, matching the original `[ -n \"$CMD\" ]` guard. */\r\nexport function runCommand(command: string | null, label: string): void {\r\n if (!command) return;\r\n try {\r\n execSync(command, { shell: \"/bin/bash\", stdio: \"inherit\" });\r\n } catch (err) {\r\n throw new Error(`${label} failed: ${err instanceof Error ? err.message : String(err)}`);\r\n }\r\n}\r\n\r\nexport type TestOutcome = \"success\" | \"failure\";\r\n\r\n/** The Test step alone is soft \u2014 a failing suite must not hide the rest of the run (guardrail,\r\n * commit, push) from happening, and must not flip the final callback to `failed`. QuikTest owns\r\n * per-test outcomes; this is only ever logged, never reported. QUIKTR-1036: this is still correct\r\n * for a NO_TARGET run (nothing was generated, so there's nothing to regress against) \u2014 a\r\n * codegen'd run's Test step is decided by regressionCheck.ts instead, using the async twin below. */\r\nexport function runTestCommand(command: string | null): TestOutcome {\r\n if (!command) return \"success\";\r\n try {\r\n execSync(command, { shell: \"/bin/bash\", stdio: \"inherit\" });\r\n return \"success\";\r\n } catch {\r\n return \"failure\";\r\n }\r\n}\r\n\r\n/** Same contract as `runTestCommand`, but non-blocking: `execSync` blocks the event loop, which\r\n * would serialize the baseline test run behind (or in front of) codegen's network-bound calls\r\n * instead of letting them overlap. QUIKTR-1036 \u2014 the baseline run is the only caller today. */\r\nexport function runTestCommandAsync(command: string | null): Promise<TestOutcome> {\r\n if (!command) return Promise.resolve(\"success\");\r\n return new Promise((resolve) => {\r\n const child = spawn(command, { shell: \"/bin/bash\", stdio: \"inherit\" });\r\n child.on(\"exit\", (code) => resolve(code === 0 ? \"success\" : \"failure\"));\r\n child.on(\"error\", () => resolve(\"failure\"));\r\n });\r\n}\r\n", "import { execFileSync } from \"node:child_process\";\r\n\r\n/** Thin wrapper around `execFileSync` \u2014 args passed as an array, never through a shell, so a\r\n * branch name or guardrail pattern can never be interpreted as shell syntax. `extraEnv` layers\r\n * on top of the inherited environment; every existing call site is unaffected since it defaults\r\n * to empty. */\r\nfunction git(args: string[], extraEnv: NodeJS.ProcessEnv = {}): string {\r\n return execFileSync(\"git\", args, {\r\n encoding: \"utf8\",\r\n env: { ...process.env, ...extraEnv },\r\n }).trim();\r\n}\r\n\r\nexport function currentBranch(): string {\r\n return git([\"rev-parse\", \"--abbrev-ref\", \"HEAD\"]);\r\n}\r\n\r\n/** Only fetches + checks out when the packet names a target branch different from the one the\r\n * workflow_dispatch already put us on \u2014 dispatch always runs against the default branch (the\r\n * only place `workflow_dispatch` can find the file), but the PR base may differ. */\r\nexport function checkoutTargetBranch(targetBranch: string | null): void {\r\n if (!targetBranch || targetBranch === currentBranch()) return;\r\n git([\"fetch\", \"origin\", targetBranch]);\r\n git([\"checkout\", targetBranch]);\r\n}\r\n\r\nexport function addAll(): void {\r\n git([\"add\", \"-A\"]);\r\n}\r\n\r\n/** `:(glob)` pathspec \u2014 same semantics `**` needs that a hand-rolled glob-to-regex would risk\r\n * getting wrong. */\r\nexport function diffCachedNamesMatching(pattern: string): string[] {\r\n const out = git([\"diff\", \"--cached\", \"--name-only\", \"--\", `:(glob)${pattern}`]);\r\n return out ? out.split(\"\\n\").filter(Boolean) : [];\r\n}\r\n\r\n/** Tracked files under `pathspec`, relative to cwd \u2014 same cwd every other export here already\r\n * assumes is the checkout root, so a caller can feed these straight to readFileSync/writeFileSync\r\n * with no translation. QUIKTR-1035 \u2014 `pathspec` is always concrete; \"null means repo root\" is\r\n * targeting.ts's workspaceRoot concept, not a generic git one. */\r\nexport function listFiles(pathspec: string): string[] {\r\n const out = git([\"ls-files\", \"--\", pathspec]);\r\n return out ? out.split(\"\\n\").filter(Boolean) : [];\r\n}\r\n\r\nexport function hasStagedChanges(): boolean {\r\n try {\r\n execFileSync(\"git\", [\"diff\", \"--cached\", \"--quiet\"]);\r\n return false;\r\n } catch {\r\n return true;\r\n }\r\n}\r\n\r\nexport function configureCommitIdentity(): void {\r\n git([\"config\", \"user.name\", \"quikpilot[bot]\"]);\r\n git([\"config\", \"user.email\", \"quikpilot@users.noreply.github.com\"]);\r\n}\r\n\r\nexport function checkoutNewBranch(branch: string): void {\r\n git([\"checkout\", \"-b\", branch]);\r\n}\r\n\r\nexport function commit(message: string): void {\r\n git([\"commit\", \"-m\", message]);\r\n}\r\n\r\n/**\r\n * Push, authenticated with a repo-scoped GitHub installation token (QUIKTR-804, D16) rather than\r\n * whatever ambient credential checkout configured. `x-access-token:<token>` Basic-auth, GitHub's\r\n * documented scheme for installation tokens over HTTPS git.\r\n *\r\n * Carried via `GIT_CONFIG_COUNT`/`GIT_CONFIG_KEY_0`/`GIT_CONFIG_VALUE_0` env vars rather than a\r\n * `-c http.extraheader=...` argv flag or a `.git/config` write: env vars are not visible to `ps`,\r\n * argv is \u2014 the same class of exposure `packet.ts`'s own header comment already avoids for this\r\n * runner's other credential. Scoped to this one invocation only; never persisted.\r\n *\r\n * QUIKTR-943 rehearsal, 7.0.1 \u2014 the key MUST be `http.https://github.com/.extraheader`\r\n * (URL-scoped), not the unscoped `http.extraheader`. `actions/checkout` persists its own\r\n * credential under the URL-scoped key, pointing at the job's ambient token (contents: read since\r\n * QUIKTR-804 dropped it). Git prefers the more specific URL-scoped key, so an unscoped header here\r\n * silently loses to checkout's read-only one \u2014 the push then fails with \"denied to\r\n * github-actions[bot]\" even though this token itself has write access and the exchange succeeded.\r\n *\r\n * QUIKTR-943 rehearsal, 7.0.2 \u2014 url-scoping alone re-broke the push a second way:\r\n * `http.<url>.extraheader` is multi-valued (git appends, it doesn't replace), so checkout's\r\n * `.git/config` entry and this call's env-var entry are BOTH sent, and GitHub 400s with\r\n * `Duplicate header: \"Authorization\"`. `--unset-all` clears checkout's entry from `.git/config`\r\n * first, so our env-var header (scoped to this one invocation, never written to disk) is the only\r\n * one on the wire. Tolerates the key already being absent (exit 5) \u2014 nothing to clear is not a\r\n * failure, and a workflow that ever runs with `persist-credentials: false` shouldn't crash here.\r\n */\r\nfunction clearCheckoutExtraHeader(): void {\r\n try {\r\n git([\"config\", \"--unset-all\", \"http.https://github.com/.extraheader\"]);\r\n } catch (err: unknown) {\r\n const status = (err as { status?: number }).status;\r\n if (status !== 5) throw err;\r\n }\r\n}\r\n\r\nexport function push(branch: string, installationToken: string): void {\r\n clearCheckoutExtraHeader();\r\n const basicAuth = Buffer.from(`x-access-token:${installationToken}`).toString(\"base64\");\r\n git([\"push\", \"--set-upstream\", \"origin\", branch], {\r\n GIT_CONFIG_COUNT: \"1\",\r\n GIT_CONFIG_KEY_0: \"http.https://github.com/.extraheader\",\r\n GIT_CONFIG_VALUE_0: `AUTHORIZATION: basic ${basicAuth}`,\r\n });\r\n}\r\n", "import {\r\n checkoutNewBranch,\r\n commit,\r\n configureCommitIdentity,\r\n hasStagedChanges,\r\n push,\r\n} from \"./git\";\r\n\r\nexport interface CommitResult {\r\n changed: boolean;\r\n branch?: string;\r\n}\r\n\r\n/**\r\n * QUIKTR-1067 \u2014 \"QuikPilot Phase 0 skeleton\" used to be hardcoded for every commit, including one\r\n * carrying a real generated fix (PR #19) \u2014 indistinguishable from the genuinely-empty NO_TARGET\r\n * marker commit without opening the diff, and git history is permanent. `targeted: false` is the\r\n * one case that message is still accurate for. `issueKey`/`issueTitle` null with `targeted: true`\r\n * is defensive only \u2014 dispatch never reaches commit before Gate 1, which always attaches an issue.\r\n */\r\nexport function buildCommitMessage(\r\n runId: string,\r\n targeted: boolean,\r\n issueKey: string | null,\r\n issueTitle: string | null,\r\n): string {\r\n if (!targeted) return `QuikPilot Phase 0 skeleton (run ${runId})`;\r\n if (issueKey && issueTitle) return `${issueKey}: ${issueTitle}\\n\\nQuikPilot run ${runId}`;\r\n return `QuikPilot generated changes (run ${runId})`;\r\n}\r\n\r\n/** Runs regardless of the Test step's outcome \u2014 a failing suite must not hide the generated diff\r\n * from a reviewer (the whole reason Test alone is a soft failure). Only reached when Setup, Lint,\r\n * and the guardrail check all passed. The branch name comes from the packet, not `runId`: QuikTrack\r\n * already computed and stored it, and two sources for one value will eventually disagree.\r\n * `installationToken` (QUIKTR-804) is the repo-scoped GitHub credential the push authenticates\r\n * with \u2014 see git.ts's `push` for why. */\r\nexport function commitAndPush(\r\n branch: string | null,\r\n runId: string,\r\n installationToken: string,\r\n targeted: boolean,\r\n issueKey: string | null,\r\n issueTitle: string | null,\r\n): CommitResult {\r\n if (!hasStagedChanges()) return { changed: false };\r\n if (!branch) {\r\n throw new Error(\"packet carried no branch name\");\r\n }\r\n configureCommitIdentity();\r\n checkoutNewBranch(branch);\r\n commit(buildCommitMessage(runId, targeted, issueKey, issueTitle));\r\n push(branch, installationToken);\r\n return { changed: true, branch };\r\n}\r\n", "import { readFileSync, writeFileSync, mkdirSync } from \"node:fs\";\r\nimport { dirname } from \"node:path\";\r\nimport { checkHardFailure, unwrapExecute } from \"./envelope\";\r\nimport type { PilotPacket } from \"./packet\";\r\nimport { fetchWithRetry } from \"./retryFetch\";\r\nimport type { PilotTarget, SkippedCase } from \"./targeting\";\r\n\r\n/**\r\n * QUIKTR-823 \u2014 one `/ai/execute` call per file, proven working against a real request this\r\n * morning (Suyash): `x-run-token` header carrying the packet's `gateway.token`, full file content\r\n * in and out. Never a patch \u2014 a failed apply would cost a whole extra call against a tight budget,\r\n * and a patch that can't apply is exactly the kind of failure this loop can't safely paper over.\r\n *\r\n * QUIKTR-1035 \u2014 `targets` (with per-target `planStepsImplemented`) replaces the old\r\n * `targetPaths: string[]` plus a single `design`-derived `planSteps` shared across every file.\r\n * Merging targeting's per-target steps back into one shared list would destroy the reason they're\r\n * per-target: the route file and the service file need different instructions.\r\n *\r\n * \u2500\u2500 ALL-OR-NOTHING \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n *\r\n * The first failed or REFUSED file throws, and `run.ts`'s existing hard-failure handling takes it\r\n * from there: no branch, no pull request. A pull request is a claim the work is done; a\r\n * partially-applied change compiles sometimes, passes tests sometimes, and looks complete either\r\n * way. Already decided twice elsewhere for the same reason \u2014 Gate 1's spec commit is one\r\n * transaction, and `create_issue` with `testCases` is explicitly all-or-nothing. Retrying the\r\n * failed file instead of discarding the rest is the better long-run answer and belongs with\r\n * self-heal (Phase 3, unscoped) \u2014 not silently attempted here.\r\n *\r\n * `CODEGEN_FILE_TOO_LARGE` and `CODEGEN_CONTEXT_TOO_LARGE` are the AI Runtime's own distinct error\r\n * codes, checked on their side before dispatch \u2014 retrying hits the identical wall every time, so\r\n * both are deliberately not retried, same as every other failure here.\r\n *\r\n * \u2500\u2500 CONTEXT CONTRACT (contextPaths \u2192 contextContents) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n *\r\n * pilot.targeting now names, per target, which other files pilot.codegen should read\r\n * (`target.contextPaths`) \u2014 replacing the old `siblingContent` guess (nearest file by directory),\r\n * which only ever ran for NEW_FILE targets and was never more than a stated assumption about this\r\n * repo's own layout. `contextContents: [{ path, content }]` is now sent for EXISTING targets too,\r\n * not just NEW_FILE. Empty/absent contextPaths means empty contextContents \u2014 no fallback.\r\n * `workspaceListing` still goes out for NEW_FILE only, unchanged.\r\n *\r\n * \u2500\u2500 BUFFERED WRITES (QUIKTR-1035) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n *\r\n * `runCodegen` no longer writes anything \u2014 it collects `{targetPath, newContent}` in memory and\r\n * `flushCodegenResults` writes them all, only once every call has succeeded. Two independent\r\n * reasons: it makes all-or-nothing literally true for the working tree, not just the pull request\r\n * (today a failure on file 3 leaves files 1-2 already written even though the throw stops the\r\n * commit); and it lets the test baseline run against an untouched tree while codegen's network-\r\n * bound calls are still in flight (QUIKTR-1036 is what actually wires that concurrency up \u2014 this\r\n * only makes it possible).\r\n */\r\nconst FILE_TOO_LARGE_CODE = \"CODEGEN_FILE_TOO_LARGE\";\r\nconst CONTEXT_TOO_LARGE_CODE = \"CODEGEN_CONTEXT_TOO_LARGE\";\r\n/** \u00A716.7 \u2014 the AI Runtime's OWN output-cap guard telling us directly, distinct from\r\n * `looksLikeTruncatedRewrite` below (this file's interim heuristic guess at the same problem). */\r\nconst OUTPUT_TOO_LARGE_CODE = \"CODEGEN_OUTPUT_TOO_LARGE\";\r\nconst NOT_RETRIED_CODES = new Set([FILE_TOO_LARGE_CODE, CONTEXT_TOO_LARGE_CODE, OUTPUT_TOO_LARGE_CODE]);\r\n/** \u00A718.8.1 \u2014 the ONE retried refusal in this file, deliberately not in `NOT_RETRIED_CODES` above:\r\n * unlike the three sibling TOO_LARGE codes (which hit the identical wall on any retry), this one\r\n * is retried exactly once, with `judgedBy` narrowed to only the cases a test target's own\r\n * `contextPaths` ties to this code target \u2014 see `narrowJudgedByForTarget` below. */\r\nconst JUDGED_BY_TOO_LARGE_CODE = \"CODEGEN_JUDGED_BY_TOO_LARGE\";\r\n\r\n/**\r\n * \u00A716.7 \u2014 interim runner-side guard, live under \u00A715 today (not gated on self-heal or on the AI\r\n * Runtime's own `CODEGEN_OUTPUT_TOO_LARGE` check, which isn't deployed yet). Codegen's output is\r\n * capped around 8,192 tokens; `CODEGEN_FILE_TOO_LARGE` only checks the ~200k-char *input*, so a\r\n * rewrite of a file well under that can still get truncated on the way out. The dangerous case is\r\n * a retry that comes back as valid, `success: true` JSON with the file quietly abbreviated \u2014\r\n * codegen's contract is that anything missing from `newContent` is deleted, so that reads as a\r\n * clean success while silently destroying code. \u00A716.7 names this exact heuristic as QuikTrack's\r\n * own stopgap until the real guard (a pre-dispatch prediction plus a finish-reason check) ships on\r\n * the runtime side.\r\n */\r\nconst SUSPECT_PLACEHOLDER_RE =\r\n /rest(?: of the)? (?:file|code) unchanged|remainder unchanged|\\/\\/\\s*\\.\\.\\.\\s*(?:rest|remaining)/i;\r\n/** Below 60% of its original length, an EXISTING rewrite is suspect rather than a real edit \u2014 a\r\n * targeted fix (planStepsImplemented) trims, it doesn't gut a file to a stub. Raised from 0.5 to\r\n * 0.6 after the AI Runtime's 2026-09-24 incident: a real pilot-chat.ts rewrite came back 38,500 ->\r\n * 22,585 chars (58.67% remaining) with success: true and no placeholder text \u2014 the old 0.5 ratio\r\n * only fires below 50% remaining, so that exact silent deletion sailed through undetected. */\r\nconst SUSPECT_LENGTH_DROP_RATIO = 0.6;\r\n/** A drop in character count can hide behind reformatting (fewer, longer lines) \u2014 this catches\r\n * the opposite failure: a rewrite that removes a large share of *lines* without a matching drop\r\n * in characters. 30% is a deliberately conservative starting point, not a calibrated number \u2014 no\r\n * incident has been observed on this signal alone yet. Tighten once real call metrics exist. */\r\nconst SUSPECT_REMOVED_LINE_RATIO = 0.3;\r\n/** Below this many lines, the multiset diff's \"changed line looks like removed+added\" blind spot\r\n * makes the ratio check unreliable \u2014 skip it rather than false-positive on small/single-line files. */\r\nconst MIN_LINES_FOR_REMOVED_LINE_CHECK = 10;\r\n/** Exported symbols removed silently are exactly the \"code vanishes, response still looks valid\"\r\n * failure mode \u2014 TS/JS only, since this parses no grammar beyond an `export` declaration. */\r\nconst JS_TS_EXTENSION_RE = /\\.(?:ts|tsx|js|jsx|mjs|cjs)$/;\r\nconst EXPORTED_SYMBOL_RE =\r\n /^export\\s+(?:default\\s+)?(?:async\\s+)?(?:function\\*?|class|const|let|var|interface|type|enum)\\s+([A-Za-z_$][\\w$]*)/gm;\r\n\r\n/** Language-neutral, line-based multiset diff \u2014 not an LCS/AST diff. Counts lines present in\r\n * `currentContent` with no matching occurrence left in `newContent`; good enough to flag \"lines\r\n * vanished\" without claiming to be a minimal diff. */\r\nfunction countRemovedLines(currentContent: string, newContent: string): number {\r\n const remaining = new Map<string, number>();\r\n for (const line of newContent.split(\"\\n\")) {\r\n remaining.set(line, (remaining.get(line) ?? 0) + 1);\r\n }\r\n let removed = 0;\r\n for (const line of currentContent.split(\"\\n\")) {\r\n const count = remaining.get(line) ?? 0;\r\n if (count > 0) {\r\n remaining.set(line, count - 1);\r\n } else {\r\n removed++;\r\n }\r\n }\r\n return removed;\r\n}\r\n\r\nfunction extractExportedSymbols(content: string): Set<string> {\r\n const symbols = new Set<string>();\r\n for (const match of content.matchAll(EXPORTED_SYMBOL_RE)) {\r\n symbols.add(match[1]);\r\n }\r\n return symbols;\r\n}\r\n\r\n/** Symbols removed by the rewrite that the plan text never names \u2014 a naive substring check, not a\r\n * reference-tracking one: it undercounts (a symbol renamed to match a plan word would slip past)\r\n * rather than overcounts, which is the right side to err on for a hard-failing guard. */\r\nfunction removedUnexplainedSymbols(targetPath: string, planText: string, currentContent: string, newContent: string): string[] {\r\n if (!JS_TS_EXTENSION_RE.test(targetPath)) return [];\r\n const before = extractExportedSymbols(currentContent);\r\n const after = extractExportedSymbols(newContent);\r\n const lowerPlan = planText.toLowerCase();\r\n return [...before].filter((symbol) => !after.has(symbol) && !lowerPlan.includes(symbol.toLowerCase()));\r\n}\r\n\r\nfunction looksLikeTruncatedRewrite(target: PilotTarget, currentContent: string, newContent: string): string | null {\r\n if (SUSPECT_PLACEHOLDER_RE.test(newContent)) {\r\n return \"contains placeholder text suggesting an abbreviated rewrite\";\r\n }\r\n if (currentContent.length > 0 && newContent.length < currentContent.length * SUSPECT_LENGTH_DROP_RATIO) {\r\n return `sharp length drop (${currentContent.length} -> ${newContent.length} chars)`;\r\n }\r\n\r\n // A multiset line diff can't tell \"line changed\" from \"line removed\" \u2014 on a short/single-line\r\n // file, one edited line reads as 100% removed. Require a real line count before trusting it.\r\n const currentLineCount = currentContent.length > 0 ? currentContent.split(\"\\n\").length : 0;\r\n if (currentLineCount >= MIN_LINES_FOR_REMOVED_LINE_CHECK) {\r\n const removedLines = countRemovedLines(currentContent, newContent);\r\n if (removedLines > currentLineCount * SUSPECT_REMOVED_LINE_RATIO) {\r\n const pct = ((removedLines / currentLineCount) * 100).toFixed(0);\r\n return `removed ${removedLines} of ${currentLineCount} lines (${pct}%) without a matching drop in character count`;\r\n }\r\n }\r\n\r\n const planText = target.planStepsImplemented.join(\" \");\r\n const unexplainedSymbols = removedUnexplainedSymbols(target.path, planText, currentContent, newContent);\r\n if (unexplainedSymbols.length > 0) {\r\n return `removed exported symbol(s) the plan steps don't mention: ${unexplainedSymbols.join(\", \")}`;\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/** QUIKTR-1083 (\u00A715.6) \u2014 sent on every codegen call, same reasoning as targeting.ts's own constant. */\r\nconst CONTRACT_VERSION = \"test-targets-1\";\r\n\r\n/** The shape at `envelope.structuredJson` for `pilot.codegen` \u2014 NOT the envelope itself. A\r\n * refusal's reason is `refusalReason`; the envelope has no `code`/`message` fields (those were\r\n * never real \u2014 see envelope.ts). */\r\ninterface CodegenResult {\r\n outcome?: \"GENERATED\" | \"REFUSED\";\r\n newContent?: string;\r\n summary?: string;\r\n refusalReason?: string;\r\n}\r\n\r\nexport interface CodegenFileResult {\r\n targetPath: string;\r\n newContent: string;\r\n}\r\n\r\n/** \u00A718 `judgedBy` \u2014 the internal (runner-only) shape, keeping `automationId` for the\r\n * overflow-narrowing filter below; stripped down to `{title, given, when, then}` only when\r\n * actually serialized onto the wire (\u00A718.9 refuses any other key on an entry). */\r\nexport interface JudgedByCase {\r\n automationId: string;\r\n title: string;\r\n given: string;\r\n when: string;\r\n then: string;\r\n}\r\n\r\n/**\r\n * \u00A718 \u2014 every case claimed by SOME target in this run (not scoped to `contextPaths` matches \u2014\r\n * that's `narrowJudgedByForTarget`'s overflow-fallback job only, not the primary rule), minus\r\n * targeting's own `skippedCases` (\u00A715.3's `NO_BEHAVIOUR` skip), minus any entry still missing\r\n * given/when/then \u2014 defensive: a non-skipped case should already have all three by construction,\r\n * but \u00A718.9 refuses `CONTRACT_REJECTED` on any entry outside the declared shape, so this never\r\n * trusts that invariant blindly. Built once per run, in `run.ts`, and passed into `runCodegen`.\r\n */\r\nexport function buildJudgedByPool(\r\n requiredTests: PilotPacket[\"requiredTests\"],\r\n targets: PilotTarget[],\r\n skippedCases: SkippedCase[],\r\n): JudgedByCase[] {\r\n const claimedIds = new Set<string>();\r\n for (const t of targets) {\r\n for (const id of t.automationIds ?? []) claimedIds.add(id);\r\n }\r\n const skippedIds = new Set(skippedCases.map((s) => s.automationId));\r\n\r\n const pool: JudgedByCase[] = [];\r\n for (const tc of requiredTests) {\r\n if (!claimedIds.has(tc.automationId) || skippedIds.has(tc.automationId)) continue;\r\n if (!tc.given || !tc.when || !tc.then) continue;\r\n pool.push({ automationId: tc.automationId, title: tc.title, given: tc.given, when: tc.when, then: tc.then });\r\n }\r\n return pool;\r\n}\r\n\r\n/** \u00A718.8.1's overflow fallback \u2014 narrow the full pool down to only cases claimed by a test target\r\n * whose own `contextPaths` names this code target's path. Not the primary rule (a claiming test\r\n * target's `contextPaths` is model output and can be missing/wrong), only the retry narrowing. */\r\nfunction narrowJudgedByForTarget(pool: JudgedByCase[], targets: PilotTarget[], codeTargetPath: string): JudgedByCase[] {\r\n const narrowedIds = new Set<string>();\r\n for (const t of targets) {\r\n if (!t.automationIds?.length || !t.contextPaths?.includes(codeTargetPath)) continue;\r\n for (const id of t.automationIds) narrowedIds.add(id);\r\n }\r\n return pool.filter((c) => narrowedIds.has(c.automationId));\r\n}\r\n\r\n/** Strips `automationId` for the wire \u2014 \u00A718.9 refuses any key outside `{title, given, when, then}`. */\r\nfunction toWireJudgedBy(pool: JudgedByCase[]): { title: string; given: string; when: string; then: string }[] {\r\n return pool.map(({ automationId: _automationId, ...rest }) => rest);\r\n}\r\n\r\n/**\r\n * Run codegen for exactly the targets named, in order, stopping at the first failure. Throws\r\n * rather than returning a partial result \u2014 see the ALL-OR-NOTHING note above; a caller that wants\r\n * to know how far it got before failing should catch and inspect the message, not branch on a\r\n * return value that implies partial success is a valid state. Writes nothing \u2014 call\r\n * `flushCodegenResults` with the return value once this resolves.\r\n *\r\n * `warnings` is a shared, mutable array \u2014 same convention `run.ts` already uses for\r\n * QUIKTR-1064/1374's non-blocking findings \u2014 pushed into directly rather than returned, so this\r\n * function's return type stays `CodegenFileResult[]`.\r\n */\r\nexport async function runCodegen(\r\n gateway: PilotPacket[\"gateway\"],\r\n targets: PilotTarget[],\r\n workspaceListing: string[],\r\n requiredTests: PilotPacket[\"requiredTests\"],\r\n deniedPaths: string[],\r\n judgedByPool: JudgedByCase[],\r\n warnings: string[],\r\n): Promise<CodegenFileResult[]> {\r\n const results: CodegenFileResult[] = [];\r\n const listing = new Set(workspaceListing);\r\n\r\n for (const target of targets) {\r\n const isNewFile = target.kind === \"NEW_FILE\";\r\n const currentContent = isNewFile ? \"\" : readFileSync(target.path, \"utf8\");\r\n\r\n // targeting names its own context needs per target \u2014 an invented contextPath is the same\r\n // class of bug as an invented EXISTING target (targeting.ts's validateTarget): fail loudly\r\n // rather than silently sending less context than the model asked for.\r\n const contextPaths = target.contextPaths ?? [];\r\n for (const contextPath of contextPaths) {\r\n if (!listing.has(contextPath)) {\r\n throw new Error(\r\n `pilot.codegen contextPaths named a file not found in the checkout: ${contextPath} (target ${target.path})`,\r\n );\r\n }\r\n }\r\n const contextContents = contextPaths.map((path) => ({ path, content: readFileSync(path, \"utf8\") }));\r\n\r\n const contextData: Record<string, unknown> = {\r\n targetPath: target.path,\r\n currentContent,\r\n planSteps: target.planStepsImplemented,\r\n kind: target.kind,\r\n contextContents,\r\n // QUIKTR-1083 (\u00A715.6) \u2014 required on every call on the versioned path.\r\n contractVersion: CONTRACT_VERSION,\r\n };\r\n if (isNewFile) {\r\n // Bounds WHAT EXISTS \u2014 stops an invented import like hooks/useGroups \u2014 only meaningful for\r\n // a file that doesn't exist yet to compare against.\r\n contextData.workspaceListing = workspaceListing;\r\n }\r\n if (deniedPaths.length > 0) {\r\n contextData.deniedPaths = deniedPaths;\r\n }\r\n // QUIKTR-1083 (\u00A715.4) \u2014 only for a test target (one targeting named automationIds for), and\r\n // only that target's own subset \u2014 never the full list, and never for a code target at all.\r\n if (target.automationIds && target.automationIds.length > 0) {\r\n const wanted = new Set(target.automationIds);\r\n contextData.requiredTests = requiredTests.filter((tc) => wanted.has(tc.automationId));\r\n } else if (judgedByPool.length > 0) {\r\n // \u00A718 \u2014 a code target (no automationIds of its own) gets the run's claimed cases as\r\n // judging context instead. Mutually exclusive with requiredTests per call, by construction:\r\n // this is the else branch of the exact same condition. Omitted entirely when the pool is\r\n // empty, never sent as `[]`.\r\n contextData.judgedBy = toWireJudgedBy(judgedByPool);\r\n }\r\n\r\n // QUIKTR-1069 \u2014 retries a transport-level failure only (502/503/504, a dropped connection);\r\n // a real refusal always arrives as a 200 with the refusal inside the envelope, below.\r\n const callCodegen = () =>\r\n fetchWithRetry(`${gateway.baseUrl}/ai/execute`, {\r\n method: \"POST\",\r\n headers: { \"content-type\": \"application/json\", \"x-run-token\": gateway.token },\r\n body: JSON.stringify({\r\n appId: \"quiktrack\",\r\n useCase: \"pilot.codegen\",\r\n expectedOutputType: \"json\",\r\n userPrompt: \"\",\r\n contextData,\r\n }),\r\n });\r\n\r\n let res = await callCodegen();\r\n if (!res.ok) {\r\n throw new Error(`Codegen call failed for ${target.path}: ${res.status} ${res.statusText}`);\r\n }\r\n\r\n // /ai/execute wraps every result in an envelope \u2014 the use-case result lives at\r\n // structuredJson, and a failure can arrive as success:false in an HTTP 200 (see envelope.ts).\r\n // CODEGEN_FILE_TOO_LARGE / CODEGEN_CONTEXT_TOO_LARGE are checked on the RAW envelope, before\r\n // unwrapping: they arrive as a failure (success:false), so unwrapping first would throw the\r\n // generic envelope error and lose the not-retried distinction this check exists to preserve.\r\n let envelope: any = await res.json();\r\n // QUIKTR-1083 \u2014 SEMANTIC_MISMATCH/CONTRACT_REJECTED, same \"raw envelope, before unwrap\" point\r\n // as the CODEGEN_* check right below.\r\n checkHardFailure(envelope, \"pilot.codegen\");\r\n\r\n // \u00A718.8.1 \u2014 the one retried refusal here: narrow judgedBy to only the cases a test target's\r\n // own contextPaths ties to this file, then retry ONCE. Recorded on the run's trail either way\r\n // (even if the retry still fails) so the trail shows what was attempted.\r\n if (envelope?.errorCode === JUDGED_BY_TOO_LARGE_CODE && contextData.judgedBy) {\r\n const before = (contextData.judgedBy as unknown[]).length;\r\n const narrowed = narrowJudgedByForTarget(judgedByPool, targets, target.path);\r\n if (narrowed.length > 0) {\r\n contextData.judgedBy = toWireJudgedBy(narrowed);\r\n } else {\r\n delete contextData.judgedBy;\r\n }\r\n warnings.push(`judgedBy narrowed for ${target.path}: ${before} \u2192 ${narrowed.length} cases`);\r\n\r\n res = await callCodegen();\r\n if (!res.ok) {\r\n throw new Error(`Codegen call failed for ${target.path}: ${res.status} ${res.statusText}`);\r\n }\r\n envelope = await res.json();\r\n checkHardFailure(envelope, \"pilot.codegen\");\r\n }\r\n\r\n if (typeof envelope?.errorCode === \"string\" && NOT_RETRIED_CODES.has(envelope.errorCode)) {\r\n const detail = envelope.error ? `: ${envelope.error}` : \"\";\r\n throw new Error(`Codegen refused ${target.path}: ${envelope.errorCode} (not retried)${detail}`);\r\n }\r\n if (envelope?.errorCode === JUDGED_BY_TOO_LARGE_CODE) {\r\n // Still too large after narrowing (or the retry hit some other JUDGED_BY_TOO_LARGE cause) \u2014\r\n // no further retry, same all-or-nothing posture as every other codegen failure here.\r\n const detail = envelope.error ? `: ${envelope.error}` : \"\";\r\n throw new Error(`Codegen refused ${target.path}: ${envelope.errorCode} (after narrowing)${detail}`);\r\n }\r\n\r\n const body = unwrapExecute<CodegenResult>(envelope, \"pilot.codegen\");\r\n\r\n if (body.outcome !== \"GENERATED\" || typeof body.newContent !== \"string\") {\r\n throw new Error(\r\n `Codegen refused ${target.path}${body.refusalReason ? `: ${body.refusalReason}` : \"\"}`,\r\n );\r\n }\r\n\r\n if (!isNewFile) {\r\n const suspectReason = looksLikeTruncatedRewrite(target, currentContent, body.newContent);\r\n if (suspectReason) {\r\n throw new Error(\r\n `Codegen output for ${target.path} looks like a truncated/abbreviated rewrite (${suspectReason}) ` +\r\n `\u2014 refusing to apply it. Interim guard per \u00A716.7; the AI Runtime's own output-cap check is not live yet.`,\r\n );\r\n }\r\n }\r\n\r\n // AI Runtime, 2026-09-24 \u2014 one structured line per call, to build the input/output/removed-line\r\n // distribution SUSPECT_LENGTH_DROP_RATIO and SUSPECT_REMOVED_LINE_RATIO were guessed without.\r\n // Not itself a safety check \u2014 plain data collection for calibrating the two guards above.\r\n console.log(\r\n JSON.stringify({\r\n event: \"codegen.metrics\",\r\n targetPath: target.path,\r\n kind: target.kind,\r\n inputLength: currentContent.length,\r\n outputLength: body.newContent.length,\r\n removedLines: isNewFile ? null : countRemovedLines(currentContent, body.newContent),\r\n }),\r\n );\r\n\r\n results.push({ targetPath: target.path, newContent: body.newContent });\r\n }\r\n\r\n return results;\r\n}\r\n\r\n/** Writes every result to disk. Only ever call this after every `runCodegen` call succeeded \u2014\r\n * see the buffered-writes note above. Creates the parent directory first: a NEW_FILE target can\r\n * legitimately name a directory that doesn't exist yet (e.g. a repo's first hooks/ file). */\r\nexport function flushCodegenResults(results: CodegenFileResult[]): void {\r\n for (const { targetPath, newContent } of results) {\r\n mkdirSync(dirname(targetPath), { recursive: true });\r\n writeFileSync(targetPath, newContent);\r\n }\r\n}\r\n", "/**\r\n * QUIKTR-1046 \u2014 `/ai/execute` wraps every use-case result in an envelope; the use-case's own result\r\n * lives at `envelope.structuredJson`, not at the top level. Both `targeting.ts` and `codegen.ts`\r\n * read the raw response directly and have never worked against a real reply \u2014 this is the one\r\n * place that unwraps it, so there is exactly one place to get it right.\r\n *\r\n * A failed call can arrive as `success: false` in an HTTP 200 body \u2014 `res.ok` alone is not enough.\r\n * Observed live 2026-09-18/19/21, including a real RUN_CREDENTIAL_SCOPE refusal shaped exactly\r\n * like this.\r\n */\r\n/**\r\n * QUIKTR-1083 (\u00A715 of the spec-phase contract) \u2014 two hard-failure codes the AI Runtime raises on\r\n * the versioned `pilot.targeting`/`pilot.codegen` path, neither ever retried: `SEMANTIC_MISMATCH`\r\n * (the JSON shape was valid, a rule failed \u2014 e.g. a generated test file missing its\r\n * `[<automationId>]` marker) and `CONTRACT_REJECTED` (the request itself was refused \u2014 an unknown\r\n * or removed `contextData` key, or an unrecognised `contractVersion`). Both carry the explanation\r\n * in `envelope.error`.\r\n *\r\n * Checked on the RAW envelope, before `unwrapExecute` \u2014 same reason codegen.ts's existing\r\n * `CODEGEN_FILE_TOO_LARGE`/`CODEGEN_CONTEXT_TOO_LARGE` check already runs there: unwrapping first\r\n * would throw `unwrapExecute`'s generic `success:false` error and lose the distinction. No custom\r\n * error class \u2014 `run.ts`'s top-level catch already prints any thrown error's message, and\r\n * `fetchWithRetry` never retries a 200 response regardless of body, so \"print the violation list\"\r\n * and \"never retried\" both already hold once this throws a message that names the code and detail.\r\n */\r\nconst HARD_FAILURE_CODES = new Set([\"SEMANTIC_MISMATCH\", \"CONTRACT_REJECTED\"]);\r\n\r\nexport function checkHardFailure(envelope: any, useCase: string): void {\r\n const code = envelope?.errorCode;\r\n if (typeof code === \"string\" && HARD_FAILURE_CODES.has(code)) {\r\n const detail = envelope.error ?? envelope.normalizedText ?? \"no detail\";\r\n throw new Error(`${useCase} failed (${code}, not retried): ${detail}`);\r\n }\r\n}\r\n\r\nexport function unwrapExecute<T>(envelope: any, useCase: string): T {\r\n if (envelope?.success === false) {\r\n throw new Error(\r\n `${useCase} failed: ${envelope.errorCode ?? \"UNKNOWN\"} \u2014 ` +\r\n `${envelope.error ?? envelope.normalizedText ?? \"no message\"}`,\r\n );\r\n }\r\n if (!envelope?.structuredJson || typeof envelope.structuredJson !== \"object\") {\r\n throw new Error(`${useCase} returned no structuredJson: ${JSON.stringify(envelope)}`);\r\n }\r\n return envelope.structuredJson as T;\r\n}\r\n", "/**\r\n * QUIKTR-1069 \u2014 a gateway timeout in front of the AI Runtime is not a refusal: the demo rehearsal\r\n * hit a 504 from a devtunnel/load balancer, not the runtime, and the same call succeeded on retry.\r\n * Retries ONLY transport-level signals \u2014 HTTP 502/503/504, or a thrown network error\r\n * (ECONNRESET/ETIMEDOUT) \u2014 twice, with a short fixed backoff. Every other failure (a real refusal,\r\n * CODEGEN_FILE_TOO_LARGE, success:false+errorCode, any 4xx) arrives as a normal HTTP 200 with the\r\n * refusal inside the envelope body, or a genuine non-transient 4xx \u2014 neither ever matches this\r\n * function's retry condition, so nothing here needs to special-case them.\r\n *\r\n * Spend: a retried call the runtime actually completed has been paid for twice. maxRunUsd already\r\n * caps the run (enforced at the gateway, per packet.ts's own comment), so this fails safe \u2014 the\r\n * worst case is hitting the budget wall slightly sooner, never an uncapped spend.\r\n */\r\nconst RETRYABLE_STATUS_CODES = new Set([502, 503, 504]);\r\nconst RETRYABLE_NETWORK_ERROR_CODES = new Set([\"ECONNRESET\", \"ETIMEDOUT\"]);\r\n\r\nfunction isRetryableNetworkError(err: unknown): boolean {\r\n const code =\r\n (err as { cause?: { code?: string } } | undefined)?.cause?.code ??\r\n (err as { code?: string } | undefined)?.code;\r\n return typeof code === \"string\" && RETRYABLE_NETWORK_ERROR_CODES.has(code);\r\n}\r\n\r\nexport async function fetchWithRetry(\r\n url: string,\r\n init: RequestInit,\r\n { retries = 2, backoffMs = 250 }: { retries?: number; backoffMs?: number } = {},\r\n): Promise<Response> {\r\n for (let attempt = 0; ; attempt++) {\r\n try {\r\n const res = await fetch(url, init);\r\n if (RETRYABLE_STATUS_CODES.has(res.status) && attempt < retries) {\r\n await new Promise((r) => setTimeout(r, backoffMs));\r\n continue;\r\n }\r\n return res;\r\n } catch (err) {\r\n if (isRetryableNetworkError(err) && attempt < retries) {\r\n await new Promise((r) => setTimeout(r, backoffMs));\r\n continue;\r\n }\r\n throw err;\r\n }\r\n }\r\n}\r\n", "import { readFileSync } from \"node:fs\";\r\nimport { resolve, join } from \"node:path\";\r\nimport type { CodegenFileResult } from \"./codegen\";\r\n\r\n/**\r\n * QUIKTR-1045 \u2014 codegen importing a package the repository doesn't have currently fails safely\r\n * (setup already ran, so the package genuinely isn't installed, and the regression check catches\r\n * the resulting test failure) but with the WRONG diagnosis: it reads as \"the generated logic is\r\n * broken\" when the real problem is a fabricated import. This names that failure correctly instead.\r\n *\r\n * Only a minimal regex import-scanner \u2014 not a real JS/TS parser. Same reasoning\r\n * `regressionCheck.ts` already states for its own hand-rolled JUnit scanner: this package is\r\n * dependency-free on purpose (published outside the monorepo, bundled into a single CLI file with\r\n * no externals \u2014 see build.mjs), so a real parser is off the table, not merely unused.\r\n *\r\n * Explicitly scoped to JS/TS: it only acts when a `package.json` is found. A repo in another\r\n * language has none, `readDeclaredDependencies` returns null, and the check no-ops \u2014 this is what\r\n * keeps it from looking like a general \"detect the repo's language\" mechanism, which it isn't.\r\n */\r\nexport interface DependencyViolation {\r\n file: string;\r\n packages: string[];\r\n}\r\n\r\nexport interface DependencyCheck {\r\n blocked: boolean;\r\n violations: DependencyViolation[];\r\n}\r\n\r\nconst SCANNABLE_EXTENSIONS = [\".ts\", \".tsx\", \".js\", \".jsx\", \".mjs\", \".cjs\", \".mts\", \".cts\"];\r\n\r\n// import ... from \"x\" / import \"x\" / export ... from \"x\" / require(\"x\") / import(\"x\")\r\nconst IMPORT_RE = /(?:\\bimport\\b[^'\"]*?\\bfrom\\s*|\\bimport\\s*\\(\\s*|\\bexport\\b[^'\"]*?\\bfrom\\s*|\\brequire\\s*\\(\\s*|\\bimport\\s+)(['\"])([^'\"]+)\\1/g;\r\n\r\n// Not exhaustive \u2014 same \"minimal, not exhaustive\" treatment regressionCheck.ts's own scanner uses.\r\nconst NODE_BUILTINS = new Set([\r\n \"assert\", \"buffer\", \"child_process\", \"cluster\", \"crypto\", \"dgram\", \"dns\", \"domain\", \"events\",\r\n \"fs\", \"http\", \"http2\", \"https\", \"net\", \"os\", \"path\", \"perf_hooks\", \"process\", \"punycode\",\r\n \"querystring\", \"readline\", \"repl\", \"stream\", \"string_decoder\", \"sys\", \"timers\", \"tls\", \"tty\",\r\n \"url\", \"util\", \"v8\", \"vm\", \"worker_threads\", \"zlib\", \"inspector\", \"async_hooks\",\r\n]);\r\n\r\n// QUIKTR-1063 \u2014 the two path-alias conventions common enough to assume even\r\n// when a repo's tsconfig can't be read or parsed: \"@/...\" (QuikTrack,\r\n// QuikChat, and most of this monorepo's own apps) and \"~/...\". Without this,\r\n// \"@/lib/x\" was parsed as the scoped package \"@/lib\" \u2014 a real package.json\r\n// entry it could never actually match \u2014 and every aliased import in a repo\r\n// using either convention was reported as an invented dependency.\r\n//\r\n// QUIKTR-1068 \u2014 this is now a FLOOR, not the whole answer: `resolveAliasPrefixes`\r\n// below adds whatever a real tsconfig.json/jsconfig.json actually declares in\r\n// `compilerOptions.paths`, for repos using some other convention entirely.\r\n// Always unioned in regardless of what a config says, so a repo with no\r\n// config (or an unparseable one) keeps exactly today's behavior.\r\nconst DEFAULT_ALIAS_PREFIXES = [\"@/\", \"~/\"];\r\n\r\nfunction packageNameFromSpecifier(specifier: string, aliasPrefixes: string[] = DEFAULT_ALIAS_PREFIXES): string | null {\r\n if (specifier.startsWith(\".\") || specifier.startsWith(\"/\")) return null; // relative/absolute\r\n if (specifier.startsWith(\"node:\")) return null; // explicit builtin\r\n if (aliasPrefixes.some((prefix) => specifier.startsWith(prefix))) return null; // path alias\r\n const segments = specifier.split(\"/\");\r\n const name = specifier.startsWith(\"@\") ? segments.slice(0, 2).join(\"/\") : segments[0];\r\n if (NODE_BUILTINS.has(name)) return null;\r\n return name;\r\n}\r\n\r\nfunction scanImports(source: string, aliasPrefixes: string[] = DEFAULT_ALIAS_PREFIXES): string[] {\r\n const found = new Set<string>();\r\n let match: RegExpExecArray | null;\r\n IMPORT_RE.lastIndex = 0;\r\n while ((match = IMPORT_RE.exec(source))) {\r\n const name = packageNameFromSpecifier(match[2], aliasPrefixes);\r\n if (name) found.add(name);\r\n }\r\n return [...found];\r\n}\r\n\r\n/** Pure \u2014 no fs, trivially unit-testable. `declaredDependencies === null` means \"couldn't tell\r\n * what this repo declares\" (no package.json, or unparseable) \u2014 the check no-ops rather than\r\n * blocking on a question it can't actually answer. `aliasPrefixes` defaults to the floor above;\r\n * callers with a real tsconfig read (see `resolveAliasPrefixes`) pass the fuller list. */\r\nexport function checkImportDependencies(\r\n results: CodegenFileResult[],\r\n declaredDependencies: Set<string> | null,\r\n aliasPrefixes: string[] = DEFAULT_ALIAS_PREFIXES,\r\n): DependencyCheck {\r\n if (!declaredDependencies) return { blocked: false, violations: [] };\r\n\r\n const violations: DependencyViolation[] = [];\r\n for (const { targetPath, newContent } of results) {\r\n if (!SCANNABLE_EXTENSIONS.some((ext) => targetPath.endsWith(ext))) continue;\r\n const invented = scanImports(newContent, aliasPrefixes).filter((pkg) => !declaredDependencies.has(pkg));\r\n if (invented.length > 0) violations.push({ file: targetPath, packages: invented });\r\n }\r\n return { blocked: violations.length > 0, violations };\r\n}\r\n\r\ninterface PackageJson {\r\n dependencies?: Record<string, string>;\r\n devDependencies?: Record<string, string>;\r\n peerDependencies?: Record<string, string>;\r\n}\r\n\r\nfunction dependencyNames(pkg: PackageJson): Set<string> {\r\n // devDependencies included deliberately \u2014 a generated test file may legitimately import one.\r\n return new Set([\r\n ...Object.keys(pkg.dependencies ?? {}),\r\n ...Object.keys(pkg.devDependencies ?? {}),\r\n ...Object.keys(pkg.peerDependencies ?? {}),\r\n ]);\r\n}\r\n\r\n/**\r\n * Reads the target repo's declared dependencies. Checks `results` FIRST for a generated\r\n * `package.json` \u2014 codegen may have legitimately added the very dependency it's about to import,\r\n * and reading the pre-generation file on disk would false-flag that. Falls back to the on-disk\r\n * file, and to `null` (\u2192 the check no-ops) when neither exists or parses.\r\n */\r\nexport function readDeclaredDependencies(\r\n results: CodegenFileResult[],\r\n workspaceRoot: string | null,\r\n): Set<string> | null {\r\n const packageJsonPath = join(resolve(workspaceRoot ?? \".\"), \"package.json\");\r\n const generated = results.find((r) => resolve(r.targetPath) === packageJsonPath);\r\n\r\n let raw: string | null;\r\n if (generated) {\r\n raw = generated.newContent;\r\n } else {\r\n try {\r\n raw = readFileSync(packageJsonPath, \"utf8\");\r\n } catch {\r\n raw = null;\r\n }\r\n }\r\n if (raw === null) return null;\r\n\r\n try {\r\n return dependencyNames(JSON.parse(raw) as PackageJson);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * QUIKTR-1068 \u2014 strips line and block comments plus trailing commas from a JSON(C) string, best\r\n * effort. Not a real JSONC parser: a character scanner rather than a regex replace (a regex would\r\n * corrupt a string VALUE containing `//`, e.g. a URL), but anything it can't cleanly handle just\r\n * fails `JSON.parse` afterward \u2014 `resolveAliasPrefixes` below treats that the same as no config at\r\n * all and falls back to the floor. Never throws itself.\r\n */\r\nfunction stripJsonComments(text: string): string {\r\n let out = \"\";\r\n let inString = false;\r\n let inLineComment = false;\r\n let inBlockComment = false;\r\n for (let i = 0; i < text.length; i++) {\r\n const c = text[i];\r\n const next = text[i + 1];\r\n if (inLineComment) {\r\n if (c === \"\\n\") {\r\n inLineComment = false;\r\n out += c;\r\n }\r\n continue;\r\n }\r\n if (inBlockComment) {\r\n if (c === \"*\" && next === \"/\") {\r\n inBlockComment = false;\r\n i++;\r\n }\r\n continue;\r\n }\r\n if (inString) {\r\n out += c;\r\n if (c === \"\\\\\") {\r\n out += next;\r\n i++;\r\n continue;\r\n }\r\n if (c === '\"') inString = false;\r\n continue;\r\n }\r\n if (c === '\"') {\r\n inString = true;\r\n out += c;\r\n continue;\r\n }\r\n if (c === \"/\" && next === \"/\") {\r\n inLineComment = true;\r\n i++;\r\n continue;\r\n }\r\n if (c === \"/\" && next === \"*\") {\r\n inBlockComment = true;\r\n i++;\r\n continue;\r\n }\r\n out += c;\r\n }\r\n return out.replace(/,(\\s*[}\\]])/g, \"$1\");\r\n}\r\n\r\ninterface TsOrJsConfig {\r\n compilerOptions?: { paths?: Record<string, unknown> };\r\n}\r\n\r\n/**\r\n * QUIKTR-1068 \u2014 `DEFAULT_ALIAS_PREFIXES` is a floor, not the whole answer: a repo may declare its\r\n * own alias conventions in `compilerOptions.paths`. Tries `tsconfig.json` then `jsconfig.json` at\r\n * the workspace root (same results-first-then-disk precedence as `readDeclaredDependencies` \u2014 a\r\n * generated config this run legitimately wrote should win over a stale on-disk one), unions any\r\n * `paths` keys (wildcard stripped: `\"@/*\"` \u2192 `\"@/\"`) with the floor, and dedupes. Never throws and\r\n * never returns fewer than the floor \u2014 an unreadable or malformed config is exactly the same as no\r\n * config, not a reason to block a run that could otherwise pass.\r\n *\r\n * Does NOT follow `extends` \u2014 only the root config's own `paths`, same \"minimal, not exhaustive\"\r\n * boundary this file already draws elsewhere (see the module docblock).\r\n */\r\nexport function resolveAliasPrefixes(\r\n results: CodegenFileResult[],\r\n workspaceRoot: string | null,\r\n): string[] {\r\n const root = resolve(workspaceRoot ?? \".\");\r\n\r\n for (const filename of [\"tsconfig.json\", \"jsconfig.json\"]) {\r\n const configPath = join(root, filename);\r\n const generated = results.find((r) => resolve(r.targetPath) === configPath);\r\n\r\n let raw: string | null;\r\n if (generated) {\r\n raw = generated.newContent;\r\n } else {\r\n try {\r\n raw = readFileSync(configPath, \"utf8\");\r\n } catch {\r\n raw = null;\r\n }\r\n }\r\n if (raw === null) continue;\r\n\r\n try {\r\n const parsed = JSON.parse(stripJsonComments(raw)) as TsOrJsConfig;\r\n const paths = parsed.compilerOptions?.paths;\r\n const fromConfig =\r\n paths && typeof paths === \"object\"\r\n ? Object.keys(paths).map((k) => (k.endsWith(\"*\") ? k.slice(0, -1) : k))\r\n : [];\r\n return [...new Set([...DEFAULT_ALIAS_PREFIXES, ...fromConfig])];\r\n } catch {\r\n continue; // malformed \u2014 try the next config file, or fall through to the floor\r\n }\r\n }\r\n\r\n return DEFAULT_ALIAS_PREFIXES;\r\n}\r\n\r\n/** Regressions and new failures named separately elsewhere in this package for the same reason\r\n * this exists at all: conflating diagnoses wastes someone's morning. */\r\nexport function describeDependencyViolations(check: DependencyCheck): string {\r\n return check.violations\r\n .map((v) => `${v.file} imports ${v.packages.join(\", \")}, not a dependency of this repository`)\r\n .join(\"; \");\r\n}\r\n", "import { addAll, diffCachedNamesMatching } from \"./git\";\r\n\r\n/** Stages everything, then refuses to proceed if any staged file matches a denied-path glob.\r\n * Public and inspectable on purpose (Suyash, 2026-09-10): moving this into a published package\r\n * doesn't hide the enforcement \u2014 it's the same check, just no longer duplicated per customer repo. */\r\nexport function checkGuardrail(deniedPaths: string[]): void {\r\n addAll();\r\n const violations = deniedPaths.flatMap((pattern) => diffCachedNamesMatching(pattern));\r\n if (violations.length > 0) {\r\n throw new Error(`QuikPilot touched denied paths:\\n${violations.join(\"\\n\")}`);\r\n }\r\n}\r\n", "import { describeQuikTrackFailure } from \"./quiktrackError\";\r\n\r\ninterface InstallationTokenResponse {\r\n success: boolean;\r\n data: { token: string; expiresAt: string };\r\n}\r\n\r\n/** Exchange the QuikPilot run token for a repo-scoped GitHub installation token (QUIKTR-804) \u2014\r\n * mirrors `tokenExchange.ts`'s `exchangeForRunToken` shape: bearer auth, `{success,data}`\r\n * envelope, same error-message style. */\r\nexport async function exchangeForInstallationToken(\r\n installationTokenUrl: string,\r\n runToken: string,\r\n): Promise<string> {\r\n const res = await fetch(installationTokenUrl, {\r\n method: \"POST\",\r\n headers: { Authorization: `Bearer ${runToken}` },\r\n });\r\n if (!res.ok) {\r\n throw new Error(`Exchange installation token failed: ${await describeQuikTrackFailure(res)}`);\r\n }\r\n const body = (await res.json()) as InstallationTokenResponse;\r\n if (body.success !== true) {\r\n throw new Error(\"Exchange installation token failed: response did not carry success:true\");\r\n }\r\n return body.data.token;\r\n}\r\n", "import { required } from \"./env\";\r\n\r\n/** Must equal `apps/quiktrack/lib/services/github/oidc.ts`'s own copy of this literal \u2014 that app\r\n * verifies the token this package requests. Duplicated because this package is published outside\r\n * the monorepo and cannot import from the app; same reasoning `packet.ts`'s header gives for\r\n * duplicating `PilotPacket`'s shape. */\r\nconst QUIKPILOT_OIDC_AUDIENCE = \"quiktrack-quikpilot\";\r\n\r\ninterface OidcTokenResponse {\r\n value: string;\r\n}\r\n\r\n/** Request a GitHub Actions OIDC ID token \u2014 the runner's proof of identity, exchanged at\r\n * `TOKEN_URL` for a QuikPilot run token (QUIKTR-805). `ACTIONS_ID_TOKEN_REQUEST_URL` and\r\n * `ACTIONS_ID_TOKEN_REQUEST_TOKEN` are ambient GitHub Actions env vars, present only because the\r\n * generated workflow declares `permissions: id-token: write` \u2014 no dispatch input carries them. */\r\nexport async function fetchGithubOidcToken(\r\n env: NodeJS.ProcessEnv = process.env,\r\n): Promise<string> {\r\n const requestUrl = required(\r\n \"ACTIONS_ID_TOKEN_REQUEST_URL\",\r\n env.ACTIONS_ID_TOKEN_REQUEST_URL,\r\n );\r\n const requestToken = required(\r\n \"ACTIONS_ID_TOKEN_REQUEST_TOKEN\",\r\n env.ACTIONS_ID_TOKEN_REQUEST_TOKEN,\r\n );\r\n const separator = requestUrl.includes(\"?\") ? \"&\" : \"?\";\r\n const url = `${requestUrl}${separator}audience=${encodeURIComponent(QUIKPILOT_OIDC_AUDIENCE)}`;\r\n const res = await fetch(url, {\r\n headers: { Authorization: `Bearer ${requestToken}` },\r\n });\r\n if (!res.ok) {\r\n throw new Error(`Fetch GitHub OIDC token failed: ${res.status} ${res.statusText}`);\r\n }\r\n const body = (await res.json()) as OidcTokenResponse;\r\n if (!body.value) {\r\n throw new Error(\"GitHub OIDC token response carried no value\");\r\n }\r\n return body.value;\r\n}\r\n", "import type { PilotTarget } from \"./targeting\";\r\n\r\n/**\r\n * QUIKTR-1064 \u2014 QUIKSP-3's first live run implemented \"reject negative amounts\" twice: once in\r\n * src/server.js against raw input, once in src/validation.js against parsed minor units. Targeting\r\n * split the work across two files and gave each its own planStepsImplemented describing the same\r\n * rule; codegen faithfully built both. Per-target steps are meant to be DISJOINT (QUIKTR-1035) \u2014\r\n * nothing checked that they are.\r\n *\r\n * The real fix is `pilot.targeting`'s prompt \u2014 an AI Runtime change, not this package's. This is\r\n * the cheap half the ticket assigns here: a non-blocking warning, not semantic analysis. A\r\n * significant-word overlap between two steps in DIFFERENT targets is treated as the same rule\r\n * described twice. Same-target steps are never compared \u2014 one file legitimately implementing\r\n * several related steps is normal and not what this looks for.\r\n */\r\nexport interface OverlapWarning {\r\n targetA: string;\r\n stepA: string;\r\n targetB: string;\r\n stepB: string;\r\n /** QUIKTR-1081 \u2014 \"identical\" (the exact same instruction, modulo case/whitespace) is blocking;\r\n * \"similar\" (the existing Jaccard-threshold match, reworded but not the same text) stays a\r\n * warning. Two legitimate halves of one change never share the literal same instruction. */\r\n severity: \"identical\" | \"similar\";\r\n}\r\n\r\n// QUIKTR-1081 \u2014 a path-convention heuristic, not a real \"is this a test\" signal: nothing in this\r\n// package (or apps/quiktrack/lib/services/pilot) tags a PilotTarget as covering a test today. A\r\n// behaviour appearing in both a file and its test is correct, so a pair is exempt from this check\r\n// entirely \u2014 not merely from blocking \u2014 whenever either side looks like a test file.\r\nconst TEST_PATH_RE = /(\\.(test|spec)\\.[jt]sx?$)|(^|\\/)(__tests__|tests?)\\//i;\r\n\r\nexport function isTestTarget(path: string): boolean {\r\n return TEST_PATH_RE.test(path);\r\n}\r\n\r\nconst STOPWORDS = new Set([\r\n \"a\", \"an\", \"the\", \"is\", \"are\", \"was\", \"were\", \"be\", \"been\", \"being\",\r\n \"of\", \"to\", \"in\", \"on\", \"for\", \"with\", \"at\", \"by\", \"from\", \"as\",\r\n \"and\", \"or\", \"not\", \"no\", \"nor\",\r\n \"this\", \"that\", \"these\", \"those\", \"it\", \"its\",\r\n \"cannot\", \"can't\", \"should\", \"must\", \"may\", \"will\", \"shall\",\r\n \"when\", \"if\", \"than\", \"then\", \"so\", \"do\", \"does\", \"did\",\r\n]);\r\n\r\n// Ignore words this short too \u2014 they add noise to the overlap without carrying meaning (\"id\",\r\n// \"an\", two-letter fragments from punctuation stripping).\r\nconst MIN_WORD_LENGTH = 3;\r\n\r\nfunction significantWords(step: string): Set<string> {\r\n return new Set(\r\n step\r\n .toLowerCase()\r\n .replace(/[^a-z0-9\\s]/g, \" \")\r\n .split(/\\s+/)\r\n .filter((w) => w.length >= MIN_WORD_LENGTH && !STOPWORDS.has(w)),\r\n );\r\n}\r\n\r\nfunction jaccard(a: Set<string>, b: Set<string>): number {\r\n if (a.size === 0 || b.size === 0) return 0;\r\n let intersection = 0;\r\n for (const w of a) if (b.has(w)) intersection++;\r\n const union = a.size + b.size - intersection;\r\n return intersection / union;\r\n}\r\n\r\n// QUIKTR-1081 \u2014 stricter than significantWords' normalization (which drops stopwords/short words\r\n// entirely): this only ignores case and incidental whitespace, so \"identical\" means the actual\r\n// same instruction, not merely \"shares enough meaningful words.\"\r\nfunction normalizedStep(step: string): string {\r\n return step.trim().toLowerCase().replace(/\\s+/g, \" \");\r\n}\r\n\r\n// Cheap and deliberately generous \u2014 a false positive here costs a reviewer one glance at a warning\r\n// line; a false negative is exactly the bug this exists to catch.\r\nconst OVERLAP_THRESHOLD = 0.5;\r\n\r\n/** Every cross-target pair of plan steps whose significant words overlap enough to plausibly be the\r\n * same rule described twice. Steps within the same target are never compared. */\r\nexport function findOverlappingSteps(targets: PilotTarget[]): OverlapWarning[] {\r\n const items = targets.flatMap((target) =>\r\n target.planStepsImplemented.map((step) => ({\r\n target: target.path,\r\n step,\r\n words: significantWords(step),\r\n })),\r\n );\r\n\r\n const warnings: OverlapWarning[] = [];\r\n for (let i = 0; i < items.length; i++) {\r\n for (let j = i + 1; j < items.length; j++) {\r\n if (items[i].target === items[j].target) continue;\r\n if (isTestTarget(items[i].target) || isTestTarget(items[j].target)) continue;\r\n if (jaccard(items[i].words, items[j].words) >= OVERLAP_THRESHOLD) {\r\n warnings.push({\r\n targetA: items[i].target,\r\n stepA: items[i].step,\r\n targetB: items[j].target,\r\n stepB: items[j].step,\r\n severity: normalizedStep(items[i].step) === normalizedStep(items[j].step) ? \"identical\" : \"similar\",\r\n });\r\n }\r\n }\r\n }\r\n return warnings;\r\n}\r\n\r\nexport function describeOverlapWarnings(warnings: OverlapWarning[]): string[] {\r\n return warnings.map(\r\n (w) =>\r\n `${w.targetA} and ${w.targetB} both implement what looks like the same rule \u2014 \"${w.stepA}\" / \"${w.stepB}\". Check these aren't two independent implementations of the same behavior.`,\r\n );\r\n}\r\n", "import { describeQuikTrackFailure } from \"./quiktrackError\";\r\n\r\n/** Mirrors `apps/quiktrack/lib/services/pilot/packet.ts`'s `PilotPacket` shape. Duplicated rather\r\n * than imported \u2014 this package is published outside the monorepo and cannot depend on the app. */\r\nexport interface PilotPacket {\r\n runId: string;\r\n issueKey: string | null;\r\n /** QUIKTR-1067 \u2014 same nullability as issueKey, for the same reason: the commit message needs\r\n * both to say what actually changed instead of the hardcoded \"Phase 0 skeleton\" placeholder. */\r\n issueTitle: string | null;\r\n branch: string | null;\r\n targetBranch: string | null;\r\n /** QUIKTR-1033 \u2014 the subtree targeting (QUIKTR-1035) lists files under. Null means the\r\n * repository root, as null \u2014 never normalised to \".\". */\r\n workspaceRoot: string | null;\r\n commands: {\r\n setup: string | null;\r\n test: string | null;\r\n e2e: string | null;\r\n lint: string | null;\r\n /** QUIKTR-1045 \u2014 run after codegen flushes, before lint. Soft failure. */\r\n format: string | null;\r\n };\r\n guardrails: {\r\n deniedPaths: string[];\r\n maxHealIterations: number;\r\n maxWallClockMinutes: number;\r\n // No maxRunUsd \u2014 it travels as a claim on gateway.token instead (QUIKTR-823).\r\n };\r\n /** Where to call for AI codegen, and the credential that authorizes it. */\r\n gateway: {\r\n baseUrl: string;\r\n token: string;\r\n };\r\n /** The pilot.design technical design, as context for codegen. No file paths \u2014 see the app's\r\n * spec-contract.ts. Null only in theory (dispatch requires a design to already exist). */\r\n design: {\r\n rootCause: string;\r\n approach: string;\r\n /** Mirrors `apps/quiktrack/lib/services/pilot/spec-contract.ts`'s `PilotApiChange`. */\r\n apiChanges: { surface: string; change: string; reason: string }[];\r\n riskLevel: \"LOW\" | \"MEDIUM\" | \"HIGH\";\r\n riskRationale: string;\r\n } | null;\r\n quikTest: { testRunId: string; resultsUrl: string } | null;\r\n /** QUIKTR-1065 \u2014 the approved test cases codegen still owes real test code for. Sent to\r\n * pilot.targeting so it can propose a test-file target naming which cases it covers; today\r\n * nothing reads this field yet (the AI Runtime side isn't built), so it always arrives as `[]`\r\n * or is silently unused once wired up here. */\r\n requiredTests: {\r\n automationId: string;\r\n title: string;\r\n covers: string[];\r\n given: string | null;\r\n when: string | null;\r\n then: string | null;\r\n }[];\r\n /** QUIKTR-1315, \u00A719 of the AI Runtime contract (AGREED, final tagged shape) \u2014 the repo-relative\r\n * files the last DONE run's own ingested JUnit report named, sourced from stored QuikTest data,\r\n * not a live baseline capture here. Always present (never undefined) \u2014 \u00A719.12: a project with no\r\n * prior DONE run's report is `{ report: \"ABSENT\" }`, not an omitted field. `{ report: \"PRESENT\" }`\r\n * with an empty `discoveredTestFiles` is a different, real fact: a report was ingested but\r\n * nothing in it was path-shaped. See targeting.ts for how this is forwarded. */\r\n testDiscovery:\r\n | { report: \"PRESENT\"; discoveredTestFiles: string[]; unmappedEntries: number }\r\n | { report: \"ABSENT\" };\r\n}\r\n\r\ninterface PacketResponse {\r\n success: boolean;\r\n data: PilotPacket;\r\n}\r\n\r\n/** GET the run's work packet. Bearer auth via the run token, matching the header curl sent on\r\n * stdin (`--config -`) so it never showed up in `ps` \u2014 an HTTP client's header option is already\r\n * invisible to `ps`, so no equivalent trick is needed here. */\r\nexport async function fetchPacket(\r\n packetUrl: string,\r\n runToken: string,\r\n githubRunId: string,\r\n): Promise<PilotPacket> {\r\n const url = `${packetUrl}?githubRunId=${encodeURIComponent(githubRunId)}`;\r\n const res = await fetch(url, {\r\n headers: { Authorization: `Bearer ${runToken}` },\r\n });\r\n if (!res.ok) {\r\n throw new Error(`Fetch work packet failed: ${await describeQuikTrackFailure(res)}`);\r\n }\r\n const body = (await res.json()) as PacketResponse;\r\n if (body.success !== true) {\r\n throw new Error(\"Fetch work packet failed: response did not carry success:true\");\r\n }\r\n return body.data;\r\n}\r\n", "import { appendFileSync, mkdirSync } from \"node:fs\";\r\n\r\n/** Phase 0 has no agent. This proves the loop end to end without touching real source, which would\r\n * risk breaking the build for a reason nobody would connect back to QuikPilot. Verbatim carry-over\r\n * from the inlined workflow \u2014 real codegen is separate, not-yet-built work. */\r\nexport function writePhase0Marker(runId: string): void {\r\n mkdirSync(\".quikpilot\", { recursive: true });\r\n appendFileSync(\".quikpilot/phase0-marker.txt\", `QuikPilot Phase 0 skeleton marker for run ${runId}\\n`);\r\n}\r\n", "import { readdirSync, rmSync, statSync } from \"node:fs\";\r\nimport { join } from \"node:path\";\r\n\r\nconst SKIP_DIRS = new Set([\"node_modules\", \".git\"]);\r\n\r\nfunction walkForJUnitByName(dir: string): string | null {\r\n let entries: string[];\r\n try {\r\n entries = readdirSync(dir);\r\n } catch {\r\n return null;\r\n }\r\n for (const entry of entries) {\r\n if (SKIP_DIRS.has(entry)) continue;\r\n const full = join(dir, entry);\r\n let stat;\r\n try {\r\n stat = statSync(full);\r\n } catch {\r\n continue;\r\n }\r\n if (stat.isDirectory()) {\r\n const found = walkForJUnitByName(full);\r\n if (found) return found;\r\n } else if (/^junit.*\\.xml$/.test(entry)) {\r\n return full;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction firstXmlIn(dir: string, namePattern: RegExp): string | null {\r\n let entries: string[];\r\n try {\r\n entries = readdirSync(dir);\r\n } catch {\r\n return null;\r\n }\r\n const match = entries.find((e) => namePattern.test(e));\r\n return match ? join(dir, match) : null;\r\n}\r\n\r\n/** QtPilotConfig has no column for the report path, so this is a convention over a short list of\r\n * common locations rather than a configurable setting. A project that writes its report elsewhere\r\n * reports nothing and finds out from the log \u2014 a missing artefact must not fail the run. Checked\r\n * in the same priority the original `find` clause listed them, though exact traversal order was\r\n * never guaranteed there either. */\r\nexport function findJUnitReport(cwd = process.cwd()): string | null {\r\n return (\r\n walkForJUnitByName(cwd) ??\r\n firstXmlIn(join(cwd, \"test-results\"), /\\.xml$/) ??\r\n firstXmlIn(join(cwd, \"reports\"), /^junit.*\\.xml$/) ??\r\n firstXmlIn(join(cwd, \"target\", \"surefire-reports\"), /\\.xml$/)\r\n );\r\n}\r\n\r\nfunction buildCiUrl(serverUrl: string, repository: string, githubRunId: string): string {\r\n return `${serverUrl}/${repository}/actions/runs/${githubRunId}`;\r\n}\r\n\r\n/** The ingest route's summary of automationIds present in the JUnit report that matched no\r\n * `QtTestCase` \u2014 computed and returned by QuikTrack's own ingest today (`IngestSummary.unmatched`\r\n * in `apps/quiktrack/lib/services/testIngest.ts`), but silently discarded here until QUIKTR-1374:\r\n * a bracket/format mismatch (or any other ingest failure) produced zero matches on every run with\r\n * nothing on screen to say why. */\r\nexport interface ReportToQuikTestResult {\r\n unmatched: Array<{ automationId: string; count: number }>;\r\n}\r\n\r\n/** One warning naming every unmatched id and its count \u2014 `null` when there's nothing to report,\r\n * so the caller can push straight into `warnings` without an extra length check. */\r\nexport function describeUnmatchedAutomationIds(unmatched: ReportToQuikTestResult[\"unmatched\"]): string | null {\r\n if (unmatched.length === 0) return null;\r\n const named = unmatched.map((u) => `${u.automationId} (\u00D7${u.count})`).join(\", \");\r\n return `${unmatched.length} generated test result(s) did not match any test case: ${named} \u2014 check the automationId format.`;\r\n}\r\n\r\n/** Best-effort \u2014 every branch here is designed to never throw, matching the bash step's own\r\n * `if: always()` + internally tolerant logic (null resultsUrl and \"no report found\" are both the\r\n * common path in Phase 0, not edge cases \u2014 D19). Deletes the report after a successful POST so the\r\n * guardrail's `git add -A` never commits a CI artefact into the customer's pull request. Returns\r\n * `null` whenever nothing was actually reported (no results URL, no report found, or the POST\r\n * itself failed) \u2014 the caller folds a non-null `unmatched` array into the run's warnings. */\r\nexport async function reportToQuikTest(params: {\r\n resultsUrl: string | null | undefined;\r\n runToken: string;\r\n githubServerUrl: string;\r\n githubRepository: string;\r\n githubRunId: string;\r\n cwd?: string;\r\n}): Promise<ReportToQuikTestResult | null> {\r\n const { resultsUrl, runToken, githubServerUrl, githubRepository, githubRunId, cwd } = params;\r\n if (!resultsUrl) {\r\n console.log(\"packet.quikTest is null \u2014 this run has no QuikTest run to report into.\");\r\n return null;\r\n }\r\n const report = findJUnitReport(cwd);\r\n if (!report) {\r\n console.warn(\"::warning::QuikPilot found no JUnit report \u2014 no results reported to QuikTest.\");\r\n return null;\r\n }\r\n try {\r\n console.log(`reporting ${report}`);\r\n const ciUrl = buildCiUrl(githubServerUrl, githubRepository, githubRunId);\r\n const { readFileSync } = await import(\"node:fs\");\r\n const body = readFileSync(report);\r\n // QUIKTR-1082 \u2014 this runner is the only caller QuikPilot controls; requesting \"bracket\"\r\n // explicitly here changes nothing for any other QuikTest customer's own ingestion.\r\n const url = `${resultsUrl}?ciUrl=${encodeURIComponent(ciUrl)}&automationIdFormat=bracket`;\r\n const res = await fetch(url, {\r\n method: \"POST\",\r\n headers: { Authorization: `Bearer ${runToken}`, \"Content-Type\": \"text/xml\" },\r\n body,\r\n });\r\n if (!res.ok) {\r\n throw new Error(`QuikTest report POST failed: ${res.status} ${res.statusText}`);\r\n }\r\n rmSync(report, { force: true });\r\n // QUIKTR-1374 \u2014 read the ingest summary instead of discarding it. Best-effort: the POST\r\n // itself already succeeded (res.ok), so a body that isn't the expected JSON shape must never\r\n // turn a working report into a failure \u2014 it just means no warning can be derived from it.\r\n let unmatched: ReportToQuikTestResult[\"unmatched\"] = [];\r\n try {\r\n const json = (await res.json()) as { data?: { unmatched?: ReportToQuikTestResult[\"unmatched\"] } };\r\n unmatched = json.data?.unmatched ?? [];\r\n } catch {\r\n // Not JSON, or not the expected shape \u2014 leave unmatched empty.\r\n }\r\n return { unmatched };\r\n } catch (err) {\r\n console.warn(`::warning::QuikPilot failed to report results to QuikTest: ${err instanceof Error ? err.message : String(err)}`);\r\n return null;\r\n }\r\n}\r\n", "import { readFileSync } from \"node:fs\";\r\nimport { runTestCommand, runTestCommandAsync, type TestOutcome } from \"./commands\";\r\nimport { findJUnitReport } from \"./quiktest\";\r\n\r\n/**\r\n * QUIKTR-1036 \u2014 once codegen writes real code, a failing test after it probably means the\r\n * generated code (or a generated test) is wrong. Blocking unconditionally would break any repo\r\n * with pre-existing failures, so a run captures a \"before\" snapshot (the baseline, run against the\r\n * untouched tree) and an \"after\" snapshot (post-codegen), and diffs them per test:\r\n * passed before, fails now -> regression, block\r\n * absent before, fails now -> new failure, block (codegen writing test files makes this the\r\n * common case, not an edge case \u2014 a different diagnosis from a\r\n * regression, so it's reported separately)\r\n * failed before, fails now -> not ours, stays soft (the case the soft-fail existed for)\r\n *\r\n * Only a minimal <testcase> scanner \u2014 not a full XML parser like\r\n * apps/quiktrack/lib/test/resultParser.ts, which extracts failure messages/stack traces across\r\n * multiple formats for QuikTest's ingest API and can't be imported here anyway (this package is\r\n * published outside the monorepo \u2014 same reason packet.ts duplicates its types instead of sharing\r\n * them). classname::name (or bare name with no classname) is an internal-only identity, used only\r\n * to match a test between two local runs \u2014 it never needs to match QuikTest's own configurable\r\n * automationIdFormat.\r\n */\r\nexport interface TestSnapshot {\r\n outcome: TestOutcome;\r\n /** testId -> passed. null when no JUnit report was found or it couldn't be parsed \u2014 the\r\n * fallback used when either snapshot lacks this is to stay soft, same as today, since blocking\r\n * with no way to name what broke would contradict the whole point of the classification. */\r\n results: Map<string, boolean> | null;\r\n /**\r\n * QUIKTR-1029 self-heal prerequisite 1 (Suyash, 2026-09-22 \u2014 \"buildable now and useful on its\r\n * own: today a regression blocks the push without saying why the test failed\"). testId -> a\r\n * bounded failure message, only for tests that failed IN THIS SNAPSHOT. Deliberately a second,\r\n * optional map rather than widening `results`'s value type: `checkForRegressions`'s diffing\r\n * logic (and every existing test constructing a `TestSnapshot` fixture directly) stays untouched\r\n * \u2014 this is additive context, not a new signal the diff itself reasons about.\r\n */\r\n failureText?: Map<string, string>;\r\n /**\r\n * QUIKTR-1315 \u2014 the file paths the test runner itself discovered, read from each `<testsuite>`'s\r\n * `file` attribute and each `<testcase>`'s `file`/`classname` attributes, verbatim (backslashes\r\n * normalised to forward slashes only). `null` when no report was found \u2014 same \"can't tell, don't\r\n * block\" posture as `results`. An empty (non-null) set means a report existed but carried no\r\n * file-shaped attribution at all \u2014 also treated as \"can't tell\" by `testPlacementCheck.ts`, not as\r\n * \"nothing was discovered.\" Best-effort only: `classname` is a real file path for Vitest and\r\n * derivable for pytest, but not guaranteed for Jest (depends on `jest-junit` config) or Go\r\n * (typically package-, not file-, scoped) \u2014 see `testPlacementCheck.ts`'s own docblock for how\r\n * this is matched loosely rather than exactly for that reason.\r\n */\r\n discoveredFiles?: Set<string> | null;\r\n /**\r\n * QUIKTR-1315 \u2014 every `[<automationId>]` leading-bracket token found in a `<testcase>` name,\r\n * duplicating `apps/quiktrack/lib/test/resultParser.ts`'s `LEADING_BRACKET_RE` convention (this\r\n * package can't import that file \u2014 published outside the monorepo). `null` when no report was\r\n * found, same as `discoveredFiles`.\r\n */\r\n discoveredAutomationIds?: Set<string> | null;\r\n}\r\n\r\nconst TESTCASE_RE = /<testcase\\b([^>]*?)(?:\\/>|>([\\s\\S]*?)<\\/testcase>)/g;\r\nconst NAME_ATTR_RE = /\\bname=\"([^\"]*)\"/;\r\nconst CLASSNAME_ATTR_RE = /\\bclassname=\"([^\"]*)\"/;\r\nconst FAILURE_CHILD_RE = /<failure\\b|<error\\b/;\r\n\r\n// QUIKTR-1315 \u2014 `<testsuite>` open tags only (not self-closed the way an empty `<testcase/>` can\r\n// be): a suite always wraps at least its own attributes even with zero testcases inside.\r\nconst TESTSUITE_OPEN_RE = /<testsuite\\b([^>]*?)>/g;\r\nconst FILE_ATTR_RE = /\\bfile=\"([^\"]*)\"/;\r\n// QUIKTR-1082/1374's convention, duplicated \u2014 see this file's module docblock and\r\n// `TestSnapshot`'s `discoveredAutomationIds` field for why this can't just import\r\n// resultParser.ts instead. Matches QuikPilot's own token shape (QP-<PROJECT-KEY>-<issue>-<n>)\r\n// anywhere in the name rather than requiring it at the start \u2014 a bare \"[Smoke]\"-style tag can\r\n// never satisfy this shape, so QUIKTR-1082's \"don't match an unrelated bracketed tag\" safety\r\n// property holds without depending on position, which Vitest's JUnit reporter doesn't preserve.\r\nconst QP_TOKEN_BRACKET_RE = /\\[(QP-[A-Z][A-Z0-9]*-\\d+-\\d+)\\]/;\r\n\r\nfunction normalizeSlashes(path: string): string {\r\n return path.replace(/\\\\/g, \"/\");\r\n}\r\n\r\n/** The `<failure>`/`<error>` child itself, within one `<testcase>`'s already-isolated body. */\r\nconst FAILURE_TAG_RE = /<(?:failure|error)\\b([^>]*?)(?:\\/>|>([\\s\\S]*?)<\\/(?:failure|error)>)/;\r\nconst FAILURE_MESSAGE_ATTR_RE = /\\bmessage=\"([^\"]*)\"/;\r\n\r\n/** Console/PR-message budget, not a data-integrity bound \u2014 this is display text, never re-parsed. */\r\nconst MAX_FAILURE_TEXT = 500;\r\n\r\n/** The five entities the JUnit writers in real use (Vitest, Jest, pytest, go-junit-report) all\r\n * produce \u2014 not a general XML-unescape, same \"minimal scanner, not a parser\" posture as the rest\r\n * of this file. Literal `&quot;`/`&amp;` reaching a console log or a PR body reads as broken. */\r\nfunction unescapeXmlEntities(s: string): string {\r\n return s.replace(/&lt;/g, \"<\").replace(/&gt;/g, \">\").replace(/&quot;/g, '\"').replace(/&apos;/g, \"'\").replace(/&amp;/g, \"&\");\r\n}\r\n\r\n/** `message=\"...\"` when present (short, what every framework puts the assertion diff in);\r\n * otherwise the tag's own body text (stack trace), truncated \u2014 never both, never neither if\r\n * either exists. `null` when the testcase body has no `<failure>`/`<error>` at all, or the tag\r\n * carries no text either way (both attrs and body empty \u2014 seen from at least one Go harness). */\r\nfunction extractFailureText(testcaseBody: string): string | null {\r\n const tag = FAILURE_TAG_RE.exec(testcaseBody);\r\n if (!tag) return null;\r\n const [, attrs = \"\", inner = \"\"] = tag;\r\n const raw = (FAILURE_MESSAGE_ATTR_RE.exec(attrs)?.[1] ?? inner).trim();\r\n if (!raw) return null;\r\n const text = unescapeXmlEntities(raw);\r\n return text.length > MAX_FAILURE_TEXT ? `${text.slice(0, MAX_FAILURE_TEXT)}\u2026` : text;\r\n}\r\n\r\ninterface JUnitParseResult {\r\n outcomes: Map<string, boolean>;\r\n failureText: Map<string, string>;\r\n discoveredFiles: Set<string>;\r\n discoveredAutomationIds: Set<string>;\r\n}\r\n\r\nfunction parseJUnitOutcomes(xml: string): JUnitParseResult {\r\n const outcomes = new Map<string, boolean>();\r\n const failureText = new Map<string, string>();\r\n const discoveredFiles = new Set<string>();\r\n const discoveredAutomationIds = new Set<string>();\r\n\r\n TESTSUITE_OPEN_RE.lastIndex = 0;\r\n let suiteMatch: RegExpExecArray | null;\r\n while ((suiteMatch = TESTSUITE_OPEN_RE.exec(xml))) {\r\n const file = FILE_ATTR_RE.exec(suiteMatch[1])?.[1];\r\n if (file) discoveredFiles.add(normalizeSlashes(file));\r\n }\r\n\r\n let match: RegExpExecArray | null;\r\n TESTCASE_RE.lastIndex = 0;\r\n while ((match = TESTCASE_RE.exec(xml))) {\r\n const [, attrs, body = \"\"] = match;\r\n const name = NAME_ATTR_RE.exec(attrs)?.[1];\r\n if (!name) continue;\r\n const classname = CLASSNAME_ATTR_RE.exec(attrs)?.[1];\r\n const id = classname ? `${classname}::${name}` : name;\r\n const failed = FAILURE_CHILD_RE.test(body);\r\n outcomes.set(id, !failed);\r\n if (failed) {\r\n const text = extractFailureText(body);\r\n if (text) failureText.set(id, text);\r\n }\r\n const file = FILE_ATTR_RE.exec(attrs)?.[1];\r\n if (file) discoveredFiles.add(normalizeSlashes(file));\r\n if (classname) discoveredFiles.add(normalizeSlashes(classname));\r\n const bracket = QP_TOKEN_BRACKET_RE.exec(name)?.[1];\r\n if (bracket) discoveredAutomationIds.add(bracket);\r\n }\r\n return { outcomes, failureText, discoveredFiles, discoveredAutomationIds };\r\n}\r\n\r\nfunction readJUnitOutcomes(cwd: string): JUnitParseResult | null {\r\n const report = findJUnitReport(cwd);\r\n if (!report) return null;\r\n try {\r\n return parseJUnitOutcomes(readFileSync(report, \"utf8\"));\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport function captureTestSnapshot(command: string | null, cwd = process.cwd()): TestSnapshot {\r\n const outcome = runTestCommand(command);\r\n const parsed = readJUnitOutcomes(cwd);\r\n return {\r\n outcome,\r\n results: parsed?.outcomes ?? null,\r\n failureText: parsed?.failureText,\r\n discoveredFiles: parsed?.discoveredFiles ?? null,\r\n discoveredAutomationIds: parsed?.discoveredAutomationIds ?? null,\r\n };\r\n}\r\n\r\nexport async function captureBaselineSnapshot(\r\n command: string | null,\r\n cwd = process.cwd(),\r\n): Promise<TestSnapshot> {\r\n const outcome = await runTestCommandAsync(command);\r\n const parsed = readJUnitOutcomes(cwd);\r\n return {\r\n outcome,\r\n results: parsed?.outcomes ?? null,\r\n failureText: parsed?.failureText,\r\n discoveredFiles: parsed?.discoveredFiles ?? null,\r\n discoveredAutomationIds: parsed?.discoveredAutomationIds ?? null,\r\n };\r\n}\r\n\r\nexport interface RegressionCheck {\r\n blocked: boolean;\r\n regressions: string[];\r\n newFailures: string[];\r\n preExisting: string[];\r\n /** testId -> bounded failure text, for whichever `regressions`/`newFailures` entries had one in\r\n * the AFTER snapshot (the failure that actually blocks the push \u2014 the baseline's own failure\r\n * text, if any, is irrelevant here). Always present, possibly empty \u2014 never omitted, so a\r\n * caller never has to guard its absence the way `results` itself still requires. */\r\n failureText: Map<string, string>;\r\n}\r\n\r\nexport function checkForRegressions(baseline: TestSnapshot, after: TestSnapshot): RegressionCheck {\r\n if (!baseline.results || !after.results) {\r\n return { blocked: false, regressions: [], newFailures: [], preExisting: [], failureText: new Map() };\r\n }\r\n\r\n const regressions: string[] = [];\r\n const newFailures: string[] = [];\r\n const preExisting: string[] = [];\r\n const failureText = new Map<string, string>();\r\n const afterFailureText = after.failureText;\r\n\r\n for (const [testId, passed] of after.results) {\r\n if (passed) continue;\r\n const before = baseline.results.get(testId);\r\n if (before === true) {\r\n regressions.push(testId);\r\n const text = afterFailureText?.get(testId);\r\n if (text) failureText.set(testId, text);\r\n } else if (before === false) {\r\n preExisting.push(testId);\r\n } else {\r\n newFailures.push(testId);\r\n const text = afterFailureText?.get(testId);\r\n if (text) failureText.set(testId, text);\r\n }\r\n }\r\n\r\n return { blocked: regressions.length > 0 || newFailures.length > 0, regressions, newFailures, preExisting, failureText };\r\n}\r\n\r\n/** Regressions and new failures named separately \u2014 conflating them is the thing that wastes\r\n * someone's morning (they're different diagnoses: one means the generated code broke something\r\n * that worked, the other means a generated test doesn't pass yet). Pre-existing failures are\r\n * noted, not hidden, so the message doesn't read as if they were silently dropped.\r\n *\r\n * QUIKTR-1029 self-heal prerequisite 1 \u2014 each named test now carries its failure text inline\r\n * when one was captured, so a run that blocks says WHY, not only WHAT. */\r\nexport function describeRegressions(check: RegressionCheck): string {\r\n const withText = (id: string) => {\r\n const text = check.failureText.get(id);\r\n return text ? `${id} (${text})` : id;\r\n };\r\n const parts: string[] = [];\r\n if (check.regressions.length > 0) {\r\n parts.push(\r\n `${check.regressions.length} regression(s) (passed before, now fail): ${check.regressions.map(withText).join(\", \")}`,\r\n );\r\n }\r\n if (check.newFailures.length > 0) {\r\n parts.push(\r\n `${check.newFailures.length} new failure(s) (did not exist before): ${check.newFailures.map(withText).join(\", \")}`,\r\n );\r\n }\r\n if (check.preExisting.length > 0) {\r\n parts.push(`${check.preExisting.length} pre-existing failure(s), unrelated to this change, not blocking`);\r\n }\r\n return parts.join(\"; \");\r\n}\r\n", "import { readFileSync } from \"node:fs\";\r\nimport type { CodegenFileResult } from \"./codegen\";\r\nimport type { PilotTarget } from \"./targeting\";\r\n\r\n/**\r\n * QUIKTR-1081 \u2014 QUIKSPL-5's PR #22 fixed the reported bug in src/validation.js and also silently\r\n * added an undeclared PUT endpoint to src/server.js that returned success while updating nothing.\r\n * Tests passed, the dependency check passed, and nothing compared what codegen actually added\r\n * against the design's own declared `apiChanges` \u2014 because nothing did.\r\n *\r\n * Same \"minimal, not exhaustive\" standard as dependencyCheck.ts's import scanner and\r\n * regressionCheck.ts's JUnit scanner, for the same reason: this package is dependency-free,\r\n * bundled into a single CLI file with no externals, published outside the monorepo, and the\r\n * target repository is arbitrary \u2014 no real per-framework route parser is on the table. This is a\r\n * same-line METHOD+PATH text heuristic, a tripwire against the ticket's own incident (method and\r\n * path both named on the documenting comment's line), not a route parser for every framework a\r\n * customer repo might use. It will not catch a Next.js-style `export function PUT(...)` whose path\r\n * comes from file location rather than an in-file string \u2014 ROUTE_EXPORT_RE below covers that one\r\n * export shape specifically, matched by method presence alone since it has no in-file path to\r\n * compare.\r\n *\r\n * \"Exported symbols\" (the ticket's own words) is deliberately narrowed to route-handler-shaped\r\n * exports here, not any new exported symbol: an arbitrary new exported helper is routine,\r\n * legitimate refactoring, and checking every export against free-text `apiChanges` would produce\r\n * exactly the kind of false-positive noise this package's checks otherwise avoid.\r\n */\r\nexport interface ScopeViolation {\r\n file: string;\r\n method: string;\r\n path: string;\r\n}\r\n\r\nexport interface ScopeCheck {\r\n blocked: boolean;\r\n violations: ScopeViolation[];\r\n}\r\n\r\ninterface RouteMention {\r\n method: string;\r\n path: string;\r\n}\r\n\r\nconst ROUTE_METHOD_RE = /\\b(GET|POST|PUT|PATCH|DELETE)\\b/i;\r\nconst ROUTE_PATH_RE = /\\/[A-Za-z0-9_\\-{}[\\]]+(?:\\/[A-Za-z0-9_\\-:{}[\\]]+)+/;\r\nconst ROUTE_EXPORT_RE = /\\bexport\\s+(?:async\\s+)?function\\s+(GET|POST|PUT|PATCH|DELETE)\\s*\\(/;\r\n\r\n/** No in-file path \u2014 a Next.js-style route handler's path comes from where the file lives, not a\r\n * string in it. Matched against `apiChanges` by method presence alone (see `surfaceCovers`). */\r\nconst NO_PATH = \"(this file's route)\";\r\n\r\nfunction detectMentions(text: string): RouteMention[] {\r\n const found: RouteMention[] = [];\r\n for (const line of text.split(\"\\n\")) {\r\n const methodMatch = ROUTE_METHOD_RE.exec(line);\r\n const pathMatch = ROUTE_PATH_RE.exec(line);\r\n if (methodMatch && pathMatch) {\r\n found.push({ method: methodMatch[1].toUpperCase(), path: pathMatch[0] });\r\n }\r\n const exportMatch = ROUTE_EXPORT_RE.exec(line);\r\n if (exportMatch) {\r\n found.push({ method: exportMatch[1].toUpperCase(), path: NO_PATH });\r\n }\r\n }\r\n return found;\r\n}\r\n\r\n/** `:id`, `{id}`, `[id]` all become `*` so a declared surface and a detected mention compare equal\r\n * regardless of the exact param name either side happens to use. */\r\nfunction normalizePath(path: string): string {\r\n return path.replace(/:[A-Za-z0-9_]+|\\{[^}]+\\}|\\[[^\\]]+\\]/g, \"*\");\r\n}\r\n\r\nfunction surfaceCovers(surface: string, mention: RouteMention): boolean {\r\n if (!new RegExp(`\\\\b${mention.method}\\\\b`, \"i\").test(surface)) return false;\r\n if (mention.path === NO_PATH) return true; // method presence is all a route-export mention has\r\n const declaredPath = normalizePath(surface);\r\n const mentionPath = normalizePath(mention.path);\r\n return declaredPath.includes(mentionPath) || mentionPath.includes(declaredPath);\r\n}\r\n\r\n/** Lines present in `after` but not in `before` \u2014 a set difference, not a positional diff (code\r\n * can shift line numbers around an addition). Good enough to separate \"genuinely new this run\"\r\n * from \"was already there\" without a real diff algorithm, same spirit as this package's other\r\n * scanners. */\r\nfunction addedLines(before: string, after: string): string {\r\n const beforeLines = new Set(before.split(\"\\n\"));\r\n return after\r\n .split(\"\\n\")\r\n .filter((line) => !beforeLines.has(line))\r\n .join(\"\\n\");\r\n}\r\n\r\nexport function checkApiScope(\r\n results: CodegenFileResult[],\r\n targets: PilotTarget[],\r\n apiChanges: { surface: string; change: string; reason: string }[],\r\n): ScopeCheck {\r\n const targetsByPath = new Map(targets.map((t) => [t.path, t]));\r\n const violations: ScopeViolation[] = [];\r\n\r\n for (const { targetPath, newContent } of results) {\r\n const target = targetsByPath.get(targetPath);\r\n const isNewFile = target?.kind === \"NEW_FILE\";\r\n\r\n let scanned: string;\r\n if (isNewFile) {\r\n scanned = newContent;\r\n } else {\r\n let currentContent: string;\r\n try {\r\n currentContent = readFileSync(targetPath, \"utf8\");\r\n } catch {\r\n currentContent = \"\";\r\n }\r\n scanned = addedLines(currentContent, newContent);\r\n }\r\n\r\n for (const mention of detectMentions(scanned)) {\r\n if (!apiChanges.some((c) => surfaceCovers(c.surface, mention))) {\r\n violations.push({ file: targetPath, method: mention.method, path: mention.path });\r\n }\r\n }\r\n }\r\n\r\n return { blocked: violations.length > 0, violations };\r\n}\r\n\r\nexport function describeScopeViolations(check: ScopeCheck): string {\r\n return check.violations\r\n .map((v) => `${v.file} adds ${v.method} ${v.path}, not declared in the design's API changes`)\r\n .join(\"; \");\r\n}\r\n", "import { resolve, relative, isAbsolute } from \"node:path\";\r\nimport { matchesDeniedPath } from \"./deniedPaths\";\r\nimport { listFiles } from \"./git\";\r\nimport { checkHardFailure, unwrapExecute } from \"./envelope\";\r\nimport type { PilotPacket } from \"./packet\";\r\nimport { fetchWithRetry } from \"./retryFetch\";\r\n\r\n/**\r\n * QUIKTR-1035 \u2014 `pilot.targeting`: turns the design plus a file listing into real per-file\r\n * instructions, replacing codegen.ts's old planStepsFromDesign entirely. Proven live by the AI\r\n * Runtime against a real 624-file QuikChat listing before this was wired in.\r\n *\r\n * QUIKTR-1083 (\u00A715) \u2014 the versioned test-target contract. `contractVersion: \"test-targets-1\"` is\r\n * sent unconditionally: per \u00A715.6 the unversioned path is only \"exactly today's behaviour\" for a\r\n * caller that never asks for the new shape, and this runner always wants it once it ships.\r\n */\r\nconst CONTRACT_VERSION = \"test-targets-1\";\r\n\r\nexport type TargetKind = \"EXISTING\" | \"NEW_FILE\";\r\n\r\nexport interface PilotTarget {\r\n path: string;\r\n kind: TargetKind;\r\n planStepsImplemented: string[];\r\n // Context contract change \u2014 pilot.targeting now names, per target, which other files\r\n // pilot.codegen should read before writing this one (\"to write this file, read these\").\r\n // codegen.ts validates and reads these; absent/empty means no context, no fallback.\r\n contextPaths?: string[];\r\n /** \u00A715.3 \u2014 present only on a test target: the automation IDs (not database ids \u2014 see\r\n * \u00A715.3's own naming rationale) this target's generated file must cover. codegen.ts forwards\r\n * only the matching `requiredTests` subset for a target carrying this. */\r\n automationIds?: string[];\r\n}\r\n\r\n/** \u00A715.3 amendment 1 \u2014 a case with no behaviour (given/when/then all null) is named here instead\r\n * of silently dropped; the model has no discretion over which cases land here vs. in a target's\r\n * `automationIds` (completeness is enforced on the runtime side). Informational on this side \u2014\r\n * folded into `run.ts`'s `warnings`, never blocking. */\r\nexport interface SkippedCase {\r\n automationId: string;\r\n reason: \"NO_BEHAVIOUR\";\r\n}\r\n\r\nexport type TargetingResult =\r\n | { outcome: \"TARGETED\"; targets: PilotTarget[]; skippedCases: SkippedCase[] }\r\n | { outcome: \"NO_TARGET\"; reason: string | null };\r\n\r\ninterface TargetingResponse {\r\n outcome?: \"TARGETED\" | \"NO_TARGET\";\r\n targets?: {\r\n path: string;\r\n kind: string;\r\n planStepsImplemented: string[];\r\n contextPaths?: string[];\r\n automationIds?: string[];\r\n }[];\r\n skippedCases?: SkippedCase[];\r\n noTargetReason?: string;\r\n}\r\n\r\n/**\r\n * Tracked files under the packet's workspace root, or the whole checkout when it's null\r\n * (QUIKTR-1033) \u2014 never normalised to \".\" at the packet layer itself, only here where a concrete\r\n * pathspec is actually needed. An unscoped listing on a large monorepo is ~210k tokens, which fits\r\n * one provider and breaks the fallback chain \u2014 see workspaceRoot's own doc comment on PilotPacket.\r\n */\r\nexport function listWorkspaceFiles(workspaceRoot: string | null): string[] {\r\n return listFiles(workspaceRoot ?? \".\");\r\n}\r\n\r\n/**\r\n * VALIDATION IS OURS \u2014 the AI Runtime's schema doesn't guarantee a path is actually safe to write.\r\n * An EXISTING target must already be in the checkout; a NEW_FILE target must resolve inside the\r\n * workspace root. Either failure throws \u2014 a dropped target is a plan half-executed, and run.ts's\r\n * existing top-level try/catch already turns this into the same hard failure any other pre-setup\r\n * step gets.\r\n */\r\nfunction validateTarget(\r\n target: { path: string; kind: string },\r\n workspaceRoot: string | null,\r\n workspaceListing: Set<string>,\r\n deniedPaths: string[],\r\n): void {\r\n // QUIKTR-1083 (\u00A715.3) \u2014 layer 2 of three: checked here, before any codegen spend, regardless of\r\n // kind. Layer 1 (the runtime's own targeting validator) should already exclude a denied path;\r\n // this does not trust that and re-checks independently.\r\n const denied = matchesDeniedPath(target.path, deniedPaths);\r\n if (denied) {\r\n throw new Error(\r\n `pilot.targeting proposed a target matching a denied path (${denied}): ${target.path}`,\r\n );\r\n }\r\n if (target.kind !== \"EXISTING\" && target.kind !== \"NEW_FILE\") {\r\n throw new Error(`pilot.targeting returned an unknown kind \"${target.kind}\" for ${target.path}`);\r\n }\r\n if (target.kind === \"EXISTING\") {\r\n if (!workspaceListing.has(target.path)) {\r\n throw new Error(\r\n `pilot.targeting named an EXISTING file not found in the checkout: ${target.path}`,\r\n );\r\n }\r\n return;\r\n }\r\n const root = resolve(workspaceRoot ?? \".\");\r\n const rel = relative(root, resolve(target.path));\r\n if (rel.startsWith(\"..\") || isAbsolute(rel)) {\r\n throw new Error(\r\n `pilot.targeting named a NEW_FILE path that escapes the workspace root: ${target.path}`,\r\n );\r\n }\r\n}\r\n\r\nexport async function runTargeting(\r\n gateway: PilotPacket[\"gateway\"],\r\n design: PilotPacket[\"design\"],\r\n workspaceRoot: string | null,\r\n workspaceListing: string[],\r\n requiredTests: PilotPacket[\"requiredTests\"],\r\n deniedPaths: string[],\r\n testDiscovery: PilotPacket[\"testDiscovery\"],\r\n): Promise<TargetingResult> {\r\n // QUIKTR-1069 \u2014 retries a transport-level failure only (502/503/504, a dropped connection); a\r\n // real refusal always arrives as a 200 with the refusal inside the envelope, below.\r\n const contextData: Record<string, unknown> = {\r\n // NESTED, NOT FLATTENED \u2014 a second vocabulary for the design shape is exactly what\r\n // QUIKTR-1034 cost.\r\n workspaceListing,\r\n design,\r\n // QUIKTR-1065/1083 \u2014 requiredTests carried through so targeting can propose a test-file\r\n // target naming which cases it covers (\u00A715.1's Case shape, unchanged).\r\n requiredTests,\r\n // QUIKTR-1083 (\u00A715.6) \u2014 required on the versioned path.\r\n contractVersion: CONTRACT_VERSION,\r\n };\r\n // QUIKTR-1083 (\u00A715.3) \u2014 optional on the wire; omitted rather than sent empty, matching\r\n // codegen.ts's identical treatment.\r\n if (deniedPaths.length > 0) {\r\n contextData.deniedPaths = deniedPaths;\r\n }\r\n // QUIKTR-1315, \u00A719 of the AI Runtime contract \u2014 AGREED (2026-09-28), confirmed deployed and\r\n // live (2026-09-29). ALWAYS sent, never omitted \u2014 \u00A719's whole point is the tagged\r\n // `{ report: \"PRESENT\" | \"ABSENT\" }` shape replacing an absent-vs-empty key distinction, so this\r\n // must not fall back to \"omit when nothing to say\" the way `deniedPaths` does above. The packet\r\n // already resolves this to a real value in every case (never undefined) \u2014 see packet.ts.\r\n contextData.testDiscovery = testDiscovery;\r\n\r\n const res = await fetchWithRetry(`${gateway.baseUrl}/ai/execute`, {\r\n method: \"POST\",\r\n headers: { \"content-type\": \"application/json\", \"x-run-token\": gateway.token },\r\n body: JSON.stringify({\r\n appId: \"quiktrack\",\r\n useCase: \"pilot.targeting\",\r\n expectedOutputType: \"json\",\r\n userPrompt: \"\",\r\n contextData,\r\n }),\r\n });\r\n\r\n if (!res.ok) {\r\n throw new Error(`Targeting call failed: ${res.status} ${res.statusText}`);\r\n }\r\n\r\n // /ai/execute wraps every result in an envelope \u2014 the use-case result lives at\r\n // structuredJson, and a failure can arrive as success:false in an HTTP 200 (see envelope.ts).\r\n // QUIKTR-1083 \u2014 SEMANTIC_MISMATCH/CONTRACT_REJECTED are checked on the raw envelope, before\r\n // unwrapping, same reason codegen.ts's pre-existing CODEGEN_* checks do: unwrapping first would\r\n // throw unwrapExecute's generic success:false error and lose the distinction.\r\n const envelope = await res.json();\r\n checkHardFailure(envelope, \"pilot.targeting\");\r\n const body = unwrapExecute<TargetingResponse>(envelope, \"pilot.targeting\");\r\n\r\n if (body.outcome === \"NO_TARGET\") {\r\n return { outcome: \"NO_TARGET\", reason: body.noTargetReason ?? null };\r\n }\r\n if (body.outcome !== \"TARGETED\" || !Array.isArray(body.targets)) {\r\n throw new Error(`pilot.targeting returned an unexpected shape: ${JSON.stringify(body)}`);\r\n }\r\n\r\n const listing = new Set(workspaceListing);\r\n for (const target of body.targets) {\r\n validateTarget(target, workspaceRoot, listing, deniedPaths);\r\n }\r\n\r\n return {\r\n outcome: \"TARGETED\",\r\n targets: body.targets as PilotTarget[],\r\n skippedCases: body.skippedCases ?? [],\r\n };\r\n}\r\n", "/**\r\n * QUIKTR-1083 (\u00A715.3) \u2014 layer 2 of the three denied-path layers the contract describes: after\r\n * `pilot.targeting` responds, every proposed target's path is checked against `deniedPaths` here,\r\n * before any codegen spend. (Layer 1 is the AI Runtime's own targeting validator; layer 3 is\r\n * `guardrail.ts`'s post-commit check on the actually-staged diff.)\r\n *\r\n * Hand-rolled rather than a `minimatch`/`picomatch` dependency: this package is published\r\n * publicly and carries no secrets or heavy deps on purpose (see workflow-template.ts's own\r\n * docblock), and the denied-path patterns in real use (a dotfile glob under a double-star prefix,\r\n * a workflows directory suffixed with a double star, a bare lockfile name under a double-star\r\n * prefix) never need brace expansion, character classes, or `?` \u2014 only a double star (any depth,\r\n * including none) and a single star (anything but a path separator). A dependency for two glob\r\n * tokens is not worth the weight.\r\n */\r\nfunction globToRegExp(pattern: string): RegExp {\r\n const escaped = pattern\r\n .split(\"\")\r\n .map((c) => (/[.+^${}()|[\\]\\\\]/.test(c) ? `\\\\${c}` : c))\r\n .join(\"\");\r\n // Order matters: the more specific `**/` token first, so the generic `**`/`*` passes below\r\n // don't consume it first and lose the \"zero directories is also a match\" behaviour every\r\n // default pattern (`**/*.env*`, `**/package-lock.json`, ...) actually depends on \u2014 a repo-root\r\n // `.env` must match `**/*.env*` exactly as a nested one does, the same way `.gitignore`'s own\r\n // `**/` prefix works.\r\n const withGlobs = escaped\r\n .replace(/\\*\\*\\//g, \" SLASH \")\r\n .replace(/\\*\\*/g, \" STAR \")\r\n .replace(/\\*/g, \"[^/]*\")\r\n .replace(/ SLASH /g, \"(?:.*/)?\")\r\n .replace(/ STAR /g, \".*\");\r\n return new RegExp(`^${withGlobs}$`);\r\n}\r\n\r\n/** The first pattern `path` matches, or `null`. `path` is repo-relative, matching how every\r\n * `deniedPaths` entry and every target's `path` are already written elsewhere in this package. */\r\nexport function matchesDeniedPath(path: string, patterns: string[]): string | null {\r\n for (const pattern of patterns) {\r\n if (globToRegExp(pattern).test(path)) return pattern;\r\n }\r\n return null;\r\n}\r\n", "import type { PilotTarget } from \"./targeting\";\r\n\r\n/**\r\n * QUIKTR-1315 \u2014 targeting can claim a test case's `automationId` against a SOURCE-file target while\r\n * proposing a separate, empty test-file target alongside it (no plan steps, no automationIds).\r\n * Verified against a real captured AI Runtime sample (`targeting-versioned.json`): the model wrote\r\n * `tests/auth/login.test.ts` with `automationIds: []` and claimed all three cases on\r\n * `src/auth/middleware.ts`/`src/auth/login.ts` instead. When that happens, the generated test lands\r\n * inside a source file the repository's test runner never discovers \u2014 the case has zero real\r\n * coverage even though its id is present in the generated text, and \u00A715's own completeness rule\r\n * (every case appears exactly once) is satisfied regardless.\r\n *\r\n * Two detectors, both using the repository's OWN JUnit report as ground truth for \"which files the\r\n * test runner actually looks at\" \u2014 no naming convention, derived by running the repo's own tooling,\r\n * language-neutral by construction:\r\n *\r\n * `checkTestPlacement` \u2014 BEFORE the write, against the BASELINE report (pre-codegen).\r\n * Scoped to EXISTING targets only: a NEW_FILE test target is never\r\n * in the baseline set because it does not exist yet, so this check\r\n * must never run on one \u2014 a legitimate first test file would be\r\n * indistinguishable from the suspicious case.\r\n * `checkAutomationIdCoverage` \u2014 AFTER the change, against the AFTER report (post-codegen). The\r\n * stronger of the two: catches inverted placement regardless of\r\n * why it happened, including whatever the first check's loose\r\n * file-matching missed.\r\n *\r\n * Both are TRIPWIRES, not proofs \u2014 same posture as this package's other `*Check.ts` scanners\r\n * (`dependencyCheck.ts`, `scopeCheck.ts`): a minimal heuristic against an arbitrary target repo,\r\n * deliberately erring toward under-flagging (fewer false positives blocking a real run) rather than\r\n * over-flagging, since both are hard-failing checks.\r\n */\r\nexport interface TestPlacementViolation {\r\n file: string;\r\n automationIds: string[];\r\n}\r\n\r\nexport interface TestPlacementCheck {\r\n blocked: boolean;\r\n violations: TestPlacementViolation[];\r\n}\r\n\r\n/** A target's path counts as \"discovered\" if it exactly equals, is a suffix of, or has as a suffix,\r\n * any candidate string the JUnit report produced. Loose on purpose: `classname` is a real file path\r\n * for Vitest and derivable for pytest, but not guaranteed for Jest or Go \u2014 see this file's module\r\n * docblock. A tighter, exact-only match would false-positive on every repo where the report's path\r\n * is relative to a different root than the target's own path. */\r\nfunction isDiscovered(targetPath: string, discoveredFiles: Set<string>): boolean {\r\n const normalized = targetPath.replace(/\\\\/g, \"/\");\r\n for (const candidate of discoveredFiles) {\r\n if (candidate === normalized) return true;\r\n if (candidate.endsWith(normalized) || normalized.endsWith(candidate)) return true;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * `discoveredFiles` is the BASELINE run's `TestSnapshot.discoveredFiles` \u2014 `undefined`/`null`/empty\r\n * all mean \"can't tell,\" and the check no-ops rather than blocking on a question it can't answer\r\n * (no baseline report at all, or one with no file-shaped attribution). A repository producing no\r\n * JUnit report gets no detector \u2014 not a gap here, `readiness-panel`'s existing dry-run warning\r\n * (QUIKTR-1084) is what tells the user to fix that.\r\n */\r\nexport function checkTestPlacement(\r\n targets: PilotTarget[],\r\n discoveredFiles: Set<string> | null | undefined,\r\n): TestPlacementCheck {\r\n if (!discoveredFiles || discoveredFiles.size === 0) return { blocked: false, violations: [] };\r\n\r\n const violations: TestPlacementViolation[] = [];\r\n for (const target of targets) {\r\n if (target.kind !== \"EXISTING\") continue;\r\n if (!target.automationIds || target.automationIds.length === 0) continue;\r\n if (!isDiscovered(target.path, discoveredFiles)) {\r\n violations.push({ file: target.path, automationIds: target.automationIds });\r\n }\r\n }\r\n return { blocked: violations.length > 0, violations };\r\n}\r\n\r\nexport function describeTestPlacementViolations(check: TestPlacementCheck): string {\r\n return check.violations\r\n .map(\r\n (v) =>\r\n `${v.file} claims test case(s) ${v.automationIds.join(\", \")} but the repository's own test runner never discovered this file`,\r\n )\r\n .join(\"; \");\r\n}\r\n\r\nexport interface AutomationCoverageCheck {\r\n blocked: boolean;\r\n missing: string[];\r\n}\r\n\r\n/**\r\n * `discoveredAutomationIds` is the AFTER run's `TestSnapshot.discoveredAutomationIds` \u2014\r\n * `undefined`/`null` means \"can't tell\" (no post-codegen report at all), same no-op posture as\r\n * `checkTestPlacement`. An EMPTY (present) set is different and deliberate: it means a report\r\n * existed but nothing in it carried a bracketed id at all, which \u2014 if this run claimed any\r\n * `automationIds` \u2014 is exactly the failure this check exists to catch, so it blocks.\r\n */\r\nexport function checkAutomationIdCoverage(\r\n targets: PilotTarget[],\r\n discoveredAutomationIds: Set<string> | null | undefined,\r\n): AutomationCoverageCheck {\r\n if (discoveredAutomationIds === null || discoveredAutomationIds === undefined) {\r\n return { blocked: false, missing: [] };\r\n }\r\n\r\n const claimed = new Set<string>();\r\n for (const target of targets) {\r\n for (const id of target.automationIds ?? []) claimed.add(id);\r\n }\r\n const missing = [...claimed].filter((id) => !discoveredAutomationIds.has(id));\r\n return { blocked: missing.length > 0, missing };\r\n}\r\n\r\nexport function describeAutomationCoverageViolations(check: AutomationCoverageCheck): string {\r\n return `test case(s) ${check.missing.join(\", \")} have no matching test discovered in the test run \u2014 generated, but never executed`;\r\n}\r\n", "import { describeQuikTrackFailure } from \"./quiktrackError\";\r\n\r\ninterface TokenExchangeResponse {\r\n success: boolean;\r\n data: { runToken: string; expiresAt: string };\r\n}\r\n\r\n/** Exchange a GitHub OIDC ID token for a QuikPilot run token (QUIKTR-805) \u2014 mirrors `packet.ts`'s\r\n * `fetchPacket` shape: bearer auth, `{success,data}` envelope, same error-message style. */\r\nexport async function exchangeForRunToken(tokenUrl: string, oidcToken: string): Promise<string> {\r\n const res = await fetch(tokenUrl, {\r\n method: \"POST\",\r\n headers: { Authorization: `Bearer ${oidcToken}` },\r\n });\r\n if (!res.ok) {\r\n throw new Error(`Exchange run token failed: ${await describeQuikTrackFailure(res)}`);\r\n }\r\n const body = (await res.json()) as TokenExchangeResponse;\r\n if (body.success !== true) {\r\n throw new Error(\"Exchange run token failed: response did not carry success:true\");\r\n }\r\n return body.data.runToken;\r\n}\r\n", "import { reportBack } from \"./callback\";\r\nimport { runCommand, runTestCommand } from \"./commands\";\r\nimport { commitAndPush } from \"./commit\";\r\nimport { buildJudgedByPool, flushCodegenResults, runCodegen } from \"./codegen\";\r\nimport {\r\n checkImportDependencies,\r\n describeDependencyViolations,\r\n readDeclaredDependencies,\r\n resolveAliasPrefixes,\r\n} from \"./dependencyCheck\";\r\nimport type { PilotRunEnv } from \"./env\";\r\nimport { checkGuardrail } from \"./guardrail\";\r\nimport { checkoutTargetBranch } from \"./git\";\r\nimport { exchangeForInstallationToken } from \"./installationToken\";\r\nimport { fetchGithubOidcToken } from \"./oidc\";\r\nimport { describeOverlapWarnings, findOverlappingSteps } from \"./overlapCheck\";\r\nimport { fetchPacket, type PilotPacket } from \"./packet\";\r\nimport { writePhase0Marker } from \"./phase0\";\r\nimport { describeUnmatchedAutomationIds, reportToQuikTest } from \"./quiktest\";\r\nimport { captureBaselineSnapshot, captureTestSnapshot, checkForRegressions, describeRegressions } from \"./regressionCheck\";\r\nimport { checkApiScope, describeScopeViolations } from \"./scopeCheck\";\r\nimport { listWorkspaceFiles, runTargeting } from \"./targeting\";\r\nimport {\r\n checkAutomationIdCoverage,\r\n checkTestPlacement,\r\n describeAutomationCoverageViolations,\r\n describeTestPlacementViolations,\r\n} from \"./testPlacementCheck\";\r\nimport { exchangeForRunToken } from \"./tokenExchange\";\r\n\r\n/**\r\n * QUIKTR-572 \u2014 the run sequence, preserving the original inlined workflow's error semantics exactly:\r\n * Fetch packet / Checkout branch / Setup / Lint / Guardrail are hard failures that skip everything\r\n * remaining except the QuikTest report and the final callback (both ran under `if: always()`\r\n * before). Test alone is soft \u2014 its failure never blocks Guardrail/Commit/Push and never flips the\r\n * final callback to `failed` (QuikTest owns per-test outcomes; captured here only for the log).\r\n *\r\n * QUIKTR-1045 \u2014 Format is soft, same reasoning as Test: a formatting hiccup must not block a\r\n * correct fix. Caught locally at its own call site (not a new commands.ts function) and logged;\r\n * never sets hardFailure, never blocks the Lint/regression-check/Guardrail/Commit/Push that follow.\r\n *\r\n * QUIKTR-805 \u2014 the very first thing the run does is exchange a GitHub OIDC ID token for a run\r\n * token (no QuikPilot credential exists before this). It is folded into the same top-level try as\r\n * every other hard failure, with one deliberate exception: if THIS step fails, there is no run\r\n * token to report failure with either, so reportToQuikTest/reportBack are skipped rather than\r\n * called with nothing to authenticate \u2014 the job's own log is the only record, and the run's\r\n * existing DISPATCHING-expiry sweep is what notices it (same accepted fallback dispatch.ts's own\r\n * docblock documents for its \"RESIDUAL WINDOW\" crash case).\r\n *\r\n * QUIKTR-804 \u2014 immediately before pushing, the run token (already in hand by this point) is\r\n * exchanged for a repo-scoped GitHub installation token, which authenticates the push itself\r\n * instead of the ambient `github.token`. Folded into the EXISTING Guardrail/Commit/Push try block\r\n * below rather than given its own \u2014 a failure here is just another commit/push hard failure, with\r\n * no new edge case: unlike the OIDC exchange above, the run token already exists, so\r\n * reportToQuikTest/reportBack fire normally either way.\r\n */\r\n/** Caller narrows `RunnerEnv` to `PilotRunEnv` first \u2014 `index.ts` branches on `mode` before either\r\n * this or `readinessCheck.ts`'s `runReadinessCheck` is invoked. No default parameter: the old\r\n * `readRunnerEnv()` default returned this shape unconditionally, which is no longer true now\r\n * that `RunnerEnv` is a union (QUIKTR-1084). */\r\nexport async function run(env: PilotRunEnv): Promise<{ hardFailure: boolean }> {\r\n let hardFailure = false;\r\n let packet: PilotPacket | undefined;\r\n let branch: string | undefined;\r\n let runToken: string | undefined;\r\n let warnings: string[] = [];\r\n // QUIKTR-1067 \u2014 hoisted out of the try block's TARGETED branch: commitAndPush\r\n // needs it later, outside that scope, to build a real commit message instead\r\n // of the \"Phase 0 skeleton\" placeholder. Defaults false \u2014 correct for\r\n // NO_TARGET and for any early hard failure, both of which skip commitAndPush\r\n // or must fall back to the marker message anyway.\r\n let targeted = false;\r\n\r\n try {\r\n runToken = await exchangeForRunToken(env.tokenUrl, await fetchGithubOidcToken());\r\n packet = await fetchPacket(env.packetUrl, runToken, env.githubRunId);\r\n checkoutTargetBranch(packet.targetBranch);\r\n\r\n const workspaceListing = listWorkspaceFiles(packet.workspaceRoot);\r\n const targeting = await runTargeting(\r\n packet.gateway,\r\n packet.design,\r\n packet.workspaceRoot,\r\n workspaceListing,\r\n packet.requiredTests,\r\n packet.guardrails.deniedPaths,\r\n packet.testDiscovery,\r\n );\r\n if (targeting.outcome === \"NO_TARGET\") {\r\n // Nothing to write \u2014 a marker commit is more honest than an empty one. Nothing was\r\n // generated, so there's nothing to regress against \u2014 Test stays soft, unchanged.\r\n writePhase0Marker(env.runId);\r\n runCommand(packet.commands.setup, \"Setup\");\r\n runCommand(packet.commands.lint, \"Lint\");\r\n runTestCommand(packet.commands.test);\r\n } else {\r\n targeted = true;\r\n // QUIKTR-1083 (\u00A715.3) \u2014 informational, never blocking: a case with no given/when/then has\r\n // nothing to test, and the runtime already enforces every requiredTests case lands in\r\n // exactly one of a target's automationIds or here, never both, never neither. Folded into\r\n // the same warnings array the overlap-check below already populates and reportBack sends.\r\n if (targeting.skippedCases?.length) {\r\n for (const skipped of targeting.skippedCases) {\r\n const w = `Test case ${skipped.automationId} has no given/when/then \u2014 skipped, no test was written for it.`;\r\n warnings.push(w);\r\n console.warn(`QuikPilot targeting warning (not blocking): ${w}`);\r\n }\r\n }\r\n // QUIKTR-1064 \u2014 cheap: two targets whose planStepsImplemented describe the same rule (the\r\n // real fix is pilot.targeting's prompt, an AI Runtime change, not this package's \u2014 see\r\n // overlapCheck.ts). QUIKTR-1081 \u2014 a literal identical instruction now blocks outright: two\r\n // legitimate halves of one change never share the exact same instruction, and PR #23 merged\r\n // 28 seconds after opening on exactly this signal. A near-identical, reworded pair stays a\r\n // non-blocking warning, logged and reported back, same as before.\r\n const overlaps = findOverlappingSteps(targeting.targets);\r\n const blockingOverlaps = overlaps.filter((o) => o.severity === \"identical\");\r\n const softOverlaps = overlaps.filter((o) => o.severity === \"similar\");\r\n if (softOverlaps.length > 0) {\r\n warnings = describeOverlapWarnings(softOverlaps);\r\n for (const w of warnings) {\r\n console.warn(`QuikPilot targeting warning (not blocking): ${w}`);\r\n }\r\n }\r\n if (blockingOverlaps.length > 0) {\r\n throw new Error(\r\n `QuikPilot's generated plan gives two files identical instructions \u2014 ${describeOverlapWarnings(blockingOverlaps).join(\"; \")}`,\r\n );\r\n }\r\n\r\n // QUIKTR-1036 \u2014 Setup moves here (was after codegen/flush): the baseline test needs\r\n // dependencies installed, but has to run against the PRE-codegen tree. Installing\r\n // dependencies doesn't depend on which application source files exist, so this is safe, and\r\n // running Setup a second time later would undercut \"the baseline costs almost no wall-clock.\"\r\n runCommand(packet.commands.setup, \"Setup\");\r\n\r\n // \u00A718 \u2014 built once, from every case claimed by any target in the run, minus the\r\n // NO_BEHAVIOUR skips above. Sent only to code targets (codegen.ts's own else-branch);\r\n // targeting.skippedCases is the same list already folded into warnings just above.\r\n const judgedByPool = buildJudgedByPool(\r\n packet.requiredTests,\r\n targeting.targets,\r\n targeting.skippedCases ?? [],\r\n );\r\n\r\n // Baseline runs concurrently with codegen's network-bound calls \u2014 codegen writes nothing\r\n // until flushCodegenResults, so there's nothing for the baseline to race against.\r\n const [baseline, results] = await Promise.all([\r\n captureBaselineSnapshot(packet.commands.test),\r\n runCodegen(\r\n packet.gateway,\r\n targeting.targets,\r\n workspaceListing,\r\n packet.requiredTests,\r\n packet.guardrails.deniedPaths,\r\n judgedByPool,\r\n warnings,\r\n ),\r\n ]);\r\n\r\n // QUIKTR-1045 \u2014 checked on the in-memory results, BEFORE anything is\r\n // written: an invented import is never written to disk at all, matching\r\n // the same all-or-nothing treatment every other codegen failure already\r\n // gets here. Hard failure \u2014 a generation that imports a package this\r\n // repository doesn't have can't be trusted.\r\n const depCheck = checkImportDependencies(\r\n results,\r\n readDeclaredDependencies(results, packet.workspaceRoot),\r\n resolveAliasPrefixes(results, packet.workspaceRoot),\r\n );\r\n if (depCheck.blocked) {\r\n throw new Error(\r\n `QuikPilot's generated code imports packages this repository doesn't have \u2014 ${describeDependencyViolations(depCheck)}`,\r\n );\r\n }\r\n\r\n // QUIKTR-1081 \u2014 QUIKSPL-5's PR #22: codegen added an undeclared PUT endpoint alongside the\r\n // fix nobody asked for. Checked here for the same reason as the dependency check above \u2014\r\n // in-memory, before anything is written \u2014 against the design's own declared apiChanges.\r\n const scopeCheck = checkApiScope(results, targeting.targets, packet.design?.apiChanges ?? []);\r\n if (scopeCheck.blocked) {\r\n throw new Error(\r\n `QuikPilot's generated code exceeds the approved design \u2014 ${describeScopeViolations(scopeCheck)}`,\r\n );\r\n }\r\n\r\n // QUIKTR-1315 \u2014 same \"in-memory results, before anything is written\" point as the two checks\r\n // above: a test case claimed against a source-file target instead of the real test file has\r\n // zero coverage even though its id is present, and nothing else here catches that. Uses the\r\n // BASELINE run's JUnit report (already captured above) as the ground truth for which files\r\n // the test runner actually discovers \u2014 never the workspace listing, which includes files the\r\n // runner never looks at.\r\n const placementCheck = checkTestPlacement(targeting.targets, baseline.discoveredFiles);\r\n if (placementCheck.blocked) {\r\n throw new Error(\r\n `QuikPilot's generated tests are not where the test runner will find them \u2014 ${describeTestPlacementViolations(placementCheck)}`,\r\n );\r\n }\r\n\r\n flushCodegenResults(results);\r\n try {\r\n runCommand(packet.commands.format, \"Format\");\r\n } catch (err) {\r\n // QUIKTR-1045 \u2014 soft, like Test: see the file docblock.\r\n console.error(`Format failed (not blocking): ${err instanceof Error ? err.message : String(err)}`);\r\n }\r\n runCommand(packet.commands.lint, \"Lint\");\r\n\r\n const after = captureTestSnapshot(packet.commands.test);\r\n const check = checkForRegressions(baseline, after);\r\n if (check.blocked) {\r\n throw new Error(\r\n `QuikPilot's generated code introduced test failures \u2014 ${describeRegressions(check)}`,\r\n );\r\n }\r\n\r\n // QUIKTR-1315 \u2014 the stronger of the two placement checks: run against the REAL, post-codegen\r\n // JUnit report, so it catches inverted placement regardless of why it happened, including\r\n // whatever checkTestPlacement's baseline-only, loose file-matching missed above.\r\n const coverageCheck = checkAutomationIdCoverage(targeting.targets, after.discoveredAutomationIds);\r\n if (coverageCheck.blocked) {\r\n throw new Error(\r\n `QuikPilot's generated tests were not executed \u2014 ${describeAutomationCoverageViolations(coverageCheck)}`,\r\n );\r\n }\r\n }\r\n } catch (err) {\r\n hardFailure = true;\r\n console.error(err instanceof Error ? err.message : String(err));\r\n }\r\n\r\n if (!runToken) {\r\n console.error(\"No run token \u2014 the OIDC exchange failed before QuikTrack could be reached.\");\r\n return { hardFailure: true };\r\n }\r\n\r\n const quikTestReport = await reportToQuikTest({\r\n resultsUrl: packet?.quikTest?.resultsUrl,\r\n runToken,\r\n githubServerUrl: env.githubServerUrl,\r\n githubRepository: env.githubRepository,\r\n githubRunId: env.githubRunId,\r\n });\r\n // QUIKTR-1374 \u2014 the ingest response already knows which generated automationIds matched no\r\n // test case; read it and surface it here instead of letting it disappear once reportToQuikTest\r\n // returns. Reuses the same warnings -> reportBack path QUIKTR-1064's overlap detection already\r\n // uses, which QuikTrack folds into the run's own event timeline \u2014 no new plumbing.\r\n const unmatchedWarning = quikTestReport ? describeUnmatchedAutomationIds(quikTestReport.unmatched) : null;\r\n if (unmatchedWarning) {\r\n warnings.push(unmatchedWarning);\r\n console.warn(`QuikPilot ingest warning (not blocking): ${unmatchedWarning}`);\r\n }\r\n\r\n if (!hardFailure && packet) {\r\n try {\r\n checkGuardrail(packet.guardrails.deniedPaths);\r\n const installationToken = await exchangeForInstallationToken(\r\n env.installationTokenUrl,\r\n runToken,\r\n );\r\n const result = commitAndPush(\r\n packet.branch,\r\n env.runId,\r\n installationToken,\r\n targeted,\r\n packet.issueKey,\r\n packet.issueTitle,\r\n );\r\n branch = result.branch;\r\n } catch (err) {\r\n hardFailure = true;\r\n console.error(err instanceof Error ? err.message : String(err));\r\n }\r\n }\r\n\r\n await reportBack({\r\n callbackUrl: env.callbackUrl,\r\n runToken,\r\n status: hardFailure ? \"failed\" : \"completed\",\r\n branch,\r\n warnings,\r\n });\r\n\r\n return { hardFailure };\r\n}\r\n", "import type { ReadinessCheckEnv } from \"./env\";\r\nimport { runCommand, runTestCommand } from \"./commands\";\r\nimport { findJUnitReport } from \"./quiktest\";\r\nimport { describeQuikTrackFailure } from \"./quiktrackError\";\r\n\r\n/**\r\n * QUIKTR-1084 \u2014 readiness's \"later session\": actually run the customer's `setupCmd`/`testCmd` and\r\n * report whether the run produced a JUnit report the pilot-run path (`quiktest.ts`) will ever\r\n * find. Checked out onto the default branch already by the workflow's own `actions/checkout` step\r\n * \u2014 no packet, no design, no codegen, no commit, no push.\r\n *\r\n * Both command failures are soft here, deliberately unlike `run.ts`'s hard-fails-on-Setup: a\r\n * repo's setup or test suite failing is not what this check is FOR \u2014 it exists purely to answer\r\n * \"if a real run happened, would QuikTest hear about it,\" which only needs the report to exist,\r\n * not the tests to pass.\r\n */\r\nexport interface ReadinessCheckResult {\r\n setupOk: boolean;\r\n testOk: boolean;\r\n junitFound: boolean;\r\n junitPath: string | null;\r\n}\r\n\r\nexport async function runReadinessCheck(env: ReadinessCheckEnv): Promise<void> {\r\n let setupOk = true;\r\n try {\r\n runCommand(env.setupCmd || null, \"Setup\");\r\n } catch (err) {\r\n setupOk = false;\r\n console.error(err instanceof Error ? err.message : String(err));\r\n }\r\n\r\n const testOutcome = runTestCommand(env.testCmd);\r\n const testOk = testOutcome === \"success\";\r\n\r\n const junitPath = findJUnitReport();\r\n const result: ReadinessCheckResult = {\r\n setupOk,\r\n testOk,\r\n junitFound: junitPath !== null,\r\n junitPath,\r\n };\r\n\r\n try {\r\n const res = await fetch(env.readinessCallbackUrl, {\r\n method: \"POST\",\r\n headers: { Authorization: `Bearer ${env.readinessToken}`, \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify(result),\r\n });\r\n if (!res.ok) {\r\n throw new Error(`Readiness callback POST failed: ${await describeQuikTrackFailure(res)}`);\r\n }\r\n } catch (err) {\r\n // Same \"never throws\" posture as reportToQuikTest/reportBack \u2014 the job's own log is the\r\n // fallback record if even this fails. The expiry sweep readiness.ts will need (mirroring\r\n // dispatch.ts's DISPATCHING-expiry sweep) is what notices a dry run stuck in RUNNING.\r\n console.warn(\r\n `::warning::QuikPilot readiness check failed to report its result: ${err instanceof Error ? err.message : String(err)}`,\r\n );\r\n }\r\n}\r\n", "import { readRunnerEnv } from \"./env\";\r\nimport { run } from \"./run\";\r\nimport { runReadinessCheck } from \"./readinessCheck\";\r\n\r\nconst env = readRunnerEnv();\r\n\r\n// QUIKTR-1084 \u2014 narrows the RunnerEnv union before either branch runs; run()/runReadinessCheck()\r\n// each take only their own variant, not the union, so this `if` is what makes that safe.\r\nconst task =\r\n env.mode === \"readiness_check\"\r\n ? runReadinessCheck(env).then(() => ({ hardFailure: false }))\r\n : run(env);\r\n\r\ntask\r\n .then(({ hardFailure }) => {\r\n process.exitCode = hardFailure ? 1 : 0;\r\n })\r\n .catch((err) => {\r\n // reportBack/the readiness callback itself throwing is the one failure mode neither branch can\r\n // recover from internally \u2014 still exit non-zero so the raw Actions UI shows the run as failed.\r\n console.error(err instanceof Error ? err.message : String(err));\r\n process.exitCode = 1;\r\n });\r\n"],
5
+ "mappings": "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",
6
6
  "names": ["env", "resolve", "import_node_child_process", "import_node_fs", "import_node_path", "env", "import_node_fs", "import_node_fs", "import_node_path", "readFileSync", "import_node_fs", "import_node_fs", "import_node_path", "CONTRACT_VERSION", "env", "env"]
7
7
  }
package/package.json CHANGED
@@ -1,26 +1,26 @@
1
- {
2
- "name": "@quikit/quikpilot-runner",
3
- "version": "8.1.0",
4
- "description": "QuikPilot's CI runner. Fetches the run's work packet, runs setup/lint/test, reports results to QuikTest, enforces path guardrails, commits and pushes, and reports back to QuikTrack. Published publicly (Q12): the workflow file that invokes it lives in the customer's own repository, so this package is how a fix ships without a new pull request into every onboarded repo.",
5
- "bin": {
6
- "quikpilot-runner": "./dist/index.js"
7
- },
8
- "files": [
9
- "dist"
10
- ],
11
- "engines": {
12
- "node": ">=18"
13
- },
14
- "scripts": {
15
- "build": "node build.mjs",
16
- "typecheck": "tsc --noEmit",
17
- "test": "vitest run",
18
- "test:watch": "vitest"
19
- },
20
- "devDependencies": {
21
- "@types/node": "^20.17.10",
22
- "esbuild": "^0.28.1",
23
- "typescript": "^5.3.3",
24
- "vitest": "^4.1.4"
25
- }
26
- }
1
+ {
2
+ "name": "@quikit/quikpilot-runner",
3
+ "version": "8.2.0",
4
+ "description": "QuikPilot's CI runner. Fetches the run's work packet, runs setup/lint/test, reports results to QuikTest, enforces path guardrails, commits and pushes, and reports back to QuikTrack. Published publicly (Q12): the workflow file that invokes it lives in the customer's own repository, so this package is how a fix ships without a new pull request into every onboarded repo.",
5
+ "bin": {
6
+ "quikpilot-runner": "./dist/index.js"
7
+ },
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "engines": {
12
+ "node": ">=18"
13
+ },
14
+ "scripts": {
15
+ "build": "node build.mjs",
16
+ "typecheck": "tsc --noEmit",
17
+ "test": "vitest run",
18
+ "test:watch": "vitest"
19
+ },
20
+ "devDependencies": {
21
+ "@types/node": "^20.17.10",
22
+ "esbuild": "^0.28.1",
23
+ "typescript": "^5.3.3",
24
+ "vitest": "^4.1.4"
25
+ }
26
+ }