Skip to content

feat: record the SDK's contract with its consumers - #75

Merged
retr0h merged 1 commit into
mainfrom
feat/sdk-standards
Aug 16, 2026
Merged

feat: record the SDK's contract with its consumers#75
retr0h merged 1 commit into
mainfrom
feat/sdk-standards

Conversation

@retr0h

@retr0h retr0h commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

First of the capabilities coming out of specify-documentation-homes section 3. Spec only — no implementation, per the workflow.

Why this one first

It is the only one of the five that already binds a second repository. osapi-orchestrator is built entirely on pkg/sdk/client and pins it by version, so the contract has a real consumer and real evidence for what the rules must be.

Today those rules live in two documents inside osapiCLAUDE.md (method naming) and docs/docs/sidebar/sdk/guidelines.md (type exposure, JSON tags, error handling). Both are addressed to people working inside osapi. The repository that depends on them cannot see them, and nothing detects a change to the contract until the consumer breaks.

Recorded, not corrected

I checked every rule against the code before writing it down:

Rule Checked
No method repeats its service name 0 stutters across all services
No public signature exposes a gen type 0 — generated types appear only inside method bodies
Every exported result field has a JSON tag 0 untagged
No consumer imports gen orchestrator never does

That is what makes this a recording. A requirement written from documentation alone records what someone intended; one checked against the code records what is true.

My first check for the gen rule was wrong — it grepped method bodies and reported five violations. Constructing a generated request inside a method is exactly what the SDK is supposed to do; the rule is about signatures. Re-checked by parsing parameters and return types only.

One rule turned out to be load-bearing

"JSON tags required" reads like style until you find what depends on it: results are converted to generic maps by round-tripping through JSON. An untagged field arrives as Hostname rather than hostname, so the lookup misses and the value is silently absent. The requirement states that reason, because a rule whose justification is invisible is one someone will later relax.

The same applies to omitempty — the requirement draws the line at whether absence carries meaning. Changed omitted when false makes "nothing changed" indistinguishable from "this SDK version does not report changes".

Scope

Stops at the SDK boundary. How the API it calls is designed, how a provider behaves, and how Go is written across the organization are separate capabilities with separate readers — recorded in design.md as a rejected alternative.

Sections 2 and 3 stay open: they are the implementation, and per CONTRIBUTING the spec merges first.

🤖 Generated with Claude Code

osapi publishes a Go SDK that osapi-orchestrator is built on, and the
rules governing it live in two documents addressed to people working
inside osapi. The consumer cannot see the contract it depends on.

Each rule was checked against the code before being written, so the
capability records what is true rather than what was intended.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Thank you for contributing to this project! 😊🕹️

@retr0h
retr0h merged commit 63fdac7 into main Aug 16, 2026
6 checks passed
@retr0h
retr0h deleted the feat/sdk-standards branch August 16, 2026 06:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant