@fairfox/polly 0.83.0 → 0.84.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.
@@ -3356,6 +3356,8 @@ var init_witness = __esm(() => {
3356
3356
  // tools/verify/src/codegen/witness.ts
3357
3357
  var exports_witness2 = {};
3358
3358
  __export(exports_witness2, {
3359
+ witnessVerdict: () => witnessVerdict,
3360
+ witnessPolarity: () => witnessPolarity,
3359
3361
  routeWitness: () => routeWitness,
3360
3362
  buildWitnessModule: () => buildWitnessModule,
3361
3363
  buildWitnessInvariant: () => buildWitnessInvariant,
@@ -3364,6 +3366,23 @@ __export(exports_witness2, {
3364
3366
  WitnessTranslationError: () => WitnessTranslationError,
3365
3367
  WITNESS_INVARIANT: () => WITNESS_INVARIANT
3366
3368
  });
3369
+ function witnessPolarity(tags) {
3370
+ return tags.includes("forbidden") ? "forbidden" : "positive";
3371
+ }
3372
+ function witnessVerdict(polarity, reachable) {
3373
+ if (polarity === "forbidden") {
3374
+ return reachable ? {
3375
+ status: "violated",
3376
+ ok: false,
3377
+ message: "the forbidden state is REACHABLE — a defect; the counterexample is the path to it"
3378
+ } : { status: "excluded", ok: true, message: "the model proves this state unreachable" };
3379
+ }
3380
+ return reachable ? { status: "reachable", ok: true, message: "the model reaches this outcome" } : {
3381
+ status: "unreachable",
3382
+ ok: false,
3383
+ message: "the model proves this outcome impossible (the scenario lies)"
3384
+ };
3385
+ }
3367
3386
  function flattenField(path3) {
3368
3387
  return path3.split(".").join("_");
3369
3388
  }
@@ -8783,6 +8802,8 @@ async function runWitnessVerification(config) {
8783
8802
  buildWitnessCfg: buildWitnessCfg2,
8784
8803
  buildWitnessModule: buildWitnessModule2,
8785
8804
  routeWitness: routeWitness2,
8805
+ witnessPolarity: witnessPolarity2,
8806
+ witnessVerdict: witnessVerdict2,
8786
8807
  WITNESS_INVARIANT: WITNESS_INVARIANT2
8787
8808
  } = await Promise.resolve().then(() => (init_witness2(), exports_witness2));
8788
8809
  const subsystems = config.subsystems;
@@ -8795,8 +8816,14 @@ async function runWitnessVerification(config) {
8795
8816
  let idx = 0;
8796
8817
  for (const w of witnesses) {
8797
8818
  const id = `${w.feature} › ${w.scenario}`;
8819
+ const polarity = witnessPolarity2(w.tags);
8798
8820
  if (!w.predicate) {
8799
- results.push({ id, status: "skipped", note: "no state-observable Then to witness" });
8821
+ results.push({
8822
+ id,
8823
+ status: "skipped",
8824
+ ok: true,
8825
+ note: "no state-observable Then to witness"
8826
+ });
8800
8827
  continue;
8801
8828
  }
8802
8829
  const subsystem = routeWitness2(w.fields, subsystems);
@@ -8804,6 +8831,7 @@ async function runWitnessVerification(config) {
8804
8831
  results.push({
8805
8832
  id,
8806
8833
  status: "skipped",
8834
+ ok: true,
8807
8835
  note: `fields [${w.fields.join(", ")}] not owned by a single subsystem`
8808
8836
  });
8809
8837
  continue;
@@ -8814,6 +8842,7 @@ async function runWitnessVerification(config) {
8814
8842
  results.push({
8815
8843
  id,
8816
8844
  status: "error",
8845
+ ok: false,
8817
8846
  subsystem,
8818
8847
  note: `subsystem spec missing: ${subsystem}`
8819
8848
  });
@@ -8826,6 +8855,7 @@ async function runWitnessVerification(config) {
8826
8855
  results.push({
8827
8856
  id,
8828
8857
  status: "error",
8858
+ ok: false,
8829
8859
  subsystem,
8830
8860
  note: err instanceof Error ? err.message : String(err)
8831
8861
  });
@@ -8835,58 +8865,66 @@ async function runWitnessVerification(config) {
8835
8865
  const witnessTla = path4.join(specDir, `${moduleName}.tla`);
8836
8866
  fs4.writeFileSync(witnessTla, buildWitnessModule2(moduleName, `UserApp_${subsystem}`, tlaPredicate));
8837
8867
  fs4.writeFileSync(path4.join(specDir, `${moduleName}.cfg`), buildWitnessCfg2(fs4.readFileSync(subsystemCfg, "utf8")));
8838
- console.log(color(`⚙️ ${id}`, COLORS.blue));
8868
+ const polarityTag = polarity === "forbidden" ? color(" [forbidden — must be unreachable]", COLORS.gray) : "";
8869
+ console.log(color(`⚙️ ${id}`, COLORS.blue) + polarityTag);
8839
8870
  console.log(color(` ${subsystem} ⊨ ${w.predicate}`, COLORS.gray));
8840
8871
  let tlc;
8841
8872
  try {
8842
8873
  tlc = await docker.runTLC(witnessTla, { workers, timeout });
8843
8874
  } catch (err) {
8844
8875
  const msg = err instanceof Error ? err.message : String(err);
8845
- results.push({ id, status: "inconclusive", subsystem, predicate: w.predicate, note: msg });
8846
- console.log(color(" ⚠ inconclusive — TLC did not finish (raise the config timeout)", COLORS.yellow));
8847
- continue;
8848
- }
8849
- if (!tlc.success && tlc.violation?.name === WITNESS_INVARIANT2) {
8850
- results.push({ id, status: "reachable", subsystem, predicate: w.predicate });
8851
- console.log(color(" ✓ reachable — the model reaches this outcome", COLORS.green));
8852
- } else if (tlc.success) {
8853
8876
  results.push({
8854
8877
  id,
8855
- status: "unreachable",
8878
+ status: "inconclusive",
8879
+ ok: true,
8856
8880
  subsystem,
8857
8881
  predicate: w.predicate,
8858
- note: `${tlc.stats?.distinctStates ?? 0} distinct states, no path`
8882
+ note: msg
8859
8883
  });
8860
- console.log(color(" UNREACHABLEthe model proves this outcome impossible (the scenario lies)", COLORS.red));
8861
- fs4.writeFileSync(path4.join(specDir, `${moduleName}.tlc-output.log`), tlc.output);
8862
- } else {
8884
+ console.log(color(" inconclusiveTLC did not finish (raise the config timeout)", COLORS.yellow));
8885
+ continue;
8886
+ }
8887
+ const reachable = !tlc.success && tlc.violation?.name === WITNESS_INVARIANT2;
8888
+ if (!tlc.success && !reachable) {
8863
8889
  results.push({
8864
8890
  id,
8865
8891
  status: "error",
8892
+ ok: false,
8866
8893
  subsystem,
8867
8894
  predicate: w.predicate,
8868
8895
  note: tlc.error ?? tlc.violation?.name ?? "TLC error"
8869
8896
  });
8870
8897
  console.log(color(` ! error — ${tlc.error ?? "see log"}`, COLORS.yellow));
8871
8898
  fs4.writeFileSync(path4.join(specDir, `${moduleName}.tlc-output.log`), tlc.output);
8899
+ continue;
8872
8900
  }
8901
+ const verdict = witnessVerdict2(polarity, reachable);
8902
+ const note = reachable ? undefined : `${tlc.stats?.distinctStates ?? 0} distinct states explored`;
8903
+ results.push({
8904
+ id,
8905
+ status: verdict.status,
8906
+ ok: verdict.ok,
8907
+ subsystem,
8908
+ predicate: w.predicate,
8909
+ note
8910
+ });
8911
+ console.log(color(` ${verdict.ok ? "✓" : "✗"} ${verdict.status} — ${verdict.message}`, verdict.ok ? COLORS.green : COLORS.red));
8912
+ if (!verdict.ok)
8913
+ fs4.writeFileSync(path4.join(specDir, `${moduleName}.tlc-output.log`), tlc.output);
8873
8914
  }
8874
8915
  displayWitnessReport(results);
8875
8916
  }
8876
8917
  function displayWitnessReport(results) {
8877
8918
  const count = (s) => results.filter((r) => r.status === s).length;
8878
- const reachable = count("reachable");
8879
- const unreachable = count("unreachable");
8880
- const inconclusive = count("inconclusive");
8881
- const errors = count("error");
8882
- const skipped = count("skipped");
8883
8919
  console.log();
8884
8920
  console.log(color(`Witness results:
8885
8921
  `, COLORS.blue));
8886
8922
  for (const r of results) {
8887
8923
  const mark = {
8888
8924
  reachable: color("✓", COLORS.green),
8925
+ excluded: color("✓", COLORS.green),
8889
8926
  unreachable: color("✗", COLORS.red),
8927
+ violated: color("✗", COLORS.red),
8890
8928
  inconclusive: color("⚠", COLORS.yellow),
8891
8929
  error: color("!", COLORS.yellow),
8892
8930
  skipped: color("·", COLORS.gray)
@@ -8894,17 +8932,27 @@ function displayWitnessReport(results) {
8894
8932
  const note = r.note ? color(` (${r.note})`, COLORS.gray) : "";
8895
8933
  console.log(` ${mark} ${r.status.padEnd(12)} ${r.id}${note}`);
8896
8934
  }
8935
+ const tally = [
8936
+ "reachable",
8937
+ "excluded",
8938
+ "unreachable",
8939
+ "violated",
8940
+ "inconclusive",
8941
+ "error",
8942
+ "skipped"
8943
+ ].map((s) => `${count(s)} ${s}`).join(", ");
8897
8944
  console.log();
8898
- console.log(color(` ${reachable} reachable, ${unreachable} unreachable, ${inconclusive} inconclusive, ${errors} error, ${skipped} skipped`, COLORS.gray));
8945
+ console.log(color(` ${tally}`, COLORS.gray));
8899
8946
  console.log();
8900
- if (unreachable > 0 || errors > 0) {
8947
+ const failures = results.filter((r) => !r.ok);
8948
+ if (failures.length > 0) {
8901
8949
  console.log(color("Witness result: ✗ FAIL", COLORS.red));
8902
- console.log(color(" A scenario the exhaustive model cannot reach describes an impossible outcome.", COLORS.gray));
8950
+ console.log(color(" An outcome a scenario claims is unreachable, or a forbidden state the model can reach.", COLORS.gray));
8903
8951
  console.log();
8904
8952
  process.exit(1);
8905
8953
  }
8906
8954
  console.log(color("Witness result: ✓ PASS", COLORS.green));
8907
- console.log(color(" Every witnessable scenario's outcome is reachable in the model.", COLORS.gray));
8955
+ console.log(color(" Every claimed outcome is reachable; every forbidden state is proven unreachable.", COLORS.gray));
8908
8956
  console.log();
8909
8957
  }
8910
8958
  function displayEnsuresSummary(results) {
@@ -9213,4 +9261,4 @@ main().catch((error) => {
9213
9261
  process.exit(1);
9214
9262
  });
9215
9263
 
9216
- //# debugId=006B6ED4C6E5114F64756E2164756E21
9264
+ //# debugId=F9E0214A7A9A110B64756E2164756E21