Skip to content

contract: generate every derived surface — typed stdio client, CLI from one spec table, tool-reference docs, miner dedup, UI z.infer types #9521

Description

@JSONbored

Context

Part of #9515 — the "nothing hand-maintained" payoff issue. With the contract registry (#9517/#9518) and the route seam (#9519) in place, every remaining hand-kept surface becomes generatable. Today's inventory of hand-maintained duplicates:

  • Stdio API client: apiGet/apiPost/apiDelete (packages/loopover-mcp/bin/loopover-mcp.ts:6950-7002) return payload: any; ~50 endpoints consumed via optional-chaining guesswork (payload.pendingActions ?? [], result.predictedGate, …). A Worker response rename fails silently at runtime.
  • Four independent CLI command lists: CLI_COMMAND_SPEC (:112-146), the 34-branch runCli if-chain (:4169-4207), printHelp (:5393-5447), and the README's 47-line command block (packages/loopover-mcp/README.md:29-76) — only fragments are pin-tested; printHelp already omits commands.
  • CLI flag parsers re-implementing zod shapes: branchEligibilityFromOptions (:7337-7348), validationFromOptions/parseValidationEntry (:6351-6368), parseOptions' hand-listed repeatable/boolean sets (:5483+).
  • No tool-reference doc anywhere: the README dodges it ("run loopover-mcp tools"), 32 tool names are hand-typed across apps/loopover-ui/content/docs/*.mdx with zero drift check, and scripts/check-docs-drift.ts + scripts/gen-command-reference.ts have no MCP coverage at all. The miner README's tool table (packages/loopover-miner/README.md:239-286) and 18-row storage table (:112-131) are hand-kept prose (name-level parity test only).
  • Miner hand-copies: lib/github-token-resolution.ts re-implements the stdio MCP's config/profile/apiUrl/session resolution by hand (self-declared, :6-11); lib/tenant-credential-resolution.ts:2-3 duplicates src/orb/broker-client.ts.
  • UI: ui: derive API response types from the backend's real zod/OpenAPI schemas, stop hand-duplicating them #9282 (accepted decision: share zod schemas, z.infer on the UI side) — its pilot (PublicStats/PublicRulePrecision) plus the drift check belong to this group.
  • Telemetry property allowlist duplicated three ways (packages/loopover-mcp/lib/telemetry.ts:61-66, src/mcp/telemetry.ts, README prose :296-301).

The repo already owns the two mechanisms needed — the env-reference generators (gen-selfhost-env-reference.ts, packages/loopover-miner/scripts/generate-env-reference.mjs: one row set → markdown doc + typed UI module, with --check) and gen-command-reference.ts ("a hand-copy is exactly how the 9-command queue-digest family went completely undocumented"). This issue points those patterns at MCP.

Requirements

  1. Typed, validated stdio API client. Replace ad-hoc apiFetch call sites with a thin generated/derived client whose per-endpoint response types are z.infer of the contract route schemas (api: one route-registration seam — runtime zod validation + spec emission, with a route↔spec ratchet to zero unspecced routes #9519), and which safeParses responses at the boundary (schema-failure → the tool's error envelope naming the endpoint + first issue path; behind the same validation posture recorded in api: one route-registration seam — runtime zod validation + spec emission, with a route↔spec ratchet to zero unspecced routes #9519). Zero payload: any remains — enforce with a lint/grep gate in CI.
  2. One CLI source of truth. CLI_COMMAND_SPEC becomes the single typed table (command, subcommands, flags with types/repeatable/boolean, summary); runCli dispatch, printHelp, shell completion, and flag parsing (including repeatable/boolean sets and enum coercion via the contract enums) all derive from it. The regex-scraping test (test/unit/mcp-cli-completion-spec.test.ts reading the built bundle) is replaced by direct import assertions.
  3. Generated MCP reference docs. A generator (extend gen-command-reference.ts's pattern) emits from the contract registry: (a) the README tool tables for packages/loopover-mcp and packages/loopover-miner between markers, (b) a typed apps/loopover-ui/src/lib/mcp-tool-reference.ts module for the docs site, (c) the CLI command block in the stdio README. Each with --check wired into test:ci; check-docs-drift.ts gains an MCP surface asserting every tool name mentioned in apps/loopover-ui/content/docs/** exists in the registry.
  4. Miner dedup: github-token-resolution.ts imports the config/profile/session resolution from one shared home (@loopover/contract runtime helpers or an engine module both bins already depend on — record the choice in the PR); tenant-credential-resolution.ts imports the broker-client logic instead of duplicating it. The hand-sync header comments are deleted because the hand-sync is gone.
  5. UI derived types (ui: derive API response types from the backend's real zod/OpenAPI schemas, stop hand-duplicating them #9282 execution): land the recorded option 1 — pilot PublicStats/PublicRulePrecision via z.infer from the shared schemas, plus the drift check preventing hand-typed API interfaces from reappearing under apps/loopover-ui/src/components/site/*; migrate remaining hand-typed API interfaces opportunistically per that issue's own scoping.
  6. Telemetry allowlist single-sourced from one exported constant consumed by both telemetry modules and the generated README section.
  7. Stale sample output in the stdio README (3.0.0 at :51/:61) becomes generated or version-agnostic. Full coverage per house bar; fix-what-you-find applies.

Non-goals

  • New tools/commands; observability behavior changes (that's the observability sub-issue — this one only single-sources the property list).
  • Publishing a public standalone SDK package (can be a later follow-up once the typed client exists).

Deliverables

Expected outcome

Every tool table, command list, help block, client type, and doc reference is generated from the contract registry or route schemas with a drift gate; a renamed response field or tool is a CI failure everywhere it matters, not a silent runtime surprise.

References

Part of #9515. Blocked by #9517 (needs the registry) and #9519 (route schemas for the client); #9282 is executed by this issue and should be cross-linked on completion.

Metadata

Metadata

Assignees

Labels

maintainer-onlyOwner-only work — yields no Gittensor points.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions