@lcv-ideas-software/cross-review 4.0.8 → 4.1.1

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.
@@ -175,7 +175,7 @@ const events = [];
175
175
  const holder = {};
176
176
  const orchestrator = new CrossReviewOrchestrator(config, (event) => {
177
177
  events.push(event.type);
178
- holder.orchestrator?.store.appendEvent(event);
178
+ void holder.orchestrator?.store.appendEvent(event);
179
179
  });
180
180
  holder.orchestrator = orchestrator;
181
181
  const adapterExpectations = [
@@ -260,27 +260,32 @@ const overlappingPem = [
260
260
  pemMarker("END", "RSA PRIVATE KEY"),
261
261
  ].join("\n");
262
262
  assert.equal(redact(`before ${overlappingPem} after`), "before [REDACTED] after");
263
+ // v4.1.0 / F4 security hardening: pre-v4.1.0 LEAKED unterminated PRIVATE
264
+ // KEY blocks (BEGIN without matching END — e.g. truncated logs). v4.1.0
265
+ // redacts from `begin.index` to end-of-string for unterminated blocks.
266
+ // Test was previously pinning the leak as expected behavior; updated to
267
+ // pin the no-leak contract.
263
268
  const unterminatedPem = `${pemMarker("BEGIN", "EC PRIVATE KEY")}\nmissing end`;
264
- assert.equal(redact(unterminatedPem), unterminatedPem);
269
+ assert.equal(redact(unterminatedPem), "[REDACTED]");
265
270
  const completeThenUnterminated = [
266
271
  pemBlock("RSA PRIVATE KEY", "first"),
267
272
  "preserve this middle text",
268
273
  pemMarker("BEGIN", "RSA PRIVATE KEY"),
269
274
  "missing end",
270
275
  ].join("\n");
271
- assert.equal(redact(completeThenUnterminated), [
272
- "[REDACTED]",
273
- "preserve this middle text",
274
- pemMarker("BEGIN", "RSA PRIVATE KEY"),
275
- "missing end",
276
- ].join("\n"));
276
+ assert.equal(redact(completeThenUnterminated), ["[REDACTED]", "preserve this middle text", "[REDACTED]"].join("\n"));
277
+ // v4.1.0 / F4 security hardening: pre-v4.1.0 left these adversarial
278
+ // inputs UNREDACTED (returning the original) because the unterminated-
279
+ // BEGIN branch silently fell through. v4.1.0 redacts from the first
280
+ // BEGIN marker to end-of-string. The performance budget (< 1 s for 2 000
281
+ // nested begins) is preserved.
277
282
  const adversarialPem = `${pemMarker("BEGIN", "EC PRIVATE KEY")}\n${pemMarker("BEGIN", "DSA PRIVATE KEY").repeat(2_000)}`;
278
283
  const adversarialStarted = Date.now();
279
- assert.equal(redact(adversarialPem), adversarialPem);
284
+ assert.equal(redact(adversarialPem), "[REDACTED]");
280
285
  assert.equal(Date.now() - adversarialStarted < 1_000, true);
281
286
  const repeatedSameLabelStarted = Date.now();
282
287
  const repeatedSameLabel = pemMarker("BEGIN", "RSA PRIVATE KEY").repeat(2_000);
283
- assert.equal(redact(repeatedSameLabel), repeatedSameLabel);
288
+ assert.equal(redact(repeatedSameLabel), "[REDACTED]");
284
289
  assert.equal(Date.now() - repeatedSameLabelStarted < 1_000, true);
285
290
  const constructedToken = ["sk", "test", "A".repeat(24)].join("-");
286
291
  assert.equal(redact(`token ${constructedToken}`), "token [REDACTED]");
@@ -569,6 +574,8 @@ assert.equal(checkConvergence(["codex", "claude"], "READY", [fakeReady("codex"),
569
574
  assert.ok(/assert\.equal\(\s*roundState\.outcome,\s*"converged"/.test(runtimeSmokeSrc), 'v3.7.4 / runtime-smoke: must assert roundState.outcome === "converged"');
570
575
  assert.ok(/assert\.equal\(\s*unanimousState\.outcome,\s*"converged"/.test(runtimeSmokeSrc), 'v3.7.4 / runtime-smoke: must assert unanimousState.outcome === "converged"');
571
576
  assert.ok(/assert\.equal\(\s*cancelState\.outcome,\s*"aborted"/.test(runtimeSmokeSrc), 'v3.7.4 / runtime-smoke: must assert cancelState.outcome === "aborted"');
577
+ assert.ok(/TERMINAL_OUTCOMES\s*=\s*new Set\(\["converged", "aborted", "max-rounds"\]\)/.test(runtimeSmokeSrc), "runtime-smoke: pollUntilDone must return on terminal outcome even when job status lags.");
578
+ assert.ok(/POLL_TIMEOUT_MS\s*=\s*60_000/.test(runtimeSmokeSrc), "runtime-smoke: pollUntilDone must allow a 60s deadline so a slow-but-converged stub flow is not reported as timeout.");
572
579
  console.log("[smoke] runtime_smoke_outcome_assert_test: PASS");
573
580
  }
574
581
  const probes = await orchestrator.probeAll();
@@ -601,28 +608,28 @@ assert.match(reviewPrompt, /not as instructions that override/);
601
608
  assert.match(reviewPrompt, /OUT OF SCOPE/);
602
609
  assert.ok(reviewPrompt.indexOf("## Review Focus") < reviewPrompt.indexOf("## Original Task"), "Review Focus must be front-loaded before the task body");
603
610
  assert.doesNotMatch(reviewPrompt, /\/focus\s+services\/billing/);
604
- const evidence = orchestrator.store.attachEvidence(result.session.session_id, {
611
+ const evidence = await orchestrator.store.attachEvidence(result.session.session_id, {
605
612
  label: "smoke evidence",
606
613
  content: "smoke evidence body",
607
614
  content_type: "text/markdown",
608
615
  extension: "md",
609
616
  });
610
617
  assert.equal(fs.existsSync(path.join(config.data_dir, "sessions", result.session.session_id, evidence.path)), true);
611
- const escalated = orchestrator.store.escalateToOperator(result.session.session_id, {
618
+ const escalated = await orchestrator.store.escalateToOperator(result.session.session_id, {
612
619
  reason: "smoke operator escalation",
613
620
  severity: "info",
614
621
  });
615
622
  assert.equal(escalated.operator_escalations?.at(-1)?.severity, "info");
616
- const fresh = orchestrator.store.init("fresh unfinished smoke session", "operator", probes);
623
+ const fresh = await orchestrator.store.init("fresh unfinished smoke session", "operator", probes);
617
624
  assert.equal(SWEEP_MIN_IDLE_MS, 24 * 60 * 60 * 1000);
618
- assert.equal(orchestrator.store.sweepIdle(0, "aborted", "fresh_smoke_stale").length, 0);
625
+ assert.equal((await orchestrator.store.sweepIdle(0, "aborted", "fresh_smoke_stale")).length, 0);
619
626
  assert.equal(orchestrator.store.read(fresh.session_id).outcome, undefined);
620
- const stale = orchestrator.store.init("old unfinished smoke session", "operator", probes);
627
+ const stale = await orchestrator.store.init("old unfinished smoke session", "operator", probes);
621
628
  const staleMetaPath = orchestrator.store.metaPath(stale.session_id);
622
629
  const staleMeta = JSON.parse(fs.readFileSync(staleMetaPath, "utf8"));
623
630
  staleMeta.updated_at = new Date(Date.now() - 25 * 60 * 60 * 1000).toISOString();
624
631
  fs.writeFileSync(staleMetaPath, `${JSON.stringify(staleMeta, null, 2)}\n`, "utf8");
625
- const swept = orchestrator.store.sweepIdle(0, "aborted", "smoke_stale");
632
+ const swept = await orchestrator.store.sweepIdle(0, "aborted", "smoke_stale");
626
633
  assert.equal(swept.some((session) => session.session_id === stale.session_id), true);
627
634
  assert.equal(orchestrator.store.read(stale.session_id).outcome, "aborted");
628
635
  assert.equal(orchestrator.store.read(fresh.session_id).outcome, undefined);
@@ -861,8 +868,8 @@ assert.equal(untilStoppedDefaultBudget.converged, false);
861
868
  assert.equal(untilStoppedDefaultBudget.session.outcome, "max-rounds");
862
869
  assert.equal(untilStoppedDefaultBudget.session.outcome_reason, "budget_exceeded");
863
870
  assert.equal(untilStoppedDefaultBudget.rounds, 1);
864
- const recoverySession = orchestrator.store.init("interrupted smoke session", "operator", probes);
865
- orchestrator.store.markInFlight(recoverySession.session_id, {
871
+ const recoverySession = await orchestrator.store.init("interrupted smoke session", "operator", probes);
872
+ await orchestrator.store.markInFlight(recoverySession.session_id, {
866
873
  round: 1,
867
874
  peers: ["codex"],
868
875
  started_at: new Date().toISOString(),
@@ -873,7 +880,7 @@ orchestrator.store.markInFlight(recoverySession.session_id, {
873
880
  reviewer_peers: ["codex"],
874
881
  },
875
882
  });
876
- const recoveredInterrupted = orchestrator.store.recoverInterruptedSessions();
883
+ const recoveredInterrupted = await orchestrator.store.recoverInterruptedSessions();
877
884
  assert.equal(recoveredInterrupted.some((session) => session.session_id === recoverySession.session_id), true);
878
885
  assert.equal(orchestrator.store.read(recoverySession.session_id).control?.status, "recovered_after_restart");
879
886
  const abortController = new AbortController();
@@ -900,6 +907,7 @@ const preflightBlocked = await preflightOrchestrator.askPeers({
900
907
  assert.equal(preflightBlocked.converged, false);
901
908
  assert.equal(preflightBlocked.round.rejected.at(-1)?.failure_class, "budget_preflight");
902
909
  assert.equal(preflightBlocked.session.outcome_reason, "budget_preflight");
910
+ await orchestrator.store.flushPendingEvents();
903
911
  const eventful = orchestrator.store.readEvents(formatRecovered.session.session_id);
904
912
  assert.equal(eventful.some((event) => event.type === "round.completed"), true);
905
913
  assert.equal(eventful.some((event) => event.type === "peer.token.delta"), true);
@@ -927,6 +935,7 @@ const directStreamChars = directStreamEvents
927
935
  .reduce((total, event) => total + Number(event.data?.chars ?? 0), 0);
928
936
  assert.equal(directStreamChars, directStubResult.text.length);
929
937
  assert.deepEqual(eventful.map((event) => event.seq), eventful.map((_, index) => index + 1));
938
+ await orchestrator.store.flushPendingEvents();
930
939
  const metrics = orchestrator.store.metrics();
931
940
  assert.equal(metrics.fallback_events, 1);
932
941
  assert.equal((metrics.peer_failures.cancelled ?? 0) >= 1, true);
@@ -940,8 +949,8 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
940
949
  ...config,
941
950
  data_dir: smokeTmpDir("session-doctor"),
942
951
  });
943
- const doctorSession = doctorStore.init("doctor self-lead legacy fixture", "claude", []);
944
- doctorStore.markInFlight(doctorSession.session_id, {
952
+ const doctorSession = await doctorStore.init("doctor self-lead legacy fixture", "claude", []);
953
+ await doctorStore.markInFlight(doctorSession.session_id, {
945
954
  round: 1,
946
955
  peers: ["codex"],
947
956
  started_at: new Date().toISOString(),
@@ -955,25 +964,25 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
955
964
  lead_peer: "claude",
956
965
  },
957
966
  });
958
- doctorStore.appendEvent({
967
+ await doctorStore.appendEvent({
959
968
  type: "peer.token.delta",
960
969
  session_id: doctorSession.session_id,
961
970
  round: 1,
962
971
  peer: "codex",
963
972
  data: { chars: 12 },
964
973
  });
965
- doctorStore.appendEvent({
974
+ await doctorStore.appendEvent({
966
975
  type: "peer.token.completed",
967
976
  session_id: doctorSession.session_id,
968
977
  round: 1,
969
978
  peer: "codex",
970
979
  data: { chars: 12 },
971
980
  });
972
- const malformedSession = doctorStore.init("doctor malformed events fixture", "operator", []);
981
+ const malformedSession = await doctorStore.init("doctor malformed events fixture", "operator", []);
973
982
  fs.writeFileSync(doctorStore.eventsPath(malformedSession.session_id), "{bad-json\n", "utf8");
974
983
  // v2.22.0 (A.P2): self_lead_metadata is hidden by default. Pass
975
984
  // includeLegacy=true here to preserve the original behavior assertion.
976
- const doctor = doctorStore.sessionDoctor(5, true);
985
+ const doctor = await doctorStore.sessionDoctor(5, true);
977
986
  assert.equal(doctor.totals.sessions, 2);
978
987
  assert.equal(doctor.totals.open, 2);
979
988
  assert.equal(doctor.totals.self_lead_metadata, 1);
@@ -996,8 +1005,8 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
996
1005
  data_dir: smokeTmpDir("session-doctor-legacy"),
997
1006
  });
998
1007
  // Fixture: legacy self-lead session (caller==lead_peer)
999
- const legacySession = filterStore.init("legacy self-lead fixture", "claude", []);
1000
- filterStore.markInFlight(legacySession.session_id, {
1008
+ const legacySession = await filterStore.init("legacy self-lead fixture", "claude", []);
1009
+ await filterStore.markInFlight(legacySession.session_id, {
1001
1010
  round: 1,
1002
1011
  peers: ["codex"],
1003
1012
  started_at: new Date().toISOString(),
@@ -1012,13 +1021,13 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
1012
1021
  },
1013
1022
  });
1014
1023
  // Default call: array hidden, totals visible, recommendation mentions include_legacy.
1015
- const defaultReport = filterStore.sessionDoctor(20);
1024
+ const defaultReport = await filterStore.sessionDoctor(20);
1016
1025
  assert.equal(defaultReport.totals.self_lead_metadata, 1, "totals.self_lead_metadata count must remain visible when array is suppressed");
1017
1026
  assert.equal(defaultReport.findings.self_lead_metadata.length, 0, "findings.self_lead_metadata must be empty by default (legacy noise suppression)");
1018
1027
  const hasIncludeLegacyHint = defaultReport.recommendations.some((rec) => rec.includes("include_legacy=true"));
1019
1028
  assert.equal(hasIncludeLegacyHint, true, "recommendation must mention include_legacy=true when array is suppressed and count > 0");
1020
1029
  // Explicit include_legacy=true: array populated.
1021
- const inclusiveReport = filterStore.sessionDoctor(20, true);
1030
+ const inclusiveReport = await filterStore.sessionDoctor(20, true);
1022
1031
  assert.equal(inclusiveReport.totals.self_lead_metadata, 1, "totals must match between default and inclusive calls");
1023
1032
  assert.equal(inclusiveReport.findings.self_lead_metadata.length, 1, "findings.self_lead_metadata must be populated when include_legacy=true");
1024
1033
  assert.equal(inclusiveReport.findings.self_lead_metadata[0]?.lead_peer, "claude");
@@ -1034,7 +1043,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
1034
1043
  ...config,
1035
1044
  data_dir: smokeTmpDir("session-doctor-drilldown"),
1036
1045
  });
1037
- const driveSession = drillStore.init("evidence drill-down fixture", "operator", []);
1046
+ const driveSession = await drillStore.init("evidence drill-down fixture", "operator", []);
1038
1047
  // Fabricate evidence_checklist directly via meta path: 3 open items
1039
1048
  // (codex x1, gemini x2), one of them chronic (round_count=4).
1040
1049
  const metaPath = drillStore.metaPath(driveSession.session_id);
@@ -1076,7 +1085,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
1076
1085
  },
1077
1086
  ];
1078
1087
  fs.writeFileSync(metaPath, JSON.stringify(fabricatedMeta, null, 2));
1079
- const drillReport = drillStore.sessionDoctor(20);
1088
+ const drillReport = await drillStore.sessionDoctor(20);
1080
1089
  const entry = drillReport.findings.open_evidence_sessions.find((e) => e.session_id === driveSession.session_id);
1081
1090
  assert.ok(entry, "open_evidence_sessions must include the fabricated session");
1082
1091
  assert.equal(entry?.open_evidence_items, 3);
@@ -1097,7 +1106,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
1097
1106
  data_dir: smokeTmpDir("budget-warning"),
1098
1107
  budget: { ...config.budget, max_session_cost_usd: 20 },
1099
1108
  });
1100
- const budgetSession = budgetStore.init("budget warning fixture", "operator", []);
1109
+ const budgetSession = await budgetStore.init("budget warning fixture", "operator", []);
1101
1110
  // Verify init snapshotted the ceiling.
1102
1111
  const initial = budgetStore.read(budgetSession.session_id);
1103
1112
  assert.equal(initial.cost_ceiling_usd, 20, "cost_ceiling_usd must snapshot config at init");
@@ -1126,7 +1135,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
1126
1135
  const threshold = ceilingForCheck * 0.75;
1127
1136
  assert.equal(cumulative1 >= threshold, true, "fixture must cross 75% threshold");
1128
1137
  assert.equal(seededMeta.budget_warning_emitted, false, "warning must not have fired yet");
1129
- budgetStore.markBudgetWarningEmitted(budgetSession.session_id);
1138
+ await budgetStore.markBudgetWarningEmitted(budgetSession.session_id);
1130
1139
  const afterFirst = budgetStore.read(budgetSession.session_id);
1131
1140
  assert.equal(afterFirst.budget_warning_emitted, true, "markBudgetWarningEmitted must persist the one-shot guard");
1132
1141
  // Round 2: cumulative = 18 (still over threshold). Emit guard must
@@ -1149,7 +1158,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
1149
1158
  data_dir: smokeTmpDir("budget-warning-no-ceiling"),
1150
1159
  budget: { ...config.budget, max_session_cost_usd: undefined },
1151
1160
  });
1152
- const noCeilingSession = noCeilingStore.init("no ceiling fixture", "operator", []);
1161
+ const noCeilingSession = await noCeilingStore.init("no ceiling fixture", "operator", []);
1153
1162
  const noCeilingMeta = noCeilingStore.read(noCeilingSession.session_id);
1154
1163
  assert.equal(noCeilingMeta.cost_ceiling_usd, null, "cost_ceiling_usd must be null when config.max_session_cost_usd is unset");
1155
1164
  console.log("[smoke] budget_warning_emit_test: PASS");
@@ -1213,10 +1222,10 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
1213
1222
  const { SessionStore } = await import("../src/core/session-store.js");
1214
1223
  const fsModule = await import("node:fs");
1215
1224
  const seqStoreA = new SessionStore(config);
1216
- const seqMeta = seqStoreA.init("seq-durability-test", "operator", []);
1225
+ const seqMeta = await seqStoreA.init("seq-durability-test", "operator", []);
1217
1226
  const seqId = seqMeta.session_id;
1218
1227
  // Emit a normal event.
1219
- seqStoreA.appendEvent({
1228
+ await seqStoreA.appendEvent({
1220
1229
  type: "session.heartbeat",
1221
1230
  session_id: seqId,
1222
1231
  message: "first",
@@ -1231,7 +1240,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
1231
1240
  interceptorFired = true;
1232
1241
  throw new Error("simulated EIO");
1233
1242
  });
1234
- seqStoreA.appendEvent({
1243
+ await seqStoreA.appendEvent({
1235
1244
  type: "session.heartbeat",
1236
1245
  session_id: seqId,
1237
1246
  message: "should-fail",
@@ -1239,7 +1248,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
1239
1248
  // Restore fs and try again — the intended seq (2) must still be
1240
1249
  // available, not skipped to 3.
1241
1250
  fsModule.default.appendFileSync = realAppend;
1242
- seqStoreA.appendEvent({
1251
+ await seqStoreA.appendEvent({
1243
1252
  type: "session.heartbeat",
1244
1253
  session_id: seqId,
1245
1254
  message: "after-recovery",
@@ -1250,7 +1259,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
1250
1259
  // Restart simulation: fresh SessionStore reads from disk and the next
1251
1260
  // seq should be 3 (current line count + 1).
1252
1261
  const seqStoreB = new SessionStore(config);
1253
- seqStoreB.appendEvent({
1262
+ await seqStoreB.appendEvent({
1254
1263
  type: "session.heartbeat",
1255
1264
  session_id: seqId,
1256
1265
  message: "after-restart",
@@ -1269,9 +1278,9 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
1269
1278
  {
1270
1279
  const { SessionStore } = await import("../src/core/session-store.js");
1271
1280
  const flightStore = new SessionStore(config);
1272
- const flightMeta = flightStore.init("mark-in-flight-guard-test", "operator", []);
1281
+ const flightMeta = await flightStore.init("mark-in-flight-guard-test", "operator", []);
1273
1282
  const flightId = flightMeta.session_id;
1274
- flightStore.markInFlight(flightId, {
1283
+ await flightStore.markInFlight(flightId, {
1275
1284
  round: 1,
1276
1285
  peers: [...PEERS],
1277
1286
  started_at: new Date().toISOString(),
@@ -1284,7 +1293,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
1284
1293
  });
1285
1294
  let secondMarkRejected = false;
1286
1295
  try {
1287
- flightStore.markInFlight(flightId, {
1296
+ await flightStore.markInFlight(flightId, {
1288
1297
  round: 2,
1289
1298
  peers: [...PEERS],
1290
1299
  started_at: new Date().toISOString(),
@@ -1358,13 +1367,13 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
1358
1367
  {
1359
1368
  const { SessionStore } = await import("../src/core/session-store.js");
1360
1369
  const staleStore = new SessionStore(config);
1361
- const staleMeta = staleStore.init("stale-session-abort-test", "operator", []);
1370
+ const staleMeta = await staleStore.init("stale-session-abort-test", "operator", []);
1362
1371
  const staleId = staleMeta.session_id;
1363
1372
  const staleMetaPath = staleStore.metaPath(staleId);
1364
1373
  const staleRaw = JSON.parse(fs.readFileSync(staleMetaPath, "utf8"));
1365
1374
  staleRaw.updated_at = new Date(Date.now() - 25 * 60 * 60 * 1000).toISOString();
1366
1375
  fs.writeFileSync(staleMetaPath, JSON.stringify(staleRaw, null, 2), "utf8");
1367
- const sweep = staleStore.abortStaleSessions();
1376
+ const sweep = await staleStore.abortStaleSessions();
1368
1377
  assert.ok(sweep.aborted >= 1, `abortStaleSessions must abort ≥1 stale session, got ${sweep.aborted}`);
1369
1378
  const after = staleStore.read(staleId);
1370
1379
  assert.equal(after.outcome, "aborted");
@@ -1376,9 +1385,9 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
1376
1385
  {
1377
1386
  const { SessionStore } = await import("../src/core/session-store.js");
1378
1387
  const inflightStore = new SessionStore(config);
1379
- const inflightMeta = inflightStore.init("stale-session-skip-test", "operator", []);
1388
+ const inflightMeta = await inflightStore.init("stale-session-skip-test", "operator", []);
1380
1389
  const inflightId = inflightMeta.session_id;
1381
- inflightStore.markInFlight(inflightId, {
1390
+ await inflightStore.markInFlight(inflightId, {
1382
1391
  round: 1,
1383
1392
  peers: [...PEERS],
1384
1393
  started_at: new Date().toISOString(),
@@ -1393,7 +1402,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
1393
1402
  const inflightRaw = JSON.parse(fs.readFileSync(inflightMetaPath, "utf8"));
1394
1403
  inflightRaw.updated_at = new Date(Date.now() - 25 * 60 * 60 * 1000).toISOString();
1395
1404
  fs.writeFileSync(inflightMetaPath, JSON.stringify(inflightRaw, null, 2), "utf8");
1396
- const sweep = inflightStore.abortStaleSessions();
1405
+ const sweep = await inflightStore.abortStaleSessions();
1397
1406
  const after = inflightStore.read(inflightId);
1398
1407
  assert.equal(after.outcome, undefined, `in-flight session must NOT be aborted by stale sweep (got outcome=${after.outcome}, sweep=${JSON.stringify(sweep)})`);
1399
1408
  console.log("[smoke] stale_session_skipped_when_running_test: PASS");
@@ -1831,7 +1840,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
1831
1840
  const meta = tpOrch.store.read(sessionId);
1832
1841
  meta.evidence_checklist = fixtureItems;
1833
1842
  fs.writeFileSync(path.join(tpConfig.data_dir, "sessions", sessionId, "meta.json"), JSON.stringify(meta, null, 2));
1834
- const ad = tpOrch.store.runEvidenceChecklistAddressDetection(sessionId, FIXTURE_ROUND);
1843
+ const ad = await tpOrch.store.runEvidenceChecklistAddressDetection(sessionId, FIXTURE_ROUND);
1835
1844
  // (1) The open item with last_round===currentRound MUST NOT appear under
1836
1845
  // peer_resurfaced_terminal. This is the regression the buggy
1837
1846
  // truthy-OR predicate would have triggered.
@@ -1934,7 +1943,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
1934
1943
  });
1935
1944
  const item = opRound1.session.evidence_checklist?.[0];
1936
1945
  assert.ok(item, "R1 must produce a checklist item");
1937
- const result = opOrch.store.setEvidenceChecklistItemStatus(opRound1.session.session_id, item.id, "satisfied", { note: "smoke verified manually", by: "operator" });
1946
+ const result = await opOrch.store.setEvidenceChecklistItemStatus(opRound1.session.session_id, item.id, "satisfied", { note: "smoke verified manually", by: "operator" });
1938
1947
  assert.equal(result.item.status, "satisfied", "mutator must set status to satisfied");
1939
1948
  assert.equal(result.history_entry.from, "open");
1940
1949
  assert.equal(result.history_entry.to, "satisfied");
@@ -1956,7 +1965,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
1956
1965
  // type-system level: the mutator's signature excludes "addressed". We
1957
1966
  // assert that calling setEvidenceChecklistItemStatus with "deferred"
1958
1967
  // works as a different terminal transition.
1959
- const result2 = opOrch.store.setEvidenceChecklistItemStatus(opRound1.session.session_id, item.id, "deferred", { note: "retract satisfied, defer instead", by: "operator" });
1968
+ const result2 = await opOrch.store.setEvidenceChecklistItemStatus(opRound1.session.session_id, item.id, "deferred", { note: "retract satisfied, defer instead", by: "operator" });
1960
1969
  assert.equal(result2.item.status, "deferred");
1961
1970
  assert.equal(result2.history_entry.from, "satisfied");
1962
1971
  assert.equal(result2.history_entry.to, "deferred");
@@ -1994,6 +2003,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
1994
2003
  caller: "operator",
1995
2004
  peers: ["codex"],
1996
2005
  });
2006
+ await phOrch.store.flushPendingEvents();
1997
2007
  const metrics = phOrch.store.metrics();
1998
2008
  const perPeer = metrics.per_peer_health;
1999
2009
  assert.ok(perPeer, "metrics must include per_peer_health");
@@ -2835,7 +2845,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
2835
2845
  // would leave the durable log empty.
2836
2846
  const holder = {};
2837
2847
  const rollupOrch = new CrossReviewOrchestrator(cfg, (event) => {
2838
- holder.orch?.store.appendEvent(event);
2848
+ void holder.orch?.store.appendEvent(event);
2839
2849
  });
2840
2850
  holder.orch = rollupOrch;
2841
2851
  const r1 = await rollupOrch.askPeers({
@@ -2851,6 +2861,9 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
2851
2861
  caller: "operator",
2852
2862
  peers: ["claude"],
2853
2863
  });
2864
+ // v4.1.0: emit pipeline uses `void store.appendEvent(...)` (fire-
2865
+ // and-forget). Flush pending writes before reading the events file.
2866
+ await rollupOrch.store.flushPendingEvents();
2854
2867
  const rollup = rollupOrch.store.aggregateShadowJudgments();
2855
2868
  assert.ok(rollup.decisions_total >= 1, `aggregate must record at least 1 shadow decision (got ${rollup.decisions_total})`);
2856
2869
  assert.ok(rollup.would_promote_total >= 1, `aggregate must record at least 1 would_promote (got ${rollup.would_promote_total})`);
@@ -2860,7 +2873,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
2860
2873
  assert.ok(claudeStats.would_promote >= 1);
2861
2874
  assert.ok((claudeStats.by_confidence.verified ?? 0) >= 1);
2862
2875
  assert.ok(claudeStats.first_seen_at && claudeStats.last_seen_at);
2863
- const metrics = rollupOrch.store.metrics();
2876
+ const metrics = rollupOrch.store.metrics(); // already flushed above
2864
2877
  assert.ok(metrics.shadow_judgment, "metrics().shadow_judgment must be present");
2865
2878
  assert.equal(metrics.shadow_judgment.decisions_total, rollup.decisions_total);
2866
2879
  console.log("[smoke] metrics_shadow_judgment_rollup_test: PASS");
@@ -2898,7 +2911,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
2898
2911
  const holder = {};
2899
2912
  const orch = new CrossReviewOrchestrator(cfg, (e) => {
2900
2913
  events.push({ type: e.type, data: e.data });
2901
- holder.orch?.store.appendEvent(e);
2914
+ void holder.orch?.store.appendEvent(e);
2902
2915
  });
2903
2916
  holder.orch = orch;
2904
2917
  // Drive runUntilUnanimous with FORCE_DRIFT (lead generation triggers
@@ -2942,7 +2955,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
2942
2955
  const holder = {};
2943
2956
  const orch = new CrossReviewOrchestrator(cfg, (e) => {
2944
2957
  events.push({ type: e.type, data: e.data });
2945
- holder.orch?.store.appendEvent(e);
2958
+ void holder.orch?.store.appendEvent(e);
2946
2959
  });
2947
2960
  holder.orch = orch;
2948
2961
  const result = await orch.runUntilUnanimous({
@@ -2980,7 +2993,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
2980
2993
  const holder = {};
2981
2994
  const orch = new CrossReviewOrchestrator(cfg, (e) => {
2982
2995
  events.push({ type: e.type, data: e.data });
2983
- holder.orch?.store.appendEvent(e);
2996
+ void holder.orch?.store.appendEvent(e);
2984
2997
  });
2985
2998
  holder.orch = orch;
2986
2999
  const result = await orch.runUntilUnanimous({
@@ -3017,7 +3030,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
3017
3030
  const holder = {};
3018
3031
  const orch = new CrossReviewOrchestrator(cfg, (e) => {
3019
3032
  events.push({ type: e.type, data: e.data });
3020
- holder.orch?.store.appendEvent(e);
3033
+ void holder.orch?.store.appendEvent(e);
3021
3034
  });
3022
3035
  holder.orch = orch;
3023
3036
  await orch.runUntilUnanimous({
@@ -3052,7 +3065,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
3052
3065
  };
3053
3066
  const holder = {};
3054
3067
  const aeOrch = new CrossReviewOrchestrator(cfg, (e) => {
3055
- holder.orch?.store.appendEvent(e);
3068
+ void holder.orch?.store.appendEvent(e);
3056
3069
  });
3057
3070
  holder.orch = aeOrch;
3058
3071
  // Init session, attach 2 evidence files, run askPeers, read R1 prompt.
@@ -3071,12 +3084,12 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
3071
3084
  const sessionId = initial.session.session_id;
3072
3085
  // The first askPeers above completed R1 already without attachments
3073
3086
  // — that is the "before" baseline. Now attach files and run R2.
3074
- aeOrch.store.attachEvidence(sessionId, {
3087
+ await aeOrch.store.attachEvidence(sessionId, {
3075
3088
  label: "gates-output",
3076
3089
  content: "EXIT 0 typecheck\nEXIT 0 lint\nEXIT 0 build\nEXIT 0 smoke 41/41 PASS\n",
3077
3090
  extension: "log",
3078
3091
  });
3079
- aeOrch.store.attachEvidence(sessionId, {
3092
+ await aeOrch.store.attachEvidence(sessionId, {
3080
3093
  label: "diff-stat",
3081
3094
  content: " path/to/file.ts | +12/-3\n 1 file changed, 12 insertions, 3 deletions\n",
3082
3095
  extension: "txt",
@@ -3132,7 +3145,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
3132
3145
  const sessionId = initial.session.session_id;
3133
3146
  const big = "X".repeat(30_000);
3134
3147
  for (let i = 0; i < 4; i++) {
3135
- capOrch.store.attachEvidence(sessionId, {
3148
+ await capOrch.store.attachEvidence(sessionId, {
3136
3149
  label: `att-${i}`,
3137
3150
  content: big,
3138
3151
  extension: "txt",
@@ -3316,7 +3329,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
3316
3329
  };
3317
3330
  const holder = {};
3318
3331
  const prOrch = new CrossReviewOrchestrator(cfg, (event) => {
3319
- holder.orch?.store.appendEvent(event);
3332
+ void holder.orch?.store.appendEvent(event);
3320
3333
  });
3321
3334
  holder.orch = prOrch;
3322
3335
  // R1: produce a NEEDS_EVIDENCE ask. R2: ask resurfaces (so far ground
@@ -3351,6 +3364,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
3351
3364
  caller: "operator",
3352
3365
  peers: ["claude"],
3353
3366
  });
3367
+ await prOrch.store.flushPendingEvents();
3354
3368
  const report = prOrch.store.computeJudgmentPrecisionReport();
3355
3369
  assert.ok(report.decisions_total >= 1, `at least 1 decision recorded`);
3356
3370
  const claudeStats = report.by_judge_peer.claude;
@@ -3400,7 +3414,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
3400
3414
  const holder = {};
3401
3415
  const acOrch = new CrossReviewOrchestrator(cfg, (e) => {
3402
3416
  events.push(e.type);
3403
- holder.orch?.store.appendEvent(e);
3417
+ void holder.orch?.store.appendEvent(e);
3404
3418
  });
3405
3419
  holder.orch = acOrch;
3406
3420
  // R1: produce a NEEDS_EVIDENCE ask via FORCE_NEEDS_EVIDENCE.
@@ -3470,9 +3484,9 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
3470
3484
  peers: ["claude"],
3471
3485
  });
3472
3486
  const originalId = initial.session.session_id;
3473
- cvOrch.store.finalize(originalId, "max-rounds", "test_finalize");
3487
+ await cvOrch.store.finalize(originalId, "max-rounds", "test_finalize");
3474
3488
  // Contest it.
3475
- const contestation = cvOrch.store.contestVerdict({
3489
+ const contestation = await cvOrch.store.contestVerdict({
3476
3490
  session_id: originalId,
3477
3491
  reason: "Caller disagrees with the verdict; new evidence has surfaced.",
3478
3492
  new_task: "Contest test re-deliberation",
@@ -3491,7 +3505,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
3491
3505
  // Double-contesting must throw.
3492
3506
  let threw = null;
3493
3507
  try {
3494
- cvOrch.store.contestVerdict({
3508
+ await cvOrch.store.contestVerdict({
3495
3509
  session_id: originalId,
3496
3510
  reason: "Trying to contest twice",
3497
3511
  new_task: "Should not happen",
@@ -3513,7 +3527,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
3513
3527
  // but typically the session still has no outcome until finalize.)
3514
3528
  threw = null;
3515
3529
  try {
3516
- cvOrch.store.contestVerdict({
3530
+ await cvOrch.store.contestVerdict({
3517
3531
  session_id: inFlight.session.session_id,
3518
3532
  reason: "in-flight should reject",
3519
3533
  new_task: "should not happen",
@@ -3919,8 +3933,8 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
3919
3933
  };
3920
3934
  // Scenario A: finalize("converged") on a session whose latest round
3921
3935
  // did NOT converge MUST be rejected with a structured error code.
3922
- const sess = invariantStore.init("invariant-fixture", "operator", []);
3923
- invariantStore.appendRound(sess.session_id, {
3936
+ const sess = await invariantStore.init("invariant-fixture", "operator", []);
3937
+ await invariantStore.appendRound(sess.session_id, {
3924
3938
  caller_status: "READY",
3925
3939
  prompt_file: "round-1-prompt.md",
3926
3940
  peers: [],
@@ -3948,7 +3962,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
3948
3962
  });
3949
3963
  let rejected = null;
3950
3964
  try {
3951
- invariantStore.finalize(sess.session_id, "converged", "unanimous_ready");
3965
+ await invariantStore.finalize(sess.session_id, "converged", "unanimous_ready");
3952
3966
  }
3953
3967
  catch (err) {
3954
3968
  rejected = err;
@@ -3959,8 +3973,8 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
3959
3973
  assert.equal(invariantStore.read(sess.session_id).outcome, undefined, "finalize-reject MUST NOT mutate meta.outcome");
3960
3974
  // Scenario B: finalize("converged") on a session whose latest round
3961
3975
  // DID converge succeeds and leaves a consistent meta.
3962
- const sess2 = invariantStore.init("invariant-fixture-2", "operator", []);
3963
- invariantStore.appendRound(sess2.session_id, {
3976
+ const sess2 = await invariantStore.init("invariant-fixture-2", "operator", []);
3977
+ await invariantStore.appendRound(sess2.session_id, {
3964
3978
  caller_status: "READY",
3965
3979
  prompt_file: "round-1-prompt.md",
3966
3980
  peers: [],
@@ -3986,14 +4000,14 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
3986
4000
  },
3987
4001
  started_at: new Date().toISOString(),
3988
4002
  });
3989
- const finalized = invariantStore.finalize(sess2.session_id, "converged", "unanimous_ready");
4003
+ const finalized = await invariantStore.finalize(sess2.session_id, "converged", "unanimous_ready");
3990
4004
  assert.equal(finalized.outcome, "converged");
3991
4005
  assert.equal(finalized.convergence_health?.state, "converged");
3992
4006
  // Scenario C: appendRound on a finalized session MUST throw with the
3993
4007
  // structured code.
3994
4008
  let appendRejected = null;
3995
4009
  try {
3996
- invariantStore.appendRound(sess2.session_id, {
4010
+ await invariantStore.appendRound(sess2.session_id, {
3997
4011
  caller_status: "READY",
3998
4012
  prompt_file: "round-2-prompt.md",
3999
4013
  peers: [],
@@ -4932,9 +4946,9 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
4932
4946
  entries: [],
4933
4947
  };
4934
4948
  fs.mkdirSync(path.join(config.data_dir, "sessions", manifestSession), { recursive: true });
4935
- writeCacheManifest(config.data_dir, manifestSession, manifestData);
4949
+ await writeCacheManifest(config.data_dir, manifestSession, manifestData);
4936
4950
  for (let i = 0; i < 5; i += 1) {
4937
- appendCacheManifestEntry(config.data_dir, manifestSession, {
4951
+ await appendCacheManifestEntry(config.data_dir, manifestSession, {
4938
4952
  ts: new Date().toISOString(),
4939
4953
  round: i + 1,
4940
4954
  peer: "codex",
@@ -5283,7 +5297,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
5283
5297
  /this\.store\.finalize\([\s\S]{0,100}"max-rounds"[\s\S]{0,100}"circular_max_rotations_exceeded"/.test(orchSrc), "v2.25.0 / circular_mode: orchestrator finalizes with outcome=max-rounds + reason=circular_max_rotations_exceeded");
5284
5298
  // (9) Meta carries circular_state with the expected shape.
5285
5299
  assert.ok(/circular_state\?:\s*\{[\s\S]{0,300}rotation_order:\s*PeerId\[\][\s\S]{0,300}consecutive_no_change_count:\s*number[\s\S]{0,300}last_revision_round:\s*number\s*\|\s*null/.test(typesSrc), "v2.25.0 / circular_mode: SessionMeta.circular_state declares {rotation_order, consecutive_no_change_count, last_revision_round}");
5286
- assert.ok(/setCircularState\(/.test(storeSrc) && /meta\.circular_state\s*=\s*state/.test(storeSrc), "v2.25.0 / circular_mode: SessionStore.setCircularState() persists circular_state under session lock");
5300
+ assert.ok(/setCircularState\(/.test(storeSrc) && /meta\.circular_state\s*=\s*state/.test(storeSrc), "v2.25.0 / circular_mode: await SessionStore.setCircularState() persists circular_state under session lock");
5287
5301
  // (10) MCP tool schemas accept "circular".
5288
5302
  const circularEnumOccurrences = (mcpSrc.match(/z\.enum\(\["ship",\s*"review",\s*"circular"\]\)/g) ?? []).length;
5289
5303
  assert.ok(circularEnumOccurrences >= 2, `v2.25.0 / circular_mode: MCP schemas in mcp/server.ts must include z.enum(["ship","review","circular"]) for both run_until_unanimous + session_start_unanimous (found ${circularEnumOccurrences} occurrences)`);
@@ -5862,12 +5876,12 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
5862
5876
  fs.mkdirSync(path.join(repairCfg.data_dir, "sessions", corruptId), { recursive: true });
5863
5877
  fs.writeFileSync(path.join(repairCfg.data_dir, "sessions", corruptId, "meta.json"), JSON.stringify(corruptMeta, null, 2));
5864
5878
  // repair=false (default) — read-only, the contradiction is NOT touched.
5865
- const readOnly = repairStore.sessionDoctor(20, false, false);
5879
+ const readOnly = await repairStore.sessionDoctor(20, false, false);
5866
5880
  assert.equal(readOnly.repaired, undefined, "v3.6.0 / C: repair=false must NOT include a `repaired` array (stays read-only)");
5867
5881
  const afterReadOnly = repairStore.read(corruptId);
5868
5882
  assert.equal(afterReadOnly.convergence_health?.state, "blocked", "v3.6.0 / C: repair=false must leave the corrupt health state untouched");
5869
5883
  // repair=true — the contradiction is recomputed from the latest round.
5870
- const repaired = repairStore.sessionDoctor(20, false, true);
5884
+ const repaired = await repairStore.sessionDoctor(20, false, true);
5871
5885
  assert.ok(Array.isArray(repaired.repaired) && repaired.repaired.length === 1, `v3.6.0 / C: repair=true must report exactly 1 repaired session, got ${repaired.repaired?.length}`);
5872
5886
  assert.equal(repaired.repaired?.[0]?.session_id, corruptId);
5873
5887
  assert.equal(repaired.repaired?.[0]?.from_health_state, "blocked");
@@ -5876,7 +5890,7 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
5876
5890
  assert.equal(afterRepair.convergence_health?.state, "converged", "v3.6.0 / C: repair=true must recompute health to converged");
5877
5891
  assert.ok(/v3\.6\.0 doctor repair/.test(afterRepair.convergence_health?.detail ?? ""), "v3.6.0 / C: repaired health detail must record the repair provenance");
5878
5892
  // Idempotent — a second repair pass finds nothing to fix.
5879
- const secondPass = repairStore.sessionDoctor(20, false, true);
5893
+ const secondPass = await repairStore.sessionDoctor(20, false, true);
5880
5894
  assert.equal(secondPass.repaired?.length, 0, "v3.6.0 / C: repair must be idempotent — second pass repairs nothing");
5881
5895
  console.log("[smoke] session_doctor_repair_test: PASS");
5882
5896
  }
@@ -6214,6 +6228,98 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
6214
6228
  !verifyScript.includes("readFile(") &&
6215
6229
  verifyScript.includes("npm_package_name") &&
6216
6230
  verifyScript.includes("npm_package_version"), "v4.0.8 / F3: verify-registry-dist.mjs must not read package.json from disk; PACKAGE_NAME/PACKAGE_VERSION come from env (or npm-script-injected npm_package_name/version). Removing the file-data → fetch flow kills the recurring js/file-access-to-http CodeQL false positive at the source.");
6231
+ // v4.1.0 / F4: redactPrivateKeyBlocks must handle UNTERMINATED -----BEGIN
6232
+ // PRIVATE KEY----- blocks by redacting from BEGIN to end-of-string. Pre-
6233
+ // v4.1.0 leaked partial keys to events.ndjson when logs were truncated
6234
+ // mid-key. Empirical regression test:
6235
+ {
6236
+ const { redact } = await import("../src/security/redact.js");
6237
+ const truncatedKey = `error: -----BEGIN PRIVATE KEY-----\nMIIBVQIBADANBgkqhkiG9w0BAQEF...[TRUNCATED`;
6238
+ const redacted = redact(truncatedKey);
6239
+ assert.ok(redacted.includes("[REDACTED]"), "v4.1.0 / F4: redact() must emit [REDACTED] for unterminated -----BEGIN PRIVATE KEY----- blocks.");
6240
+ assert.ok(!redacted.includes("MIIBVQIBADANBgkqhkiG9w0BAQEF"), "v4.1.0 / F4: redact() must NOT leak the partial key body when the BEGIN marker has no matching END.");
6241
+ assert.equal(redact("just a normal log line"), "just a normal log line", "v4.1.0 / F4: redact() must be passthrough when no PRIVATE KEY markers are present.");
6242
+ console.log("[smoke] redact_unterminated_private_key_test: PASS");
6243
+ }
6244
+ // v4.1.0 / F5: writeJson + cache-manifest writeJsonAtomic must be
6245
+ // async AND no source file under src/ may contain the
6246
+ // `while (Date.now() - start < wait)` CPU-burning busy-wait pattern.
6247
+ // Pre-v4.1.0 this pattern blocked the event loop for up to 310 ms
6248
+ // under Windows AV stress. Codex R1 NEEDS_EVIDENCE catch on session
6249
+ // 059b0093 asked for repo-wide grep (the original pin only covered
6250
+ // session-store.ts and missed cache-manifest.ts:47).
6251
+ {
6252
+ const storeSrc = fs.readFileSync(path.join(process.cwd(), "src", "core", "session-store.ts"), "utf8");
6253
+ assert.ok(/async\s+function\s+writeJson\b/.test(storeSrc), "v4.1.0 / F5: writeJson must be declared `async function writeJson` in src/core/session-store.ts.");
6254
+ assert.ok(/new\s+Promise[\s\S]{0,80}?setTimeout/.test(storeSrc), "v4.1.0 / F5: writeJson must use a Promise-based async delay (`new Promise(r => setTimeout(r, wait))`) for retry backoff so the event loop remains responsive.");
6255
+ const cacheManifestSrc = fs.readFileSync(path.join(process.cwd(), "src", "core", "cache-manifest.ts"), "utf8");
6256
+ assert.ok(/async\s+function\s+writeJsonAtomic\b/.test(cacheManifestSrc), "v4.1.0 / F5: writeJsonAtomic in cache-manifest.ts must be `async function writeJsonAtomic`.");
6257
+ // Repo-wide invariant: scan every .ts under src/ for executable
6258
+ // busy-wait patterns. Strip block comments so the pin only checks
6259
+ // executable code (comments may reference the removed pattern).
6260
+ function walkTs(dir, out) {
6261
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
6262
+ const full = path.join(dir, entry.name);
6263
+ if (entry.isDirectory()) {
6264
+ walkTs(full, out);
6265
+ }
6266
+ else if (entry.isFile() && entry.name.endsWith(".ts")) {
6267
+ out.push(full);
6268
+ }
6269
+ }
6270
+ return out;
6271
+ }
6272
+ const tsFiles = walkTs(path.join(process.cwd(), "src"), []);
6273
+ for (const file of tsFiles) {
6274
+ const raw = fs.readFileSync(file, "utf8");
6275
+ // Strip /* ... */ and // ... so the busy-wait grep doesn't trip
6276
+ // on documentation. The lint runs on EXECUTABLE source only.
6277
+ const stripped = raw.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|\n)\s*\/\/[^\n]*/g, "$1");
6278
+ assert.ok(!/while\s*\(\s*Date\.now\(\)\s*-\s*\w+\s*<\s*\w+\s*\)\s*\{[^}]*\}/.test(stripped), `v4.1.0 / F5: ${path.relative(process.cwd(), file)} contains a synchronous busy-wait (\`while (Date.now() - start < wait) {}\`). Replace with \`await new Promise(r => setTimeout(r, wait))\`.`);
6279
+ assert.ok(!/Atomics\.wait\s*\(/.test(stripped), `v4.1.0 / F5: ${path.relative(process.cwd(), file)} uses Atomics.wait — also a synchronous block. Replace with a Promise+setTimeout.`);
6280
+ }
6281
+ console.log("[smoke] writeJson_async_no_busy_wait_test: PASS");
6282
+ }
6283
+ // v4.1.0 / F6: withSessionLock in src/core/session-store.ts must use
6284
+ // `proper-lockfile` (mkdir-atomic locking) instead of the pre-v4.1.0
6285
+ // `fs.openSync(lockPath, "wx")` followed by separate writeFileSync. The
6286
+ // pre-v4.1.0 pattern had a multi-process TOCTOU race: between open()
6287
+ // (creates empty inode) and writeFileSync (populates content) another
6288
+ // process could observe the empty lock, JSON-parse-fail, and rmSync the
6289
+ // lock — letting both processes enter the critical section. proper-
6290
+ // lockfile uses fs.mkdir which is atomic across NTFS and POSIX so the
6291
+ // lock comes into existence as a directory in one syscall with no
6292
+ // empty-window race. Additionally — Codex 059b0093 R1..R4 catches —
6293
+ // v4.1.0 must NEVER auto-remove a pre-v4.1.0 legacy regular `.lock`
6294
+ // file: under live cross-version v4.0/v4.1 operation, every
6295
+ // auto-clean variant raced a concurrent v4.0.x process's own
6296
+ // stale-removal-and-recreate path. v4.1.0 fails closed with a
6297
+ // clear remediation error; operator manually cleans up at upgrade.
6298
+ {
6299
+ const storeSrc = fs.readFileSync(path.join(process.cwd(), "src", "core", "session-store.ts"), "utf8");
6300
+ assert.ok(/from\s+["']proper-lockfile["']/.test(storeSrc), "v4.1.0 / F6: session-store.ts must import from 'proper-lockfile'.");
6301
+ assert.ok(/lockfile\.lock\(/.test(storeSrc), "v4.1.0 / F6: withSessionLock must call lockfile.lock() to acquire the session lock.");
6302
+ assert.ok(!/fs\.openSync\([^,]+,\s*["']wx["']\)/.test(storeSrc), "v4.1.0 / F6: session-store.ts must not contain the pre-v4.1.0 `fs.openSync(..., 'wx')` lock-acquire pattern that had the TOCTOU race.");
6303
+ assert.ok(/async\s+withSessionLock|withSessionLock[^(]*\([^)]*\)\s*:\s*Promise/.test(storeSrc), "v4.1.0 / F6: withSessionLock must be declared async (returning Promise<T>).");
6304
+ // Fail-closed migration policy: surface a remediation error
6305
+ // instead of removing legacy regular `.lock` files. The string
6306
+ // "detected a pre-v4.1.0 lock file" is the contract every caller
6307
+ // sees; the F6 smoke pin asserts it remains pinned.
6308
+ assert.ok(/detected a pre-v4\.1\.0 lock file/.test(storeSrc), "v4.1.0 / F6: session-store.ts must throw the fail-closed `detected a pre-v4.1.0 lock file` error when a legacy regular `.lock` file is observed (NO auto-removal under live cross-version operation).");
6309
+ // Belt-and-suspenders: no rmSync(lockfilePath, ...) anywhere in
6310
+ // withSessionLock — fail-closed implies the legacy file is
6311
+ // NEVER deleted by v4.1.0.
6312
+ assert.ok(!/fs\.rmSync\(\s*lockfilePath\b/.test(storeSrc), "v4.1.0 / F6: session-store.ts must NOT contain `fs.rmSync(lockfilePath, ...)` — v4.1.0 fails closed on legacy locks and never auto-removes them.");
6313
+ assert.ok(!/if\s*\(\s*!\s*fs\.existsSync\(\s*target\s*\)\s*\)\s*\{[\s\S]{0,300}fs\.writeFileSync\(\s*target/.test(storeSrc), "v4.1.1 / CodeQL: meta placeholder creation must not use existsSync(target) before writeFileSync(target); rely on writeFileSync(..., { flag: 'wx' }) and EEXIST handling instead.");
6314
+ console.log("[smoke] session_lock_proper_lockfile_test: PASS");
6315
+ }
6316
+ {
6317
+ const migrationRaceSrc = fs.readFileSync(path.join(process.cwd(), "scripts", "race-migration-toctou.mjs"), "utf8");
6318
+ assert.ok(/fs\.openSync\(\s*lockfilePath,\s*["']r["']\s*\)/.test(migrationRaceSrc), "v4.1.1 / CodeQL: race-migration-toctou must open lockfilePath and snapshot through the file descriptor.");
6319
+ assert.ok(/fs\.fstatSync\(\s*endFd\s*\)/.test(migrationRaceSrc), "v4.1.1 / CodeQL: race-migration-toctou must use fstatSync(endFd) rather than statSync(lockfilePath) before reading.");
6320
+ assert.ok(!/fs\.statSync\(\s*lockfilePath\s*\)[\s\S]{0,120}fs\.readFileSync\(\s*lockfilePath/.test(migrationRaceSrc), "v4.1.1 / CodeQL: race-migration-toctou must not statSync(lockfilePath) then readFileSync(lockfilePath).");
6321
+ console.log("[smoke] codeql_file_system_race_regression_test: PASS");
6322
+ }
6217
6323
  for (const required of ["dist", "shasum", "integrity", "tarball"]) {
6218
6324
  assert.ok(verifyScript.includes(required), `v4.0.5 / AUDIT-6: verify-registry-dist.mjs must validate npm registry dist.${required}.`);
6219
6325
  }
@@ -6263,6 +6369,21 @@ assert.equal(Object.hasOwn(metrics.decision_quality, "undefined"), false);
6263
6369
  }
6264
6370
  console.log("[smoke] npm_registry_discipline_test: PASS");
6265
6371
  }
6372
+ {
6373
+ const prettierIgnore = fs.readFileSync(path.join(process.cwd(), ".prettierignore"), "utf8");
6374
+ const ignoredPatterns = prettierIgnore
6375
+ .split(/\r?\n/)
6376
+ .map((line) => line.trim())
6377
+ .filter((line) => line && !line.startsWith("#"));
6378
+ for (const forbidden of ["README.md", "**/README.md", "src", "src/**", "scripts", "scripts/**"]) {
6379
+ assert.ok(!ignoredPatterns.includes(forbidden), `hard-gate / no-mask: .prettierignore must not hide ${forbidden} from Prettier coverage.`);
6380
+ }
6381
+ const eslintConfig = fs.readFileSync(path.join(process.cwd(), "eslint.config.js"), "utf8");
6382
+ assert.ok(!/"@typescript-eslint\/no-explicit-any"\s*:\s*["']off["']/.test(eslintConfig), "hard-gate / no-mask: eslint.config.js must not disable @typescript-eslint/no-explicit-any globally.");
6383
+ assert.ok(!/"@typescript-eslint\/no-unused-vars"\s*:\s*["']off["']/.test(eslintConfig), "hard-gate / no-mask: eslint.config.js must not disable @typescript-eslint/no-unused-vars globally.");
6384
+ assert.ok(/"@typescript-eslint\/no-unused-vars"\s*:\s*\[\s*["']error["']/.test(eslintConfig), "hard-gate / no-mask: @typescript-eslint/no-unused-vars must remain an error.");
6385
+ console.log("[smoke] hard_gate_no_linter_formatter_masking_test: PASS");
6386
+ }
6266
6387
  // v2.6.1 NOTE: smoke coverage for `peer.fallback.budget_blocked` and
6267
6388
  // `peer.moderation_recovery.budget_blocked` is intentionally NOT
6268
6389
  // included. These two gates use the same arithmetic shape as preflight