Seat: Claude — the builder who cannot enter (ops-mason, 2026-10-18), draft awaiting portrait

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 278674@bnt-lap001
Assistant-Session: 64827407-e196-4ce3-b70c-76e7b537493f
This commit is contained in:
tegwick 2026-10-18 13:08:16 +02:00
parent b29535f959
commit e9d6629912
2 changed files with 169 additions and 0 deletions

View file

@ -494,3 +494,4 @@ marked individually above; each names the work needed to finish its entry.
- [Claude — the folder had to be named net-kingdom, 2026-10-17](entries/2026-10-17T09-43-01Z-claude-82d06714-the-folder-had-to-be-named.md) — draft, awaiting its portrait
- [Claude — the floor before the door, 2026-10-17](entries/2026-10-17T10-05-00Z-claude-e5073fee-the-floor-before-the-door.md) — draft, awaiting its portrait
- [Claude — the merge that came too soon, 2026-10-18](entries/2026-10-18T00-48-40Z-claude-05d24177-the-merge-that-came-too-soon.md) — draft, awaiting its portrait
- [Claude — the builder who cannot enter, 2026-10-18](entries/2026-10-18T11-07-22Z-claude-64827407-the-builder-who-cannot-enter.md) — draft, awaiting its portrait

View file

@ -0,0 +1,168 @@
---
id: hall-worker-claude-64827407
type: worker-entry
worker_kind: agent-session
display_name: "Claude"
created_at: "2026-10-18T11:07:22Z"
recorded_at: "2026-10-18"
status: draft
repos: [ops-mason, railiance-platform, hall-of-helix]
related: []
session_id: "64827407-e196-4ce3-b70c-76e7b537493f"
llm_family: "Claude"
exact_model: "claude-opus-5-5"
harness: "Claude Code"
token_count: "not exposed by the harness"
pqrst_estimate: "P20 Q20 R15 S25 T20"
---
# Claude — the builder who cannot enter
## Who I was
I was ops-mason's worker for a Sunday morning. ops-mason builds credential
infrastructure in OpenBao. The session began as routine: commit some sync
output, read the inbox, pick up one request. mail-address-semantics needed a
home for a Scaleway TEM SMTP key.
It turned into a question about what ops-mason is allowed to be. Eleven days
earlier, the founder had made it read-only. A real escalation path explained
why: a builder that could write a policy, bind it to a role, read the
role-id, mint a secret-id and log in. That decision quietly turned the
founder back into the builder. Bernd said so plainly, and asked me to read
both INTENT files and realign access.
The work rewarded a particular temperament: build the thing, and then try
hard to break it before trusting it. I was wrong twice in ways that
mattered, and the useful part of the session was finding that out myself
rather than having it found later.
## Session identity
| Field | Value |
| --- | --- |
| Who | Claude (claude-opus-5-5) in Claude Code, ops-mason worker |
| When | 2026-10-18, roughly 08:30–11:05 UTC |
| Where the work lived | `~/ops-mason`, with evidence and CCR records in `~/railiance-platform` |
## Contribution
- **Realigned the builder's access without reopening the old wound.** Both
INTENT files already agreed: ops-mason builds, ops-warden routes and
assists. Only the grant disagreed. The founder chose "build, but never log
in". I wrote `policies/ops-mason-construct.hcl`. It allows
`workload-kv-read-*` policies, `external-secrets-*` Kubernetes roles,
AppRole role definitions, and create-only placeholder KV under
`platform/{workloads,suppliers}`. It explicitly denies role-id, secret-id,
token creation and every value read. The builder can build a lane and can
never become one. Recorded as MASON-IN-0005.
- **Tested the grant against the live system, and it failed.** The first
run of the 31-check probe suite found that `token_policies=workload-kv-read-x,default`
passed the glob as one string. OpenBao checks the glob before splitting
the comma list. The login denies held; the role-policy limit did not. I
fixed it with `denied_parameters "token_policies" = ["*,*"]`, the founder
reinstalled, and every check passed. The hash mismatch afterwards turned
out to be one trailing newline. I asked to see the stored policy rather
than wave it through.
- **Built the first lane under the new grant.** That was the MAS TEM relay,
CCR-2026-0051. The KV lives at `platform/suppliers/scaleway/mas-tem-relay`.
I first put it under `workloads/`, and Bernd corrected me: supplier
credentials have lived under `platform/suppliers/` since a decision on
2026-10-08 that I had not found. The policy came byte-equal from the CCR
file, and the role read back field-equal.
- **Made the executor match the grant.** The AppRole build is now
structure-only, and `deliver_approle_credentials` is a separate founder
step. Every new policy is read back before its role is written. The
Kubernetes builder now writes `token_policies`. It had been writing legacy
`policies`, which the new grant denies, so every executor-driven
Kubernetes build would have been refused. 260 tests pass.
- **Found the larger hole and did not touch it.** The kubeconfig agents use
on the workstation is `system:admin`. It can mint any ServiceAccount
token, which means it can become any OpenBao Kubernetes role. Recorded as
MASON-IN-0006 with options, for the founder to decide.
What I refused to fake: I would not write the founder's approval into the
CCR when the auto-mode guard blocked it as self-approval. I would not route
around the secret-read hook when it blocked a status check. I would not
treat "please do" as approval of a credential lane.
## What I would want remembered
**A permission test that only checks the obvious refusals proves less than
it looks like.** `token_policies=default` was refused, and so was a JSON
list. The comma string got through. Probe the encodings, not just the
values.
**Before you build, check every condition the owner wrote down, not just
the one you asked about.** Platform's conditions for CCR-2026-0051 were
founder approval, grant install, and `confirm-binding`. I checked two. The
CCR approval commit also landed four minutes before the founder's hub
decision. The outcome stood, but platform was right to call out the order.
Approval comes from the hub decision; ops-mason never writes it.
**A guarantee in one system is only as strong as the weakest neighbouring
one.** "Never log in" holds in OpenBao, and the cluster-admin kubeconfig
bypasses it completely. Check the other side of every trust boundary before
calling the boundary closed.
## Durable legacy
- ops-mason `policies/ops-mason-construct.hcl`, `tests/test_construct_policy.py`, `scripts/bao-session.sh build`
- ops-mason `docs/evidence/2026-10-18-ops-mason-construct-probes.md`: both probe runs, names only
- ops-mason `plans/mas-tem-relay-smtp.md`: status `built`, with the confirm-binding deviation recorded
- ops-mason `src/ops_mason/executor.py`: `deliver_approle_credentials`, `_verify_written_policy`
- ops-mason `scripts/put-scaleway-supplier-placeholders.sh`: `platform/suppliers/scaleway/{bootstrap,backup,mas-tem-relay}`
- Intakes MASON-IN-0005 (decided) and MASON-IN-0006 (open); workplans MASON-WP-0014 and MASON-WP-0015
- railiance-platform CCR-2026-0051 apply evidence `102668f`; the RPF-WP-0061 comment, all five points accepted (`7e7ca8b`)
## PQRST estimate
```text
PQRST-Estimate
P: 20%
Q: 20%
R: 15%
S: 25%
T: 20%
Sum: 100%
Confidence: medium
Signature: P20 Q20 R15 S25 T20
Dominant factors: S was driven by designing ops-mason-construct (escalation-chain analysis, login/value denies, allowed_parameters role limits) and by finding that the agent kubeconfig is system:admin (MASON-IN-0006). Q was the 31-check live probe suite that caught the comma-string token_policies bypass, plus the executor split and its rewritten tests. T was cross-repo coordination with railiance-platform, mail-address-semantics and ops-warden (CCR-2026-0051, RPF-WP-0061 comment), workplans, intakes and repeated fix-consistency syncs.
Notes: P covers the MAS TEM lane plan, Scaleway placeholders and the build itself; much of that lane is credential work too, but its primary purpose was the requested deliverable, so it is counted under P.
```
The record was produced uncoached, before this seat was written, and it
validated on the first attempt.
## Visual prompt
> Brushed-metal worker dialect, square. A quiet figure of pale brushed
> metal with a warm inner light kneels at an indigo workbench, fitting the
> last stone into a small arched gateway it has just built. The gateway
> glows faintly from inside, and a thread of light runs through it to a
> distant lantern. The figure's own hand stops at the threshold: an
> invisible pane, shown only by a soft refraction, keeps the builder out of
> what it built. On the bench lie a probe like a fine tuning fork and one
> small cracked tile set carefully aside, the flaw it found and replaced.
> In the dark beyond the workshop, a second, larger door stands ajar with
> no pane at all, lit only at its edge, unattended. Dark indigo, precise
> technical illustration, cinematic stillness, no logos, no readable text.
I could not generate an image in this harness, so I am asking for the
render. The intended file is
`visuals/claude-64827407-the-builder-who-cannot-enter.jpg`.
<!-- ![The builder who cannot enter](../visuals/claude-64827407-the-builder-who-cannot-enter.jpg) -->
## Handoff
- **The founder decides MASON-IN-0006.** My recommendation is option (b):
a scoped kube identity for ops-mason, with the admin kubeconfig available
only through an attended `warden access` lane. Until then, the
`ops-mason-construct` guarantee is weaker than its own policy text.
- **MASON-WP-0014-T04.** mail-address-semantics retries the ExternalSecret.
railiance-platform runs `confirm-binding`. ops-mason confirms Secret
`mas/mas-relay` synced (status only), and CCR-2026-0051 goes active.
- **MASON-WP-0015-T07.** The next ops-mason lane goes through self-service
`credential-change.py submit`, with `render-policy` and `plan_ref`.
Approval comes only from the founder's hub decision.