Let a declaration reach into the body and count up what goes out - #39
Merged
Conversation
A helpdesk ticket update carries its comment inside the record:
{"ticket": {"comment": {"body": ..., "public": true}}}. Whether that
comment goes out to the requester is a boolean two levels down, and
params could only name arguments and top-level body properties - the
one value that separates an internal note from an outgoing mail was
the model's to write. The code such a declaration replaces kept the
two apart as differently named functions; a declaration must be able
to pin the same value structurally, not ask nicely in the instruction.
params now reads a dotted name as a path into the JSON body when no
parameter carries the name literally. A fixed leaf disappears from the
declaration and is written wherever its parent object is sent -
overwriting anything found there, never conjuring the parent up.
Published update operations also accept the whole record - status,
assignee, tags - when an agent is only meant to add a comment. Pinning
every unwanted field enumerates a list that goes stale silently as the
description grows. The new only key turns the enumeration around: it
names what the model may write, everything else leaves the declaration
and is never sent, and a new field stays unexposed until someone
declares it. The two are one mechanism seen from both sides, so their
rules hold each other: a fix cannot pin what only hands the model, a
prefix cannot wrap what only withholds, and a required argument cannot
fall between them.
🤖 Generated with Claude Code
A dot in an only entry was always read as a path into the body, while params gives a literal match the first claim. The two readings drifted apart: a parameter whose name carries a dot validated cleanly when listed, and the runtime then silently took it out of the declaration - and a dotted entry keyed exposure by its first segment, so a request parameter sharing that name rode along whole, never listed, against only's promise that everything unlisted stays unsent. Now a name some parameter carries literally stays whole on both sides, and the readings that cannot be told apart are refused like the existing two-places rule: an entry naming both a request parameter and a body property, and a body path whose first segment a request parameter also claims. 🤖 Generated with Claude Code
When everything the model wrote inside an object was unlisted, the filter kept the emptied shell and the request carried it - a write the model never made, and one the nested-fix path already refuses to conjure. Nothing surviving the filter now means nothing is sent, the same reading "no comment written means no comment sent" gives the fixes. 🤖 Generated with Claude Code
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two additions to
openapi:, designed together because they are onemechanism seen from both sides: what the declaration pins, and what the
model may write.
A dotted
paramsname reaches into the JSON bodyServices commonly nest what matters. A helpdesk ticket update carries its
comment inside the record:
{"ticket": {"comment": {"body": "...", "public": true}}}Whether that comment goes out to the requester — mail, irreversible — is a
boolean two levels down.
paramscould only name arguments and top-levelbody properties, so the one value that separates an internal note from an
outgoing reply was the model's to write, guarded by nothing but
describeand the instruction. The code such a declaration replaces kept the two
apart as differently named functions; the declaration has to be able to pin
the same value structurally.
carries the name literally — query parameters with dots in their names
exist in the wild and keep meaning what they always meant. A name both
readings can claim is refused, like the existing parameter-vs-body
ambiguity.
declared value is written wherever its parent object is sent — overwriting
anything found there (smuggled values included), never conjuring the
parent up: no comment written means no comment sent.
sending it around the fix.
validatewalks the path through$refand one level ofallOfperstep, reports certain misses with the properties that do exist at the
level that missed, and stays quiet where the schema cannot be enumerated —
the same certainty rule flat names follow.
prefix/suffixstill demanda string leaf.
onlycounts up what the model may writePublished update operations accept the whole record — status, assignee,
tags, custom fields — when an agent is only meant to add a comment. With
fixes alone one would enumerate every unwanted field, and that list goes
stale silently as the description grows.
onlyturns the enumerationaround:
when smuggled into the arguments. A
paramsvalue still rides — that ishow a hidden field is pinned.
the named subtree, and the outgoing body is filtered to it.
validateholds the two against each other: an entry cannot name what afix already pins, a
prefixcannot wrap whatonlywithholds, a nestedfix cannot sit under a parent
onlynever sends, and a required argumentmust be either listed or fixed.
The README example shows the pair composed: the model writes nothing but
the ticket id and the comment text, and the declaration keeps the comment
internal.