Skip to content

feat(contract): name every op a cmd may carry, and home the app's own codes - #868

Merged
frahlg merged 1 commit into
masterfrom
agent/registry-ops-client-errors
Aug 9, 2026
Merged

feat(contract): name every op a cmd may carry, and home the app's own codes#868
frahlg merged 1 commit into
masterfrom
agent/registry-ops-client-errors

Conversation

@frahlg

@frahlg frahlg commented Aug 9, 2026

Copy link
Copy Markdown
Member

Contract-pair: srcfl/ftw-webapp@claude/admiring-pike-1cd1cc

Pairs with srcfl/ftw-webapp#18 — the two copies of contract/registry.yaml are one file and must merge together.

What

Two additions to the registry, mirrored byte for byte on the app side.

An ops block. site.mode.set and battery.hold crossed the wire as hand-written strings on both sides, and the scope each op demands was written twice more: in defaultOps() beside this dispatcher and again in the app's simulator. Nothing compared the copies. The block now names each op and its scope. The generator renders it as RegistryOps — data, not constants, following the RegistryModeTiers precedent: generating a constant for an op no code handles yet only invites someone to use it. TestRegistryOpsMatchCommandTable holds defaultOps() to the map: every op this box accepts must be declared, with the same scope. Containment rather than equality, deliberately — the registry may name an op ahead of the box. battery.hold is exactly that today: an app may say it, this box rejects it with E_UNKNOWN_OP, and TestAnUnknownOpIsRejectedNotIgnored pins that answer (its comment now says why that name).

Homes in client_errors. E_NO_ACK, E_NO_ANSWER and E_BAD_BODY are codes the app raises for itself; they sat outside the registry although its header claims every such code has a home there. They now sit beside E_RESPONSE_TOO_LARGE. The box generates nothing from that block and must never send one of them — the copy here changes only because the file is one file in two repositories.

Tests

  • TestRegistryOpsMatchCommandTable — verified red first with a mutated scope in the generated map, then green.
  • go generate ./internal/... re-run; TestContractGenIsCurrent green.
  • Pre-commit make verify ran the full suite clean: vet, every Go package, optimizer contract, compose migration.

🤖 Generated with Claude Code

… codes

The registry gains an ops block — site.mode.set and battery.hold, each
with the scope its grant must carry. The pair was hand-written twice, here
beside the dispatcher and again in the app's simulator, and nothing
compared the copies. The generator now renders the block as RegistryOps
and TestRegistryOpsMatchCommandTable holds defaultOps() to it, the same
arrangement mode tiers already have.

client_errors takes in E_NO_ACK, E_NO_ANSWER and E_BAD_BODY, the three
app-raised codes that sat outside the registry. The box generates nothing
from that block; the copy changes because the file is one file in two
repositories, byte for byte.

Contract-pair: srcfl/ftw-webapp@claude/admiring-pike-1cd1cc

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@frahlg

frahlg commented Aug 9, 2026

Copy link
Copy Markdown
Member Author

App side: https://github.com/srcfl/ftw-webapp/pulls?q=head%3Aclaude%2Fadmiring-pike-1cd1cc — see the PR just opened from that branch.

@frahlg
frahlg merged commit daded6e into master Aug 9, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant