The API foundation has three implemented mechanical authorities: an explicit Go schema/operation registry, generated API contracts, and authenticated keyset cursors.
Schema descriptors cover exact objects, arrays, strings with closed formats/enums, bounded int64
integers, booleans, null, named references, and one-of unions. Registry construction rejects an
invalid descriptor, duplicate operation ID, duplicate method/path, public/auth mismatch, or an
unknown request/response schema. Duplicate route identity ignores placeholder names:
GET example/{first} and GET example/{second} cannot coexist, because chi would
silently replace one handler and its auth middleware. Method, static segments,
namespace and parameter positions remain significant; merging independent registries
enforces the same duplicate rule. Runtime response fixtures validate against the same descriptor
values consumed by runtime mounting, OpenAPI generation, TypeScript generation, and the committed
v1 compatibility pin. Authenticated Soul Recovery and minigame routes mount exclusively from this
registry. Mounting checks the entire binding set and every required auth middleware before
wrapping handlers or registering routes. Missing, extra, unsorted, or nil runtime bindings,
or absent required auth middleware, fail without changing the caller's existing router.
Path-parameter descriptors have unique names in template order (not lexical order),
and their resolved kind must be string, integer or boolean. Named-reference chains
preserve their declared type and bounds but cannot conceal an object, array, null
or union. Invalid descriptors fail with ErrInvalidOperation before generation or
mounting. This is descriptor admission, not new URI-value validation middleware or
a change to the separate static/parameter route-overlap policy below.
Raw-response hash headers use the same admission rule at registry construction and
cached emission: their existing name grammar applies, and they cannot equal ETag,
Cache-Control, Content-Type, Content-Length or X-Request-ID case-insensitively.
A conflicting descriptor fails with ErrInvalidOperation before mounting/generation;
valid custom headers still preserve exact raw bytes and the independently owned metadata.
HTTP registry admission first rejects malformed UTF-8, then checks raw object-member uniqueness
before decoding to maps. Invalid encoding returns ErrInvalidSchema rather than letting Go
replace corrupt bytes with U+FFFD. This follows the network JSON encoding requirement in
RFC 8259 §8.1 and the generated client's
existing fatal UTF-8 decoding. Valid Unicode (including literal U+FFFD) and JSON escapes remain
admitted. Go's existing BOM refusal is unchanged; this does not choose a new surrogate policy
or tighten shared artifact decoding. Raw response validation still hashes original bytes.
Duplicate names at any level, including different escape spellings of the same name, return ErrInvalidSchema
rather than silently keeping the final value. Valid escaped names, string contents resembling
JSON and repeated names in separate objects remain allowed. ValidateRequest and
ValidateResponse share this check; it does not add request-validation middleware to handlers
that do not already call the registry, or rewrite any successful handler response.
Registered exact-response literals require the same admission at construction. The shared
ValidateJSON descriptor checker retains encoding/json last-value decoding for artifact
owners; formula replay artifacts depend on that existing Go/TypeScript contract. Their original
bytes and hash identity are not normalized or rewritten by HTTP validation.
Bootstrap, session creation/refresh, minigame create/command/resolve and all four Soul-Recovery
writes now validate original size-bounded request bytes through their registered descriptors
before credential or gameplay work. Duplicate/escaped duplicate names and case aliases cannot
bypass admission through Go struct decoding; nested tenant commands are checked too, and
minigame resolution requires an object rather than null. Existing operation-specific invalid
errors, authentication/limiter order and unavailable-service precedence remain. Live HTTP/Postgres
tests retain unchanged credential/activity/gameplay/history rows on refusal and the existing
successful lifecycle. This does not change the command union, implement Typer/Arcade wire arms,
or claim conformance for handwritten import/intents or historical empty-body account/Founder calls.
Operations may declare exact scalar query parameters (string, bounded integer, or boolean). They
are byte-sorted by name and never shadow a path parameter. The reserved cursor parameter is a
non-required string, and it is present exactly when the operation declares a cursor key.
Registry.ParseQuery decodes only declared parameters. Each parameter may appear at most once,
integers are strict base-10 (no sign, padding, or leading zero), and every value is checked by the
same descriptor validator as response bodies. A failure returns InvalidQueryError naming the
parameter; undeclared parameters are ignored.
HTTP paged readers use Registry.ParseRawQuery on the original query string before
descriptor validation. Malformed percent escapes or unescaped semicolons in a
declared field return its existing typed invalid error; they cannot disappear into
a default page, conceal a duplicate or produce a conditional304. Valid escaped
names/values and ignored undeclared fields retain their existing behavior. The
decoded-values ParseQuery helper remains available to callers that already own
successful form decoding.
String values retain their exact valid UTF-8 content through JSON encoding before descriptor
validation, including JSON-escaped control characters. Empty and malformed UTF-8 query strings
are rejected; a literal Unicode replacement character is valid, not a malformed-byte substitute.
Query parameters are generated as OpenAPI in: query entries, and TypeScript gets
queryParameters plus an optional-aware query type. Query-free operations generate
byte-identical output. The compatibility pin records the query set only for operations that have
one, and rejects any change to an existing operation's query set. That is stricter than C2 (which
would allow a new optional request field), but never looser.
A schema response may also declare a sorted immutable set of exact JSON wire bytes. This is a runtime-validation narrowing layered over the generated DTO, not a generated-client or OpenAPI shape change. Minigame error responses use it to bind each operation/status to the shipped category/detail pairs and encoder newline, so a schema-valid cross-product or appended byte is not accepted as contract evidence.
The shared error-detail enum includes soul_recovery (unavailable/internal recovery errors)
and company_stream (start without an active Company), matching existing handlers. These
are additive descriptor corrections, not handler or error-mapping changes. Real authenticated
Postgres-backed replies are checked against this same registry; invented details still fail.
The generator exports apiErrorCategories and apiErrorDetails from those descriptor fields.
It follows validated named-reference chains for the error envelope and scalar enum fields;
referencing the same declared enum cannot erase its metadata or make it unbounded. The emitted
TypeScript aliases and OpenAPI reference graph are preserved, not flattened. This does not
authorize a compatibility-breaking change to the production descriptor or imply general runtime
DTO/union validation.
The shared Minigame/Soul/Garden operation adapter requires both registered enum memberships
before constructing a typed API rejection. Unknown details produce the existing body-free
transport error instead of copying reply text into the typed exception. An enum-free detail
schema generates null metadata rather than falsely declaring an empty string domain; the
current production descriptor has a closed enum. Minigame's operation/status-specific ExactJSON
bindings remain the stronger additional check. Global enum membership alone does not prove
operation/status/pair conformance for other operations or validate successful DTOs.
make api-schema regenerates canonical OpenAPI 3.1 at docs/generated/api.json and exact client
DTO/operation metadata at client/src/api/generated/types.ts. make api-check regenerates and
byte-compares both outputs as part of make verify-server. The committed
docs/generated/api-compat-v1.json baseline enforces the v1 additive-only law: existing
operations, request unions, statuses, required fields, and bounds cannot narrow or disappear;
responses may add optional fields or widen an enum/union. Updating the compatibility baseline is
an explicit make api-pin operation, never an incidental effect of ordinary generation.
This is a metadata/schema check, not a routing-equivalence guarantee. Registry construction
rejects duplicate method/path patterns (including renamed placeholders) but does not reject
a static path overlapping an existing parameter path. The six-case registered-chi probe
recorded as RP-562 shows that such
an addition can pass compatibility while changing the handler and response for a previously
admitted URL. Disjoint tenant namespaces are proposed in
rfc/minigame-tenant-http-bindings.md; no checker-policy change is adopted, and this experiment
does not establish a fault in an existing production route.
A single response object may become a closed-object union without replacing that baseline:
the first arm must preserve the old contract, and every added arm must be provably disjoint
from it through required-key exclusion. Overlapping arms could invalidate old bytes under
oneOf and are refused, as are request/shared widening and cases whose disjointness this
bounded check cannot prove. Recovery uses this for its already-shipped watchdog terminal on
the heartbeat route; ordinary progress and other response descriptors are unchanged.
For an existing response union, appended arms must likewise be provably disjoint from the old
arms; otherwise oneOf could reject formerly valid bytes by matching them twice. This check
resolves each side's named references and recognizes distinct JSON kinds, disjoint string enums,
exact integer ranges and object required-key/discriminator exclusions. Arrays are not assumed
disjoint merely because their item types differ: both can admit []. Unproven intersections
remain conservative. This covers appended-arm growth, not a general proof of all cross-arm
interactions when existing arms themselves change; compatibility and full API acceptance remain
separate from routing, runtime fixture and complete consumer proofs.
Existing string-enum arms are also checked together: every old uniquely admitted literal must
still match exactly one current arm. Both old and newly declared literals are examined using
the runtime string-format validator and named references, including an old unbounded-string
arm. Newly ambiguous values that were never admitted previously do not themselves break
backward compatibility; safe response enum growth remains allowed. This is the string-domain
check, not a general inclusion solver for numeric/object cross-arm changes.
Integer arms receive an exact interval check: collect minima and guarded maximum + 1
cut points from both schema versions, then compare exclusive matches at each region's first
int64. Membership is constant inside each region, so this covers the whole integer domain,
including missing bounds and both int64 limits, without floating-point conversion or exhaustive
value iteration. Old-invalid and new-only overlaps do not invalidate compatibility by themselves.
Object cross-arm changes remain separate from these scalar-domain checks.
Existing object and array arms now receive an intersection proof as well: for each current arm and
different old arm, their shared domain must be provably covered by another old arm. Such
values already matched at least twice and were not old valid replies. Otherwise growth
is refused; an optional property or required-field demotion is not automatically safe inside
an exclusive union. The proof follows side-specific named definitions, closed object field
presence/domains, homogeneous array item domains, nested unions/arrays, runtime string formats
and exact integer intervals. Whole-array coverage matters: a mixed-element array can have
one old match even when every singleton and the empty array were already ambiguous.
Scalar membership checks alone do not cover growth of array alternatives. Empty-array
overlap is retained rather than treated as proof that no old valid arrays exist.
Unchanged arms and provably safe growth remain allowed, including already-invalid overlap
covered by a third old arm. Unknown intersections fail closed; this is a sufficient proof,
not a general inclusion solver or full C2/API/consumer acceptance.
Existing optional fields cannot become required in requests, responses or shared definitions,
including through array/reference/union nesting; failures identify the affected field. Numeric
bounds compare as exact signed int64 values, not float64 projections, so a one-unit narrowing
above 2^53 or at an int64 boundary still fails. This checks schema metadata, not production math.
Schema names follow the current-plus-legacy convention: an unversioned name denotes the current
shape, while a retained historical shape uses an explicit V<n> suffix. A compatibility-pin
refresh must cite its authorizing ruling and be recorded in the owning planning log in the same
change; an otherwise valid widening is not permission for a silent re-baseline.
The generated registry is not yet the complete runtime API. Current metadata covers twenty-two
operations, including the existing session creation and refresh routes and their actual error
alternatives. Both routes mount from the registry with their existing shared unauthenticated IP
limiter. Their successful two-string token pairs reuse the BootstrapSession owner descriptor;
creation takes {account_id,recovery_code}, refresh takes {refresh_token}. Registered errors
are exact operation/status-specific bytes: 400 invalid/body, 429 rate_limited/ip, creation's
401 unauthorized/credential, and refresh's 401 unauthorized/refresh_token or
401 refresh_reused/session_family_revoked. Both session handlers validate their original,
size-bounded request bytes against those existing descriptors before decoding/credential use.
Duplicate/escaped duplicate members, case aliases, missing members and nulls therefore refuse
as 400 invalid/body, rather than bypassing exact-key validation through Go struct decoding.
Valid single escaped names remain accepted. The shared IP limiter and no-store wrapper still
precede admission. Session schemas/pins and renewal policy are unchanged.
Explicit generated calls can now represent those routes/errors; they do not add automatic
renewal, credential replacement, recovery UX or retry policy. The deliberate additive pin refresh
under API C1/C2 also captures the already-registered Garden route and optional Garage response
shapes; it changes no original operation rows. Tests against the actual committed pin reject
removal of either session operation or its 401 alternative. Bootstrap, main state reads and the
Minigame/Soul/Garden ports use the generated client; intents still call fetcher outside the
generated directory. api-check passes
for the registered subset, not AC4 completion. Manual
make research-refresh-generated-contract now verifies represented refresh callers and
in-memory metadata-removal refusals outside CI/verify; its earlier retained report remains
historical evidence of the gap. It does not implement or authorize browser renewal. See the
bounded census.
The existing account lifecycle routes also mount exclusively from registered rows:
create_account (POST /api/v1/account, unauthenticated), create_founder
(POST /api/v1/founder, access token) and get_founder (GET /api/v1/founder, access token).
Account creation retains the shared IP limiter and no-store credential reply; both Founder
routes retain shared account limiting and failed-auth IP limiting. Their handlers and accepted
body forms are unchanged. Generated POST calls use the canonical empty object; the live parser
still admits an empty body as well and rejects internally spaced { }.
AccountCreated is {account_id,created_at,recovery_code}. FounderCreated is
{id,created_at,imported}; FounderProfile is {id,created_at,display:{}}. Display is an exact
empty object, not permission to introduce arbitrary profile data. Unlike bootstrap's fixed
.000Z format, these existing handlers use time.Time's UTC millisecond encoding with trailing
fractional zeros omitted. The separate date-time-utc-ms string descriptor validates those
bytes without relaxing any existing date-time-ms descriptor or re-encoding a reply.
Actual 400 invalid/body, 401 unauthorized/access_token, 404 unknown_id/account|founder,
429 rate_limited/ip|account and 500 internal_invariant/account_create|founder_create errors
are registered only on their applicable operations/statuses. The deliberate C1/C2 pin refresh
adds these three operations; no existing operation row changes. Real Postgres tests cover
creation → session → current Founder → New Founder → refreshed Founder binding, retained
archives, refusal nonmutation and shared limiting. This does not add recovery UX or deletion
policy. Bodiless deletion responses, intent/import routes, C9 enforcement and full API
acceptance remain unfinished.
Exact empty-object descriptors now generate Record<string, never>, not TypeScript {}
(which accepts extra fields and primitives). This corrects SDK typing for account creation,
New Founder, the empty display object and existing Minigame resolution requests; it changes
no OpenAPI shape, HTTP parser or wire acceptance set.
createAPIClient(fetcher?, baseURL?) is emitted inside the generated module from an embedded
generator template, with operation-specific method/path, auth, query and response metadata
from the registry. call(operationID, input) accepts generated path/request/query types,
explicit access tokens only for private operations, and optional request ID/abort signal.
Path components are URL-encoded; declared query values are serialized in registry order.
Unknown path/query fields, missing auth and inexact integer parameters fail before HTTP.
Exact ./.. path components also fail before dispatch because URL parsing treats them
as navigation, not resource identities. Ordinary dotted names, percent-encoded literal
inputs and query dots retain their existing encoding; this does not validate catalog IDs.
Content-Type is sent only for operations with a JSON request body, not bodiless reads.
The client never forwards an access token on a public operation. There is no token storage,
refresh, retry, timeout, or request-ID policy hidden in it.
OperationResponses preserves status/body associations. Schema responses are JSON-decoded;
these TypeScript types are not runtime schema validation. Wrappers retain their existing
application decoders. When a status declares multiple representations, the client selects
the descriptor by the response's media type (ignoring parameters such as charset) before
choosing its decoder; a missing or undeclared type refuses before reading the body.
Media type/subtype matching is case-insensitive, as required by
HTTP semantics §8.3.1;
Application/JSON is the same declared type as application/json, not a new representation.
Raw response bytes and their digest header remain exact and are never case-folded.
Single-representation schema responses also require their registered JSON media type before
reading the body. Missing/undeclared media raises a body-free transport error, even when the
bytes happen to be valid JSON. Existing JSON charset handling and status/error payloads are
unchanged; this is media conformance, not runtime DTO validation. Raw successes are Uint8Array, not an omitted success type or parsed
JSON. They require the registered media type and content-hash header, checked against SHA256
over downloaded bytes. Error statuses on raw operations remain JSON. Undeclared status,
malformed JSON, raw type/hash failure and network/abort errors are surfaced, never retried.
Schema replies are decoded from bytes with fatal UTF-8 validation before JSON parsing, matching
JSON's network encoding requirement.
Corrupt encoding cannot be silently repaired into replacement characters. Existing BOM tolerance,
valid Unicode (including an explicitly encoded replacement character), and JSON escape handling
are preserved; this is encoding validation, not runtime DTO or credential validation. Raw evidence
continues to be returned byte-exact after hash verification, not UTF-8/JSON-decoded by the transport.
Malformed encoding/JSON reports its HTTP status without echoing reply bytes. Body-read failures
propagate unchanged rather than being relabelled as encoding/JSON errors.
The generated module exports this same decodeJSONResponse primitive for the
remaining legacy intent caller. It owns only UTF-8/JSON decoding, not status/media
admission or DTO validation. The intent operation still awaits its typed-dictionary
contract and generated dispatch; reusing decoding does not complete C9 migration.
The undeclared 304 arm remains open; this client does not invent an alternative for it.
OpenAPI retains every raw hash header across same-status representations, combining header names case-insensitively. A header is marked required at the status level only when every representation declares it; otherwise its generated description names the media type that requires it. This expresses the existing representation contract, not optional raw verification: the SDK still requires and verifies the selected raw descriptor's hash header.
The actual Game UI bootstrap and main state reads now use this transport without changing the bootstrap journal, credential storage, snapshot decoder or revision reconciliation. Lost replies and HTTP/parser failures retain the persisted bootstrap key for an explicit retry; no client-level retry is added. Remaining HTTP callers and the C9 raw-fetch lint are still unfinished, so this is not AC4 completion. Unit/browser tests use controlled fetches; the existing composed journey separately exercises these migrated calls against real HTTP, Postgres and WebSocket services. The composed Exit fixture additionally runs the generated client against live public HTTP downloads and the TypeScript replay verifier, as described below; controlled-byte SDK tests alone are not that integration evidence.
The Minigame, Soul Recovery and Garden ports dispatch by generated operation ID with typed
path/request inputs. Their shared adapter reads the current access token once per explicit
call and preserves the existing MinigameAPIError/MinigameTransportError classes and surface
rejection mappings. Error categories come from the generated registry, not a second list.
Undeclared HTTP statuses are transport failures. Error bodies require exactly two fields,
a known category and a nonempty detail. Where a response declares ExactJSON, generated
operations[].responses[].exactJSON metadata carries those same literals, and the adapter
also requires the category/detail pair to belong to that operation and status. Wrong-family,
wrong-status and undeclared details become body-free transport failures, not typed gameplay
refusals. This compares semantic pairs after JSON decoding, not original whitespace/member
order or raw duplicate keys. Garden/Soul rows currently have no literal narrowing and retain
the previous guard; neither they nor success bodies gain runtime schema validation here.
Existing wire-binding/error tests cover all nine port calls;
the real composed journey covers Pitch and default locked-Garden reads, not a complete
persisted Soul Recovery or active-Garden workflow.
GU-C26 authorized the Game UI schema v3 compatibility-pin baseline. Accepted Garage Player
Surfaces GS0.1 (2026-09-25) authorizes the v4 re-baseline. The unversioned GameUISnapshot is the
current v4 shape. GameUISnapshotV1, GameUISnapshotV2 and GameUISnapshotV3 retain exact
stored-bootstrap receipt validation, and the live Founder-state operation returns only v4.
Public pagination cursors contain canonical {filter_sha256,key,op,v} JSON followed by an
HMAC-SHA256 signature, encoded as unpadded base64url. The codec verifies the signature with the
current or previous deployment key before parsing JSON, binds the cursor to operation and complete
normalized query, and rejects noncanonical or oversized input. Board variables use canonical
exact-key JSON with integer booleans and explicit-null faction.
server/publicread owns the unauthenticated /api/public/v1/ registry. publicapi.APIErrorSchema()
is the single APIError definition that both registries reference. publicapi.MergeRegistries
unions the private and public registries into one generation authority. A schema name may be
shared only if the definition is byte-identical, and operation IDs must not collide. As a result,
docs/generated/api.json, the TypeScript module and the compatibility pin cover both surfaces,
while each surface still mounts from its own registry.
The shared error schema belongs to publicapi, not the private Account repository. Public
readers no longer import Account to construct their registry. A production-source import guard
checks both publicread and publicapi, rejecting direct Account/Session/Save/Production owner
imports (including aliases and subpackages). It ignores comments and test fixtures and refuses
unparseable source. This is a direct package-boundary check, not proof of every transitive
repository dependency or runtime disclosure; those remain separate privacy acceptance gates.
The move preserves the error fields/enums, all operation/status-specific exact replies, and
byte-identical generated OpenAPI, TypeScript and compatibility pins.
GET /api/public/v1/epochs (list_public_epochs) returns the C12 PublicEpochPage:
itemsare newest-first. Each hasaccepted_hashes(byte-sorted in Go, an empty list when there are none), the exact UTF-8changelog_markdownread from the stagedchangelog_ref, and UTC millisecondstarted_at/ended_at(ended_atis explicitnullwhile open).next_cursoris a C15 keyset cursor onepoch_id, bound to the normalized filter{"limit":N}.limitdefaults to 50 and is bounded 1..100.- Rejections: a malformed limit returns exactly
400 {"category":"invalid","detail":"limit"}. A malformed, tampered or filter-mismatched cursor returns400 invalid/cursor. - Failures: repository or changelog failures, including a missing or non-UTF-8 staged
changelog, return
500 internal_invariant/public_api. - Caching and validation: successful bytes are validated against the registry row. They are
then served through the shared cache/limiter runtime with the
catalogs_epochsclass (public,max-age=3600, strong ETag, and a 304 that spends no rate token). - Page source:
leaderboard.Repository.PublicEpochPage, which reads the page from a single SQL statement.
GET /api/public/v1/boards/{category} (list_public_board) returns the C12 BoardPage
{category_id, epoch_id, items, mandate_level, next_cursor, ranking_kind, variables}.
- Query: C13's normalized query.
variablesis the base64url canonical JSON{advisor,commons,faction,glitched}(sorted keys, 0/1 flags, explicit-null faction).epoch,mandate(0..20) andvariablesare required;limit(1..100, default 50) andcursorare optional. - Ranking kind: resolved from the pinned categories artifact of every stored constants hash
accepted into the epoch. Timed categories (
rta/attended) aretime_msand the untimed valuation category ismagnitude.countis declared for the union, but no category produces it yet. Catalogs that disagree, or a stored catalog that cannot load, are internal invariants. The accepted-hash result must complete successfully: a row-iteration failure is propagated as a server failure, never resolved as an unknown category from an incomplete result. - Items:
{founder_id, key, rank, run_id, verified_at, world_first}, wherekeyis the closed union{kind:"time_ms"|"count",value}/{kind:"magnitude",exponent,quantized_mantissa}.rankis the competition rank over the whole board. - Cursor: the keyset cursor (
{key|exponent+quantized_mantissa, run_id}) is MAC-bound to the complete normalized filter (category, variables, epoch, mandate, limit). A cursor whose arm doesn't match the ranking kind is rejected. - Paging: the reader fetches
limit+1rows, so a page that is exactly full carries no cursor. - Rejections:
400 invalid/{cursor,epoch,limit,mandate,variables};404 unknown_id/{category,epoch};429 rate_limited/ip;500 internal_invariant/public_api.
- Caching: the
boardsclass (public,max-age=60).
GET /api/public/v1/registry/routes (list_public_routes) returns the C12 RoutePage
{items, next_cursor}.
- Source:
registry_routesjoined withaccount_founders, throughrouteprojection.Projector.PublicRoutePage. - Items:
{adoption_count, credited_at, first_executor_founder_id, naming_deadline, naming_status, public_name, route_id}.public_nameis the approved player name only whenpublished. Reserved, pending (unmoderated) and expired names show the house name.first_executor_founder_idisnullonce that Founder's account is anonymized (or no ownership row exists).- Moderation state beyond the status enum and all account identity are absent.
naming_statusis the stored projection state. The composed server primes unused-name expiry before readiness and repeats it once per minute; an unused row can reportreserveduntil the next successful pass. The exact deadline already prevents a late backend name submission. The public house-name fallback and expiry driver do not supply a player naming/moderation workflow.
- Order and paging: ordered by the immutable
route_id;credited_atcan move when an earlier execution re-credits a route. The keyset cursor is bound to{"limit":N}, andlimitis 1..100 (default 50). - Rejections:
400 invalid/{cursor,limit},429 rate_limited/ip,500 internal_invariant/public_api. - Caching: the
registryclass (public,max-age=300).
Privacy (AC5) is enforced two ways:
- Structural:
publicread/privacy_test.gorequires every public operation to be an unauthenticated GET under/api/public/v1/with no request body. Every named schema, includingAPIError, must have a contract-derived publication field set; full field paths are checked against it, so innocent-looking extra fields and nested reuse of an allowed name cannot bypass the check. The existing account/email/token/session/recovery/password/secret/stream/save/IP/ device/presence exclusions also remain. Founder identity is permitted only atPublicBoardItem.founder_idandPublicRoute.first_executor_founder_id. The field expectations are independent test assertions, not a second runtime schema or permission to publish new data. - Composed: the composed-server witness seeds a real private account. It then requests every public registry operation (a missing request builder fails the test) and asserts that no response body or header contains the seeded account ID, recovery code, tokens, founder ID or company stream ID. Evidence endpoints return identical, non-cacheable 404s for private and unknown runs. A separate actual verified-run download check permits C4's public Founder/Company history but rejects account IDs, recovery codes and session tokens in the manifest, genesis and decompressed replay archive. Raw-response privacy requires this content check; the schema walker cannot inspect a gzip body.
publicread.NewRouter composes the surface. It loads the strict policy, resolves the named cursor
secrets (CursorSecretResolver, see docs/gameserver.md), builds the request-ID runtime and
limiter, and mounts every public registry operation (and only those) through Registry.Mount.
Policy admission requires every exact, non-null root and nested member; case aliases and
case-alias collisions refuse before mounting. In particular, missing/null trusted_proxy_hops
cannot silently select zero. Explicit zero remains valid for a direct deployment, and escaped
canonical JSON member names remain equivalent. Configured values and proxy/limiter semantics
are otherwise unchanged.
Unknown public paths and non-GET methods return 404 unknown_id/route and never fall through to
the account router, subject to the same IP budget as registered operations. The gameserver
mounts it at /api/public/v1/, and composition fails closed without a valid policy or cursor
pair. The composed-server Postgres witness checks all of this:
the served epoch page, request-ID echo, cache headers, a 304 on a matching ETag, the unknown-route
404, and fail-closed composition. The composed Game UI lane also fetches the page through the Vite
proxy.
The public runtime charges one token per non-304 response, including malformed queries,
private/unknown identities, router refusals and operational failures. Before exhaustion their
existing statuses and exact error bytes are unchanged; after exhaustion the response is the
same uncached 429 rate_limited/ip used for successful uncached reads. Request IDs remain
present; rejected response bodies and stale cache/length/encoding metadata are discarded.
The cached writer and outer response writer share one admission decision, not two tokens.
Authorized matching 304s remain free even after errors exhaust the bucket. IP attribution,
burst/refill/entry limits and authentication policy are unchanged. This is response-budget
enforcement: representation authorization/reader work still happens before the response
decision, so it is not a pre-reader database-work bound. Mounted error/cache regressions use
controlled readers; the existing composed Postgres checks separately exercise the live server.
Gameserver composition binds shared request-ID mechanics to both API surfaces, using
the same C20 policy grammar/bounds. Valid caller IDs echo unchanged;
invalid/missing IDs become UUIDv7, never truncated. The resolved ID is available through
httpapi.RequestID (and the compatibility publicapi.RequestID accessor), without adding
it to response JSON. Nested public middleware reuses that context rather than generating
another ID. Composition installs private publicapi.WithRequestID and logging at
Server's outer API boundary, before intent admission, so the existing drain503
also echoes/logs a valid or generated ID. PublicRead resolves through its
runtime so identity failures still use its existing public response bucket. Public,
unauthenticated Account and authenticated Account budgets remain separately owned. Standalone
Account router callers must supply this HTTP composition themselves. This implements
response/context correlation. Composition also supplies its existing structured logger
to both API surfaces. After successful identity assignment, one api request entry
records the resolved request_id before application handling, including cache hits,
typed errors and limiter refusals. The entry adds no method, URL/query, body, headers,
IP, account/Founder identity or credentials. The ID is caller-controlled correlation
material, not an authenticated identity. It is not a new metrics label or gameplay
telemetry stream.
httpapi.LogRequestID reads only the shared context, never a raw caller header;
downstream header replacement cannot change the logged authority. Failed identity
assignment does not fabricate an ID or a correlated request entry. Embedded public
router callers can omit the optional logger; embedded Compose's existing nil-logger
default is a discard sink. The production gameserver supplies its JSON stdout logger.
This proves emission, not supported-host journal retention, delivery or capacity.
Identity-generation failure refuses before application work with uncached
500 {"category":"internal_invariant","detail":"request_id"}. It fabricates no request ID
and never exposes the underlying error. One RequestIDFailureResponse declaration supplies
the middleware bytes and BindRequestIDFailure's per-operation500 alternatives. Existing
exact errors remain valid; broad500 descriptors are not narrowed. An existing gzip500
representation is retained alongside the JSON failure, ordered by status and media type;
binding is idempotent and does not mutate its input registry. Conflicting JSON500
descriptors still refuse binding. With an available clock, public identity failures charge the
same IP bucket and become429 at exhaustion; valid-ID authorized304s remain free even while
entropy is unavailable. A broken clock cannot truthfully classify a caller as rate-limited.
Raw HTTP mechanics retain their generic failure callback for non-API users; production API
composition supplies the typed owner response.
The drain boundary still rejects only the existing POST /api/v1/intents path,
with unchanged503 server_draining/retry_same_intent_id bytes. This request-ID
correction does not broaden admission to other mutators or implement the draft
tenant-binding contract. If private identity assignment itself fails, its existing
typed500/no-ID refusal occurs before admission. Ordinary private/public reads
remain available during drain; the request-ID regression observes no changes to
the selected persisted application rows after refused intents.
The intentional C2-compatible pin refresh adds the request-ID error and three missing500
statuses. It also captures the already-generated optional upgrade ineligible_reason and
Soul progress active/terminal union; those are not new behavior or acceptance in this batch.
The composed Postgres/HTTP error-budget check exhausts an exact fresh forwarded-IP burst
with real private/unknown run reads and invalid queries, retains authorized304 and a second
IP's404, and reads the authenticated account-owned Founder. It also exhausts the actual
unforwarded peer's public budget before creating and reading the SQL linkage for a new
Account, with credential no-store retained. That second loop accounts for earlier spent
tokens rather than claiming another fresh-burst measurement. No pre-reader work bound,
production Caddy/clean-host, supported-host log retention or whole-API acceptance follows.
Its entropy-failure supplement checks real Account/bootstrap/public responses, unchanged account/save/credential row counts, declared error bytes, the actual public failure budget, and valid-ID SQL/cache controls. These are controlled infrastructure faults, not an observed failure of deployed system entropy or a whole-release claim.
The registry mounts three unauthenticated GETs at
/api/public/v1/runs/{stream}/{seq}/{genesis,replay-log,verdict}. The stream is a canonical
Company UUID; the sequence is an exact positive integer without signs or leading zeros.
Within the shared IP budget, private/unverified, unknown and invalid run identities return exactly
404 {"category":"unknown_id","detail":"run"}; corrupt authorized evidence or operational
failures return 500 internal_invariant/public_api. Neither response exposes evidence or
carries cache/content-hash metadata.
verdict returns the exact nine-field PublicRunVerdict descriptor:
catalog_url, constants_hash, engine_version, genesis_sha256, genesis_url,
replay_log_sha256, replay_log_url, run_id, verdict. The only verdict is verified.
URLs are relative public API paths; hashes use sha256: prefixes. The catalogs URL names
the run's pinned constants, never current constants. Its HTTP reader is still unavailable.
Genesis version is present in the archive rather than an extra manifest field.
genesis serves the original stored JSON as application/json; replay-log serves the
original gzip bytes as application/gzip. Both raw registry arms require X-Content-SHA256
(unprefixed hex over served bytes). All three successful responses have strong SHA256 ETags
and public,max-age=31536000,immutable. Matching conditional reads return bodiless 304s
before charging the shared IP bucket, retaining cache/ETag and raw hash headers. Exhausted
uncached reads return non-cacheable 429 rate_limited/ip without a raw hash header.
The shared cache runtime evaluates If-None-Match using HTTP weak comparison:
strong/weak tags, comma-separated lists (including repeated field lines), optional whitespace
and a lone * match an authorized current representation. Quoted commas stay inside their
opaque tag; malformed conditions and nonmatching tags take the ordinary rate-limited path.
The entire combined field is validated, so a matching first field cannot hide a malformed
second field. Authorization/evidence validation still precedes caching: private or unknown
run requests with * return the same non-cacheable 404 while within budget, and the shared
429 when exhausted, never a 304 or evidence. See
RFC 9110 §13.1.2.
This runtime conformance repair does not declare the still-held generated-client 304 arm.
leaderboard.Repository.PublicRunEvidence supplies C14's stored bytes and pinned metadata in
one statement snapshot. Only an actual verified_runs record authorizes retrieval; a queue
verdict, run pin or archive alone does not. Invalid/unknown run identities return
ErrUnknownPublicRun without evidence. Missing or corrupt evidence for an authorized public
run returns ErrInvalidPublicRunEvidence; database errors propagate as operational errors.
The source returns the original genesis JSON bytes/version, the original gzip+json.v1 replay
archive, engine version and constants hash. Genesis must be valid UTF-8 as well as JSON;
json.Valid alone would admit corrupt string encoding. Invalid encoding is corrupt public
evidence, not normalized/repaired output. Valid Unicode, including literal U+FFFD, retains
its original bytes and digest. This source check is separate from opaque raw transport.
It verifies that genesis uses the pinned constants
hash and that archive bytes match the stored SHA256, and computes the genesis SHA256 over the
stored bytes. It does not re-encode JSON, recompress gzip, substitute current engine/constants,
or expose account/session metadata. Caller mutation does not rewrite stored evidence.
The repository's real-Postgres test uses synthetic evidence to verify retrieval and refusal,
including queue-only verification, missing bytes, corrupt hashes and cancellation. The normal
composed lane requires this test to execute. It also executes the existing composed Exit/board
witness: a real queue-verified run is downloaded over unauthenticated HTTP, every served byte
and digest is checked against immutable storage, and its Company/founder_advanced event
projection reverifies with the pinned DB catalog bundle. This matches the database verifier's
selection; the archive retains additional Founder history (including Fiscal events), which
that kernel projection does not reverify. A deliberately corrupted downloaded receipt is
rejected. Embedded genesis JSON is compared with whitespace-only compaction because the
existing archive encoder embeds the stored JSON value compactly; endpoint/storage equality
remains byte-exact.
The same witness also advances its disposable database through the real epoch writer to a distinct active constants hash, closing the run's original epoch without accepting its hash in the new one. It reloads the historical bundle from Postgres and repeats the HTTP byte/hash/cache checks and replay refusal controls. The composed lane additionally repeats generated-SDK/TypeScript replay after that rollover. This proves historical evidence retrieval under changed database epoch state; the running composition is not restarted, no deployed content is minted, and catalogs still come from the DB fixture, not public HTTP. It is not an upgrade/release-artifact or complete public catalog proof.
The root composed lane additionally requires public-replay-composed.mjs to execute while
that Go fixture's HTTP server remains alive. It loads the actual generated SDK and TypeScript
verifier with the existing Vite SSR mechanism, downloads manifest/genesis/archive without
credentials, binds engine/constants/URLs, and checks raw bytes and hashes against the Go
fixture's storage-checked evidence. The TypeScript verifier accepts the downloaded Company
projection and rejects changed receipts/events, a missing first entry and wrong constants.
Pinned catalog bytes come from the database fixture, not a public catalog endpoint or current
filesystem fallback. This is source-module SDK/HTTP/Postgres-to-TypeScript replay integration,
not a browser-mounted or release-bundled public verification UI. Ordinary Go lanes explicitly
do not run or claim this Node seam. No cross-epoch public catalog retrieval, complete
third-party download loop, whole API acceptance or release-artifact proof follows.
leaderboard.Repository.PublicCatalog now supplies the exact stored artifact set for an
epoch-accepted constants hash, including historical epochs. It reads acceptance and bytes in
one statement snapshot; a stored but unaccepted set is indistinguishable from an unknown hash
(ErrUnknownPublicCatalog). Multiple epochs accepting the same hash do not duplicate artifacts.
The internal bundle carries the constants hash and artifacts sorted by name, each with its
original bytes and sha256: digest. It recomputes the bundle identity using the existing
length-framed constants-hash authority. Missing, additional or altered bytes, invalid names,
duplicate names, invalid UTF-8 or malformed JSON fail as ErrInvalidPublicCatalog; database
and interrupted-row errors propagate without returning partial evidence. Returned buffers do
not alias the source. The reader neither consults current filesystem catalogs nor generates
formulas. A historical set lacking formulas remains exactly that set.
leaderboard.VerifyPublicCatalogBundle also verifies an already assembled internal bundle:
every advertised child digest must match its exact bytes, and the complete artifact set must
match the existing length-framed constants hash. It reuses the same source validator, returning
a detached, name-sorted snapshot or no result. It preserves surrounding whitespace and existing
last-value JSON semantics; hash-matching malformed JSON/UTF-8 still refuses. This is a consumer
construction primitive, not epoch authorization, owner semantic validation or a mounted HTTP
consumer. The current manifest's complete nineteen-source population verifies unchanged;
compacting any formatted source refuses even if its child digest is relabelled.
These are internal byte sources, not registered wire DTOs. The real-Postgres test retrieves the committed artifact set, mints a test-only newer formula-bearing set through the epoch repository, and retrieves both identities without substituting newer bytes into the older one. It also checks unaccepted sets, corrupt/missing accepted evidence and cancellation. The test mint does not modify the product manifest or authorize a release mint; it does not establish the complete public HTTP/TypeScript verification loop. The separate replay integration below now covers loading that kind of stored set.
publicread.ComposeCatalogSchemas(servedFamilies, owners) builds C12/C18's closed
PublicCatalogArtifact name-discriminated union and PublicCatalogBundle {artifacts, constants_hash}
from explicit owner definitions. The composition root must supply the complete authoritative
current/historical served-family set; the helper checks coverage of that input, not its inventory
provenance. Every owner must declare its root. Missing/extra/repeated owners, reserved or repeated
definitions (including identical redeclarations), unknown references, cycles and unsupported
schema kinds refuse with no partial result. Shared dependencies are defined once and may be
referenced across owner groups. Arms/definitions are sorted; returned trees do not alias inputs.
The actual epoch8 nineteen-family manifest with fifteen real exports produces a named coverage
error for economy, minigame_api, relevance and routes. The existing fifteen exports share
one validated namespace and accept their original current source bytes. Successful two-family
unit contexts prove constructor/generator behavior, not a completed real nineteen-family union.
Historical bundles may contain fewer artifacts than the full union; exact ordering, membership,
hash identity and owner semantics still require their existing readers/loaders.
No production registry/router/generated-wire change or catalog endpoint is added yet. A real
category-source diagnostic also proves that json.Marshal over json.RawMessage compacts the
embedded bytes: the envelope passes its exact descriptor while the received value's digest no
longer matches the claimed original-source digest (RP-597). The complete public writer/consumer
must preserve/recover original bytes; object reserialization is not third-party verification.
A second diagnostic uses the actual category loader and a duplicate-member candidate. Both the loader and C18 structural descriptor accept it; registry HTTP admission rejects it (RP-598). This is a construction conflict, not evidence of duplicate members in a deployed catalog. The artifact-byte transport amendment proposes a narrow, owner-declared lexical boundary plus exact-byte recovery. It is draft, not implemented: the current global HTTP uniqueness rule, schema language, generated SDK and endpoint set are unchanged. Neither a generic raw-JSON escape nor owner-grammar narrowing is authorized.
server/formulas owns the extracted version-14 production-formula model and exports its
closed ProductionFormulasV14 descriptor through Schemas(). The actual generator consumes
that model and validates its output before writing; the published artifact remains byte-identical.
Validate checks stored bytes without rewriting or regenerating them, rejecting unsupported
versions, undeclared/missing fields, wrong nested shapes/enums, malformed UTF-8/JSON, invalid
digests/Decimal strings and integers outside signed int64. The integer domain mirrors the
existing model, not newly chosen operating limits. This is a grammar check, not proof that
arbitrary prose is mathematically true or belongs to a particular epoch.
The descriptor covers the current formula version only, including a null axis pin and all three declared populated input variants. Historical version support must be explicit; no open-JSON arm or current regeneration fallback is introduced. This owner export is not yet registered in the catalog response union or product epoch manifest.
Both replay loaders now accept an optional stored formulas artifact, validate its version-14
grammar, and include its original bytes in the full constants identity. Go's subsequent catalog
resolution rechecks that grammar and identity, including caller mutation. Older sets without
formulas remain loadable and never gain current formulas. make formulas derives the client's
closed descriptor metadata from the Go owner; signed int64 bounds are decimal strings, and
the client preserves raw number tokens before validating them with BigInt. No JavaScript Number
rounding, formula regeneration, new command or simulation arithmetic is introduced.
The acceptance-set extension advances the mirrored replay kernel to 0.3.168; formula validator
sources and generated metadata now belong to its affecting-path guard.
Shared controls exercise required shapes, null/populated branches, malformed values, exact int64 limits/overflow, JSON last-value semantics and string formats in both runtimes. A real Postgres fixture mint loads and resolves alongside the older epoch, and its public repository bytes also load without rewriting; a hash-matching unsupported formula version refuses. These are test-only epochs, not adopted balance or proof of the HTTP/third-party verifier loop.
leaderboard.CategorySchemas() now exports the closed CategoryCatalogV1 owner descriptor.
Its five existing category arms bind each ID to its name key, timer and predicate shape;
fact-set keys and nested predicate fields are closed. Current, historical and candidate catalog
bytes validate without normalization. Unknown categories/fields, mismatched row bindings,
unsupported versions, wrong types and invalid int64 literals refuse. The descriptor does not
replace LoadCategoryCatalog: array cardinality/order, gate correspondence, fact membership
and canonical policy values remain loader checks. A grammar-valid count of 41 is still refused
by that loader's existing Phase-0 policy. No balance rule or historical bytes changed.
achievements.AchievementSchemas() additionally exports the existing v1 owner descriptor.
Its five condition arms are unrolled through the owner's depth-four limit, avoiding a recursive
schema; all three proof arms and the root/row keys are closed. The current catalog and two stored
copies validate unchanged. Copy/provenance/scope compatibility, order, cardinality and total-node
limits still belong to LoadCatalog, not the structural descriptor. The accompanying exact-key
admission correction is real kernel behavior and carries version0.3.191; no metadata-only bump,
balance change, duplicate/numeric policy rewrite or artifact mint is claimed.
meters.MeterSchemas() exports the existing v1 closed structural descriptor. Current and stored
bytes, both signed input arms, all registered contribution slots and null/active decay validate.
Loader-only order/cardinality/uniqueness/reseed relationships remain explicit. Exact-name Go
admission and the omitted TS axis_stack slot are corrected under existing contracts, carrying
the genuine kernel version0.3.192; no balance retune or metadata-only bump.
activeplay.ActivePlaySchemas() exports the v1 opportunities grammar with four closed effect
arms, declared sampler/substream literals, canonical Decimal strings and bounded positive
integers. Current/stored artifacts load with their corresponding Economy catalogs. Semantic
binding, cardinality/order, Decimal relationships and production horizon checks remain mandatory.
Actual A9 case-alias/wrong-arm-null/unsafe-duration admissions are corrected with kernel0.3.193;
no balance, scheduling, payout or buff semantics are retuned.
doctrine.DoctrineSchemas() exports the existing identity-only v1 grammar: exact root/row keys,
mechanical IDs and bounded integer source tiers. Current and stored catalogs validate with their
corresponding Routes catalogs. Boundary agreement, branching/order and cross-artifact binding
remain loader checks. Real case-alias/implicit-zero/final-null admissions are corrected with
kernel0.3.194; no doctrine effects, choices, burst arithmetic or content mint is added.
fiscal.FiscalSchemas() exports the existing v1 root/policy/row shapes with safe-integer/PPM
bounds, IDs and slot enums derived from the shared registered authority. Current/stored bytes
validate with their matching Economy catalogs; relationships, sequence horizon, nonempty/order
and declaration binding remain loader checks. Exact-name/non-null admission corrections carry
kernel0.3.195; no harvest/risk/cost/production policy or content mint changes.
soul.SoulSchemas() exports the v1 policy/band/debit/activity/ending grammar, including heartbeat
and presentation fields. Current/stored artifacts resolve against the tracked copy registry.
Partition, copy/value/catch-up/watchdog relationships, epoch-versus-fixture rules and original-byte
uniqueness remain loader checks. Null-to-zero/false admissions are corrected with kernel0.3.196;
no drain/recovery/ending policy or source mint changes.
curriculum.CurriculumSchemas() exports the current first-hour v1 grammar with three closed
branch/starter pairings. Current, epoch-8 stored and candidate data validate against matching
Economy/Routes and tracked copy declarations; order/cardinality, binding and positive Decimal
relations remain loader checks. Case-alias/default-zero/wrong-arm admissions are corrected with
kernel0.3.197. Generic Reputation starter validation and payoff literals remain unchanged.
prestige.PrestigeSchemas() exports the existing policy grammar, including a closed five-key
payout object, bounded spawn entries and the Go expiry representation bound. Current/stored bytes
and valid retunes pass; positive threshold semantics, table cardinality and Economy resource
binding remain owner/composition checks. Go exact-name/non-null admissions and the TS duration
mirror are corrected with kernel0.3.198; no payout formula, configured value or offer policy changes.
pitch.PitchSchemas() exports the current v1 card/hack/funding grammar and four closed effect
arms with the existing policy literals and safe-integer domains. Current, fixture and stored
bytes validate unchanged; cardinality/order, positive Decimal values, copy bindings, chain
partners and raw-member uniqueness remain owner checks. Kernel0.3.199 corrects Go's null-price
admission without forbidding explicit free prices or changing shop/scoring/payout mechanics.
pet.PetSchemas() exports the closed v1/v2 care-policy union, including the version-bound
presence of each action's Soul gate, owner vocabulary and existing integer/PPM domains.
Required null numeric values no longer default to zero in Go (kernel0.3.200). Current,
historical and valid-zero controls remain; policy relations, eligibility, deterministic FSM
uniqueness and Soul context still require owner/composition validation. Mutable-state codecs,
care/attendance arithmetic and content bytes are unchanged.
faction.FactionSchemas() exports the existing Phase-0 root/row/nullable-Compact grammar,
closed faction/resource sets and stock domains. Kernel0.3.201 corrects case aliases and missing
nullable fields in Go. The complete cycle, copy/Compact relationships, declared Commons tithe
band and empty modifier lists remain mandatory loader/composition checks; no incorporation,
stock, tithe or content values change.
guild.GuildSchemas() exports the current closed Phase-0 literal policy. Kernel0.3.202 fixes
Go's case aliases and absent/null bonus defaults while preserving explicit zero and complete
last-value controls. All eleven declared policy values and current/stored bytes remain unchanged;
this metadata does not widen policy admission or substitute for Guild lifecycle/clearing proof.
commons.CommonsSchemas() exports the closed root/source grammar, current non-Commons slot
registry and shared integer/PPM/Decimal domains. Kernel0.3.203 corrects Go aliases/defaults/
unsafe representations and the TS omission of axis_stack. Relations and Economy source
bindings remain mandatory; current/stored/generated bytes and formula math are unchanged.
Formula source-weight DTOs no longer transitively import Commons into production, restoring
the existing C6 dependency guard without weakening it or changing document wire bytes.
minigame.MinigameSchemas() exports the historical-v2/current-v3 policy union with ranked
scaling, payout, three fallback arms, offline-quality, rating and closed scalar unlock values.
Kernel0.3.204 repairs required-null defaults and incomplete curve/fallback rows. Existing policy
values, result nullability and payout/quality/clock mechanics remain; ordering, relations and
composition bindings still require the owner. Formula generation changes only the current
source fingerprint, not expressions or historical artifacts.
Economy's CostCurveSchemas() exports the closed K2 pricing component with original arm keys.
Kernel0.3.205 rejects aliases/wrong-arm nulls without changing price queries or data. State and
step/ratio semantics remain owner checks. This component does not yet describe the complete
Economy artifact and is not counted as a completed catalog-owner export.
economy.ResourceSchemas() adds the K1 row/cap component with the existing four scopes and
explicit nullable cap. Kernel0.3.206 fixes Go's literal-key admission without changing resource
values, cap/ledger semantics or stored bytes. Relationships remain owner checks; the complete
Economy artifact is still unexported and uncounted.
economy.GeneratorSchemas() and OperatingPolicySchemas() add version-bound generator rows,
four closed role arms and manual/offline policy components. Kernel0.3.207 fixes original-key and
wrong-arm/optional-object null admission. Current/stored rows and legacy compatibility controls
validate without rewriting bytes; relationships and version selection remain owner requirements.
These are components, not a full Economy descriptor or a registered public response arm.
Kernel0.3.208 repairs the remaining Economy version/root/row admission and the Route owner's
shared condition admission. It does not export a full Economy or Route descriptor. The draft
Artifact Schema Ownership now proposes one
Route-owned companion and reviewed kernel-neutral descriptor delivery without changing the
pure evaluator's imports. No adoption, companion, guard exception or new public arm follows
from that proposal. The existing integer/dictionary/bodiless amendments remain separate.
The catalog HTTP reader, remaining generated-client caller migration and full public TypeScript verification loop remain open. Categories, Achievements, Meters, Opportunities, Doctrines, Fiscal, Soul, Curriculum, Prestige, Pitch, Pets, Factions, Guilds, Commons and Minigames provide fifteen owner descriptors for the nineteen currently pinned artifact families; the other four and the composed C18 catalog union remain unfinished. The separately exported formula artifact needs a protocol-compliant product mint and public registration. No open JSON wire arm or current-formula fallback is introduced.
The relevance-policy owner accepts exact integral decimal/exponent JSON tokens
within its safe-integer domain, while the registry's existing SchemaInteger
validator accepts only plain integer tokens. An actual owner/descriptor readiness
probe records this mismatch (RP-566). A complete C18 relevance descriptor remains
unimplemented until the representation contract preserves those historical bytes
and admissible tokens; rejecting them merely to fit the current DSL is not a fix.
Quoted numbers are not part of that dialect and now refuse in the Go owner, matching
the client. No descriptor extension, catalog union or public route is implied.
The integer token encoding draft now specifies an
opt-in exact-safe mode while preserving default integer behavior. It is not adopted or implemented.