You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
4 pre-existing Alloy model violations exposed by the #199 detector fix #218
PR #214 (issue #199) fixed the Alloy runners so they actually detect assertion violations. That fix immediately surfaced 4 genuine, pre-existing formal-model violations that the dead /Counterexample/i regex had been silently recording as pass. These are NOT regressions introduced by #214 — they exist on main today and have been reported green the whole time.
All 4 report assertion counterexamples (not vacuity / not parser errors — the new parser's 18 existing runner tests stay green).
Why this matters
This is the core risk that issue #199 was about: the formal-verification surface could not report a violation, so 4 genuinely-violated invariants were being counted as verified. Each needs triage:
Real system bug — the modeled behavior is wrong → fix the implementation.
Wrong assertion — the spec over-constrains → fix the .als.
Stale model — the spec drifted from the current design → update or retire it.
Action
Triage quorum-compositionAllRulesHold (start here — confirmed real counterexample)
Deep assessment complete — all 4 are SPEC bugs, none are implementation bugs
Each violation was reproduced with Alloy 6 and cross-referenced against the implementation. The code is correct in every case; the models were wrong, and the dead /Counterexample/i regex hid it. Being fixed in PR #214 (spec-only, no waivers):
Check
Verdict
Root cause
Fix
quorum-composition / AllRulesHold
SPEC_BUG
Asserts High ⇒ ≥1 slot unconditionally; facts only guarantee that when #availableSlots > 0. Empty/all-down roster is the counterexample — real system routes it to solo mode.
Add the #availableSlots > 0 guard so the assertion matches the facts.
install-scope / AllEquivalence
SPEC_BUG
Claims all fully-installed states are identical, but scope (Local/Global) is an orthogonal free choice (--all --global vs --all --local).
Tie both states to a shared InstallOp at one fixed scope (mirrors the passing InstallIdempotent).
Under-constrained: no relation binds a Classification to the snapshot it was classified against, so the solver picks mismatched pairs.
Bind Classification.against to its snapshot + model the is_new classifier contract as a fact. Also: stale provenance — SCBD-05/06/07 referenced but absent from requirements.json.
transcript-scan / PairingUniqueCheck
SPEC_BUG
No fact enforces unique tool_use/tool_result IDs, so the solver collapses many onto one Id atom.
Add injectivity facts (real transcripts always have unique block.id).
Bounds successCount by minSize per a removed qgsd-stop.js:453 break; current code breaks at successCount >= maxSize (nf-stop.js:1069) since the #192 min_live_voters rework.
Add injectivity facts + re-anchor the ceiling to maxSize, update source-line comments.
Net: no implementation changes needed. Once #214's spec fixes land green, this issue is resolved (modulo the separate cleanup of the missing SCBD-05/06/07 requirement entries, which I'll leave noted here).
The 4 Alloy specs are fixed and merged via #214 (#199) — all spec/model bugs, no implementation changes. Formal CI is green. Leaving this issue open only for the residual cleanup: create the missing SCBD-05/06/07 requirement entries in .planning/formal/requirements.json (referenced by the taxonomy-safety spec's @requirement tags).
Activity
jobordu commentedon Jun 19, 2026
Deep assessment complete — all 4 are SPEC bugs, none are implementation bugs
Each violation was reproduced with Alloy 6 and cross-referenced against the implementation. The code is correct in every case; the models were wrong, and the dead
/Counterexample/iregex hid it. Being fixed in PR #214 (spec-only, no waivers):quorum-composition / AllRulesHoldHigh ⇒ ≥1 slotunconditionally; facts only guarantee that when#availableSlots > 0. Empty/all-down roster is the counterexample — real system routes it to solo mode.#availableSlots > 0guard so the assertion matches the facts.install-scope / AllEquivalence--all --globalvs--all --local).InstallOpat one fixed scope (mirrors the passingInstallIdempotent).taxonomy-safety / TaxonomyClosed + NewCategoryConsistentClassificationto the snapshot it was classified against, so the solver picks mismatched pairs.Classification.againstto its snapshot + model theis_newclassifier contract as a fact. Also: stale provenance —SCBD-05/06/07referenced but absent from requirements.json.transcript-scan / PairingUniqueChecktool_use/tool_resultIDs, so the solver collapses many onto one Id atom.block.id).transcript-scan / SuccessCountNeverExceedsMinSizeChecksuccessCountbyminSizeper a removedqgsd-stop.js:453break; current code breaks atsuccessCount >= maxSize(nf-stop.js:1069) since the #192 min_live_voters rework.maxSize, update source-line comments.Net: no implementation changes needed. Once #214's spec fixes land green, this issue is resolved (modulo the separate cleanup of the missing SCBD-05/06/07 requirement entries, which I'll leave noted here).
jobordu commentedon Jun 19, 2026
The 4 Alloy specs are fixed and merged via #214 (#199) — all spec/model bugs, no implementation changes. Formal CI is green. Leaving this issue open only for the residual cleanup: create the missing
SCBD-05/06/07requirement entries in.planning/formal/requirements.json(referenced by the taxonomy-safety spec's @requirement tags).