S00-001: Define the Web scope passport and native exclusion boundaries

Changes: Add proposed scope ADR with reasons for all ten excluded IDs, retained Web obligations, lifecycle limits, external provider roles and deferred decisions. Add a document coverage/lifecycle checker with four negative mutations and executor evidence/handoff for security review.
Validation: python3 experiments/0000-scope/check.py passed for ten excluded IDs and seven lifecycle scenarios; all four negative mutations were rejected. make check passed validation and 66 tooling tests. Whitespace and allowed source paths checked. No live browser or provider integration was tested; ADR awaits independent review.

Task: S00-001
Agent: auto-orchestrator-48aab142ecde
Role: orchestrator
Action: claim
Status: review

Task title: Утвердить Web-профиль
This commit is contained in:
wt committed 2026-10-15 01:01:57 +07:00
1 parent 522311022f
commit d5ed7eaaed
9 files changed
+247 -8

No files matched your search

+69
View File
@@ -0,0 +1,69 @@
"""Check the scope passport against canonical applicability and WEB-002 limits.
Document-only experiment; no product runtime or provider connection is simulated.
"""
import json
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
ID = re.compile(r"\| ((?:[A-Z]+-)+\d{3}) \| (.+?) \| (.+?) \|")
STATES = {"foreground", "hidden", "closed-tab", "browser-terminated",
"permission-denied", "offline", "logged-out"}
def check(document, requirements):
excluded = {r["id"] for r in requirements if r["applicability"] == "out_of_scope"}
rows = ID.findall(document)
assert len(rows) == len({r[0] for r in rows}), "Duplicate excluded ID"
assert {r[0] for r in rows} == excluded, "Excluded coverage differs from canonical registry"
for rid, reason, retained in rows:
assert len(reason.strip()) >= 40, f"Missing substantive reason: {rid}"
assert len(retained.strip()) >= 30, f"Missing Web boundary: {rid}"
entry = next(r for r in requirements if r["id"] == rid)
assert f"**{rid}.**" in (ROOT / entry["source"]).read_text(), rid
lifecycle = {}
for line in document.splitlines():
cells = [c.strip() for c in line.split("|")[1:-1]]
if cells and cells[0] in STATES:
assert len(cells) == 5 and cells[0] not in lifecycle, "Malformed lifecycle row"
lifecycle[cells[0]] = cells[1:]
assert set(lifecycle) == STATES, "Incomplete lifecycle scenarios"
assert all(v in {"conditional", "none", "not-guaranteed"}
for row in lifecycle.values() for v in row), "Unsupported guarantee"
for state in {"closed-tab", "browser-terminated", "offline", "logged-out"}:
row = lifecycle[state]
assert row[0] == "none" and row[2:] == ["none", "none"], f"False session/media promise: {state}"
assert lifecycle["hidden"][0] == "not-guaranteed", "Hidden socket continuity promise"
assert lifecycle["closed-tab"][1] == "conditional", "Push confused with session or guaranteed delivery"
assert lifecycle["permission-denied"][1:] == ["none"] * 3, "Denied permissions bypassed"
assert lifecycle["logged-out"] == ["none"] * 4, "Logout reactivation promise"
return len(excluded), len(lifecycle)
def main():
document = (ROOT / "docs/decisions/0000-scope.md").read_text()
requirements = json.loads((ROOT / "planning/requirements.json").read_text())
counts = check(document, requirements)
mutations = [
re.sub(r"^\| ACC-003 \|.*\n", "", document, flags=re.M),
re.sub(r"^\| ACC-003 \|.*$", "| ACC-003 | | |", document, flags=re.M),
document.replace("| closed-tab | none | conditional | none | none |",
"| closed-tab | conditional | conditional | none | none |"),
document.replace("| closed-tab | none | conditional | none | none |",
"| closed-tab | none | conditional | conditional | none |"),
]
for index, mutant in enumerate(mutations, 1):
assert mutant != document, "Negative fixture did not mutate document"
try:
check(mutant, requirements)
except AssertionError:
continue
raise AssertionError(f"False passport accepted: mutation {index}")
print(f"PASS: {counts[0]} excluded IDs match registry/specs with reasons; "
f"{counts[1]} lifecycle scenarios; {len(mutations)} negative mutations rejected.")
print("LIMIT: document validation only; browser/provider behavior is untested.")
if __name__ == "__main__":
main()