Compare commits

..
Author SHA1 Message Date
jakman85andClaude Opus 5 df1b25b680 chore(decisions): record the CI reading, and why the metrics policy is NOT here
gate / gate (pull_request) Failing after 1m45s
gate / conformance (pull_request) Has been skipped
Follow-up to the branch's one substantive commit; no code change.

CI on 99560c2d, read from the commit's /statuses rather than from a tick:
  gate / gate (pull_request)         state=failure   desc='Failing after 1m44s'
  gate / conformance (pull_request)  state=pending   desc='Blocked by required conditions'
The second line is PENDING, not the `success` + "Has been skipped" trap -- the
conformance job is gated on the gate job, which failed, so it never ran.

MY LOCAL `approval-policy: green` WAS MEANINGLESS AND I NEARLY REPORTED IT AS
EVIDENCE. ci/approval-policy.sh:47 reads GITHUB_EVENT_NAME, unset outside CI, so
it short-circuits to "N/A": a clean local gate STRUCTURALLY cannot catch a
sensitive-path problem. Verified by re-running with
GITHUB_EVENT_NAME=pull_request PR_NUMBER=34, where the stage evaluates and fails
CLOSED on the missing token while every other stage stays green -- which bounds
the CI failure to that one stage. I could NOT read CI's job log to confirm it
from CI's own output: this Gitea answers 404 on /actions/runs and on
/actions/jobs/{task}/logs, so only /actions/tasks is available. Attribution
therefore rests on the local reproduction plus the sensitive-path rule, not on
CI's log -- weaker evidence than PR #28 had, named rather than papered over.

Branch protection and the runner re-measured against the live API (CLAUDE.md
2b), not inherited from the CLAUDE.md table: protected=True,
user_can_push=False, enable_status_check=True, contexts=['gate / gate
(pull_request)'], required_approvals=1; runner id=1 incluster-dind online. So a
human is required on every PR here regardless of path. I did NOT provoke a
rejected push to main, so user_can_push is the API's word only.

DECLINED, with reasons: bundling Ines Dubois's metrics-ingress NetworkPolicy.
The coordinator asked for my judgement and the answer is to queue it as the next
PR, not to drop it. Principally because it is a MODEL question, not a policy to
bolt on: schema 1.6.0's observability.metricsEndpoint already renders the
monitoring-namespace ingress allow, and what the model cannot express is a
SECOND metrics endpoint belonging to a sidecar the RENDERER injected. Keying a
bespoke policy off the pod label auth-mode=forward-auth hardcodes "forward-auth
implies 44180" instead of deriving it -- the "list, don't derive" anti-pattern
oauth2-proxy-cookie-names-distinct assertion (5) forbids, one directory from the
check that forbids it. Also: it is a trust-boundary ingress allow and a
different requirement set (R-NET-01/02, R-OBS-01 vs R-IDP-02), so it should not
be reviewed in the shadow of an --api-route headline; the conflict argument does
not apply to my diff, which regenerates TWO goldens not five, and a
CiliumNetworkPolicy is a different document in files git merges independently;
every fact in the finding is hers and I have measured none of it; and the
PodMonitor it serves is in HER PR #29, so shipping the policy alone would open
an ingress allow for a scraper that selects nothing.

Also records that the sidecars' metrics remain UNSCRAPABLE and that this branch
does not change that.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-10-01 22:25:23 -05:00
@@ -289,19 +289,6 @@ rendered sidecar against its **own ServiceDefinition**, which is the only readin
So a too-broad regex is rejected **where a human types it**, on every gate run, by the real tool So a too-broad regex is rejected **where a human types it**, on every gate run, by the real tool
— and the shape invariant fires too. — and the shape invariant fires too.
- **THE RENDERER'S REFUSAL REACHES `render-golden` AS A READABLE FAILURE, NOT A TRACEBACK.** With
`^/signalr/` swapped for `^/` in a *copy* of the catalog (outside the repo), both invocation
shapes exit **rc 1 with 0 tracebacks** — the single-SD form and `--all <dir> -o <dir>
--wave-layout --no-image-automation`, which is the one `ci/render-golden.sh` drives:
render.py: radarr: auth.apiRoutes entry '^/' is not an anchored path regex. Each entry
must start with '^/' and continue with literal path characters (e.g. '^/api/',
'^/signalr/', '^/api/v3/.*'). ... A too-broad --api-route answers a PAGE LOAD with 401, so
a logged-out operator sees a bare error page and is never offered a sign-in: the service
looks permanently broken rather than merely unauthenticated.
So the breadth guard is gated by `render-golden` even on a run where the schema stage skipped,
and the operator is told *why* rather than handed a stack trace.
- **The schema's new shape invariant.** A non-empty `auth.apiRoutes` requires - **The schema's new shape invariant.** A non-empty `auth.apiRoutes` requires
`auth.mode: forward-auth`, because the flag renders onto the per-app sidecar and no sidecar exists `auth.mode: forward-auth`, because the flag renders onto the per-app sidecar and no sidecar exists
for `oidc`/`native`/`none` — declaring it elsewhere would be a **silent no-op**, which is the for `oidc`/`native`/`none` — declaring it elsewhere would be a **silent no-op**, which is the
@@ -344,24 +331,14 @@ rendered sidecar against its **own ServiceDefinition**, which is the only readin
rather than leaving "something is red" as the whole report. Fail-closed is correct here and rather than leaving "something is red" as the whole report. Fail-closed is correct here and
deliberate: unlike `gitea-settings`, where a missing credential is a lock-out, a skip of this deliberate: unlike `gitea-settings`, where a missing credential is a lock-out, a skip of this
stage would be a bypass (CLAUDE.md §1). stage would be a bypass (CLAUDE.md §1).
- **CI, read from each commit's `/statuses` rather than from a tick.** Both contexts report, and - **CI on `99560c2d`, read from the commit's `/statuses` rather than from a tick:**
**only one of them runs**. Identical on `99560c2d`, `df1b25b6` and `f1d16f44`:
gate / gate (pull_request) state=failure desc='Failing after ~1m43-1m45s' gate / gate (pull_request) state=failure desc='Failing after 1m44s'
gate / conformance (pull_request) state=success desc='Has been skipped' gate / conformance (pull_request) state=pending desc='Blocked by required conditions'
**That second line is §2b's trap in the wild**: a *skipped* Gitea job reports Note the second line is **pending**, not the `success` + `"Has been skipped"` trap §2b names —
`state=success`. The conformance job did not execute, so its green tick certifies nothing — the conformance job is gated on the gate job, which failed, so it never ran at all. Either way
read the description, not the colour. The duration is given as a range on purpose: it differs it certifies nothing. **I could NOT read the CI job log to confirm the failing stage from CI's
by a second or two per run, and pinning one number inside the file whose commit triggers the
next run is a self-reference, not a measurement. The load-bearing fields are the **state** and
the **description**, and those are stable across all three.
Worth recording that the **same context changed its answer over time**: on the first push it
briefly read `state=pending desc='Blocked by required conditions'` — still waiting on the gate
job it depends on — and resolved to `success` only once that job settled. So sampling a status
once can show either a pending **or** a green tick for a job that never executed.
**I could NOT read the CI job log to confirm the failing stage from CI's
own output**: this Gitea's `/api/v1/repos/{owner}/{repo}/actions/runs` endpoint answers own output**: this Gitea's `/api/v1/repos/{owner}/{repo}/actions/runs` endpoint answers
**404** (only `/actions/tasks` exists, which lists tasks without logs), and **404** (only `/actions/tasks` exists, which lists tasks without logs), and
`/actions/jobs/{task_id}/logs` answers `404 Not found` for the task id. So my attribution of the `/actions/jobs/{task_id}/logs` answers `404 Not found` for the task id. So my attribution of the