status
Foundation checks / foundation (push) Failing after 2m49s

This commit is contained in:
wt committed 2026-10-15 18:43:29 +07:00
1 parent ce4d994598
commit c0ce1bd026
5 files changed
+377 -3

No files matched your search

+21
View File
@@ -0,0 +1,21 @@
# Browser passport validation
From project root, Python 3.10+ stdlib only:
```sh
python3 experiments/0005-browser-matrix/check.py
```
`matrix.json` contains target recipes, resource ceilings, required run-record
fields and capability fallback rules. Normative measurement and permission
procedures: `docs/decisions/0005-browser-matrix.md`. Target OS families/stable
channels must be resolved to supported full builds before a real qualification;
archive full build identifiers, installer hash or Apple OS build, app and fixture
hashes, actual viewport and tool configuration. No browser binaries are supplied.
The checker rejects missing targets/reproduction fields/fallbacks, compiler floor
regressions, impossible RAM ceilings and missing iOS Home Screen mode. Negative
fixtures exercise those refusals; percentile fixtures verify nearest-rank p95.
It does not execute a browser, simulate a successful permission request, measure
resources, qualify hardware or prove a real fallback implementation. A passing
passport check must not be reported as passing production browser acceptance.
+88
View File
@@ -0,0 +1,88 @@
"""Validate a qualification passport, not browser capability or app performance."""
import copy
import json
import math
from pathlib import Path
HERE = Path(__file__).resolve().parent
REQUIRED_FALLBACKS = {
"secure-context", "crypto-worker-wasm", "indexeddb", "persistence", "push",
"install", "media", "recording-codec", "geolocation", "webauthn",
"permissions-query", "lifecycle",
}
REPRODUCTION = {
"target_id", "run_utc", "device_model", "cpu", "ram_gib", "os_full_build",
"browser_full_build", "browser_channel", "installer_source",
"installer_sha256_or_os_build", "viewport_css", "actual_inner_size_css",
"dpr", "refresh_hz", "display_mode", "app_commit", "asset_sha256",
"fixture_sha256", "profile_reset_recipe", "network_profile",
"measurement_tool_version",
}
def validate(data):
targets = data["targets"]
ids = [t["id"] for t in targets]
assert len(ids) == len(set(ids)), "Duplicate target"
assert set(ids) == {"win-chrome", "win-edge", "linux-firefox", "mac-safari",
"android-chrome", "ios-safari"}, "Missing engine/device target"
assert set(data["freeze_fields"]) >= REPRODUCTION, "Incomplete reproduction record"
for t in targets:
for key in ("device", "cpu", "os", "browser", "channel", "budget"):
assert isinstance(t[key], str) and t[key].strip(), f"Missing {key}"
assert t["channel"] == "stable", "Unqualified channel"
assert t["ram_gib"] > 0 and t["dpr"] > 0 and t["hz"] == 60
assert len(t["viewport_css"]) == 2 and min(t["viewport_css"]) >= 320
assert "tab" in t["modes"] and len(t["modes"]) == len(set(t["modes"]))
floor = {"Chrome":111, "Edge":111, "Firefox":114, "Safari":18}[t["browser"]]
assert t["minimum_major"] >= floor, "Target below accepted syntax/OS floor"
b = data["budgets"][t["budget"]]
assert all(isinstance(v, (int, float)) and v > 0 for v in b.values())
assert b["warm_start_p95_ms"] <= b["cold_start_p95_ms"]
assert b["raf_gap_p95_ms"] <= b["raf_gap_max_ms"]
assert b["ram_growth_mib"] < b["ram_peak_mib"] < t["ram_gib"] * 1024
assert set(data["fallbacks"]) >= REQUIRED_FALLBACKS, "Missing capability fallback"
for rule in data["fallbacks"].values():
assert len(rule["detection"].strip()) >= 20, "No actionable detection"
assert len(rule["fallback"].strip()) >= 50, "No actionable fallback"
ios = next(t for t in targets if t["id"] == "ios-safari")
assert "home-screen" in ios["modes"], "iOS push mode missing"
def p95(values):
assert values and all(math.isfinite(v) and v >= 0 for v in values)
return sorted(values)[math.ceil(0.95 * len(values)) - 1]
def main():
data = json.loads((HERE / "matrix.json").read_text())
validate(data)
# Reject plausible omissions and unsafe qualification drift.
mutants = []
m = copy.deepcopy(data); m["targets"].pop(); mutants.append(m)
m = copy.deepcopy(data); m["targets"][0]["cpu"] = ""; mutants.append(m)
m = copy.deepcopy(data); m["freeze_fields"].remove("browser_full_build"); mutants.append(m)
m = copy.deepcopy(data); del m["fallbacks"]["crypto-worker-wasm"]; mutants.append(m)
m = copy.deepcopy(data); m["fallbacks"]["media"]["fallback"] = ""; mutants.append(m)
m = copy.deepcopy(data); m["targets"][0]["minimum_major"] = 80; mutants.append(m)
m = copy.deepcopy(data); m["targets"][-1]["modes"] = ["tab"]; mutants.append(m)
m = copy.deepcopy(data); m["budgets"]["mobile"]["ram_peak_mib"] = 10000; mutants.append(m)
for i, m in enumerate(mutants, 1):
try:
validate(m)
except AssertionError:
continue
raise AssertionError(f"Invalid passport accepted: mutation {i}")
# Thirty-run nearest-rank semantics: two slow runs fail a 2500 ms p95 gate;
# a single tail still remains in raw evidence, not silently discarded.
assert p95([1000] * 28 + [3000, 4000]) == 3000
assert p95([2500] * 30) == 2500
assert p95([1000] * 29 + [4000]) == 1000
print(f"PASS: {len(data['targets'])} target recipes, {len(REPRODUCTION)} freeze fields, "
f"{len(data['fallbacks'])} capability fallbacks; {len(mutants)} negative mutations rejected; "
"nearest-rank percentile fixtures passed.")
print("LIMIT: document validation only; no browser/device execution or app budget pass.")
if __name__ == "__main__":
main()
@@ -0,0 +1,30 @@
{
"schema_version": 1,
"targets": [
{"id":"win-chrome","device":"Lenovo ThinkPad T14 Gen 2 Intel","cpu":"Intel Core i5-1135G7","ram_gib":16,"os":"Windows 11 24H2 x64","browser":"Chrome","minimum_major":111,"channel":"stable","viewport_css":[1366,768],"dpr":1,"hz":60,"modes":["tab","installed"],"budget":"desktop"},
{"id":"win-edge","device":"Lenovo ThinkPad T14 Gen 2 Intel","cpu":"Intel Core i5-1135G7","ram_gib":16,"os":"Windows 11 24H2 x64","browser":"Edge","minimum_major":111,"channel":"stable","viewport_css":[1366,768],"dpr":1,"hz":60,"modes":["tab","installed"],"budget":"desktop"},
{"id":"linux-firefox","device":"Lenovo ThinkPad T14 Gen 2 Intel","cpu":"Intel Core i5-1135G7","ram_gib":16,"os":"Ubuntu 24.04 LTS x64 GNOME Wayland","browser":"Firefox","minimum_major":114,"channel":"stable","viewport_css":[1366,768],"dpr":1,"hz":60,"modes":["tab"],"budget":"desktop"},
{"id":"mac-safari","device":"MacBook Air 13-inch M1 2020","cpu":"Apple M1 8-core CPU / 7-core GPU","ram_gib":8,"os":"macOS 15","browser":"Safari","minimum_major":18,"channel":"stable","viewport_css":[1280,800],"dpr":2,"hz":60,"modes":["tab","installed"],"budget":"desktop"},
{"id":"android-chrome","device":"Google Pixel 6a 128GB","cpu":"Google Tensor","ram_gib":6,"os":"Android 15","browser":"Chrome","minimum_major":111,"channel":"stable","viewport_css":[393,851],"dpr":2.75,"hz":60,"modes":["tab","installed"],"budget":"mobile"},
{"id":"ios-safari","device":"Apple iPhone 13 128GB","cpu":"Apple A15 Bionic","ram_gib":4,"os":"iOS 18","browser":"Safari","minimum_major":18,"channel":"stable","viewport_css":[390,844],"dpr":3,"hz":60,"modes":["tab","home-screen"],"budget":"mobile"}
],
"freeze_fields":["target_id","run_utc","device_model","cpu","ram_gib","os_full_build","browser_full_build","browser_channel","installer_source","installer_sha256_or_os_build","viewport_css","actual_inner_size_css","dpr","refresh_hz","display_mode","app_commit","asset_sha256","fixture_sha256","profile_reset_recipe","network_profile","measurement_tool_version"],
"budgets": {
"desktop":{"cold_start_p95_ms":2500,"warm_start_p95_ms":1200,"interaction_p95_ms":100,"raf_gap_p95_ms":20,"raf_gap_max_ms":100,"ram_peak_mib":350,"ram_growth_mib":30,"cache_mib":128},
"mobile":{"cold_start_p95_ms":4000,"warm_start_p95_ms":2000,"interaction_p95_ms":150,"raf_gap_p95_ms":25,"raf_gap_max_ms":150,"ram_peak_mib":250,"ram_growth_mib":25,"cache_mib":64}
},
"fallbacks": {
"secure-context":{"detection":"isSecureContext false / endpoint TLS failure","fallback":"Block login and protected operations; explain HTTPS/WSS requirement; never bypass certificates."},
"crypto-worker-wasm":{"detection":"Required WebCrypto, Worker, WASM initialization or self-test fails","fallback":"Block encrypted send/unlock; show unsupported capability; never plaintext or fake crypto."},
"indexeddb":{"detection":"Open/transaction fails including private-mode policy or quota","fallback":"Report local save failure; no checkpoint advance; preserve bounded pending memory; explicit recovery per ADR 0004."},
"persistence":{"detection":"persist absent/false; estimate absent or quota smaller than cache budget","fallback":"Explain best-effort storage and loss risk; lower disposable cache limit; never delete crypto or unsynced history."},
"push":{"detection":"Service worker/PushManager/Notifications missing, denied, revoked, subscription invalid, provider absent or iOS ordinary tab","fallback":"Disable background notification claim; show active-tab unread UI; offer Home Screen setup on iOS only by user action."},
"install":{"detection":"No install prompt or standalone mode","fallback":"Continue supported tab UI; show manual browser install instructions only where applicable."},
"media":{"detection":"getUserMedia/WebRTC absent, NotAllowedError, NotFoundError, NotReadableError or track ended","fallback":"Stop affected capture/call state, release tracks, explain reason; retain text; offer audio only if microphone actually works."},
"recording-codec":{"detection":"MediaRecorder absent or isTypeSupported false; runtime encoder/decoder fails","fallback":"Disable affected recording/playback with explanation; allow supported file selection/download; do not claim a sent recording."},
"geolocation":{"detection":"API absent, denied, timeout, unavailable or revoked","fallback":"Stop watch, show failure, permit explicit manual location entry; never invent coordinates."},
"webauthn":{"detection":"PublicKeyCredential missing, authenticator unavailable, cancel or failure","fallback":"Offer only accepted S00-007 unlock alternative; otherwise stay locked; no claim of hardware vault."},
"permissions-query":{"detection":"navigator.permissions absent or query descriptor rejects","fallback":"Use contextual API request after user gesture and observe its real result; no granted-state inference."},
"lifecycle":{"detection":"hidden, frozen, discarded, offline or closed tab","fallback":"No socket/media continuity promise; reconcile actual state on resume; closed-tab push remains conditional per ADR 0000."}
}
}