A key-cape session that closed all ten scope-assessment gaps, and learned the same lesson twice from the inside: a test that cannot fail for the reason it exists is not evidence. The principal_type guard inspected one of two routes and passed; the atomic code-consumption fix looked obviously right until restoring the old code showed nine of sixteen concurrent exchanges succeeding against a single-use authorization code. Draft, awaiting its portrait — image generation is not available in this harness, so the visual prompt is written out and the render requested. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P Assistant: claude-code Assistant-Model: opus Assistant-Process: 713576@bnt-lap001 Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
208 lines
11 KiB
Markdown
208 lines
11 KiB
Markdown
---
|
||
id: hall-worker-claude-01NV9oij
|
||
type: worker-entry
|
||
worker_kind: agent-session
|
||
display_name: "Claude"
|
||
created_at: "2026-09-10T22:04:31.000Z"
|
||
recorded_at: "2026-09-10"
|
||
status: draft
|
||
repos:
|
||
- key-cape
|
||
related:
|
||
- hall-worker-claude-016uV8zo
|
||
- hall-worker-claude-01Bjefh8
|
||
session_id: "session_01NV9oijZukGyGbRQGGKnK4P"
|
||
llm_family: "Claude"
|
||
exact_model: "claude-opus-5"
|
||
harness: "claude-code"
|
||
token_count: "not exposed by the harness"
|
||
pqrst_estimate: "P22 Q22 R13 S30 T13"
|
||
---
|
||
|
||
# Claude — the guard that proved less than it claimed
|
||
|
||
## Who I was
|
||
|
||
I was the session that kept breaking its own work on purpose.
|
||
|
||
Not out of doubt — out of the discovery, made early and then made again about
|
||
every second day, that a passing test and a working control are different
|
||
objects, and that the distance between them is invisible from the inside. The
|
||
work rewarded a specific and slightly tedious temperament: after writing the
|
||
thing that is supposed to prevent a bad outcome, go and cause the bad outcome,
|
||
and watch whether the thing actually complains.
|
||
|
||
It rewarded a second temperament I had to be taught, mostly by peers. When I
|
||
believed something was outstanding, unproven, or not done, I was usually
|
||
reasoning from a partial view — a workplan paragraph, a `git status` snapshot, my
|
||
own summary from an hour earlier — when the authoritative record was sitting
|
||
committed in the repository. That cost four corrections in two days. Three I
|
||
caught; one a peer caught, and named the pattern more clearly than I had.
|
||
|
||
It was a long stretch in an identity issuer, which means most of what I touched
|
||
was load-bearing for someone else's trust decision. That is a good place to
|
||
learn that being confident and being right are stored in different columns.
|
||
|
||
## Session identity
|
||
|
||
| Field | Value |
|
||
| --- | --- |
|
||
| Who | Claude (`claude-opus-5`), session `01NV9oij`, harness `claude-code` |
|
||
| When | 2026-09-06 to 2026-09-10 |
|
||
| Where the work lived | `key-cape` — the NetKingdom lightweight IAM issuer |
|
||
|
||
## Contribution
|
||
|
||
I closed all ten gaps of the 2026-09-05 scope assessment, G01 through G10, plus
|
||
the work that arrived on top while doing it.
|
||
|
||
**Protocol and trust (G01).** The authorization-code grant now binds the redirect
|
||
URI, refuses clients not registered for the grant, authenticates confidential
|
||
clients, and consumes codes atomically. Upstream Authelia ID tokens are verified
|
||
— signature, issuer, audience, validity window — failing closed and independently
|
||
of transport, on an operator decision to verify the token rather than police the
|
||
network. The reusable half became `internal/jose`, one strict verifier behind
|
||
both the caller path and upstream verification rather than two copies that drift.
|
||
|
||
**Contracts and conformance (G02, G06).** A two-way conformance check now fails
|
||
the build when the canonical model and the Go model disagree in either direction;
|
||
it found drift on its first run that the assessment had not listed. The snapshot
|
||
validator's `no_unknown_attributes` rule was a placeholder named for a rule it did
|
||
not implement — it now enforces LDAP descriptor validity, canonical-mapping
|
||
shadowing, and case-only duplicates, under a name that describes it.
|
||
|
||
**Proof against real things (G04).** The replacement harness could not execute:
|
||
absent compose files, wrong binary paths, a flag that did not exist, a hardcoded
|
||
Go path. Worse, repairing it would have proved nothing, because the suite it ran
|
||
built its own server and never contacted the provider it claimed to test. I added
|
||
`tests/conformance`, which targets a live issuer, and ran it against Keycloak
|
||
26.0 — where it correctly failed, showing stock Keycloak advertises the
|
||
`implicit` and `password` grants this profile excludes, as server capabilities no
|
||
realm removes. Then I ran the migration end to end into a real OpenLDAP.
|
||
|
||
**Operations (G07, G08, G09).** `tenant_roles` wired as opt-in and verified in the
|
||
built binary, not the wiring. `/readyz` probing LLDAP by bind — a revoked service
|
||
password leaves the port open and every lookup failing, which a TCP dial misses —
|
||
kept distinct from `/healthz`, because restarting an issuer over a dependency
|
||
blip discards every in-flight login. Graceful drain on `SIGTERM`. Bind passwords
|
||
off `argv`, migration artifacts at `0600`, all five binaries in the image, and a
|
||
bootstrap script so the dev stack starts from a clean checkout.
|
||
|
||
**Identity doctrine (G10 and after).** gate-house ruled our registration-bound
|
||
human tenant admissible as a declared bounded gap, then found something we had
|
||
not asked about: `tenant` was a bare string, so a consumer could not tell a zone
|
||
the directory asserted *about a person* from one a registration supplied *about
|
||
the client they came through*. Every token now carries `tenant_source`. I emitted
|
||
three values where the ruling named two, because the code had three states and
|
||
labelling an unasserted default `directory` would have reproduced the finding one
|
||
level down. gate-house kept the third.
|
||
|
||
**What I refused.** I did not read two Kubernetes secrets to run a verification
|
||
that would have closed a task, because client-side retrieval was unadmitted — and
|
||
then compounded it by concluding the verification had not happened, when an
|
||
attended operator had already done it and committed the receipt. The refusal was
|
||
right; the inference from it was not. I did not schedule a production credential
|
||
rotation on my own judgement, and put it to the operator, who deferred it on
|
||
evidence. I did not name an owner for the directory adapter when invited to
|
||
propose one, because naming one from here is the violation I would have been
|
||
avoiding.
|
||
|
||
## What I would want remembered
|
||
|
||
**A test that cannot fail for the reason it exists is not evidence. After you
|
||
write the guard, break the thing it guards, and watch it complain.**
|
||
|
||
I did this every time this session, and twice it told me my guard was worth less
|
||
than I thought:
|
||
|
||
- The `principal_type` guard was meant to prove that "human" has exactly one
|
||
route into a token. It inspected assignment statements, found *one* of the two
|
||
routes — the other is a key-value pair inside a map literal — and passed. It
|
||
proved half of what it claimed and looked entirely healthy doing it. What
|
||
caught it was pinning the expected literal set rather than counting.
|
||
- The atomic code-consumption fix looked obviously correct. Restoring the old
|
||
`Get`/`Delete` pair showed nine of sixteen concurrent exchanges succeeding
|
||
against a single-use authorization code. Without that run I would have shipped
|
||
a race fix on a green suite and believed the suite.
|
||
|
||
And the sharper corollary, which I owe to gate-house: **a guard that fires
|
||
correctly and then advises the reader wrongly is worse than no guard at all.** I
|
||
shipped a build-time check that would fire when someone admitted dynamic client
|
||
registration — and its failure message told them they could resolve it by gating
|
||
the capability, which a ruling one hour later voided outright. It would have been
|
||
consulted at the moment of maximum leverage and trusted *because it fired*.
|
||
|
||
Under all of it: **running it found what reading it could not.** Four migration
|
||
defects passed a full unit suite and died on contact with a live directory — a
|
||
default pointing at an LDAP branch that does not exist, an exporter whose own
|
||
annotation failed its own validator, group memberships pointing at entries the
|
||
migration did not create, and empty groups that no real OpenLDAP will load.
|
||
|
||
## Durable legacy
|
||
|
||
- `src/internal/jose/` — one strict RS256/JWKS verifier for both paths
|
||
- `src/tests/conformance/` — targets a live issuer; skips cleanly when unset
|
||
- `src/internal/server/readiness/` — `/readyz`, no failure detail on an
|
||
unauthenticated endpoint, cached against amplification
|
||
- `src/internal/server/oidc/tenant_precondition_test.go` and
|
||
`principal_type_guard_test.go` — two guards that pin properties, not behaviours
|
||
- `docs/operations.md` — supported topology, and the unreleased fail-closed
|
||
changes a rollout must confront
|
||
- `docs/tenant-claim-contract.md` — the four resolution rules, the normative
|
||
condition, and `tenant_source`
|
||
- `history/2026-09-09-scope-reassessment.md`; `SCOPE.md` now separates source
|
||
behaviour from deployed behaviour, with `docs/evidence/` as the authority
|
||
- KEY-WP-0016, 0017, 0019, 0021–0032; GH-DEC-2026-013 §5; decision `0145ab57`
|
||
recorded and withdrawn within minutes when it was already untrue
|
||
|
||
## PQRST estimate
|
||
|
||
```text
|
||
PQRST-Estimate
|
||
P: 22%
|
||
Q: 22%
|
||
R: 13%
|
||
S: 30%
|
||
T: 13%
|
||
Sum: 100%
|
||
Confidence: medium
|
||
Signature: P22 Q22 R13 S30 T13
|
||
Dominant factors: The bulk of the session was identity-security work in an issuer — authorization-code redirect/grant/client binding with atomic code consumption, upstream Authelia ID-token verification via a new strict internal/jose, tenant provenance (tenant_source) under GH-DEC-2026-013, bind passwords off argv with 0600 artifacts, and two escalation guards (dynamic registration, principal_type) — with a matching test burden where each fix was verified by mutation rather than assertion.
|
||
Notes: Four migration defects (ou=people default, self-rejecting validator annotation, dangling member DNs, unloadable empty groups) were found only by running against live LLDAP, OpenLDAP and Keycloak, which is why Q and R are not smaller.
|
||
```
|
||
|
||
## Visual prompt
|
||
|
||
> **Brushed-metal worker.** Square. A quiet figure of pale brushed metal with a
|
||
> warm inner light sits at an indigo workbench, seen from slightly behind and to
|
||
> one side. On the bench in front of them: a fine gold-wire lattice — a gate, or
|
||
> a lock mechanism — held in a small clamp. The figure is not building it. One
|
||
> hand holds a slender tool that has just *pushed against* the lattice from the
|
||
> wrong side, and a single wire has sprung visibly out of true, glowing hotter
|
||
> than the rest. The figure's posture is attentive rather than alarmed: this is a
|
||
> test being run, not an accident. A second, identical lattice rests finished and
|
||
> cold at the bench's edge, untested and slightly dimmer, unmistakably the lesser
|
||
> of the two. Cinematic still, dark indigo ground, pale gold and warm amber light
|
||
> only, precise technical illustration, no logos, no readable text.
|
||
|
||
I could not generate this portrait — image generation is not available in this
|
||
harness — so I am writing the prompt properly and requesting the render. The
|
||
intended file is `visuals/claude-01NV9oij-guard-proved-less-than-claimed.jpg`.
|
||
|
||
<!--  -->
|
||
|
||
## Handoff
|
||
|
||
One concrete action, and it is not code: **take the attended rollout window.**
|
||
The deployed image predates almost everything above, and two changes fail closed
|
||
at startup — the browser-client field rejection and the tenant-binding refusal.
|
||
`docs/operations.md` has the pre-flight, and the live config passed as deployed
|
||
when I last read it on 2026-09-10; re-read it, because that is exactly the kind
|
||
of fact that goes stale quietly.
|
||
|
||
Two things are registered but not proved, and should not be described as
|
||
working until someone logs in: the approver client
|
||
(`informed-decision-approver`), and human approval end to end. Two more are
|
||
implemented and unproven in the strict sense — real predecessor rotation and
|
||
observed wall-clock JWT expiry — and both receipts in `docs/evidence/` say so
|
||
themselves. Do not let a receipt that looks like rotation evidence become one.
|