Skip to content

RFC-016 — Product-owned historical verifier kits ​

Status: implemented · Target: v0.25 · Compatibility: additive verifier reference, packaging, resolution, cache, and restricted-runner contracts · Depends on: RFC-014, RFC-015

1 — Problem and ownership ​

gaos.replay identifies the historical reducer and semantic adapter needed to recheck a run, but earlier releases require the verifier to obtain that code from a local module or product-supplied registry. RFC-016 makes preservation explicit without moving product rules into GAOS.

The product owns its reducer, game rules, content interpretation, command and timeout mappings, publication choice, mirrors, retention policy, and accepted kit digests. GAOS owns the export shape, canonical manifest and archive, digest, inspection, cache, resolver facts, restricted-runner protocol, and conformance tests.

GAOS never infers, synthesizes, uploads, or publishes a reducer. Packing and fetching require explicit inputs. If required product code is unavailable, a well-formed replay remains unverifiable; absence is not silently converted into failure or trust.

2 — Product export contract ​

A product bundles the same historical functions used by the local verifier:

ts
interface HistoricalVerifierModule<TLevel = unknown> {
  resolveReplayReducer(context: ReplayLevelContext<TLevel>): TickReducer<
    TLevel,
    unknown
  >;
  semanticAdapterForLevel?(
    context: ReplayLevelContext<TLevel>,
  ): ReplaySemanticAdapter<TLevel>;
}

The explicit adapter.bundle.mjs input is product-owned and self-contained. It must not select mutable package tags, fetch code during verification, or read product credentials. A rule or semantic-mapping change that can alter re-simulation requires a new kit digest.

3 — Canonical verifier-kit format ​

The unpacked logical shape is:

text
product.gaos-verifier/
├── verifier-manifest.json
├── adapter.bundle.mjs
├── fixtures/
├── sbom.spdx.json
├── LICENSES/
└── README.md

gaos.verifier-kit.v1 uses this manifest:

ts
interface VerifierKitManifestV1 {
  schema: 'gaos.verifier-kit.v1';
  game: { id: string; version: string };
  adapter: {
    id: string;
    version: string;
    entrypoint: 'adapter.bundle.mjs';
  };
  runtime: {
    kind: 'node-esm';
    gaosVersion: string;
    nodeRange: string;
  };
  replayFormats: string[];
  files: Array<{
    path: string;
    size: number;
    digest: `sha256:${string}`;
  }>;
}

The SDK writes uncompressed canonical ustar bytes with lexically ordered regular-file entries, fixed timestamps, ownership, permissions, and two terminal zero blocks. Paths are normalized, relative, unique, and limited to the v1 100-byte name field. verifier-manifest.json is generated by the packer and omitted from its self-referential files list.

The kit identity is the SHA-256 digest of the complete packed bytes. Per-file digests support inspection; the whole-kit digest is used by replays, manifests, allowlists, catalogs, and caches. Mutable URLs and tags are locators only.

4 — Replay reference ​

Existing adapter id/version fields remain unchanged. A replay may carry this optional namespaced header extension without changing gaos.replay v1.3:

json
{
  "gaos.verifier": {
    "schema": "gaos.verifier-reference.v1",
    "digest": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
    "mediaType": "application/vnd.gaos.verifier-kit.v1+tar",
    "size": 184320,
    "mirrors": [
      "https://example.invalid/releases/demo.gaos-verifier"
    ]
  }
}

The digest identifies bytes. Mirrors are untrusted retrieval hints and may change without changing kit identity. Every retrieval and cache read is checked against the expected digest. A replay cannot authorize the verifier that judges the same replay.

5 — Independent authorization and result facts ​

Authorization must be independent of the submitted replay or benchmark bundle. Products may use an independently obtained benchmark manifest, signed catalog, verifier-owned allowlist, or RFC-014 external authority.

The resolver exposes separate facts:

ts
interface VerifierKitResolution {
  reference: 'absent' | 'present';
  retrieval: 'not_attempted' | 'cached' | 'fetched' | 'unavailable';
  integrity: 'unchecked' | 'matched' | 'mismatched';
  authorization: 'unknown' | 'accepted' | 'rejected';
  execution: 'not_run' | 'passed' | 'failed' | 'restricted';
  digest?: string;
  source?: string;
  diagnostics: string[];
}

A digest match proves byte integrity, not correctness or approval. Authorization binds those bytes to product policy. Re-simulation establishes whether the approved implementation reproduces the run. These facts must not be collapsed into one universal badge.

6 — Resolution and cache ​

The explicit local workflow remains unchanged and never performs network access:

sh
gaos verify run.gaos-replay.jsonl --adapter ./adapter.mjs

Verifier-kit operations are explicit:

sh
gaos verifier pack ./adapter.bundle.mjs \
  --game creator/demo@1.0.0 \
  --output creator-demo.gaos-verifier
gaos verifier inspect creator-demo.gaos-verifier
gaos verifier fetch https://example.invalid/demo.gaos-verifier \
  --digest sha256:... \
  --cache .gaos-verifiers

pack accepts the product entry point and writes new output without overwriting an existing file. inspect validates structure and integrity without extracting or executing code. fetch accepts HTTPS, rejects redirects, validates bytes before atomically admitting them to a digest-keyed cache, and never treats a locator as identity. The library resolver supports product-supplied retrieval callbacks for HTTPS, OCI, object storage, or other explicit policies. A cached kit remains usable offline.

Before extraction or execution, inspection rejects malformed tar data, noncanonical metadata, traversal, duplicate or unordered paths, non-regular entries including links, undeclared files, size mismatch, digest mismatch, excess files, and excess total bytes.

7 — Restricted execution ​

Fetched verifier code is untrusted executable code even when integrity and authorization succeed. GAOS never imports automatically resolved adapter code inside the verifier process.

Automatic execution uses the versioned RestrictedVerifierRunner JSON request/response boundary. If no approved runner is supplied, execution is restricted and the result remains unverifiable.

The reference ContainerVerifierRunner requires an immutable image@sha256:... reference and invokes Docker or Podman with:

  • no network;
  • no inherited host environment or credentials;
  • a numeric non-root uid/gid, with all Linux capabilities dropped and no-new-privileges enabled;
  • a read-only root filesystem;
  • read-only kit and replay mounts;
  • an isolated bounded temporary filesystem;
  • explicit CPU, memory, wall-time, process, and output limits; and
  • no fallback to in-process import.

The runner image is verifier-operator policy. GAOS does not operate an image registry or make a mutable image tag trusted.

8 — Benchmark bundles and catalogs ​

A .gaos-bench bundle may carry a kit copy for offline convenience. The copy is evidence content, not its own authority. An independently supplied manifest must pin the digest before adoption.

A signed product catalog may map game id/version plus adapter id/version to a kit digest and mirrors. Catalog identity, time, transparency, rotation, and revocation use RFC-014 external-trust interfaces. GAOS validates supplied facts but does not operate the authority or hold its keys.

Replay consistency, signatures, kit integrity, authorization, availability, source availability, and score policy remain separate facts.

9 — TypeScript and Python parity ​

TypeScript exports packing, strict inspection, reference parsing, resolution, cache, safe extraction, and restricted-runner contracts. Python exports manifest/reference parsing, replay-reference discovery, and read-only archive inspection. Restricted execution remains a TypeScript CLI/operator responsibility in v0.25.

The package exports JSON Schemas for both v1 formats:

  • schemas/gaos.verifier-kit-v1.schema.json
  • schemas/gaos.verifier-reference-v1.schema.json

10 — Release gate ​

The v0.25 tests establish:

  1. identical inputs produce identical bytes and digest;
  2. changed adapter or manifest inputs change identity;
  3. malformed, corrupted, traversing, and linked entries fail before extraction;
  4. mirror substitution and corrupted cache bytes fail integrity;
  5. replay-carried references remain unauthorized without an independent pin;
  6. pinned kits resolve online and from an offline cache;
  7. unavailable kits remain unverifiable;
  8. the reference invocation is networkless, read-only, environment-clean, and resource-bounded;
  9. local adapter verification remains unchanged; and
  10. TypeScript and Python share the manifest and reference interpretation.

11 — Compatibility ​

RFC-016 is additive. gaos.replay v1.0–v1.3 retain their interpretation, existing registry callbacks and local adapters remain supported, artifacts without a verifier reference remain valid, and products may continue manual distribution. No package, repository, Python import, CLI, protocol, schema, signature, or existing adapter identifier is renamed.

12 — Out of scope ​

RFC-016 does not require publication of proprietary code, transfer ownership of product rules, prove scientific validity, trust embedded keys or self-declarations, guarantee availability without archive policy, operate a registry or authority, equate executable bytes with source availability, or prove model identity, wall-clock fairness, secrecy, or publication completeness.

The product owns what the game means. GAOS standardizes how an explicitly exported historical implementation can be preserved and checked.

Game-as-a-Benchmark: one product reducer for human play, agent evaluation, and verifiable exact runs.