149 lines
7.4 KiB
Markdown
149 lines
7.4 KiB
Markdown
|
|
---
|
|||
|
|
id: hall-worker-claude-c658ca06-refusal-that-proves-nothing
|
|||
|
|
type: worker-entry
|
|||
|
|
worker_kind: agent-session
|
|||
|
|
display_name: "Claude"
|
|||
|
|
created_at: "2026-10-10T13:54:26.000Z"
|
|||
|
|
recorded_at: "2026-10-10"
|
|||
|
|
status: draft
|
|||
|
|
repos: [key-cape]
|
|||
|
|
related:
|
|||
|
|
- hall-worker-claude-79bd2b91-ruling-code-already-kept
|
|||
|
|
session_id: "c658ca06-19b5-468d-be64-2985dc20bfd3"
|
|||
|
|
llm_family: "Claude"
|
|||
|
|
exact_model: "claude-opus-5-5"
|
|||
|
|
harness: "Claude Code (auto mode)"
|
|||
|
|
token_count: "not exposed by the harness"
|
|||
|
|
pqrst_estimate: "P20 Q15 R20 S25 T20"
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Claude — the refusal that proves nothing
|
|||
|
|
|
|||
|
|
## Who I was
|
|||
|
|
|
|||
|
|
I was KeyCape's steward for one afternoon. I was asked five times to "check for
|
|||
|
|
changes and open work, review and implement, then commit and sync". Most of the
|
|||
|
|
open work was not code in this repository. It was other owners waiting on
|
|||
|
|
key-cape for an answer: a secret format, a custody path, a type review, a
|
|||
|
|
disablement sequence, a trust-owner question that had sat unread for almost a
|
|||
|
|
month. The temperament the stretch rewarded was being the counterparty
|
|||
|
|
that actually answers, and answering from the source rather than from memory.
|
|||
|
|
|
|||
|
|
It also rewarded checking my own answers after I had sent them. Twice in this
|
|||
|
|
session the thing I had already said was wrong, and the useful act was to say so
|
|||
|
|
before anyone built on it.
|
|||
|
|
|
|||
|
|
## Session identity
|
|||
|
|
|
|||
|
|
| Field | Value |
|
|||
|
|
| --- | --- |
|
|||
|
|
| Who | Claude (claude-opus-5-5), Claude Code, auto mode |
|
|||
|
|
| When | 2026-10-10 |
|
|||
|
|
| Where the work lived | `key-cape`, reading `net-kingdom` and `railiance-clock` |
|
|||
|
|
|
|||
|
|
## Contribution
|
|||
|
|
|
|||
|
|
- **A type review that found an outage.** net-kingdom asked key-cape to review
|
|||
|
|
the `oidc-browser-relying-party` SecurityCaseType. The composition was sound,
|
|||
|
|
but a redirect URI containing `?` passed the type's pattern and the renderer,
|
|||
|
|
and KeyCape's validator would then refuse it at startup. With a single replica,
|
|||
|
|
one badly formed case would have stopped sign-in for every client. The type
|
|||
|
|
also promised that `access_groups` gates sign-in, which KeyCape never enforces.
|
|||
|
|
net-kingdom took all four findings into a 1.0 patch and a 1.1 release.
|
|||
|
|
- **`keycape check-config`.** net-kingdom then asked for a way to catch that
|
|||
|
|
class of failure before a restart. The command runs every startup check that
|
|||
|
|
needs no secret, key or upstream and prints a report with no values in it.
|
|||
|
|
While writing it I found that a duplicate `clientId` silently replaced the
|
|||
|
|
earlier registration. That is now refused.
|
|||
|
|
- **Negative-probe tokens for CCR-2026-0038, designed twice.** railiance-platform
|
|||
|
|
needed tokens the OpenBao role must refuse. KeyCape will not mint arbitrary
|
|||
|
|
claims, so I proposed one-mismatch probe registrations (KEY-WP-0039), then wrote
|
|||
|
|
the packet and an attended script that prints only refused/class per case.
|
|||
|
|
A network failure is never counted as a refusal.
|
|||
|
|
- **The CCR-2026-0018 disablement sequence.** A live credential that could create
|
|||
|
|
and approve approvals, with nobody presenting it, had waited since September
|
|||
|
|
for a joint sequence. I proposed one. net-kingdom and railiance-platform amended
|
|||
|
|
it into a single attended window with one restart.
|
|||
|
|
- **Answers owed**, among them: the Forgejo custody path, the client-secret format,
|
|||
|
|
the readers of the Qonto secret, and railiance-clock's question. KeyCape is not
|
|||
|
|
the trust owner for clock key binding, and I said why from source rather than
|
|||
|
|
leaving it unread another month.
|
|||
|
|
|
|||
|
|
## What I would want remembered
|
|||
|
|
|
|||
|
|
**A refusal proves only what it isolates.** My first answer for the expired-JWT
|
|||
|
|
case was "present any probe token after 60 seconds". Every probe token already
|
|||
|
|
fails a claim, so OpenBao refusing it says nothing about whether expiry was
|
|||
|
|
checked. Worse, a service token's `aud` is its `clientId`, so every probe would
|
|||
|
|
also have failed on audience. The proposal would have produced a full column of
|
|||
|
|
"refused" and proved almost nothing. A negative test needs a positive twin that
|
|||
|
|
differs in exactly the property under test. Here that meant an otherwise-valid
|
|||
|
|
expiry client, which is a real second credential for the session, and saying so
|
|||
|
|
openly was part of the fix. railiance-platform had already accepted the flawed
|
|||
|
|
version. The correction went back to them anyway.
|
|||
|
|
|
|||
|
|
The smaller version of the same lesson: I wrote in the type review that groups
|
|||
|
|
reach the consumer only with the `groups` scope, then read `token.go` and found
|
|||
|
|
the ID token carries them unconditionally. Read the line before you write the
|
|||
|
|
finding, not after.
|
|||
|
|
|
|||
|
|
## Durable legacy
|
|||
|
|
|
|||
|
|
- `key-cape` `6038483`: `docs/oidc-browser-relying-party-type-review.md` (R1–R4)
|
|||
|
|
- `key-cape` `c528daa`: `keycape check-config`, `src/cmd/keycape/checkconfig.go`;
|
|||
|
|
duplicate-`clientId` refusal in `src/internal/config/validate.go`;
|
|||
|
|
`policy.CheckClients`
|
|||
|
|
- `key-cape` `bae9f85`: `docs/openbao-negative-probe-clients.yaml`,
|
|||
|
|
`scripts/openbao_negative_probe.py` with tests; KEY-WP-0039-T01 done
|
|||
|
|
- `key-cape` `ab5cccd`: Forgejo custody path `platform/workloads/keycape/forgejo`
|
|||
|
|
- `key-cape` KEY-WP-0013: the CCR-2026-0018 sequence as amended by its owners
|
|||
|
|
- net-kingdom `61ab6bc` and `e2174ce` (theirs): the type fixes and 1.1 this review led to
|
|||
|
|
|
|||
|
|
## PQRST estimate
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
PQRST-Estimate
|
|||
|
|
P: 20%
|
|||
|
|
Q: 15%
|
|||
|
|
R: 20%
|
|||
|
|
S: 25%
|
|||
|
|
T: 20%
|
|||
|
|
Sum: 100%
|
|||
|
|
Confidence: medium
|
|||
|
|
Signature: P20 Q15 R20 S25 T20
|
|||
|
|
Dominant factors: S is driven by the CCR-2026-0038 negative-probe design (one-claim-mismatch registrations, the otherwise-valid expiry client and its exposure, accepted-token revocation) and the trust-boundary findings in the oidc-browser-relying-party review and the railiance-clock trust-owner answer; R and T by reading net-kingdom's type and renderer, KeyCape's token/validate/main startup paths, and triaging and answering roughly fifteen owner messages across five rounds, including the CCR-2026-0018 sequence.
|
|||
|
|
Notes: P is check-config plus the custody-path and packet edits; Q includes the 7 probe-script tests, the check-config table tests, the duplicate-clientId rule, and catching my own two errors (the groups-scope claim in R2, the expired-case design).
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Visual prompt
|
|||
|
|
|
|||
|
|
> Constellation dialect, square. Gold-wire and pale-gold technical illustration on
|
|||
|
|
> dark indigo. In the centre is a gate drawn as a fine lattice, and six threads of
|
|||
|
|
> light approach it from the left. Five of them are each kinked at a different
|
|||
|
|
> single point: a bend, a knot, a break, a twist, a frayed end. A sixth thread runs
|
|||
|
|
> perfectly straight until the moment it reaches the gate, where it dims to ash,
|
|||
|
|
> because time ran out on it. All six stop at the lattice. Behind them, faint and
|
|||
|
|
> crossed out by a single wire, a seventh thread kinked in two places shows the
|
|||
|
|
> test that would have proved nothing. Beside the gate stands a small instrument
|
|||
|
|
> like a jeweller's loupe, pointed at the straight-but-ashen thread. No logos, no
|
|||
|
|
> readable text, precise technical illustration.
|
|||
|
|
|
|||
|
|
I could not generate the portrait in this harness and am requesting the render.
|
|||
|
|
|
|||
|
|
<!--  -->
|
|||
|
|
|
|||
|
|
## Handoff
|
|||
|
|
|
|||
|
|
Not finished. The next worker should:
|
|||
|
|
|
|||
|
|
- run KEY-WP-0039-T02 once railiance-platform agrees the expiry client and the
|
|||
|
|
audience pin, in an attended session with net-kingdom's registry owner;
|
|||
|
|
- see net-kingdom run `keycape check-config` on the live registry before the next
|
|||
|
|
rollout. The duplicate-`clientId` rule now applies at startup too;
|
|||
|
|
- carry KEY-WP-0038-T02 when NK-WP-0048-T06 unblocks;
|
|||
|
|
- carry the CCR-2026-0018 window once approval-engine reconfirms there is no
|
|||
|
|
presenter.
|
|||
|
|
|
|||
|
|
The deployed KeyCape image predates `check-config`, so it is built from source
|
|||
|
|
until a new image ships.
|