mirror of
https://github.com/Monkopedia/rouse-context.git
synced 2026-10-21 22:30:32 +00:00
* Give the two untested CI gates a self-test, and mechanise the rule (#705) `scripts/lib/gate-filters.sh` opens with the rule, deliberately as the first thing a new gate author reads: every `scripts/check-*.sh` MUST ship a matching `scripts/tests/<gate>-test.sh` and MUST have it wired into CI -- "that requirement, not this file, is the part that catches the bug". It was a comment, and on main it was false for two of the nine gates. check-apk-distribution.sh is the one that matters. release.yml runs it as "Staged FOSS APK contains no Google/Firebase code"; it is the whole of #548's answer, and a violation would be invisible until someone decompiled a shipped APK. It had never been observed going red. Being invoked in CI is not the same as being known to work -- #678's step-order gate ran on every PR for months while exiting 1 with zero output on the two inputs it existed to catch, and #686's backfill exited 0 after a failed secret push. Every case in both harnesses is a demonstrated control, red case first. scripts/tests/check-apk-distribution-test.sh (42 cases). FIXTURES, NOT REAL APKs: the gate reads an APK as a zip of files and greps the bytes, so a zip of text files exercises every path it has -- the 1MB size floor, the dex-presence check and the com/rousecontext control included -- in about two seconds with no SDK. Red: firebase and gms DEX class references separately; each of the three google-services string resources on its own; a dot-form provider in the manifest; res/raw/firebase_common_keep.xml; --expect google over a clean APK (the double-staging case release.yml's shared output path makes possible); firebase without gms; a resources-only marker not satisfying --expect google; and the five preflight refusals (missing, too small, not a zip, no dex, not this app). Green: a clean fixture, and -- pinned because it is the judgement most likely to be "tidied" later -- the four dot-form GMS strings a genuinely clean FOSS build carries in its DEX, alongside the same string in the manifest asserted RED, so the slash-vs-dot asymmetry is measured rather than assumed. Part 5 mutates the gate so a pattern stops matching its own sample, and requires the gate's own anti-vacuity self-test to fire (#579's failure mode). scripts/tests/check-zombie-screens-test.sh (36 cases). #657 already found this gate printing "OK: no zombie screens" and exiting 0 over a tree containing one, with a stubbed-failing `awk`, so that red case is pinned rather than described: the real gate is run with a PATH-shimmed failing `awk` and must fail by name, and a reconstruction of the pre-#657 shape must still produce the lie on the same tree -- otherwise the first assertion could be passing for an unrelated reason. Also pinned: self-reference does not rescue a screen, nor a test-only reference, nor a non-Kotlin file, nor a substring of the name; the exemption list works and covers only the file it names. Three residues are asserted rather than left implicit -- one live composable vouches for its whole file, a PUBLIC @Preview composable is NOT exempt (only `private fun` is dropped), and the gate reports OK when its screens directory does not exist, which is green-by-absence and is filed as #758. scripts/check-gate-selftests.sh then makes the rule mechanical: every check-*.sh has a harness, and every harness is named in a workflow. The second half matters more than it looks -- a harness nobody runs is a file, not a gate. Discovery is `git ls-files`, membership is tested against the TRACKED list (an untracked harness satisfies `[[ -f ]]` locally and does not exist in CI's checkout), and zero gates, zero harnesses or zero workflows is a FAILURE rather than a vacuous pass. The predicate is name-based for a content-based class -- the objection #658 raises about the shellcheck gate's `*.sh` -- and the header says so explicitly instead of inheriting it silently: the convention is uniform across all nine gates, proximity enforces it, and the miss direction is safe (a gate not named check-* escapes the check; it cannot cause a false red). backfill-relay-secrets.sh is deliberately outside the gate set, and its harness is still covered by the wiring half -- nothing forces it to HAVE a self-test, but having one means it must be RUN. Its own harness (27 cases) covers both gaps, both together, the untracked- harness case, and every way the gate could look at an empty set and call it clean -- no gates, no harnesses, no workflows, not a work tree, no such directory. A coverage check is the easiest kind to make vacuous (#629 proved comparisons happened, not that they could detect anything). All three harnesses read the gate's output with `grep` over a FILE, never `printf ... | grep -q`. That pipeline folds three outcomes into one answer -- no match, grep could not answer, and grep matching EARLY and `pipefail` reporting the writer's SIGPIPE for `!` to invert into "no match" -- and the last is payload-size dependent and tracked as a live defect in #725. With no pipe there is no writer to kill. Four steps added to ci.yml's lint job, next to the five self-tests already there. release.yml is untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YYSPuh9bZEJkrzvnEpY1QK * TEMPORARY: a gate with no self-test, to watch #705's check go red in CI Reverted in the next commit. `scripts/check-gate-selftests.sh` is itself a gate, and a gate whose red case has only ever been exercised against fixtures in its own harness is exactly what #705 is about. This makes the real CI step fail on the real tree, once, so the link is citable. Expected: the "Every gate ships a wired self-test (#705)" step in the lint job exits 1 with 1 gate(s) ship with no self-test: scripts/check-fixture-no-harness.sh -> scripts/tests/check-fixture-no-harness-test.sh Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YYSPuh9bZEJkrzvnEpY1QK * Revert the temporary no-harness fixture gate The point is made: run 34925372964, job Lint, step "Every gate ships a wired self-test (#705)" exited 1 on the real tree with 1 gate(s) ship with no self-test: scripts/check-fixture-no-harness.sh -> scripts/tests/check-fixture-no-harness-test.sh and the two new self-test steps ahead of it passed on the same run. The coverage gate is now a demonstrated red, not an assumed one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YYSPuh9bZEJkrzvnEpY1QK --------- Co-authored-by: Monkopedia <monkopedia@gmail.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| backfill-relay-secrets-test.sh | ||
| check-apk-distribution-test.sh | ||
| check-cancellation-catch-order-test.sh | ||
| check-gate-selftests-test.sh | ||
| check-no-manual-json-test.sh | ||
| check-no-production-runblocking-test.sh | ||
| check-no-sensitive-logging-test.sh | ||
| check-roborazzi-coverage-test.sh | ||
| check-roborazzi-step-order-test.sh | ||
| check-shell-lint-test.sh | ||
| check-zombie-screens-test.sh | ||
| gate-filters-test.sh | ||