[THROWAWAY — DO NOT MERGE] test(594): prove ci-image-pin goes red on a wrong-length pin #599

Closed
timothy wants to merge 2 commits from test/594-wrong-length-pin into main
Owner

Throwaway probe. Do not merge. Will be closed as soon as ci-image-pin reports.

Satisfies ersatztv#594's Done-when box 2 — "Verified by a deliberately-wrong-length pin on a throwaway branch (must go red at the gate, not at image pull)" — for PR #598.

What this is

#598's commit, with one deliberate corruption on top: docker-build.yml's toolchain pin widened from the correct 7-char ersatztv-ci:4263cf7 to the 8-char ersatztv-ci:4263cf79.

That 8-char string is an abbreviation of the same, correct commit (4263cf7919f7dedd08911ec7f2bd490de574848f). So it passes both pre-existing checks:

  • it resolves to a commit in the repo, and
  • it resolves to exactly the commit docker/ci was last changed in — the staleness check is satisfied.

Before #594 this went green, and the failure surfaced far downstream: all five container: jobs dying at image-pull with manifest unknown, which reads like a registry outage rather than a one-character pin error.

Expected result

ci-image-pin RED, with an actionable message naming the exact tag to use (ersatztv-ci:4263cf7) and the git rev-parse --short=7 HEAD command.

A green ci-image-pin here would mean #598's guard does not work and #598 should not merge.

Note the control already exists: #598 itself carries the correct 7-char pin and its ci-image-pin is green, so this pair is a real positive/negative control rather than a one-sided check.

**Throwaway probe. Do not merge. Will be closed as soon as `ci-image-pin` reports.** Satisfies ersatztv#594's Done-when box 2 — *"Verified by a deliberately-wrong-length pin on a throwaway branch (must go red at the gate, not at image pull)"* — for PR #598. ## What this is #598's commit, with one deliberate corruption on top: `docker-build.yml`'s toolchain pin widened from the correct **7**-char `ersatztv-ci:4263cf7` to the **8**-char `ersatztv-ci:4263cf79`. That 8-char string is an abbreviation of the *same, correct* commit (`4263cf7919f7dedd08911ec7f2bd490de574848f`). So it passes both pre-existing checks: - it **resolves** to a commit in the repo, and - it resolves to exactly the commit `docker/ci` was last changed in — the staleness check is satisfied. Before #594 this went **green**, and the failure surfaced far downstream: all five `container:` jobs dying at image-pull with `manifest unknown`, which reads like a registry outage rather than a one-character pin error. ## Expected result `ci-image-pin` **RED**, with an actionable message naming the exact tag to use (`ersatztv-ci:4263cf7`) and the `git rev-parse --short=7 HEAD` command. A green `ci-image-pin` here would mean #598's guard does not work and #598 should not merge. Note the control already exists: #598 itself carries the correct 7-char pin and its `ci-image-pin` is **green**, so this pair is a real positive/negative control rather than a one-sided check.
timothy added 2 commits 2026-07-25 12:48:57 +02:00
Three independent CI/repo-hygiene fixes swept together; disjoint file sets.

fixes #586 — E2E cleanup is scoped by PID, never a pattern-wide pkill
  - New decision record `testing.e2e-cleanup-scope-by-pid`.
  - docs/e2e-local.md states the constraint where a BRIEF-WRITER sees it (the
    #586 root cause was a delegation gap, not agent error).
  - scripts/e2e-local.sh: reviewed against e2e-ui.sh's trap lifecycle and
    deliberately does NOT adopt it — its contract is to hand a running instance
    back to its caller, so an EXIT trap would kill the server the instant the
    launcher returned (both callers use `OUT="$(e2e-local.sh ...)"`). Recorded.
  - Instead it gains what actually prevents the incident: an lsof pre-flight
    that NAMES a foreign listener's PID rather than letting Kestrel fail its
    bind and surface as "process N exited before becoming ready".
  - Pre-flight probes BOTH bound ports, and ETV_STREAMING_PORT now defaults to
    ETV_UI_PORT. Program.cs binds a second listener whose port defaults to 8409
    independently of ETV_UI_PORT, so `ETV_UI_PORT=8420` alone still bound 8409
    and died against a foreign holder — i.e. the documented escape hatch was a
    dead end that led straight back to the confusion behind the pattern kill.

fixes #594 — ci-image-pin accepts any hex length
  - Length is a separate invariant from correctness: the resolve/staleness
    checks compare resolved shas, so an 8-char pin of the right commit passes
    green while matching NO registry tag, and all five container: jobs then die
    at image-pull with `manifest unknown` (reads like a registry outage).
  - Guard fails at the gate and prints the exact tag to use. Verified against
    doctored pins: 7 green; 6/8/10 red.
  - Uses a literal 7 rather than a derived `--short=7`: in a full clone git may
    widen an ambiguous abbreviation, demanding a pin ci-image.yml can never
    publish. Escape hatch documented inline.
  - Also fixes a pre-existing misdiagnosis: zero pins reported "MORE THAN ONE".
  - docs/ci-cd.md documents the 7-char rule and `git rev-parse --short=7 HEAD`.

fixes #485 — .gitignore `core` silently ignored `*/Core/` files
  - A bare `core` matched any path component named `core`; case-insensitively
    on macOS that swallowed every `*/Core/` SOURCE dir, so new untracked files
    were dropped by `git add -A` while tracked ones stayed fine — a clean local
    build and a CI checkout that fails to compile.
  - Now `/core` + `/core.[0-9]*`, both anchored (an unanchored `core.[0-9]*`
    would re-introduce the same silent-exclusion class this fixes).
  - Verified by diffing the full ignored-file set before/after: identical, and
    the three real Core/ dirs are trackable without -f.

Docs updated in-PR: docs/e2e-local.md, docs/ci-cd.md, docs/decisions/
workflow-process.md (+ regenerated catalog), docs/handoffs/chicorytv-issue-queue.md.

Follow-ups filed: #596 (the same shared-host reap in the Playwright-MCP
recovery record) and the ci-image.yml `--short=7` publisher-side fix, which
cannot ride this PR — editing ci-image.yml re-points ci-image-pin's `expected`
at this commit and reds the gate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
test(594): DELIBERATELY WRONG 8-char ci-image pin — proving ci-image-pin goes red at the gate
PR Gates / CI image pin matches docker/ci (pull_request) Failing after 12s
PR Gates / Docs update reminder (pull_request) Successful in 18s
PR Gates / decisions lifecycle (pull_request) Successful in 20s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Failing after 1s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Failing after 1s
Build ErsatzTV Image / Functional E2E (curl contracts) (pull_request) Failing after 1s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Failing after 0s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Failing after 0s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
6610ad1c73
Throwaway. Verifies ersatztv#594's Done-when box 2: an 8-char pin resolves to
the CORRECT commit, so it passes the resolve+staleness checks, but matches no
registry tag. Without the length guard this went green and failed much later at
image-pull with 'manifest unknown'. Expect ci-image-pin RED. To be closed.
Author
Owner

Result: RED, for exactly the right reason ✅

Run 1352, job CI image pin matches docker/ci → failure.

Runtime output (not the echoed script body):

Image sources last changed in: 4263cf7919f7dedd08911ec7f2bd490de574848f
Pins found in docker-build.yml: 4263cf79 (1 distinct)
::error::CI toolchain image pin ersatztv-ci:4263cf79 is 8 chars, but ci-image.yml
publishes 7-char tags … Pin exactly: ersatztv-ci:4263cf7
(locally: git rev-parse --short=7 HEAD).
  ❌  Failure - Main Verify the pin matches the last-published image

Three things this establishes, beyond "it went red":

  1. It failed at the gate, not at image pull — the ❌ Failure - Main marker is on the pin-verification step, so this is a genuine assertion failure and not a killed job (ci.killed-job-triage).
  2. It failed at the length check specifically. The log shows it cleared the count check (1 distinct) and then stopped — the resolve and staleness errors never fire, because the 8-char pin is a valid abbreviation of the correct commit. That is the whole point of #594: those two checks were satisfied, and only the new length invariant catches it.
  3. The message is actionable — it names the exact tag (ersatztv-ci:4263cf7) and the command.

Paired with #598's own ci-image-pin running green on the correct 7-char pin, this is a proper positive/negative control rather than a one-sided check.

Closing as planned; branch deleted. Evidence recorded on #594.

## Result: RED, for exactly the right reason ✅ Run [1352](http://192.168.1.95:3000/timothy/ersatztv/actions/runs/1352), job `CI image pin matches docker/ci` → `failure`. Runtime output (not the echoed script body): ``` Image sources last changed in: 4263cf7919f7dedd08911ec7f2bd490de574848f Pins found in docker-build.yml: 4263cf79 (1 distinct) ::error::CI toolchain image pin ersatztv-ci:4263cf79 is 8 chars, but ci-image.yml publishes 7-char tags … Pin exactly: ersatztv-ci:4263cf7 (locally: git rev-parse --short=7 HEAD). ❌ Failure - Main Verify the pin matches the last-published image ``` Three things this establishes, beyond "it went red": 1. **It failed at the gate, not at image pull** — the `❌ Failure - Main` marker is on the pin-verification step, so this is a genuine assertion failure and not a killed job (`ci.killed-job-triage`). 2. **It failed at the *length* check specifically.** The log shows it cleared the count check (`1 distinct`) and then stopped — the resolve and staleness errors never fire, because the 8-char pin *is* a valid abbreviation of the correct commit. That is the whole point of #594: those two checks were satisfied, and only the new length invariant catches it. 3. **The message is actionable** — it names the exact tag (`ersatztv-ci:4263cf7`) and the command. Paired with #598's own `ci-image-pin` running **green** on the correct 7-char pin, this is a proper positive/negative control rather than a one-sided check. Closing as planned; branch deleted. Evidence recorded on #594.
timothy closed this pull request 2026-07-25 12:50:46 +02:00

Pull request closed

This pull request cannot be reopened because the branch was deleted.
Sign in to join this conversation.