fix(scripts): green check-phase10 hygiene after Phase 17 and run it from check-phase17 (T-10-24, T-10-25)

- line-exact, path-bound T-17-10 raw-HTML exceptions for the RichEditorField
  read-only display and the inert template parse in lossy.ts
- dist-origin allow-list adds the never-requested literals
  https://prosemirror.net and https://admin.invalid
- self-test plants: the display line in another file, a template parse
  elsewhere, a foreign origin in the dist JS
- --spa also runs the Vitest browser suite, fail-closed
- check-phase17: browser-suite required names in the admin stage, Phase 10
  hygiene in the docs stage, asserted by its self-test
This commit is contained in:
2026-10-12 20:40:24 +02:00
parent c1d767f0f8
commit fd46d475a2
2 changed files with 85 additions and 14 deletions

View File

@@ -11,12 +11,15 @@
# name (-short).
# plugins go vet ./... in Journal, sitemap, menu, FAQ and the host; their
# Docker-free suites by required name (-short).
# admin the admin SPA typecheck and the vitest JSON report with required
# spec files and test names.
# admin the admin SPA typecheck and the vitest JSON reports with
# required spec files and test names: the happy-dom suite and the
# browser suite (vitest.browser.config.ts, Playwright Chromium;
# the richeditor read-only display, T-17-10).
# layers pnpm test (node --test, TAP) in both layers with required test
# files and names.
# docs TestDocsTree, summer docs:build --check, check-admin-openapi.sh
# --check, check-admin-dist.sh.
# --check, check-admin-dist.sh, and check-phase10.sh --hygiene, so
# admin changes made here cannot silently break Phase 10's gate.
# postgres Docker host only: the testcontainers suites by required name in
# every Go repository. Without a reachable Docker daemon this
# stage fails.
@@ -116,7 +119,6 @@ ADMIN_REQUIRE=(
"RichEditorField renders read-only values through the display policy, never as stored"
"richeditor policy helpers accepts policy links only"
"richeditor policy helpers compares tag names case-insensitively for the lossy note"
"richeditor policy helpers unwraps unknown elements and drops scripts for display"
"RichEditorField value contract an empty paragraph is the empty string, any content its HTML"
"RichEditorField value contract a value from outside replaces the document and leaves the field untouched"
"RichEditorField value contract shows the lossy note only for markup outside the editor schema"
@@ -142,6 +144,18 @@ ADMIN_REQUIRE=(
"reorder tree rules refuses a drop into the node itself or its own subtree and leaves the tree as it was"
"reorder tree rules moves only where a sibling or parent exists, and flattens pre-order from 1"
)
# admin stage, browser suite (vitest.browser.config.ts): spec files and full
# test names, copied from a --reporter=json run.
ADMIN_BROWSER_FILES=(tests/browser/richeditor-display.test.ts)
ADMIN_BROWSER_REQUIRE=(
"richeditor display in a real browser engine runs where form controls clobber form properties"
"richeditor display in a real browser engine drops clobbered forms with everything inside them"
"richeditor display in a real browser engine keeps a form control named localName from breaking the view"
"richeditor display in a real browser engine drops an off-origin form, iframes, meta refresh and disallowed links"
"richeditor display in a real browser engine parses into an inert document, so nothing loads before the value is bound"
"richeditor policy helpers unwraps unknown elements and drops scripts for display"
"RichEditorField renders read-only values exactly through the display policy"
)
# layers stage: test files (must exist and match the test script's glob) and
# TAP test names.
@@ -389,11 +403,13 @@ go_named() {
REQUIRE_TESTS="${names[*]}" go_json "$dir" $flags -count=1 -run "$regex" $pkgs
}
# vitest_json DIR [VITEST ARGS...]: extra arguments (such as --config) go to vitest.
vitest_json() {
local dir="$1" report out rc=0 dc=0
shift
report="$(mktemp)"
out="$(mktemp)"
(cd "$dir" && ./node_modules/.bin/vitest run --reporter=json --outputFile="$report") >"$out" 2>&1 || rc=$?
(cd "$dir" && ./node_modules/.bin/vitest run "$@" --reporter=json --outputFile="$report") >"$out" 2>&1 || rc=$?
detect_vitest "$report" || dc=$?
if [[ "$rc" -ne 0 || "$dc" -ne 0 ]]; then
grep -E 'FAIL|Error|×' "$out" | tail -n 40 >&2 || true
@@ -529,6 +545,11 @@ ok 1 - a
REQUIRE_FILES='tests/a.ts' expect_files outside-glob 5 "$tmp" || { rm -rf "$tmp"; return 1; }
rm -rf "$tmp"
grep -qF 'bash "$ROOT/scripts/check-phase10.sh" --hygiene' "${BASH_SOURCE[0]}" || {
echo "refuse: the docs stage does not run check-phase10.sh --hygiene" >&2
return 1
}
local mode
for mode in self-test go plugins admin layers docs postgres all; do
grep -q -- "^ --$mode" "${BASH_SOURCE[0]}" || {
@@ -583,6 +604,8 @@ run_plugins() {
run_admin() {
(cd "$ROOT/admin" && ./node_modules/.bin/vue-tsc --noEmit)
REQUIRE_FILES="$(printf '%s\n' "${ADMIN_FILES[@]}")" REQUIRE_NAMES="$(printf '%s\n' "${ADMIN_REQUIRE[@]}")" vitest_json "$ROOT/admin"
REQUIRE_FILES="$(printf '%s\n' "${ADMIN_BROWSER_FILES[@]}")" REQUIRE_NAMES="$(printf '%s\n' "${ADMIN_BROWSER_REQUIRE[@]}")" \
vitest_json "$ROOT/admin" --config vitest.browser.config.ts
echo "phase17 admin passed"
}
@@ -599,6 +622,9 @@ run_docs() {
(cd "$ROOT" && go run ./cmd/summer docs:build --check)
bash "$ROOT/scripts/check-admin-openapi.sh" --check
bash "$ROOT/scripts/check-admin-dist.sh"
# Cross-phase: Phase 10's SPA hygiene (raw-HTML sinks, dist origins, every
# module imported by a test) must stay green after Phase 17 admin changes.
bash "$ROOT/scripts/check-phase10.sh" --hygiene
echo "phase17 docs passed"
}