Skip to content

design(ai): translate the constraint, or say so — one fidelity contract for provider tool-schema projections #1684

Open
3 of 4 issues completed

Description

@dezren39

Design: Translate the constraint, or say so — one fidelity contract for provider tool-schema projections

Design doc: files/designs/opencode-schema-projection-fidelity.md in the goal workspace (keep-the-four-repos-healthy) — problem, evidence, alternatives, risks, and open questions in full. Grounded on main 618de2888fcf6e3eae88ffae3c97923a4b7e907d (files read via the GitHub API; the sandbox clone was missing at run start).

Problem

Every tool schema is written once (built-in tool, MCP server, plugin) and then translated per provider in packages/ai — and no translator has ever stated what it owes the source schema. In two days the unstated contract produced one defect per keyword:

The tell: convertSchema in antigravity.ts now carries five comment-cited special cases (#1548, #1550, #1556, #1573, #1667) accumulated in two days — each a correct local fix, none with a shared statement above it.

The contract

For every translator and every keyword, exactly one named disposition: preserved (projected schema accepts exactly what the source accepts), approximated, named (with its direction — widening or narrowing — recorded), or refused (conversion fails with a named error rather than emitting a schema that lies). Three rules over the tables: never silent (a keyword with no table row is a defect found by the corpus, not by an upstream 400); never inverted, never contradicted (#1573/#1574 are bugs in any table, not approximations); the table is the oracle (corpus tests assert the disposition table — the model of each translator's intended semantics — plus the target grammar where mechanically checkable: the 2020-12 meta-schema, the proto allowlist).

Translator inventory (verified): antigravity convertSchema; GeminiJsonSchema.normalize/cutLoops/cutDefCycles (utils/gemini-json-schema.ts); ToolSchemaProjection (utils/tool-schema.ts — moonshot, gemini, identity, objectRoot); Anthropic identity passthrough (anthropic-messages.ts:550, input_schema: tool.inputSchema verbatim); Gemini parametersJsonSchema (gemini.ts:284, after normalize). Per-translator tests exist (tool-schema-projection.test.ts, gemini-json-schema.test.ts, provider/antigravity.test.ts) but hold only their own fixes' cases — no shared corpus, no disposition stated anywhere. Dedupe: kind/design list is #587/#800/#992/#1127/#1345/#1525; the façade design #1146 owns server endpoint shapes, not packages/ai tool-schema projection — this design composes with it.

Phases

  1. Disposition tables + one fidelity corpus for the three translators — filed as a new sub-issue this run (tests + tables only, no production behaviour change; known-lossy rows for fix(ai): antigravity convertSchema drops const — a fixed-value parameter is sent upstream unconstrained #1557/fix(ai): moonshot tool-schema projection drops prefixItems when items is also present — position constraints are silently replaced #1574 marked and linked, corpus asserts the table).
  2. The two open known-lossy sites conform — adopts existing open fix(ai): antigravity convertSchema drops const — a fixed-value parameter is sent upstream unconstrained #1557 + fix(ai): moonshot tool-schema projection drops prefixItems when items is also present — position constraints are silently replaced #1574 as sub-issues; both keep their own queue lifecycles (not re-enqueued); each landing flips its corpus row.
  3. Built-in schemas meta-validated per target — adopts existing open test(ai,core): meta-validate every built-in tool schema against the draft 2020-12 meta-schema after Anthropic translation — #1550's offender is still unnamed #1668 as a sub-issue (queue/parked, work/assigned; lifecycle untouched); it is the grammar-check rule applied to the identity translator and dispositions Antigravity door: Claude leaf (claude-sonnet-5-5) 400s on workhorse attempts, Anthropic-shaped error #1550's remaining question.
  4. Not filed — inventory/disposition of every remaining schema path (bedrock, OpenAI-compatible family, gateway model-name sanitizers), a ratchet for new translators/keywords with no table row, and the refusal-semantics question (fail the request vs drop the tool vs widen deliberately; built-in vs MCP/plugin may differ). Open questions in full in the design doc.

No Drew decision is needed: the contract names existing, already-probed approximations instead of re-litigating them, and phase 1 changes no production behaviour.

🤖 Agent note · filed by repo-design-architect (opencode pass, 2026-11-04). Evidence verified singly via gh against main 618de2888f this run; the two code claims (SCHEMA_FIELDS without const; moonshotNode's prefixItems drop) were read verbatim from current main, not from the citing issues alone.

Acceptance criteria

Activity

  1. added
    priority/normalOrdinary priority (the default)
    app/aiPackage: ai (pkgs/ or apps/ in this repo)
    kind/designA design proposal (design-architect): multi-step, phased, decision-bearing
    on Nov 5, 2026
  2. added
    queue/queuedHas a queued task in the Supabase agent queue
    task/triageQueue packet kind: verify, reproduce, and route this item
    work/assignedAn agent holds this item via the queue (claimed task)
    queue/claimedA queue worker has claimed the task for this item
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 5, 2026
  3. dezren39 commented on Nov 5, 2026

    @dezren39
    Author

    🤖 Agent note · task pickup

    • Agent: repo-worker-opencode (OpenChamber scheduled lane)
    • Session / ID: queue task 10182 · lane 3fe37e8a-c61b-419c-9e97-769ecd264d5d
    • State: claimed; checking phase completion and open ownership before triage.
  4. dezren39 commented on Nov 5, 2026

    @dezren39
    Author

    Triage verdict — task 10182 (2026-11-05)

    Keep #1684 OPEN as the design/evolution tracker; do not close as duplicate or already done. Current origin/main is 8185486080ab686d3a160f16deb5357f1199fda3. The design proposal is present in the issue body (its companion design file is in the goal workspace). No PR directly owns #1684. Phase 1 is complete: child #1685 closed via PR #1723, merged 2026-11-05T11:39:47Z (merge b2dc3aa). Related phase state: #1574 and #1668 are closed; #1557 remains open. The design itself explicitly leaves phase 4 (remaining inventory/ratchet/refusal semantics) unfiled.

    Disposition / order: keep #1557 as the live phase-2 fix; do not re-enqueue completed #1685 or #1668. Keep #1684 open until #1557 is resolved and phase 4 is either split into a follow-up or explicitly deferred in this tracker. There is no competing PR or Drew-only blocker; no new task was created by this triage.

    🤖 Agent note · triaged

    • Agent: repo-worker-opencode (OpenChamber scheduled lane)
    • Session / ID: queue task 10182 · lane 3fe37e8a-c61b-419c-9e97-769ecd264d5d
    • Disposition: live tracker with remaining work; phase 1 verified complete.
  5. added
    effort/mMedium: expected under 1 day of work
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    and removed
    work/assignedAn agent holds this item via the queue (claimed task)
    queue/claimedA queue worker has claimed the task for this item
    on Nov 5, 2026
  6. dezren39 commented on Nov 5, 2026

    @dezren39
    Author

    Intake review

    🤖 Agent note · filed

    • Agent: fleet monitor
    • Session / ID: repo-fleet-monitor run 2026-11-05 12:12 CST
    • Found via: monitor reconciliation (Duty 2 intake — no acceptance criteria, not yet enriched)
    • Task: Intake enrichment: appended acceptance criteria, added status/needs-triage + effort/m, marked meta/enriched.
    • Expectation: effort/m for the design pass; "done" is the adopted contract plus contract tests, with each open defect fixed or spun out.
    • Links: design doc files/designs/opencode-schema-projection-fidelity.md (goal workspace)

    Related issues (from the body, verified as named there): #1557 (open — const dropped by antigravity), #1574 (open — prefixItems dropped by Moonshot), #1550 (open, blocked — Anthropic 400); closed defect classes #1573, #1556, #1667, #1585, #1548. Nothing merged since filing adopts the contract, so the design question is still live — not closed as solved.

    Risks: A contract written but not enforced by shared tests will drift per provider again; the acceptance criteria therefore require contract tests inherited by every projection.

    Suggested approach: Land the contract as a shared test harness first (one suite run against every provider projection), then fix #1557 and #1574 under it; #1550 stays blocked on its own track.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    app/aiPackage: ai (pkgs/ or apps/ in this repo)effort/mMedium: expected under 1 day of workkind/designA design proposal (design-architect): multi-step, phased, decision-bearingmeta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/normalOrdinary priority (the default)source/design-architectFiled by the repo design architect jobstatus/needs-triageNot yet triaged; needs a first looktask/triageQueue packet kind: verify, reproduce, and route this item

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions