NEO.K / MSSP FIELD LAB010-evidence-about-which-event
編號010-evidence-about-which-event
語言python
版本v1.0
日期2026-08-10
行數774
執行python src/main.py

010 — Evidence has to say which event it is about

candidate. Nothing here is adopted method, and section 3b of the island test is evidence against the criterion this example set out to demonstrate.

What this program does

It reviews five rounds of changes. A source file that drifted needs review unless an exemption applies — and it asks the exemptions a second question: what is this evidence evidence of?

python src/main.py             # the review under the guard SCL names
python src/main.py --strict    # exit 1 when a fatal code appears
python src/main.py --compare   # both guards over the same history
python src/island_test.py      # 26 checks across 7 sections
$ python src/main.py

  r2  2026-08-04
    !!  core/parser.py           review  the evidence is about r1, this change is r2
            evidence   tests/test_parser.py changed  [about r1]

  r4  2026-08-08
    !!  core/emit.py             review  owner-waived expired 2026-07-01, this change is 2026-08-08
            evidence   emitter rewrite in flight  [about *]

  r5  2026-08-10
    ok  build/schema_pb2.py      exempt  generated-file, unconditional by declaration, build-team until 2026-12-01

The structural decision

Evidence names what it is evidence of, and the guard compares that against what is being judged. That turned out to be two questions, not one:

axis the question the field
when which event is this about? about
what which thing is this about? subject

Freshness is not age: tests/test_parser.py changed is true, it was observed just now, and in round 4 it is about round 1. And relevance is not freshness: the same observation, in the right round, can be about a different file.

A guard can bind either axis without the other, and both failures look exactly like a pass. This example shipped in the morning binding only the first one — see below.

Where it came from

mssp-d-003, opened the morning of 2026-08-09 with this criterion:

A check that can only read one value cannot prove anything that needs two values to distinguish.

The EML-P line broke it the same afternoon. Their semantic monitor drilled correctly when it was built, and now reports no drift for a change that rewrites an interpreter's assignment semantics. Nothing broke it — the exemption "the tests changed too" reads test files the baseline has not seen, and "not seen" is relative to a baseline nobody has accepted. The observation takes several values. The value it takes belongs to a change three rounds back.

So the criterion needed a second axis: not only how many values, but which event each value is about. This example is that amendment made executable.

The island test — and the part of it I did not expect

Section 3a measures what I went in to show:

        event-blind-v1   1 distinct: exempt
        event-scoped-v1  2 distinct: exempt, review

Then section 3b asks whether that 1 is a property of the guard or of the history, by adding one file no exemption covers:

  PASS  one unexempted file makes event-blind-v1 produce two verdicts - exempt, review

event-blind-v1 is not stuck on one value. It discriminates perfectly well — on whether evidence exists, which is a different event from the one being judged. The arity framing was the wrong diagnosis of my own three defects.

The same correction arrived independently from the archaeology filed today. CPython's timestamp .pyc validation also takes two values over four edits that all changed the source — it is not a constant either. Its eight bytes of evidence are about the file's metadata; the hash-based mode's eight bytes are about the file's bytes. Same size of evidence, different event.

Section 4 is what survives: hold the observation byte-for-byte identical and move only which round it belongs to.

  PASS  both runs observed the very same thing - 'tests/test_parser.py changed'
  PASS  and they disagree only about which event it was about - r2 vs r1
  PASS  event-scoped-v1 gives different verdicts - exempt vs review
  PASS  event-blind-v1 gives the same verdict to both - exempt and exempt

An exemption is allowed to be unconditional. It is not allowed to be quiet about it.

generated-file returns about: "*" and can never refuse. That is correct: a generated file is generated, and dating that fact would be pedantry. What it pays instead is an owner and a sunset.

This is not a hedge I invented. The archaeology measured the same design upstream on the same day: CPython's UNCHECKED_HASH .pyc mode never revalidates anything, deliberately, and records that choice in two flag bits.

owner-waived is the same shape with its sunset in the past, and that is what the sunset is for.

an exemption that is caught by
cites evidence about this event and this subject valid
cites evidence about an earlier event stale-evidence the about comparison
cites evidence about a different subject wrong-subject the subject comparison
never refuses, by declaration, with an owner and a live sunset valid
never refuses, and its sunset has passed expired-waiver the date comparison
never refuses, and nobody wrote down that it never refuses malformed-evidence fail closed

Note what "unconditional" turned out to mean: generated-file is unconditional in time and still bound in subject. A waiver for core/emit.py does not waive core/parser.py, and the version published this morning could not tell the difference.

The second axis, found by someone else, hours after this shipped

Metron probed the SSD governance runtime by attaching one piece of evidence — content "A exists" — to entity A, entity B, and the relation B→A inside the same snapshot. validate() accepted all three.

They then made a distinction I had not: their runtime binds evidence to its snapshot and projection, so it refuses evidence from another time. It has nothing that refuses evidence about another subject. They declined to call that an implementation of 改良點 10, and they were right to.

Pointing the same probe at this example:

        judging  core/parser.py in r3
        evidence tests/test_lexer.py changed  [about r3, subject core/lexer.py]
        event-blind-v1               exempt
        event-scoped-v1              exempt
        event-and-subject-scoped-v1  review

event-scoped-v1 accepts it, and could not have done otherwise: it never reads change["path"]. Nothing is stale — r3 is exactly the round under judgement and the observation is true.

event-and-subject-scoped-v1 is composed on top rather than replacing it, because the older guard is now the artifact that reproduces the finding, and deleting it would delete the evidence.

Two honest qualifiers, both of which Metron applied to their own probe first:

The sets

set what is in it
FMS the guards and what each reads, the evidence contract and its two axes, the declarations, the history
SCL which guard runs here (now the subject-scoped one), and which codes are fatal
SMS the three guard implementations, resolution by id, the review walk
TMS one file per exemption rule — plain data in, evidence or nothing out, no imports
DMS the verdicts, what each was based on, and what nothing here is watching

What this example does not solve

Measurable, not measured. How often exemption evidence goes stale in a real repository, and what requiring about costs the people who write exemptions.

Not measurable here at all. Whether an exemption should be event-scoped. generated-file is unconditional because of what a generated file is; owner-waived is unconditional because a person decided. The contract knows which is which because someone wrote it down — nothing in the program found out.

And a third axis may exist. about and subject were both found by being caught out, hours apart, on the same day. There is no argument here that two is the number — only that one was demonstrably too few, twice.

The open one stays open: whether any of this is a rule, or a mistake I happen to make often. Section 3b is the strongest thing said against it, and section 6 is the second strongest — the example claiming that evidence must name what it is about shipped without evidence naming what it was about.

Source

FMS

FMS/__init__.py
FMS/contract.json
{
  "name": "010-evidence-about-which-event",
  "what_it_is": "A review gate that lets a drifting source file through when an exemption applies — and refuses the exemption when the evidence behind it is about a different change than the one being judged.",
  "the_structural_decision": "Evidence must name the event it is about, and the guard must compare that name against the event under judgement. Freshness is not age. A perfectly current, perfectly true observation can still be about something else.",
  "where_it_came_from": "mssp-d-003, 2026-08-09. The criterion I published that morning was: a check that can only read one value cannot prove anything that needs two values to distinguish. The EML-P line broke it the same day with a monitor whose exemption read an observation that took several values — and the value it took belonged to a change three rounds earlier. The criterion needed a second axis: not only how many values, but which event each value is about. This example is that amendment, made executable.",
  "status": "candidate",
  "note_on_status": "Nothing here is adopted method. mssp-d-003 is still open, and the archaeology filed the same day (010-cpython-pyc-invalidation) found a case upstream that argues against reading this as a defect detector.",
  "guards": {
    "event-blind-v1": {
      "reads": [
        "whether an exemption produced evidence"
      ],
      "does_not_read": [
        "which event the evidence is about"
      ],
      "note": "The obvious implementation. It is not wrong about anything it looks at."
    },
    "event-scoped-v1": {
      "reads": [
        "whether an exemption produced evidence",
        "evidence.about",
        "the round under judgement",
        "owner and sunset when the evidence declares itself unconditional"
      ],
      "note": "The same evidence, plus the question of what it is evidence OF."
    },
    "event-and-subject-scoped-v1": {
      "reads": [
        "everything event-scoped-v1 reads",
        "evidence.subject",
        "the path under judgement"
      ],
      "note": "Composed on top of event-scoped-v1 rather than replacing it. The older guard is the artifact that reproduces Metron's finding; deleting it would delete the evidence.",
      "credit": "Metron, mssp-board, 2026-08-10 - the probe and the axis are theirs."
    }
  },
  "evidence_contract": {
    "required_fields": [
      "rule",
      "about",
      "subject",
      "observed"
    ],
    "about": "the id of the event this observation is about, or \"*\" when the exemption is unconditional by design",
    "unconditional_requires": [
      "owner",
      "sunset"
    ],
    "why_unconditional_is_allowed": "Some exemptions genuinely are not about an event. A file that is generated is generated; dating that fact would be pedantry. What such an exemption must carry instead is an owner and an expiry, so that 'this can never refuse' is a declared position with someone's name on it rather than an accident. Measured upstream the same day: CPython's UNCHECKED_HASH .pyc mode never revalidates, deliberately, and says so in its header flags.",
    "subject": "what the evidence is about, as opposed to when. Added 2026-08-10 after Metron probed the SSD governance runtime with one piece of evidence attached to three different subjects inside the same snapshot and the validator accepted it. The same probe pointed here returned exempt, because event-scoped-v1 never reads change[\"path\"].",
    "two_axes": "\"what is this evidence of\" turned out to be two questions, not one. `about` answers which event; `subject` answers which thing. A guard can bind either without the other, and both failures look like a pass."
  },
  "exemption_order": [
    "generated-file",
    "owner-waived",
    "tests-changed-too"
  ],
  "declarations": {
    "generated": {
      "build/schema_pb2.py": {
        "owner": "build-team",
        "sunset": "2026-12-01",
        "declared_in": "r1"
      }
    },
    "waivers": {
      "core/emit.py": {
        "owner": "neo",
        "sunset": "2026-07-01",
        "reason": "emitter rewrite in flight"
      }
    },
    "test_for": {
      "core/parser.py": "tests/test_parser.py",
      "core/lexer.py": "tests/test_lexer.py",
      "core/emit.py": "tests/test_emit.py"
    }
  },
  "history": {
    "rounds": [
      {
        "id": "r1",
        "date": "2026-08-01",
        "changes": [
          {
            "path": "core/parser.py",
            "kind": "source",
            "drift": true
          },
          {
            "path": "tests/test_parser.py",
            "kind": "test",
            "drift": false
          }
        ]
      },
      {
        "id": "r2",
        "date": "2026-08-04",
        "changes": [
          {
            "path": "core/parser.py",
            "kind": "source",
            "drift": true
          }
        ]
      },
      {
        "id": "r3",
        "date": "2026-08-06",
        "changes": [
          {
            "path": "core/lexer.py",
            "kind": "source",
            "drift": true
          },
          {
            "path": "tests/test_lexer.py",
            "kind": "test",
            "drift": false
          }
        ]
      },
      {
        "id": "r4",
        "date": "2026-08-08",
        "changes": [
          {
            "path": "core/parser.py",
            "kind": "source",
            "drift": true
          },
          {
            "path": "core/emit.py",
            "kind": "source",
            "drift": true
          }
        ]
      },
      {
        "id": "r5",
        "date": "2026-08-10",
        "changes": [
          {
            "path": "build/schema_pb2.py",
            "kind": "generated",
            "drift": true
          },
          {
            "path": "core/lexer.py",
            "kind": "source",
            "drift": true
          }
        ]
      }
    ]
  },
  "sets": {
    "FMS": "this file: the guards and what each reads, the evidence contract, the declarations, and the history under review",
    "SCL": "which guard this deployment runs, and whether evidence about another event is fatal or reported",
    "SMS": "the guard implementations, resolution by id, and the review that walks the history",
    "TMS": "one file per exemption rule — each takes plain data and returns evidence or nothing, and imports nothing",
    "DMS": "the verdicts, what each was based on, and what nothing here is watching"
  },
  "non_goals": [
    "Being a review tool. Five rounds and three exemption rules over a made-up file list.",
    "Claiming the exemption set is complete. It is three rules someone wrote.",
    "Claiming event-scoped-v1 is correct in general. It refuses evidence about another event; whether that is the right call depends on whether the exemption was ever meant to be about an event at all, which is why unconditional exemptions exist here as a first-class case rather than as a bug."
  ]
}

SCL

SCL/__init__.py
SCL/policy.json
{
  "guard": "event-and-subject-scoped-v1",
  "stale_evidence_is_fatal": true,
  "expired_waiver_is_fatal": true,
  "malformed_evidence_is_fatal": true,
  "_note": "The guard is named here rather than imported, so that swapping it is a deployment decision and not an edit to SMS. island_test.py runs all three regardless of what this says - a policy that could silence the comparison would make the comparison worthless.",
  "wrong_subject_is_fatal": true
}
SCL/policy.py
"""Which guard this deployment runs, and what it treats as fatal."""
import json
import pathlib

_C = json.loads((pathlib.Path(__file__).parent / "policy.json").read_text(encoding="utf-8"))

guard = lambda: _C["guard"]                                              # noqa: E731
FATAL_CODES = {
    "stale-evidence": "stale_evidence_is_fatal",
    "expired-waiver": "expired_waiver_is_fatal",
    "malformed-evidence": "malformed_evidence_is_fatal",
    "wrong-subject": "wrong_subject_is_fatal",
}


def is_fatal(code):
    key = FATAL_CODES.get(code)
    return bool(_C.get(key)) if key else False

SMS

SMS/__init__.py
SMS/guards.py
"""Two guards over the same evidence. Only one of them asks what it is evidence OF.

Both are honest implementations. event-blind-v1 is not wrong about anything it
looks at — it is the version most people write, and across the whole history it
returns a single verdict, which is the property island_test.py section 3
measures rather than asserts.
"""


def event_blind_v1(change, evidence, view):
    if evidence is None:
        return {"verdict": "review", "code": "no-evidence",
                "because": "no exemption produced evidence"}
    return {"verdict": "exempt", "code": "evidence-exists",
            "because": f"{evidence['rule']} produced evidence"}


def event_scoped_v1(change, evidence, view):
    if evidence is None:
        return {"verdict": "review", "code": "no-evidence",
                "because": "no exemption produced evidence"}

    about = evidence.get("about")
    if not about:
        return {"verdict": "review", "code": "malformed-evidence",
                "because": "the evidence does not say what event it is about - fail closed"}

    if about == "*":
        missing = [f for f in view["unconditional_requires"] if not evidence.get(f)]
        if missing:
            return {"verdict": "review", "code": "malformed-evidence",
                    "because": f"unconditional evidence with no {', '.join(missing)} - fail closed"}
        # Dates are compared as ISO strings against the round's own date, not
        # against today, so this test means the same thing next month.
        if evidence["sunset"] < change["date"]:
            return {"verdict": "review", "code": "expired-waiver",
                    "because": f"{evidence['rule']} expired {evidence['sunset']}, this change is {change['date']}"}
        return {"verdict": "exempt", "code": "unconditional",
                "because": f"{evidence['rule']}, unconditional by declaration, {evidence['owner']} until {evidence['sunset']}"}

    if about != change["round"]:
        return {"verdict": "review", "code": "stale-evidence",
                "because": f"the evidence is about {about}, this change is {change['round']}"}

    return {"verdict": "exempt", "code": "evidence-about-this-event",
            "because": f"{evidence['rule']}, observed in {about}"}


def event_and_subject_scoped_v1(change, evidence, view):
    """Everything event-scoped-v1 does, plus what it cannot see.

    Added the same day the example shipped, because Metron probed their own
    runtime with a piece of evidence attached to the wrong subject inside the
    right snapshot, and the validator accepted it. Pointing the same probe here
    produced `exempt / evidence-about-this-event` — event-scoped-v1 never reads
    change["path"] at all, so it could not have refused.

    Composed on top rather than replacing it: the older guard is the artifact
    that reproduces the finding, and deleting it would delete the evidence.
    """
    verdict = event_scoped_v1(change, evidence, view)
    if verdict["verdict"] != "exempt":
        return verdict

    subject = evidence.get("subject")
    if not subject:
        return {"verdict": "review", "code": "malformed-evidence",
                "because": "the evidence does not say what it is about - fail closed"}
    if subject != change["path"]:
        return {"verdict": "review", "code": "wrong-subject",
                "because": f"the evidence is about {subject}, this change is {change['path']}"}
    return verdict


IMPLEMENTATIONS = {
    "event-blind-v1": event_blind_v1,
    "event-scoped-v1": event_scoped_v1,
    "event-and-subject-scoped-v1": event_and_subject_scoped_v1,
}


def resolve(name):
    """A guard id that does not resolve is not a warning. Nothing runs."""
    implementation = IMPLEMENTATIONS.get(name)
    if implementation is None:
        known = ", ".join(sorted(IMPLEMENTATIONS))
        return None, f'guard "{name}" has no implementation - fail closed (known: {known})'
    return implementation, None
SMS/review.py
"""Walk the history, ask each exemption in the declared order, judge with the named guard."""
import importlib

from SMS import guards


def load_exemptions(order):
    """Resolve rule ids to modules, and check that each module agrees it is that rule.

    The RULE-vs-order comparison is here because 008 taught it the expensive
    way: an id that is resolved but never checked against what actually runs is
    a name with nothing behind it.
    """
    loaded, problems = [], []
    for rule in order:
        module_name = "TMS.exemptions." + rule.replace("-", "_")
        try:
            module = importlib.import_module(module_name)
        except ModuleNotFoundError:
            problems.append(f'exemption "{rule}" has no module - fail closed')
            continue
        declared = getattr(module, "RULE", None)
        if declared != rule:
            problems.append(f'{module_name} declares RULE={declared!r} but was ordered as {rule!r}')
            continue
        loaded.append((rule, module))
    return loaded, problems


def first_evidence(change, ctx, exemptions):
    for _rule, module in exemptions:
        evidence = module.look(change, ctx)
        if evidence is not None:
            return evidence
    return None


def judged_changes(contract):
    """Every drifting change in the history, flattened, with its round attached."""
    for rnd in contract["history"]["rounds"]:
        for change in rnd["changes"]:
            if not change.get("drift"):
                continue
            yield {"round": rnd["id"], "date": rnd["date"],
                   "path": change["path"], "kind": change["kind"]}


def review(contract, guard_name):
    guard, problem = guards.resolve(guard_name)
    if problem:
        return None, [problem]

    exemptions, problems = load_exemptions(contract["exemption_order"])
    ctx = {"rounds": contract["history"]["rounds"], "declarations": contract["declarations"]}
    view = {"unconditional_requires": contract["evidence_contract"]["unconditional_requires"]}

    rows = []
    for change in judged_changes(contract):
        evidence = first_evidence(change, ctx, exemptions)
        rows.append({**change, "evidence": evidence, **guard(change, evidence, view)})
    return rows, problems


def verdict_values(rows):
    """How many distinct verdicts a guard produced over this history.

    One means it could not have come out any other way here - which is not proof
    that it never can, only that this history never made it.
    """
    return sorted({row["verdict"] for row in rows})

TMS

TMS/__init__.py
TMS/exemptions/__init__.py
TMS/exemptions/generated_file.py
"""A generated file is generated. That is not an event, and dating it would be pedantry.

So this exemption returns `about: "*"` — unconditional by design — and pays for
that by carrying an owner and a sunset. The point is not that it never refuses;
the point is that "this can never refuse" is a position with someone's name on
it rather than something nobody noticed.
"""
RULE = "generated-file"


def look(change, ctx):
    declared = ctx["declarations"]["generated"].get(change["path"])
    if not declared:
        return None
    return {
        "rule": RULE,
        "about": "*",
        "subject": change["path"],
        "unconditional": True,
        "observed": f"{change['path']} was declared generated in {declared['declared_in']}",
        "owner": declared["owner"],
        "sunset": declared["sunset"],
    }
TMS/exemptions/owner_waived.py
"""Someone decided this file is exempt while a rewrite is in flight.

Same shape as generated-file — unconditional, owner, sunset — and the only
difference in this history is that this one's sunset has passed. That is what
the sunset is for: an unconditional exemption is allowed, an unconditional
exemption that outlives its reason is the thing being caught.
"""
RULE = "owner-waived"


def look(change, ctx):
    waiver = ctx["declarations"]["waivers"].get(change["path"])
    if not waiver:
        return None
    return {
        "rule": RULE,
        "about": "*",
        "subject": change["path"],
        "unconditional": True,
        "observed": waiver["reason"],
        "owner": waiver["owner"],
        "sunset": waiver["sunset"],
    }
TMS/exemptions/tests_changed_too.py
"""The exemption that started all this: a source file may drift if its tests moved too.

The observation is real and it is not a constant — across the history it takes
several values. What it does not carry, unless someone asks for it, is which
round it took that value in. Note that `observed` reads identically whether the
test changed in this round or four rounds ago; only `about` can tell them apart.
"""
RULE = "tests-changed-too"


def look(change, ctx):
    test_path = ctx["declarations"]["test_for"].get(change["path"])
    if not test_path:
        return None

    # The most recent round, at or before the one under judgement, in which that
    # test file changed. Walking forward and stopping is deliberate: a test
    # change from a LATER round is not evidence about this one either.
    seen_in = None
    for rnd in ctx["rounds"]:
        for changed in rnd["changes"]:
            if changed["path"] == test_path:
                seen_in = rnd["id"]
        if rnd["id"] == change["round"]:
            break

    if seen_in is None:
        return None
    return {"rule": RULE, "about": seen_in, "subject": change["path"],
            "observed": f"{test_path} changed"}

DMS

DMS/__init__.py
DMS/report.py
"""What the review saw, what it was based on, and what nothing here is watching."""

MARK = {"exempt": "ok", "review": "!!"}


def rows(review_rows, out):
    current = None
    for row in review_rows:
        if row["round"] != current:
            current = row["round"]
            out(f"\n  {row['round']}  {row['date']}")
        out(f"    {MARK[row['verdict']]}  {row['path']:<24} {row['verdict']:<7} {row['because']}")
        evidence = row["evidence"]
        if evidence:
            out(f"            evidence   {evidence['observed']}  [about {evidence['about']}]")


def verdict_counts(review_rows, out):
    counts = {}
    for row in review_rows:
        counts[row["code"]] = counts.get(row["code"], 0) + 1
    for code in sorted(counts):
        out(f"    {counts[code]:>2}  {code}")


def blind_spots(out):
    """改良點 8: what was not solved, split into what cannot be measured here
    and what simply was not."""
    out("\n  not measured here, but measurable:")
    out("    - how often an exemption's evidence goes stale in a real repository")
    out("    - whether requiring `about` changes how often people write exemptions at all")
    out("\n  not measurable by this program at all:")
    out("    - whether an exemption SHOULD have been event-scoped. generated-file is")
    out("      unconditional because a generated file is generated; owner-waived is")
    out("      unconditional because someone said so. Only the second is a judgement,")
    out("      and nothing here can tell them apart - the contract records which is which")
    out("      because a person decided, not because the program found out.")

root

island_test.py
"""The island test, and the drill that corrected the claim this example started from.

    python src/island_test.py

Section 3 is the one that matters, and it does not come out the way I expected.
I opened mssp-d-003 with "a check that can only read one value cannot prove
anything that needs two". event-blind-v1 reads one value over this history — and
section 3b shows it is not a constant at all: extend the history by one
unexempted file and it produces two. So the defect was never the arity. It is
that the values it does take are about a different event than the one under
judgement. Section 4 holds the observation byte-identical and moves only which
event it belongs to.
"""
import copy
import json
import pathlib
import re
import sys

HERE = pathlib.Path(__file__).parent
sys.path.insert(0, str(HERE))

from SCL import policy  # noqa: E402
from SMS import guards, review  # noqa: E402

CONTRACT = json.loads((HERE / "FMS" / "contract.json").read_text(encoding="utf-8"))
FAILURES = []


def check(label, ok, detail=""):
    print(f"  {'PASS' if ok else 'FAIL'}  {label}{' - ' + detail if detail else ''}")
    if not ok:
        FAILURES.append(label)


def run(contract, guard_name):
    rows, problems = review.review(contract, guard_name)
    assert not problems, problems
    return rows


print("\n== 1. every exemption is an island, and every one honours the evidence contract")
exemption_dir = HERE / "TMS" / "exemptions"
files = sorted(f for f in exemption_dir.iterdir() if f.suffix == ".py" and f.name != "__init__.py")
check("there are three exemption files", len(files) == 3, ", ".join(f.stem for f in files))
for f in files:
    reaches = re.findall(r"^\s*(?:from|import)\s+(\S+)", f.read_text(encoding="utf-8"), re.M)
    siblings = [r for r in reaches if r.split(".")[0] in {"TMS", "SMS", "SCL", "DMS", "FMS"}]
    check(f"{f.stem} reaches no sibling set", not siblings, ", ".join(reaches) or "no imports at all")

required = CONTRACT["evidence_contract"]["required_fields"]
seen_evidence = [row["evidence"] for row in run(CONTRACT, "event-scoped-v1") if row["evidence"]]
check("every piece of evidence produced carries every required field",
      all(all(field in ev for field in required) for ev in seen_evidence),
      f"{len(seen_evidence)} pieces, fields {', '.join(required)}")
unconditional = [ev for ev in seen_evidence if ev["about"] == "*"]
check("every unconditional exemption names an owner and a sunset",
      all(ev.get("owner") and ev.get("sunset") for ev in unconditional),
      f"{len(unconditional)} unconditional: " + ", ".join(sorted({ev['rule'] for ev in unconditional})))

print("\n== 2. the guard id selects behaviour, it is not just resolved")
# 008 was lost to exactly this: an id that resolved and never reached the thing
# it named. Resolution is proved by disagreement, not by the lookup succeeding.
blind = run(CONTRACT, "event-blind-v1")
scoped = run(CONTRACT, "event-scoped-v1")
differ = [(b["round"], b["path"]) for b, s in zip(blind, scoped) if b["verdict"] != s["verdict"]]
check("the two ids produce different verdicts on the same history", bool(differ),
      f"{len(differ)} of {len(blind)} changes differ")
_, problem = guards.resolve("event-scoped-v2")
check("an id with no implementation stops the run", problem is not None, problem or "resolved anyway")
rows, problems = review.review(CONTRACT, "event-scoped-v2")
check("and nothing is reviewed when it does not resolve", rows is None, f"{len(problems)} problem(s)")

print("\n== 3a. how many verdicts each guard produced over THIS history")
for name in ("event-blind-v1", "event-scoped-v1"):
    values = review.verdict_values(run(CONTRACT, name))
    print(f"        {name:<16} {len(values)} distinct: {', '.join(values)}")
check("event-blind-v1 produced exactly one verdict here",
      review.verdict_values(blind) == ["exempt"], ", ".join(review.verdict_values(blind)))
check("event-scoped-v1 produced two", len(review.verdict_values(scoped)) == 2,
      ", ".join(review.verdict_values(scoped)))

print("\n== 3b. the drill: is that one value a property of the guard, or of the history?")
# If this section cannot come out the other way, section 3a proves nothing about
# the guard. Add one file no exemption covers and see whether blind moves.
extended = copy.deepcopy(CONTRACT)
extended["history"]["rounds"].append({"id": "r6", "date": "2026-08-11", "changes": [
    {"path": "core/unclaimed.py", "kind": "source", "drift": True}]})
blind_extended = review.verdict_values(run(extended, "event-blind-v1"))
check("one unexempted file makes event-blind-v1 produce two verdicts",
      len(blind_extended) == 2, ", ".join(blind_extended))
print("        so the single value in 3a is not an inability to say 'review'.")
print("        event-blind-v1 discriminates. It discriminates on whether evidence")
print("        EXISTS - which is a different event from the one being judged.")

print("\n== 4. the same observation, byte for byte, about two different events")
# Hold everything constant except which round the test change belongs to. If the
# `observed` strings are not identical, this section is comparing two different
# observations and proves nothing.
def parser_drift_in_r2(test_round):
    c = copy.deepcopy(CONTRACT)
    c["history"]["rounds"] = [
        {"id": "r1", "date": "2026-08-01", "changes":
            ([{"path": "tests/test_parser.py", "kind": "test", "drift": False}]
             if test_round == "r1" else [])},
        {"id": "r2", "date": "2026-08-04", "changes":
            [{"path": "core/parser.py", "kind": "source", "drift": True}]
            + ([{"path": "tests/test_parser.py", "kind": "test", "drift": False}]
               if test_round == "r2" else [])},
    ]
    return c

same_round = run(parser_drift_in_r2("r2"), "event-scoped-v1")[0]
earlier = run(parser_drift_in_r2("r1"), "event-scoped-v1")[0]
check("both runs observed the very same thing",
      same_round["evidence"]["observed"] == earlier["evidence"]["observed"],
      repr(same_round["evidence"]["observed"]))
check("and they disagree only about which event it was about",
      same_round["evidence"]["about"] != earlier["evidence"]["about"],
      f"{same_round['evidence']['about']} vs {earlier['evidence']['about']}")
check("event-scoped-v1 gives different verdicts", same_round["verdict"] != earlier["verdict"],
      f"{same_round['verdict']} vs {earlier['verdict']}")
blind_same = run(parser_drift_in_r2("r2"), "event-blind-v1")[0]
blind_earlier = run(parser_drift_in_r2("r1"), "event-blind-v1")[0]
check("event-blind-v1 gives the same verdict to both",
      blind_same["verdict"] == blind_earlier["verdict"],
      f"{blind_same['verdict']} and {blind_earlier['verdict']}")

print("\n== 5. fail closed")
view = {"unconditional_requires": CONTRACT["evidence_contract"]["unconditional_requires"]}
change = {"round": "r2", "date": "2026-08-04", "path": "core/parser.py", "kind": "source"}
for label, evidence, expected in [
    ("evidence with no `about`", {"rule": "x", "observed": "something"}, "malformed-evidence"),
    ("unconditional with no owner",
     {"rule": "x", "about": "*", "observed": "s", "sunset": "2026-12-01"}, "malformed-evidence"),
    ("unconditional past its sunset",
     {"rule": "x", "about": "*", "observed": "s", "owner": "n", "sunset": "2026-07-01"}, "expired-waiver"),
]:
    out = guards.event_scoped_v1(change, evidence, view)
    check(f"{label} -> review", out["verdict"] == "review" and out["code"] == expected, out["code"])

order = list(CONTRACT["exemption_order"]) + ["a-rule-nobody-wrote"]
_, problems = review.load_exemptions(order)
check("an ordered rule with no module is a problem, not a skip", len(problems) == 1,
      problems[0] if problems else "silently skipped")

import TMS.exemptions.owner_waived as ow  # noqa: E402
ow.RULE, restored = "something-else", "owner-waived"
_, problems = review.load_exemptions(CONTRACT["exemption_order"])
ow.RULE = restored
check("a module that disagrees with the id it was reached by is a problem",
      len(problems) == 1, problems[0] if problems else "accepted anyway")

print("\n== 6. Metron's probe: the right event, the wrong subject")
# Metron probed the SSD governance runtime by attaching one piece of evidence
# to three different subjects inside the same snapshot; validate() accepted it.
# Pointed here the same afternoon, event-scoped-v1 also accepted, because it
# never reads change["path"]. This section is that probe, kept runnable.
judged = {"round": "r3", "date": "2026-08-06", "path": "core/parser.py", "kind": "source"}
foreign = {"rule": "tests-changed-too", "about": "r3", "subject": "core/lexer.py",
           "observed": "tests/test_lexer.py changed"}
print(f"        judging  {judged['path']} in {judged['round']}")
print(f"        evidence {foreign['observed']}  [about {foreign['about']}, "
      f"subject {foreign['subject']}]")
for name in ("event-blind-v1", "event-scoped-v1", "event-and-subject-scoped-v1"):
    implementation, _ = guards.resolve(name)
    print(f"        {name:<28} {implementation(judged, foreign, view)['verdict']}")
blind_says = guards.event_blind_v1(judged, foreign, view)
scoped_says = guards.event_scoped_v1(judged, foreign, view)
both_says = guards.event_and_subject_scoped_v1(judged, foreign, view)
check("event-scoped-v1 accepts it - the finding, reproduced here",
      scoped_says["verdict"] == "exempt", scoped_says["code"])
check("event-and-subject-scoped-v1 refuses it",
      both_says["verdict"] == "review" and both_says["code"] == "wrong-subject",
      both_says["because"])
check("and the two disagree, which is the only reason either means anything",
      scoped_says["verdict"] != both_says["verdict"],
      f"{scoped_says['verdict']} vs {both_says['verdict']}")
# The drill: the subject check must be capable of passing too, or section 7
# proves only that the new guard refuses everything.
matching = dict(foreign, subject=judged["path"])
check("the same guard accepts it once the subject matches",
      guards.event_and_subject_scoped_v1(judged, matching, view)["verdict"] == "exempt",
      "so the refusal is about the subject, not about the guard being stricter")
check("evidence with no subject fails closed",
      guards.event_and_subject_scoped_v1(
          judged, {k: v for k, v in matching.items() if k != "subject"},
          view)["code"] == "malformed-evidence")
print("        NOTE: over the published history the last two guards never disagree.")
print("        The pipeline binds subject by construction - look() derives evidence")
print("        from the change's own path. This is a constructed acceptance gap,")
print("        not an observed incident, and Metron classified theirs the same way.")

print("\n== 7. what this does not settle")
print("        MEASURABLE, NOT MEASURED")
print("          - how often exemption evidence goes stale in a real repository")
print("          - what requiring `about` costs the people writing exemptions")
print("        NOT MEASURABLE HERE")
print("          - whether an exemption SHOULD be event-scoped. generated-file is")
print("            unconditional because a generated file is generated; owner-waived is")
print("            unconditional because a person said so. The contract knows which is")
print("            which because someone wrote it down, not because anything found out.")
print("          - whether event-scoped-v1 is right. Section 3b is evidence against the")
print("            form of the criterion I opened mssp-d-003 with, not for it.")

print(f"\n{len(FAILURES)} failure(s)" if FAILURES else "\nall checks passed")
for f in FAILURES:
    print(f"  - {f}")
sys.exit(1 if FAILURES else 0)
main.py
"""A review gate that asks what its evidence is evidence OF.

    python src/main.py             the review under the guard SCL names
    python src/main.py --strict    exit 1 when a fatal code appears
    python src/main.py --compare   both guards over the same history, side by side
"""
import json
import pathlib
import sys

HERE = pathlib.Path(__file__).parent
sys.path.insert(0, str(HERE))

from DMS import report  # noqa: E402
from SCL import policy  # noqa: E402
from SMS import review  # noqa: E402

CONTRACT = json.loads((HERE / "FMS" / "contract.json").read_text(encoding="utf-8"))


def main(argv):
    out = lambda line="": sys.stdout.write(line + "\n")  # noqa: E731
    strict = "--strict" in argv

    if "--compare" in argv:
        names = list(CONTRACT["guards"])
        out("\n== the same history, judged by each guard")
        out("\n  " + f"{'change':<34}" + "".join(f"{n:<30}" for n in names))
        results = {}
        for name in names:
            rows, problems = review.review(CONTRACT, name)
            if problems:
                for problem in problems:
                    out(f"  !! {problem}")
                return 1
            results[name] = rows
        for index in range(len(results[names[0]])):
            row = results[names[0]][index]
            verdicts = [results[name][index]["verdict"] for name in names]
            flag = "  <-- they disagree" if len(set(verdicts)) > 1 else ""
            out(f"  {row['round'] + ' ' + row['path']:<34}"
                + "".join(f"{v:<30}" for v in verdicts) + flag)
        for name in names:
            values = review.verdict_values(results[name])
            out(f"\n  {name:<28} produced {len(values)} distinct verdict(s): {', '.join(values)}")
        out("\n  Over THIS history the last two agree, because nothing in it")
        out("  attaches evidence to the wrong subject. That is a fact about the")
        out("  history - island_test.py section 6 supplies the input that separates them.")
        out("\n  A guard that produced one verdict over this history could not have")
        out("  come out any other way here. That is a fact about this history as")
        out("  much as about the guard - see island_test.py section 3.")
        return 0

    guard_name = policy.guard()
    rows, problems = review.review(CONTRACT, guard_name)
    if problems:
        for problem in problems:
            out(f"  !! {problem}")
        return 1

    out(f"\n== review under {guard_name}")
    report.rows(rows, out)

    out("\n== why each change was let through, or was not")
    report.verdict_counts(rows, out)

    fatal = [row for row in rows if policy.is_fatal(row["code"])]
    if fatal:
        out(f"\n  {len(fatal)} change(s) the deployment treats as fatal:")
        for row in fatal:
            out(f"    {row['round']} {row['path']:<24} {row['code']:<20} {row['because']}")

    report.blind_spots(out)

    if strict and fatal:
        return 1
    return 0


if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))