docs/RUNNER-PROBES.md — record the venue's first delivered drills (#202) #216

Merged
andres merged 3 commits from build/202-first-drills into main 2026-08-05 20:52:26 +00:00
2 changed files with 47 additions and 71 deletions
Showing only changes of commit 9c17a9e4d8 - Show all commits

View file

@ -1,64 +1,11 @@
### Added
### Changed
- `docs/RUNNER-PROBES.md` documents the standing runner-probe venue,
`heavy-duty/ceremony-runner-probe` — the place runner-only facts are measured
on demand, ruled as option A by the operator (#202).
- `docs/RUNNER-PROBES.md` records the venue's first delivered drills: the
#192 asymmetry re-observed on demand under the workflow token, the dispatch
route's 204 under both identities, and #215's boundary finding — each with
the probe-issue URL it is recorded in (#202).
- `drills/README.md` cross-links it beside the disposal rule, so the exception
is visible where the dangerous habit lives (#202).
- The runbook states that the drill disposal rule does **not** apply to it.
Archiving it defeats its purpose, and that is exactly how the three existing
drill repos each became unavailable (#202).
- It records that a probe must run as an Actions job under the workflow token:
the same call answers 500 there and 204 under a PAT, so a probe run any other
way produces a confident wrong answer (#202).
- Creating the repo is recorded as the operator's step, measured rather than
assumed: a fleet identity gets 403 on org repo creation and 201 in its own
namespace (#202).
- It carries an executable two-layer arming procedure: an immutable candidate
code SHA and an armed workflow commit on top of it. A single layer is
self-referential — rewriting a workflow makes a new commit, and a commit
cannot contain its own object ID (#202).
- Callers are pinned by layer: composite actions to the candidate code SHA,
reusable workflows to the armed SHA, which is the only revision whose inner
checkout points at the fork (#202).
- The arming gate asserts what each carrier IS, not only that the old literal
is gone: every `repository:` equals the fork, every `CEREMONY_SELF_REF` value
equal the candidate code SHA, and callers match the layer they belong to
(#202).
- It enumerates the carriers from the tree rather than encoding a count, and
distinguishes ceremony's internal self-checkouts from the consumer checkouts
that must stay `${{ github.repository }}` (#202).
- Both published snippets are ShellCheck-clean when extracted and linted
directly, not merely as part of the repository sweep (#202).
- The checker validates the MANIFEST against the target it was given, so a
manifest that describes a wrong arming consistently — wrong fork, or the
armed SHA where the candidate belongs — refuses instead of matching a tree
rewritten to the same wrong value (#202).
- The manifest is generated from the PRE-arming tree, which is the only order
that enumerates the carriers that must change (#202).
- Both published snippets were driven against a constructed candidate/probe
pair: deletion, both role swaps, wrong owner, wrong
SHA, wrong path, a deleted caller class and an extra carrier all refuse, and
the armed control passes (#202).
- The manifest records complete caller coordinates, so a path swapped under the
right owner and SHA is caught (#202).
- Generator and checker share one domain — ceremony callers — so a third-party
`actions/checkout` is neither manifested nor reported as unrecognised (#202).
- Probe results are written to an issue in the probe repo and carried to the
ceremony issue by a human, so the probe holds no path that can write to the
live board (#202).
- Two venue lessons join the runbook where the next probe author will look:
findings must be written to issues because the venue's log route 404s for
non-admin reads, and report templates must never interpolate `${{ … }}`
expressions (#202).

View file

@ -333,13 +333,42 @@ No probe touches `heavy-duty/ceremony`'s board. No labels, no comments, no
runs attributable to a probe. The venue exists so that the live board does not
have to be the test fixture.
## The probes this venue owes
## The probes this venue owes — and the records of those delivered
- **ceremony#192** — that the repaired sweep actually lifts a label under the
workflow token, which is the half its acceptance criteria cannot get from
the hermetic contract tests.
- **ceremony#205** — whether `POST /actions/workflows/{file}/dispatches`
works on this instance with a valid ref and inputs. Measured so far:
`GET /actions/workflows` 404s and the dispatch route answers 500 rather than
a 4xx, which is not enough to port against.
- A 0.6.0 consumer exercise once ceremony#198 has merged.
Delivered probes stay listed with their record: the venue's value is that a
claim like "the asymmetry reproduces" carries a URL a reader can open, not a
memory.
- **ceremony#192** — DELIVERED, first drill (2026-08-05). Under
`${{ github.token }}` in the venue:
`DELETE /issues/{n}/labels/{id}`**500**, the label still on the issue
afterward — the failure observable in the set, not merely a status — then
`PUT` full-set clear → **200**, set actually empty. Record:
[probe issue #1](https://forgejo.heavyduty.builders/heavy-duty/ceremony-runner-probe/issues/1)
(runs 1 and 4).
- **ceremony#205** — DELIVERED with a correction to the line above's
premise. The dispatch route answers **204** to a valid
`{"ref":"refs/heads/<branch>" | "<branch>", "inputs":{…}}` under both a PAT
and the workflow token; the earlier opaque `500` came from a bare
unresolvable ref or an unknown/unparseable workflow — the diagnostic !213
ships now names this. The `GET /actions/workflows` listing still 404s.
- **ceremony#215** — the discriminator drill: REST-body `inputs` DO reach a
top-level dispatched workflow, both contexts
(`inputs.*` and `github.event.inputs.*`), both identities. What loses the
value is the `workflow_call` boundary — a called workflow does not see the
caller's `event.inputs` on this instance. Records:
[probe issues #4 and #5](https://forgejo.heavyduty.builders/heavy-duty/ceremony-runner-probe/issues/4)
(runs 6 and 7).
- A 0.6.0 consumer exercise once ceremony#198 has merged. (#198 merged
2026-08-05; this probe remains open.)
Two venue lessons from the first drills, kept where the next probe author will
look:
- **Rule 4 is load-bearing on this instance**: the probe repo's web log route
404s for non-admin reads, and a log-only observation (run 2) was lost where
issue-written ones were not.
- **Never let a report template interpolate `${{ … }}`** — an escaped
`${{ github.token }}` in a comment body was expanded by the runner into the
recorded text (the run's ephemeral token; redacted in place). Build report
strings from plain shell variables only.