Repo: sdk-php
Rendered from spec at76d46f3 (2026-10-25) · its source · Edit this page
Status: Accepted
The PHP client for lemonfiber’s web API. PHP, Hippocratic 3.0.
Implements: the client half of the
web API contract, as a peer of
sdk-ts.
What this repo is
A library with no user interface and no server, built on Saloon for its HTTP layer. It speaks the web API and exposes it as typed calls, a typed event stream, and typed errors.
It is a peer of sdk-ts, not a translation of it
(ADR-0013). Both
conform to the same specification; neither is the reference for the other. An SDK
that disagrees with the contract is wrong.
What is generated and what is written
The split is the same in every SDK (ADR-0014):
Generated into src/Generated/, never edited by hand |
Response shapes, endpoint paths and parameters, action names, event names, the wire version |
| Written, once, in PHP | The stream’s behaviour, the token’s placement, the error model’s wording |
Everything generated comes from the contract/web-api/ directory, which lemonfiber
produces from the types that actually serialise the reply (ARCH-R56). A
hand-written response shape here would be a second source of truth for the
contract, which ARCH-R58 forbids.
What it owns
The parts a schema cannot express, and which each SDK must therefore implement and test for itself:
- The stream — heartbeat detection (
ARCH-R50), resumption, and marking values held across a reconnect gap as stale rather than current (ARCH-R51). - The token — supplied by the caller, sent as a header, never placed in a
URL (
ARCH-R52). - Loopback, or an address a pin vouches for — a non-loopback host is refused
unless the caller supplied that stack’s certificate pin, and where one is
supplied it is enforced during the TLS handshake so nothing is written to an
unverified peer (
ARCH-R60,ARCH-R99, ADR-0025). The pin is given when the client is built and the client configures the transport itself; there is no way to supply one address without the other, and no seam through which a caller can reach verification to weaken it. The rule citesARCH-R60rather thanC6-R1, which is about where a server binds and not about what a client may dial. - The refusal on mismatch — a wire version it cannot speak names both
versions and returns nothing (
ARCH-R55).
What it must not own
- Rendering or presentation. It is consumed by scripts and applications, and must assume neither.
- Policy. It reports what the core said. What to do about a stuck download is the core’s decision.
- State beyond the stream. No caching, no reconciliation. A figure it has not been given is one it does not have.
Quality bar
The same standard as the Rust workspace, in its PHP equivalents: static analysis at maximum with no baseline and no suppressions, 100% coverage enforced as a gate, mutation testing with a minimum score — coverage that kills no mutants proves only that lines ran — automated refactoring checks, architecture tests, and a strict formatter. Dependencies beyond the HTTP layer are avoided: a client library’s dependency tree becomes every consumer’s.
Two obligations are specific to a published library: a changelog, since people pin it, and a backward-compatibility check, so a breaking change fails the build rather than surprising a consumer.
Publishing
Not published: no release, no tag, and no Packagist registration.
lemonfiber-companion takes it from this repository as
a VCS dependency, pinned to a commit by its lockfile. Registration on Packagist
waits for a stable major worth pinning.
Related
- ADR-0013 — why the SDK exists and is separate
- ADR-0014 — why its types are generated
- web-api.md — the contract it implements
- sdk-ts.md — its peer