# 2026-05-28 ## Broker dead-code cleanup — session cache removed, issuer-machinery claim corrected Started the follow-up cleanup slice the 2026-05-27 journal flagged under "Still dormant (follow-up cleanup)." Before deleting anything, mapped the full reference graph for every candidate. The mapping surfaced a material error in yesterday's dormant list. ### Correction to the 2026-05-27 "dormant" list Yesterday's entry said of the issuer/issuance/`/tokens`/Sweeper machinery: "All of this is now unreachable from the live code paths." That is **wrong** for most of it. Verified live references: - `Issuer.List` ← `GET /tokens` (server.go:464, route at server.go:265) - `Issuer.Revoke` ← `DELETE /tokens/{label}` (server.go:484, route 266) - `Issuer.RotateLabel` ← `POST /tokens/{label}/rotate` (server.go:511, route 267) - `mintForWorld` / `appendIssuance` ← reachable via `RotateLabel` - `readIssuances` / `revokeIssuance` / `lookupWorld` ← reachable via the three routes AND the Sweeper (`main.go:189` → `sweeper.go:155,212`) So the per-user issuance subsystem is registered, reachable, and user-facing. What is actually true: nothing **populates** the issuances Secret anymore — the only writer was `Issuer.Mint`, which now has zero callers — so the `/tokens` API operates on a permanently-empty dataset. Vestigial, not dead. Retiring it is a product decision (removing a live HTTP surface + a Sweeper refactor to drop its `*Issuer` dependency), not a dead-code sweep. Left for an explicit go/no-go. ### What WAS genuinely dead, and got removed `sessionCache` / `mcp_session.go`. The open-reads + per-world-write-token rework left it constructed-but-never-read: the only production reference was `newSessionCache(...)` assigned to the `mcpGateway.sessionCache` field at `mcp_gateway.go:74`, and nothing ever dereferenced the field. Dispatch goes through `worldWriteTokens.Provision`, never `GetOrMint`/`Invalidate`. Removed: - `mcp_session.go` (whole file: `sessionCache`, `session`, `cachedWorldToken`, `mintFunc`, `mintOutcome`, `errInvalidEmail`, LRU/idle eviction, singleflight). - `mcp_session_test.go` (whole file). - `mcpGateway.sessionCache` field + the `newSessionCache(...)` wiring in `newMCPGateway`. - `golang.org/x/sync` dependency (singleflight was its only consumer) — dropped by `go mod tidy` from `tools/go.mod` + `go.sum`. `canonicalEmail` is NOT in this file (it lives in `mcp_auth.go`, used by live write paths) — left untouched. Fixed three stale comments that described the old singleflight+sessionCache token-reuse behavior (one in `mcp_tools_write.go` handleMarkAppend doc, two in `mcp_tools_write_test.go`'s merge-dispatch test) to describe the per-world write-token reuse that actually happens now. ### Still orphaned by this change (noted, not yet removed) `cfg.Server.MCP.SessionMaxIdle` + `MaxSessions` (config.go) — validated and defaulted but no longer consumed by any code after the session cache is gone. They no-op now. Folding them into the larger `/tokens`-retirement decision rather than touching the chart/config surface in this minimal diff. `FirstMint*` knobs stay live (the write dispatch retry loop still uses them). ### Verification `go build ./...`, `go test -race ./...` (broker module), and `pre-commit.sh` (fmt + vet + lint across all four modules) all green. Pure dead-code removal — no behavior change on any live path. ## Broker per-user issuance subsystem — fully retired Followed the session-cache removal with the larger retirement Fritz green-lit: rip out the entire per-user token-issuance subsystem. Net diff across the broker: 47 files, +447 / −3900. ### The journal-list correction, confirmed in code Yesterday's "dormant" list called the issuer/`/tokens`/Sweeper machinery "unreachable." Reference-mapping proved that wrong: `List`/`Revoke`/`RotateLabel` were wired to live `GET`/`DELETE`/`POST /tokens*` routes, and `mintForWorld`/`appendIssuance`/`readIssuances`/`revokeIssuance` were reachable through those routes and the Sweeper. Two more live couplings the list missed entirely: `gateWrite` (the MCP write path) called `Issuer.lookupWorld`, and both `/auth/callback` and `/me/install` called `Issuer.authorizedWorlds`. So this was never a dead-code sweep — it retired a live, registered, user-facing API that happened to operate on a permanently-empty dataset (nothing populated the issuances Secret once `Mint` lost its callers). ### What changed - **Dropped the `Issuer` type entirely.** Post-removal it issued nothing — it only carried the k8s client and two world-authz accessors. Keeping the name would have been a lie. `issuer.go` → `authz.go`: `authorizedWorlds`, `lookupWorld`, `worldAllows`/`emailMatches`/`domainMatches`/`groupsMatch`, `mutateSecret`, `TokensSecretKey`, `maxConflictRetries`, `ErrNotAuthorized` survive as free functions/values. `NewServer` and `NewSweeper` now take `k8s kubernetes.Interface` directly (main.go already had the client). Deduped the per-world `lookupWorld` (was duplicated in `worldWriteTokenStore`). - **Removed** `Mint`/`MintFiltered`/`mintForWorld`/`List`/`Revoke`/`RotateLabel`/`revokeIssuance`/`appendIssuance`/`removeIssuance`/`readIssuances`/`appendToWorldSecret`/`removeFromWorldSecret`; types `Issuance`/`Issuances`/`MintResult`; consts `IssuancesSecretKey`/`maxLabelRetries`; errors `ErrNotOwner`/`ErrNotFound`. - **HTTP:** removed the three `/tokens*` routes + `listTokens`/`deleteToken`/`rotateToken` handlers + `listTokensResponse`. `/me/install` is now the only subject-rate-limited route. - **Sweeper:** dropped the `*Issuer` dependency, the issuance/drift sweep, and `readWorldLabels`. It now retires expired refresh tokens only; leader election retained. - **Config:** removed `server.issuancesSecret` and the orphaned `server.mcp.sessionMaxIdle`/`maxSessions` knobs (decode is strict `KnownFields(true)`, so the chart had to drop the keys in lockstep — code and chart could not be staged separately). - **Chart:** deleted `templates/secret-issuances.yaml` + its unittest suite, dropped the issuances Secret from RBAC/`_helpers.tpl`/`secret-config.yaml`/`values.yaml`/README, removed the three config keys. `helm unittest` green (8 suites, 101 tests). - **Doc rot:** swept ~20 stale comments + `MCP-API.md` that still described the issuance subsystem / `/tokens` / `Issuer` / sessionCache. Left the legitimately-correct usages (OIDC IdP `Issuer`, cert-manager `ClusterIssuer`, generic refresh-token issuance). ### Tests `issuer_test.go` → `authz_test.go`: deleted the Mint/List/Revoke/Rotate/MintFiltered suites; PRESERVED the authorization-matrix coverage by re-pointing it at `worldAllows`/`authorizedWorlds` directly, and the conflict-retry coverage by testing `mutateSecret` directly. `/tokens` route tests deleted (auth-rejection coverage already exists on `/me/install` via install_test). Rate-limit tests re-targeted to `/me/install`. All `NewServer`/`NewSweeper` call sites across the 9 MCP/server/sweeper test files now pass a fake clientset. `go test -race ./...` green; `pre-commit.sh` (fmt+vet+lint, all four modules) green. ### Operator migration note (broker.knowledge.demarkus.io is live) This is NOT self-applying on existing clusters: 1. The orphaned **issuances Secret** lingers — `secret-issuances.yaml` carried `helm.sh/resource-policy: keep`, so `helm upgrade` will not delete it. Operator should `kubectl delete secret /` by hand after rollout. 2. Any **per-user token entries already written to worlds' tokens.toml** (random opaque labels from the old `mintForWorld`) remain as valid write entries until they expire. Their raw values were never persisted by the broker, so they're unusable by anyone, and they self-expire (the old mint set `Expires`). Harmless but worth a one-time prune; the only label that matters now is `broker-write-`. Left deliberately untouched: a pre-existing stale comment on `MCPConfig` ("the gateway is opt-in ... `mcp.enabled`") — unrelated to this change and out of scope. ## Shipped Merged to `main` as **PR #164** (`fix(broker): remove deadcode`, branch `refactor/broker-retire-issuance-subsystem`). CodeRabbit approved after three review rounds; all checks green (the `test-charts-kind` upgrade-wipe regression was re-pointed from the deleted `demarkus-broker-issuances` Secret to `demarkus-broker-refresh-tokens`). Review rounds also caught a real nit — `mutateSecret` now skips the `Update` on a no-op mutation (`bytes.Equal` guard) to avoid resourceVersion churn — plus a sweep of stale RBAC/mint/session-cache wording across the chart README + values.yaml. Still queued: the dead `WorldConfig.DefaultToken` knobs (`expiresAfter`, and the decision on `operations`) — see the follow-up section in [broker-stable-mint plan](/plans/broker-stable-mint.md). Not started. Operator migration on broker.knowledge.demarkus.io still applies (orphaned issuances Secret needs a manual `kubectl delete`; stale per-user token entries in worlds' tokens.toml self-expire). ## Related documents - [Broker deadcode cleanup](/plans/broker-deadcode-cleanup.md): the cleanup plan this session executed - [2026-05-27 journal](/journal/2026-05-27.md): the dormant list corrected here - [Debt](/debt.md): remaining DefaultToken knobs queued after this retirement