docs(knowledge): de-slop instruction surfaces (0.13.9) (#3338) #363
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: silent-revert-canary | |
| # Post-merge canary for #2691: detect a merge that silently deleted content | |
| # another recently-merged commit had just added. | |
| # | |
| # On 2026-08-15 three squash merges each landed a tree that dropped work a | |
| # sibling PR had merged minutes earlier (#2633 dropped both #2644 and #2642, | |
| # #2639 dropped #2635, #2641 dropped #2639). Every check stayed green through | |
| # all three, because each reverting squash removed the code AND its tests in | |
| # the same commit -- no suite can fail for a behavior whose tests are gone. | |
| # Two issues sat CLOSED as COMPLETED with their fixes absent from main. | |
| # | |
| # DETECTION, NOT PREVENTION -- and deliberately so. | |
| # | |
| # * Scanning runs on `push` to main only. There IS a `pull_request` trigger | |
| # below, but it only exercises the detector against its own tests and its | |
| # recorded corpus (see the note above `on:`); the range-resolution and scan | |
| # steps are both gated `if: github.event_name != 'pull_request'`, so no PR | |
| # is ever inspected for silent reverts. By the time the canary speaks, the | |
| # merge has happened; the value is that a human learns within minutes | |
| # instead of during a from-scratch content audit weeks later. | |
| # * It is NOT in ci.yml and is NOT wired into that workflow's `ci-status` | |
| # aggregate, which is the single required check the org ci-gate ruleset | |
| # keys on. Adding it there would make a detection heuristic able to block | |
| # merges, which is how canaries acquire a constituency for switching them | |
| # off. Same posture as link-check.yml: advisory lane, outside ci-status. | |
| # * Nothing here changes any ruleset. The global | |
| # `strict_required_status_checks_policy` stays off under the accepted ADR | |
| # in melodic-software/github-iac | |
| # (docs/adr/0001-relax-strict-required-status-checks.md), and this canary | |
| # is valuable precisely because it catches the class without that churn -- | |
| # and, per the evidence in scripts/check-silent-revert.sh, without needing | |
| # it, since all three branches were up to date with main in history and | |
| # stale only in content. `strict` would have passed every one of them. | |
| # | |
| # No cancelling concurrency group on purpose. ci.yml cancels superseded runs to | |
| # save minutes on a PR, but a cancelled canary is a silently missed detection -- | |
| # exactly the false-green this lane exists to remove. Pushes to main are | |
| # infrequent enough that letting every run finish costs nothing worth saving. | |
| # The `pull_request` trigger exercises the detector against its OWN unit tests | |
| # and its recorded incident corpus, never against the PR. The range-resolution | |
| # and scan steps are gated off for PR events below, so nothing on a PR ever | |
| # inspects that PR for silent reverts -- detection stays post-merge, per the | |
| # design note above. What a PR gets is ordinary coverage of a shipped script, | |
| # scoped by `paths` to the canary's own files so it is inert on every other PR. | |
| # | |
| # Without it the detector would ship untested until the next push to main, and | |
| # the specific way this script can break is a false GREEN: if the blame parser | |
| # stops matching (awk dialects differ between the runner's mawk and a | |
| # developer's gawk), attribution yields nothing and every commit reports `ok`. | |
| # A canary whose failure mode is silent success is the exact thing #2691 is | |
| # about, so it gets tested before it lands, not after. | |
| # | |
| # This does not make the lane a merge gate. It is not in ci.yml and not in that | |
| # workflow's `ci-status` aggregate, which is the single required check the org | |
| # ci-gate ruleset keys on, so nothing here can block a merge. | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| paths: | |
| - 'scripts/check-silent-revert.sh' | |
| - 'scripts/check-silent-revert.test.sh' | |
| - 'scripts/silent-revert-incidents.txt' | |
| - 'scripts/silent-revert-acknowledged.txt' | |
| - '.github/workflows/silent-revert-canary.yml' | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| jobs: | |
| silent-revert-canary: | |
| name: Silent-revert canary | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Check out | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| # Full history: the canary blames the lines a merge deleted against | |
| # its parent, and replays the recorded incidents from 2026-08. A | |
| # shallow clone cannot do either, and the script exits 2 rather than | |
| # reporting a clean run it did not earn. fetch-base is off because | |
| # this job never diffs against origin/$BASE_REF. | |
| - name: Deepen history | |
| uses: ./.github/actions/checkout-with-base | |
| with: | |
| fetch-base: "false" | |
| # Self-test first, unconditionally: a broken detector must not be able to | |
| # mask a real regression behind a green canary. Same never-skip, | |
| # self-test-first shape as the ci.yml gates. | |
| - name: Test the silent-revert detector | |
| run: bash scripts/check-silent-revert.test.sh | |
| # The honesty proof. The shipped thresholds are replayed against the | |
| # actual merges from #2691 and must still fire on them -- and must still | |
| # stay quiet on the verified-legitimate commit pinned alongside. A | |
| # detector that only looks plausible is worthless here, because every | |
| # signal a reader normally checks looked healthy during the incident. | |
| - name: Replay the recorded incidents | |
| run: scripts/check-silent-revert.sh --verify-known-incidents | |
| # Resolve the pushed range. `github.event.before` is all-zeros on a first | |
| # push or after a history rewrite, and absent entirely on | |
| # workflow_dispatch; in both cases fall back to the head commit and SAY | |
| # SO, rather than reporting a clean scan of nothing. Values arrive through | |
| # env, never interpolated into the script body. | |
| # Detection is post-merge only. On a pull_request event the two steps | |
| # above have already proven the detector works; scanning stops here so the | |
| # lane never inspects a PR and never has an opinion about merging it. | |
| - name: Resolve the pushed range | |
| id: range | |
| if: github.event_name != 'pull_request' | |
| env: | |
| EVENT_BEFORE: ${{ github.event.before }} | |
| EVENT_AFTER: ${{ github.event.after }} | |
| run: | | |
| set -uo pipefail | |
| zero='0000000000000000000000000000000000000000' | |
| before="${EVENT_BEFORE:-}" | |
| after="${EVENT_AFTER:-$(git rev-parse HEAD)}" | |
| if [ -z "$before" ] || [ "$before" = "$zero" ] || | |
| ! git rev-parse --verify --quiet "${before}^{commit}" >/dev/null; then | |
| echo "::warning::No usable push range (before='${before:-<unset>}');" \ | |
| "scanning only the head commit ${after}. Any earlier commit in" \ | |
| "this push was NOT scanned." | |
| { | |
| echo "mode=commit" | |
| echo "target=$after" | |
| } >>"$GITHUB_OUTPUT" | |
| else | |
| { | |
| echo "mode=range" | |
| echo "target=${before}..${after}" | |
| } >>"$GITHUB_OUTPUT" | |
| fi | |
| - name: Scan the merged commits for silent reverts | |
| if: github.event_name != 'pull_request' | |
| env: | |
| SCAN_MODE: ${{ steps.range.outputs.mode }} | |
| SCAN_TARGET: ${{ steps.range.outputs.target }} | |
| run: | | |
| set -uo pipefail | |
| if [ "$SCAN_MODE" = "commit" ]; then | |
| scripts/check-silent-revert.sh --commit "$SCAN_TARGET" | |
| else | |
| scripts/check-silent-revert.sh "$SCAN_TARGET" | |
| fi | |
| # The other half of the proof (#2855). The replay above asserts every | |
| # recorded incident is still DETECTED; this asserts the content those | |
| # incidents deleted is on the tree TODAY. Both are needed, and #2828 | |
| # is the gap made real: its content sat off main for 31h28m, from | |
| # f603880da to the 534eac138 (#2829) restore. This lane covered only | |
| # the tail -- it merged at 7b47d2253 (#2808), 6h13m out from the | |
| # restore -- and across that tail the replay still printed `ok` and | |
| # exited 0 with the content gone: it answered the other question. Two | |
| # re-lands each missed it, and a hand audit found it, not this lane. | |
| # | |
| # ORDER IS LOAD-BEARING, and this step is deliberately LAST. | |
| # | |
| # A step with no status function carries an implicit `success() &&`, so a | |
| # step that fails SKIPS every later step in the job. Placed before the | |
| # scan, a red restoration assertion would therefore skip the scan itself | |
| # -- and those commits are never re-examined, because the next push's | |
| # range starts at this push's head. That trade is unacceptable in this | |
| # direction: restoration is bound to LIVE content in living files and the | |
| # corpus header says a marker going red on a rename is intended | |
| # loudness, while the scan is the primary detector. A churn-sensitive | |
| # tripwire must never be able to silence it. Running last, this step can | |
| # fail as loudly as it likes and the scan has already spoken. | |
| # | |
| # `success() || failure()` rather than the default, so the reverse | |
| # suppression cannot happen either: a scan that fires (exit 1) must not | |
| # skip the restoration answer. It excludes cancellation, so a cancelled | |
| # run still reports nothing rather than a result it did not earn. | |
| # | |
| # UNGATED on the event, exactly like the self-test and the replay. The | |
| # failure that produced #2828 is "nobody thought to check", so an | |
| # on-demand mode would reproduce it. Running on pull_request events too is | |
| # not a merge gate: this workflow is not in ci.yml and not in that | |
| # workflow's `ci-status` aggregate, which is the single required check the | |
| # org ci-gate ruleset keys on -- and it is `paths`-scoped to the canary's | |
| # own files, so it is inert on every other PR. What it buys is that a PR | |
| # editing this corpus proves its markers resolve before the merge. | |
| # | |
| # No rev argument: it resolves against the checked-out tree, which is the | |
| # question worth asking here -- is the content on main RIGHT NOW. The | |
| # explicit-rev form exists so a reviewer can replay the assertion against | |
| # the historical tree an incident was measured on. | |
| - name: Assert the recorded incidents' content is restored | |
| if: success() || failure() | |
| run: scripts/check-silent-revert.sh --verify-restoration |