612c417024
gates / gates (push) Successful in 19s
Message bundles (internal/i18n) expanded into templates before parsing, one template set per language. Launcher, /backups, /apps/<slug> and the layout converted; household language setting, POST /settings/language, ?lang= override, report field. Parity test against fixtures captured from unconverted templates; copy gates read templates expanded; new i18n_missing_gate. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
63 lines
2.9 KiB
Python
63 lines
2.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Native-confirm gate (drill F-11; alert added v0.126.4) — native confirm()/prompt()/alert()
|
|
dialogs are OS-modals that block browser automation (CDP freezes) and are banned from the UI;
|
|
consequential actions use the inline felhomConfirm helper (layout.html) or the .confirm-overlay
|
|
dialog; error/info surfaces use showAlert (layout.html modal). alert() joined the ban after the
|
|
0.87.0 wizard leg: a decommission error path alert() froze the automation exactly like F-11
|
|
predicted (the operator had to click the OS-modal away).
|
|
|
|
Run from controller/: python scripts/native_confirm_gate.py
|
|
Exit 1 if any native confirm(/prompt(/alert( call remains in the templates.
|
|
"""
|
|
import io, os, re, sys
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
import i18n_bundle # noqa: E402
|
|
|
|
ROOTS = [
|
|
os.path.join("internal", "web", "templates"),
|
|
os.path.join("internal", "setup", "templates"),
|
|
]
|
|
|
|
# A bare confirm(/prompt(/alert( CALL with an argument: not preceded by an identifier character,
|
|
# so felhomConfirm(, showAlert( and onRestoreConfirmChange( never match. window.confirm( /
|
|
# window.alert( still match ('.' is not an identifier character).
|
|
NATIVE = re.compile(r"(?<![A-Za-z0-9_$])(?:confirm|prompt|alert)\(\s*[^)\s]")
|
|
|
|
|
|
def _html_files(root):
|
|
# R-421 (2026-09-01): AT ANY DEPTH. This was `os.listdir`, one level only. There are no
|
|
# template subdirectories today, so the gate was green and correct — and would have stayed
|
|
# green the moment anyone added `templates/partials/`, which is an ordinary thing to do.
|
|
# Measured: a planted template in a new partials/ directory passed every listdir-based gate
|
|
# and was caught by the two that already used os.walk. See AUDIT-gate-decoys-2026-09-01.md.
|
|
out = []
|
|
for dirpath, _dirs, names in os.walk(root):
|
|
for fn in sorted(names):
|
|
if fn.endswith('.html'):
|
|
out.append(os.path.join(dirpath, fn))
|
|
return sorted(out)
|
|
|
|
|
|
def main():
|
|
total = 0
|
|
for root in ROOTS:
|
|
for path in _html_files(root):
|
|
fn = os.path.relpath(path, root)
|
|
# v0.247.0: judge each language's expansion -- JS copy lives in the i18n bundle now.
|
|
seen = set()
|
|
for lang in i18n_bundle.LANGS:
|
|
for lineno, line in enumerate(i18n_bundle.read_template(path, lang).split("\n"), 1):
|
|
if NATIVE.search(line) and (lineno, line) not in seen:
|
|
seen.add((lineno, line))
|
|
total += 1
|
|
print("%s:%d [%s] %s" % (fn, lineno, lang, line.strip()[:120].encode('ascii', 'backslashreplace').decode()))
|
|
if total:
|
|
print("NATIVE CONFIRM GATE FAILED: %d native confirm()/prompt()/alert() call(s) remain" % total)
|
|
sys.exit(1)
|
|
print("native-confirm gate OK — no native confirm()/prompt()/alert() in templates")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|