<?xml version="1.0" encoding="UTF-8"?>
<spec xmlns="https://vibevm.org/spec/1">
  <title id="root">TCG-PROTOCOL-GO v0.1 — the go relay's wire contract</title>
  <status stage="spec" state="done"/>
  <p p="1"><fact id="status-line" status="impl/done">**Status: v0.1 — authored with GO-AI-NATIVE-PLAN v0.1 (Phase 3),
implemented by its Phase 7.**</fact></p>
  <p p="2"><fact id="companion-document" status="impl/done">The process model is
[`TCG-ORACLE-GO-v0.1`](TCG-ORACLE-GO-v0.1.xml).</fact></p>
  <p p="3"><fact id="DOCUMENT-OWNS-THE-OUTER-HOP-GRAMMAR" status="impl/done">This document owns the
OUTER hop's message grammar — host (vibe-tcg / one-shot CLI) ⇄
`go-ai-native-tcg serve` — and the mapping of each operation onto the
INNER hop, which is not a bespoke protocol but LSP 3.17 spoken to the
consumer's gopls.</fact></p>
  <section id="parity" title="1. Wire parity with the TS and Rust protocols">
    <p p="4"><fact id="kind-line-parity" status="impl/done">`req r1`</fact></p>
    <p p="5"><fact id="wire-parity-lead" status="impl/done">The outer hop is WIRE-PARITY with TCG-PROTOCOL v0.1 §1 (TS) and
TCG-PROTOCOL-RUST v0.1 §1:</fact></p>
    <list ordered="false" p="6">
      <item><fact id="PARITY-NDJSON-DUPLEX" status="impl/done">NDJSON duplex, one JSON object per line,</fact></item>
      <item><fact id="PARITY-FRAME-SHAPES" status="impl/done">`{proto, id, op, params}` requests and `{proto, id, ok, result |
  error}` responses,</fact></item>
      <item><fact id="PARITY-CALLER-CHOSEN-IDS" status="impl/done">caller-chosen correlation ids,</fact></item>
      <item><fact id="PARITY-ORACLE-PROTOCOL-CONSTANT" status="impl/done">`ORACLE_PROTOCOL = 1`
  on every frame,</fact></item>
      <item><fact id="PARITY-ADDITIVE-ONLY-EVOLUTION" status="impl/done">additive-only evolution within a proto (new optional
  params, new response fields — non-breaking; renames/semantic changes
  bump the constant).</fact></item>
    </list>
    <p p="7"><fact id="ONE-PRODUCT-CLIENT-DRIVES-ALL-THREE-RELAYS" status="impl/plan">One language-generic product client (`vibe-tcg`'s
`OracleRegistry` link) drives all three relays with the same frames;
the parity is pinned per-package by outer-frame replay goldens.
*Specified, not built (→ B-046) — the client named is gone by the owner's
own MCP-SOVEREIGNTY resolution (2026-07-07), and on the Go side neither
pinning mechanism exists. The `vibe-tcg` registry crate was retired with
the whole multiplexed-product topology and DELETED (PROP-026 in
vibe-mcp, `##TOPOLOGY-RETIRED` and `##TCG-CRATE-DELETED`);
`OracleRegistry` appears in no source file of any language. There is no
Go `live_chain.rs` (`go-ai-native-mcp`'s tests carry `server_replay.rs`
only) and no outer-frame golden (`##REPLAY-GOLDENS-PIN-BOTH-HOPS`). The
surviving posture is one layer up — `pub struct TcgSession`
(`go-ai-native-mcp/crates/go-ai-native-mcp/src/tools_tcg.rs:32`) — and
the planned successor to the one-client story is the multi-language
composition layer over the sovereign servers (`BACKLOG.md` B-046:
autodiscovery, autonomy preserved).*</fact></p>
    <p p="8"><fact id="RESTATES-RATHER-THAN-INCLUDES-THE-SIBLING-TEXTS" status="impl/done">This
document restates rather than includes the sibling texts
(cross-package spec inclusion is not a mechanism we have); every
DELIBERATE delta from the shared shape is listed in §3–§4, and
anything not listed there is parity by definition — drift outside that
list is a bug.</fact></p>
  </section>
  <section id="ops" title="2. Operations">
    <p p="9"><fact id="kind-line-ops" status="impl/done">`req r1`</fact></p>
    <p p="10"><fact id="POSITIONS-ARE-ONE-BASED-LINE-ZERO-BASED-CHARACTER" status="impl/done">Positions are `{line, character}`, 1-based line, 0-based character —
UNCHANGED from the shared shape for parity; the bridge converts to
LSP's 0-based lines and, when utf-8 encoding was not granted, to
UTF-16 code units through the line's text.</fact></p>
    <p p="11"><fact id="PATHS-ARE-ROOT-RELATIVE-WITH-FORWARD-SLASHES" status="impl/done">Paths are
project-root-relative with forward slashes.</fact></p>
    <list ordered="false" p="12">
      <item><fact id="OP-INIT" status="impl/done">**`init`** `{}` → `{gopls_version, position_encoding,
  pull_diagnostics, ready}` — resolves and spawns gopls (ORACLE-GO §1),
  negotiates capabilities (§2), applies §3 config, waits for readiness
  bounded by a deadline. Re-`init` on a live session restarts the
  child; overlays are cleared. The relay self-inits at `serve` start,
  so a host's first frame may be any op. The relay serves ONE project,
  so `init` takes no parameters — the root is `serve`'s own process
  root.</fact></item>
      <item><fact id="OP-UPDATE" status="impl/done">**`update`** `{file, content | null}` → `{version}` — set/replace an
  overlay (`didOpen`/`didChange`, monotonic version) or clear it
  (`didClose`).</fact></item>
      <item><fact id="OP-VALIDATE" status="impl/done">**`validate`** `{file, content?}` → `{diagnostics: [{code, category,
  message, line, character}], facts: [/* serde `Fact` records */],
  markers: [{tag, uri, reason, symbol, line}], conform_findings:
  [{rule, message, line, baselined}], advice: [string], degraded}` —
  diagnostics for the ONE document per ORACLE-GO §2; facts and markers
  from the go-extract fact vocabulary over the effective text
  (`item`, `import`, `go_unsafe`, `file_metrics`; markers are the
  `//spec:` directive stream — Go fills the field the Rust relay
  reserves empty, because the extractor already emits them);
  `conform_findings`/`advice` per §3.</fact></item>
      <item><fact id="OP-SCOPE" status="impl/done">**`scope`** `{file, position?}` → `{symbols: [{name, kind,
  type_text}], cell, seam_file, branded: [{name, seam, heuristic}]}` —
  symbols via a completion sweep at the position (or a neutral
  top-level position); `cell` is the package path relative to the
  policy's `cells_dir`; `seam_file` is the seams package's directory;
  `branded` carries the GO brand analog — exported DEFINED TYPES over
  primitives declared in seam files (`type AccountID string`),
  go-extract-detected, every entry `heuristic: true`.</fact></item>
      <item><fact id="OP-COMPLETE" status="impl/done">**`complete`** `{file, position, content?, prefix?, max?}` →
  `{entries: [{name, kind, type_text, unsafe}]}` — LSP completion;
  `prefix` filters and `max` caps (default 50) BEFORE per-entry detail
  work; `unsafe: true` flags entries that would land a §7-banned form
  in domain code (v0.1: ambient-default identifiers — `os.Getenv`,
  `time.Now`, `http.DefaultClient`-class — offered inside a cell file;
  name-based heuristic, honestly labelled in the brief).</fact></item>
      <item><fact id="OP-TYPE" status="impl/done">**`type`** `{file, position, content?}` → `{display,
  documentation}` — LSP hover, markdown stripped to text.</fact></item>
      <item><fact id="OP-SHUTDOWN" status="impl/done">**`shutdown`** `{}` → `{}` then exit 0 (the LSP shutdown/exit dance
  toward the child, kill-on-drop as backstop).</fact></item>
    </list>
  </section>
  <section id="enrichment" title="3. The enrichment fields (in-process, same engine as the gate)">
    <p p="13"><fact id="kind-line-enrichment" status="impl/done">`req r1`</fact></p>
    <p p="14"><fact id="SERVE-ASSEMBLES-THE-GATES-OWN-RULE-SET" status="impl/done">`go-ai-native-tcg serve` reads the project's `conform.toml` once per
init (config-or-default, origin printed to stderr) and assembles THE
GATE'S OWN rule set through the `go_ai_native_conform::build_rules`
pub seam.</fact></p>
    <p p="15"><fact id="VALIDATE-ENRICHMENT-PIPELINE" status="impl/done">On `validate`: the effective text → the go-extract sidecar
(`facts` + `markers`) → `conform_core::check` → `conform_findings`,
each flagged `baselined` against the project's frozen ratchet
baseline, plus `advice` strings in Class-F form citing GUIDE REQs
(an `init()` or ambient call in a cell → §2 + the capability-injection
recipe; a missing Example on a new exported seam item → §4 Class G; a
seam error type without a REQ-citing message → §5; a file over the
length budget → §3).</fact></p>
    <p p="16"><fact id="FINDING-PARITY-TEST-CATCHES-DRIFT" status="impl/done">The package/cell strings for the single file are
computed by a relay-local mapping mirroring the engine's, and a
finding-parity test diffs the relay's finding set against
`go-ai-native-conform check` on the same demo file — drift is a red
test, not a silent lie.</fact></p>
    <p p="17"><fact id="ENRICHMENT-FIELDS-EXIST-ONLY-ON-THIS-HOP" status="impl/done">A consumer that talks to gopls directly gets
LSP; the enrichment fields exist only on this hop, and their absence
means "no policy layer", not an error.</fact></p>
  </section>
  <section id="errors" title="4. Error taxonomy">
    <p p="18"><fact id="kind-line-error-taxonomy" status="impl/done">`req r1`</fact></p>
    <p p="19"><fact id="five-error-kinds-lead" status="impl/done">Five kinds, each actionable, mirrored as typed variants in
`go-ai-native-tcg-bridge`; the two environment rows are the DELIBERATE
renames against the shared table (§1):</fact></p>
    <table p="20">
      <tr>
        <td>kind</td>
        <td>meaning</td>
        <td>recipe carried</td>
      </tr>
      <tr>
        <td><fact id="ROW-ERROR-GOPLS-MISSING" status="impl/done">`gopls-missing`</fact></td>
        <td><fact id="ROW-ERROR-GOPLS-MISSING-MEANING" status="impl/done">no gopls resolvable (ORACLE-GO §1)</fact></td>
        <td><fact id="ROW-ERROR-GOPLS-MISSING-RECIPE-CARRIED" status="impl/done">`go install golang.org/x/tools/gopls@latest`</fact></td>
      </tr>
      <tr>
        <td><fact id="ROW-ERROR-WORKSPACE-UNLOADABLE" status="impl/done">`workspace-unloadable`</fact></td>
        <td><fact id="ROW-ERROR-WORKSPACE-UNLOADABLE-MEANING" status="impl/done">the project failed to load (no go.mod, `go env` failed)</fact></td>
        <td><fact id="ROW-ERROR-WORKSPACE-UNLOADABLE-RECIPE-CARRIED" status="impl/done">check `go env` / `go list ./...` standalone</fact></td>
      </tr>
      <tr>
        <td><fact id="ROW-ERROR-ORACLE-CRASHED" status="impl/done">`oracle-crashed`</fact></td>
        <td><fact id="ROW-ERROR-ORACLE-CRASHED-MEANING" status="impl/done">child died / stream closed mid-session</fact></td>
        <td><fact id="ROW-ERROR-ORACLE-CRASHED-RECIPE-CARRIED" status="impl/done">respawn guidance; the host registry retries once</fact></td>
      </tr>
      <tr>
        <td><fact id="ROW-ERROR-PROTOCOL" status="impl/done">`protocol`</fact></td>
        <td><fact id="ROW-ERROR-PROTOCOL-MEANING" status="impl/done">unparseable frame, proto mismatch, unknown op</fact></td>
        <td><fact id="ROW-ERROR-PROTOCOL-RECIPE-CARRIED" status="impl/done">version note; unknown-op errors list the known ops</fact></td>
      </tr>
      <tr>
        <td><fact id="ROW-ERROR-TIMEOUT" status="impl/done">`timeout`</fact></td>
        <td><fact id="ROW-ERROR-TIMEOUT-MEANING" status="impl/done">no response within the caller's budget</fact></td>
        <td><fact id="ROW-ERROR-TIMEOUT-RECIPE-CARRIED" status="impl/done">the op and the budget, for tuning</fact></td>
      </tr>
    </table>
    <p p="21"><fact id="RENAMES-RIDE-WITHOUT-A-PRODUCT-EDIT" status="impl/done">The product's link layer special-cases only `oracle-crashed`
(session-grain) and passes every other kind through as a
recipe-carrying detail — the same contract the TS and Rust relays
proved, so the renames ride WITHOUT a product edit.</fact></p>
  </section>
  <section id="compat" title="5. Compatibility rules">
    <p p="22"><fact id="kind-line-compat" status="impl/done">`req r1`</fact></p>
    <p p="23"><fact id="identical-to-the-sibling-protocols-lead" status="impl/done">Identical to the sibling protocols' §5, restated:</fact></p>
    <list ordered="false" p="24">
      <item><fact id="COMPAT-ADDITIVE-EVOLUTION" status="impl/done">additive evolution
  within a `proto` (optional params, new response fields, new
  advice/finding entries — consumers ignore the unknown);</fact></item>
      <item><fact id="COMPAT-BREAKING-CHANGES-BUMP-THE-CONSTANT" status="impl/done">renames, type
  changes, and semantic changes bump `ORACLE_PROTOCOL` and the bridge
  treats the mismatch as its own error class.</fact></item>
    </list>
    <p p="25"><fact id="REPLAY-GOLDENS-PIN-BOTH-HOPS" status="spec/done">Replay goldens pin the
CURRENT outer shape in this package's tests; recorded LSP transcripts
pin the inner hop the same way (both gopls-free in the unit suite).
*Specified, not built — the outer half. The inner hop is real and
gopls-free (`crates/go-ai-native-tcg-bridge/src/client/tests.rs`,
`Script`); the outer hop — `host ⇄ go-ai-native-tcg serve`, the grammar
this document owns (`##DOCUMENT-OWNS-THE-OUTER-HOP-GRAMMAR`) — is pinned
by nothing: `run_serve` (`serve.rs:227`) is called from `main.rs` alone,
no test constructs a `{proto, id, op, params}` frame, and no recorded
stream is checked in.*</fact></p>
    <p p="26"><fact id="MARKERS-FIELD-IS-FILLED-HERE" status="impl/done">The `markers` field is FILLED here (unlike the Rust relay's reserved
empty array) — that is a per-language capability difference inside the
shared shape, not a protocol fork.</fact></p>
  </section>
</spec>
