Skip to content

Prune the description to the declared operations at packing time - #40

Merged
haruotsu merged 3 commits into
mainfrom
openapi-archive-prune
Aug 27, 2026
Merged

Prune the description to the declared operations at packing time#40
haruotsu merged 3 commits into
mainfrom
openapi-archive-prune

Conversation

@haruotsu

Copy link
Copy Markdown
Collaborator

gete archive now prunes the OpenAPI description to the declared
operations, and validate reports a path template placeholder no path
parameter declares.

Why gete does the cutting

A published description holds far more than an agent declares, and
operations being required already keeps the runtime honest — the model is
offered only what was declared however much the file holds. The tempting
next step is to keep a hand-trimmed copy of the description in the repo,
and that step breaks quietly, in at least two ways:

  1. flattening a $ref drops the parameters it carried;
  2. dropping a path item's own parameters entry drops the same parameters
    another way — OpenAPI lets path-level parameters live outside the
    operation, and by reference at that.

Both mistakes validate cleanly: the operations are still there, they just
can no longer say which record they address. Nothing notices until someone
counts the arguments on the deployed tools. If pruning is worth doing, the
only safe place is where read_operations already knows what a path item
contributes and where every reference leads.

What archive packs now

  • The declared operations ride with their whole path item — path-level
    parameters included — so nothing an operation inherits is lost.
  • Every node the kept parts reference is grafted at its original JSON
    pointer, transitively
    , so $ref keeps resolving; unreferenced
    components stay behind. A pointer into paths is deliberately not
    grafted — it would re-select what pruning just left out.
  • The published servers stay behind too; nothing ever reads them
    (request URLs come from the connection's base_url).
  • A file two blocks share (a read block and a write block, typically)
    keeps the union of their operations.
  • The bytes are deterministic, as everything in an archive must be —
    Terraform decides deployment by the archive hash.
  • The vendor's original stays untouched in the repo; validate keeps
    running against it. Only what travels — and what a cold start reads —
    shrinks.

The validate rule

For descriptions gete did not produce (hand-written or hand-trimmed),
validate now reports the resulting shape early and by name:

operations: 'ShowTicket' has {ticket_id} in its path, and no path parameter declares it

A runtime-equivalence test holds the two paths together: the tools built
from a pruned description carry declarations identical to those built from
the whole one.

Published descriptions are big - hundreds of paths, components for all
of them - and an agent declares a handful of operations. The size alone
is not the problem: operations is required, so the runtime offers only
what was declared however much the file holds. The problem is what
people do about the size. Cutting a description down by hand breaks
quietly, twice over: flattening a $ref takes the arguments it carried,
and dropping a path item's own parameters entry takes the same
arguments another way. Both mistakes validate cleanly - the operations
are still there, they just cannot say which record they address - and
nothing notices until someone counts the arguments on the deployed
tools. If pruning is worth doing, the only place it is safe is where
read_operations already knows what a path item contributes and where
every reference leads.

gete archive now packs a pruned description: the declared operations
with their whole path items - path-level parameters included - and
every node they reference, grafted transitively at its original
pointer. The vendor's original stays untouched in the repo; the
runtime and a cold start read only what the agent declared. A file two
blocks share keeps the union of their choices, and the bytes stay
deterministic, as everything in an archive must.

validate separately learned to report a {placeholder} in a path
template that no path parameter declares - the exact shape a hand-cut
description ends up in, said early and by name, for descriptions gete
did not produce.

🤖 Generated with Claude Code
validate reads the repo's file; the runtime reads the archive. Between
the two sits pruning, and one thing pruning deliberately breaks: a
reference into another path's subtree resolves in the repo and dangles
once that path is left out. Such a declaration packed cleanly and then
failed at the deployed agent's cold start, when the runtime held it
against the pruned description.

The packing now runs the same check against the pruned document, so
the miss is refused before anything deploys.

🤖 Generated with Claude Code
🤖 Generated with Claude Code
@haruotsu
haruotsu merged commit d3256c1 into main Aug 27, 2026
3 checks passed
@haruotsu
haruotsu deleted the openapi-archive-prune branch August 27, 2026 14:56
@github-actions github-actions Bot mentioned this pull request Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant