From 5f630c19c042a466f753b2aa124c24e7294f0a35 Mon Sep 17 00:00:00 2001 From: "basquin-bot[bot]" <307641014+basquin-bot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2026 10:29:44 -0400 Subject: [PATCH] =?UTF-8?q?ci(dd045):=20run=20the=20DD-043=20PR-3=20harnes?= =?UTF-8?q?s=20in=20CI=20=E2=80=94=20item=200,=20proven=20able=20to=20fail?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit scripts/verify-dd043-pr3.sh certifies the Maven injector, and until now nothing ran it but a developer's shell. That is why three of its own assertions stayed broken across multiple approver rounds: jar:baked-version could not pass on a CRLF checkout, the jar stage graded a stale build because the compile's exit code was discarded, and jvm:zero-edits passed on a directory it never examined. All three are the same defect — a check that cannot fail — and none of them needed a reviewer to find, only an execution. Adds a verify-dd043-pr3 job running `unit jar guards`. jvm and native stay out: they need docker and 15+ minutes, and a comment on the job says so rather than leaving the scope limit implicit. On failure the job uploads bench-results/verify-*/ so a red run is diagnosable from the Actions UI instead of only by reproducing it. A CI job wired to a script that always exits 0 would be a fresh instance of the very defect this closes, so the job's ability to go red was measured, not argued: unmodified 13 passed, 0 failed, exit 0 Sisu index naming a nonexistent class 9 passed, 2 failed, exit 1 restored 13 passed, 0 failed, exit 0 The middle run is the load-bearing one. Pointing basquin-maven-injector/src/main/resources/META-INF/sisu/javax.inject.Named at a class that does not exist is the exact silent-non-discovery shape the jar stage exists to catch — Maven finds core extensions through that index, so a stale one means the participant never loads while the build stays green. unit failed via verifyInjectorIsDiscoverable (gradle rc=1) and jar refused to grade at all, reporting UNMEASURED: the jar build FAILED rather than certifying the previous build's artifact. The final exit=0 was captured live off the invocation. No path filter changed: both lists already carried every path this invocation reads. TODO.md item 0 and the ROADMAP entry are marked delivered rather than left as open debt, and the trailing ROADMAP note that said no job invokes the harness is corrected in the same commit — a fix that leaves its own deferral record standing has produced false debt on this repo twice. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01LHBLwqfM1acog2bHRS8WCb --- .github/workflows/ci.yml | 32 ++++++++++++++++++++++++++++++ TODO.md | 25 ++++++++++++++++-------- docs/ROADMAP.md | 42 ++++++++++++++++++++++------------------ 3 files changed, 72 insertions(+), 27 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0bf6b88..10823eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -96,6 +96,38 @@ jobs: run: python3 scripts/check-citations.py + # DD-045 item 0 — the DD-043 PR-3 verification harness had never run anywhere but a developer's + # shell, so several of its own assertions (jar:baked-version on a CRLF checkout, the jar stage + # grading a stale build because the compile's exit code was discarded, jvm:zero-edits passing on + # a directory it never examined) stayed broken for multiple approver rounds before anyone + # noticed. Wiring it in here turns that class of defect into a push-time failure. + # + # Scope: only `unit jar guards` — deliberately NOT `jvm` or `native`. Those two need docker and + # take 15+ minutes (native alone is a serialized ~15-minute compile); they stay manual-only, run + # by hand per the script's own header. `unit jar guards` need no docker and are what would have + # caught the findings above. + verify-dd043-pr3: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Make gradlew executable + run: chmod +x gradlew + - name: Set up Java 17 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '17' + - name: Verify DD-043 PR-3 harness (unit jar guards) + run: bash scripts/verify-dd043-pr3.sh unit jar guards + - name: Upload verification run directory + if: failure() + uses: actions/upload-artifact@v4 + with: + name: verify-dd043-pr3-results + path: bench-results/verify-*/ + if-no-files-found: warn + build-and-test: runs-on: ubuntu-latest strategy: diff --git a/TODO.md b/TODO.md index 290d8be..3e8b5a1 100644 --- a/TODO.md +++ b/TODO.md @@ -1135,14 +1135,23 @@ Full rationale and the ordered item list are in `docs/ROADMAP.md`'s "Start here pointer so the debt is visible from here too. The one-line version: **PR-3 took eight approver rounds, the feature held in every one, and almost every finding was in the machinery that certifies it.** -- [ ] **0 — run the harness in CI.** No job invokes `scripts/verify-dd043-pr3.sh`; it is manual-only. - It is *not* outside the path filters any more — this PR put `'scripts/**'` in both of `ci.yml`'s - lists (`.github/workflows/ci.yml:51` push, `:79` pull_request), so a harness-only commit does - trigger the workflow; what it still does not trigger is any job that runs the harness. Being - manual-only is why `jar:baked-version` could not pass on a CRLF - checkout for three rounds and why the `jar` stage passed against a jar it never built until round - 8 ran it deliberately. `unit jar guards` needs no docker and finishes in minutes. Do this first — - the rest shorten the feedback loop; this changes when the loop closes. +- [x] **0 — run the harness in CI. Delivered.** `.github/workflows/ci.yml`'s `verify-dd043-pr3` job + (`.github/workflows/ci.yml:109`) now runs `bash scripts/verify-dd043-pr3.sh unit jar guards` on + every push and pull_request that matches the existing path filters — `jvm` and `native` stay out + of scope (docker, 15+ minutes) per a comment on the job. Both path-filter lists already covered + everything this invocation reads (`basquin-maven-injector/**`, `build.gradle`, + `basquin-init.gradle`, `gradle/**`, `gradlew`, `scripts/**`), so no filter changed. On failure the + job uploads `bench-results/verify-*/` via `actions/upload-artifact@v4` so a red run is + diagnosable from the Actions UI, not just locally. + **Proved empirically, not asserted:** an unmodified run on this branch passed 13/13 (0 failed, 0 + skipped, exit 0). The injector jar's Sisu index + (`basquin-maven-injector/src/main/resources/META-INF/sisu/javax.inject.Named`) was then changed + to name a nonexistent class, which made the built jar's index stale — the exact silent-non-discovery + shape the `jar` stage exists to catch — and re-running failed 2 rows (`unit`: 359 tests but `gradle + rc=1` from `verifyInjectorIsDiscoverable`; `jar`: `UNMEASURED: the jar build FAILED`), tallying 9 + passed / 2 failed / 0 skipped, exit 1. Restoring the file and re-running passed 13/13 again, exit 0 + — captured live via `echo "exit=$?"` immediately after the invocation. All three runs were ad hoc + (not committed as run-of-record evidence; the CI job now produces those going forward). - [x] **1 — citation-resolution CI check, whole-tree scoped. Delivered.** Built as `scripts/check-citations.py` (resolves each citation against the cited file's current text, not just the path; whole-tree, not diff-scoped — a diff-scoped version missed four dead citations in diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 467f7ce..87428bb 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -229,16 +229,21 @@ extraction; scope under "Open PRs" below). Four threads are ready to pick up, in **The pieces, in priority order:** - 0. **Run the verification harness in CI.** No job invokes `scripts/verify-dd043-pr3.sh` — it is - manual-only. (It is no longer outside the path filters: this PR added `'scripts/**'` to both of - `ci.yml`'s lists, `.github/workflows/ci.yml:51` for `push` and `:79` for `pull_request`, so a - commit touching only the harness now triggers the workflow — it just triggers no job that runs - the harness.) Manual-only is the root cause behind most of - the findings in row 1 of the table: `jar:baked-version` could not pass on a CRLF checkout for three - rounds because nothing ran it, and the `jar` stage passed against a jar it never built until round 8 - executed it deliberately. The `unit jar guards` stages need no docker and complete in minutes; wire - those into CI and the whole first row becomes a push-time failure rather than a review-round finding. - Everything below is detection; this is the one that changes when detection happens. + 0. **Run the verification harness in CI. Delivered.** The `verify-dd043-pr3` job + (`.github/workflows/ci.yml:109`) runs `bash scripts/verify-dd043-pr3.sh unit jar guards` on the + existing `push`/`pull_request` path filters — `jvm` and `native` are deliberately out of scope + (docker, 15+ minutes), stated in a comment on the job — and uploads + `bench-results/verify-*/` via `actions/upload-artifact@v4` when it fails, so a red run is + diagnosable without reproducing it locally. Manual-only was the root cause behind most of the + findings in row 1 of the table: `jar:baked-version` could not pass on a CRLF checkout for three + rounds because nothing ran it, and the `jar` stage passed against a jar it never built until + round 8 executed it deliberately. Proved this can actually fail, not merely reasoned about: an + unmodified run passed 13/13, then naming a nonexistent class in + `basquin-maven-injector/src/main/resources/META-INF/sisu/javax.inject.Named` — a stale Sisu + index, the exact silent-non-discovery shape the `jar` stage exists to catch — dropped it to 9 + passed / 2 failed / 0 skipped (exit 1: `unit` failed via `verifyInjectorIsDiscoverable`, `jar` + reported `UNMEASURED: the jar build FAILED`), and restoring the file brought it back to 13/13, + exit 0. Everything below is detection; this was the one that changed when detection happens. 1. **A citation-resolution CI check, whole-tree scoped. Built** as `scripts/check-citations.py` plus `scripts/check-citations-allowlist.txt`, wired into `.github/workflows/ci.yml` as the @@ -302,15 +307,14 @@ extraction; scope under "Open PRs" below). Four threads are ready to pick up, in it contains the pasted output of its own verification, and partial evidence is never committed. **Entry condition:** none — this is tooling over the existing tree, and it is independently useful - before PR-4 begins. Do **0 first**: until CI runs the harness, every other item here only shortens - the feedback loop for defects that still reach review. 1 is now built; 2-3 are the remaining - structural pieces. 4-6 are cheap once those exist. - - **Also worth noting for whoever picks this up:** `scripts/verify-dd043-pr3.sh` is now *inside* - `ci.yml`'s path filters — this PR added `'scripts/**'` to both lists - (`.github/workflows/ci.yml:51`, `:79`) so the `citation-integrity` job fires on script-only - commits. The remaining half of the gap is that no job invokes the harness, so a commit touching - only it still gets no harness run; item 0 is what closes that. + before PR-4 begins. 0 and 1 are now built; 2-3 are the remaining structural pieces. 4-6 are cheap + once those exist. + + **Also worth noting for whoever picks this up:** `scripts/verify-dd043-pr3.sh` is *inside* + `ci.yml`'s path filters — `'scripts/**'` is in both lists + (`.github/workflows/ci.yml:51`, `:79`) — and, since item 0, a job actually runs it: the + `verify-dd043-pr3` job (`.github/workflows/ci.yml:109`) invokes `unit jar guards` on both + `push` and `pull_request`. 2. **DD-041 — clustered exploration across replicas (the one the user asked for, for service-backed apps).** Not specced yet — so the next step is *brainstorm → spec → plan*, NOT code. DD-039 leaves