docs(skills): the formula catalogue is the bare-callable public subset, not everything that resolves - #15519
Merged
Conversation
…bare-callable public subset
`skills/objectstack-formula/SKILL.md` claimed "Only the functions above are
callable" and called `CEL_STDLIB_FUNCTIONS` "the canonical list". Both read as a
complete registry of what resolves. Measurement says otherwise: receiver-only
methods (`s.split(',')`, `list.map(...)`) resolve when called on a value, and
four bare primitives (`bytes`, `dyn`, `type`, `uint`) resolve but are withheld
from the catalogue by an authoring decision.
The correction states the membership rule the engine's own docblock already
carries as load-bearing (`packages/formula/src/validate.ts`), and keeps the
sentence that was true and useful: an unknown name still fails `os build` with a
no-matching-overload type error.
The engine is untouched — no edit to `CEL_STDLIB_FUNCTIONS` or
`packages/formula/**`, and the four withheld primitives are named as withheld,
never added to any list the skill presents as callable.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox
This was referenced Sep 4, 2026
os-zhuang
approved these changes
Sep 5, 2026
os-zhuang
marked this pull request as ready for review
September 5, 2026 01:29
os-zhuang
enabled auto-merge
September 5, 2026 01:29
os-zhuang
deleted the
claude/issue-13933-formula-skill-callable-wording
branch
September 5, 2026 02:14
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.
Fixes #13933
Ruling item 3 only. Items 1, 2 and 4 are already true on
main— the membership rule is load-bearing inpackages/formula/src/validate.ts, the drift pinpackages/formula/src/cel-stdlib-drift.test.tsexists, and the oracle carve-out sits in the same docblock. This PR is the skills half, and nothing else.What was wrong
The published formula skill told an author that the catalogue is everything that resolves. It is not, and the engine's own docblock has said so since the drift pin landed:
CEL_STDLIB_FUNCTIONSis the bare-callable public subset — the names an author may write asfn(x). Receiver-only methods (s.split(','),list.map(...)) resolve when called on a value, and four bare primitives (bytes,dyn,type,uint) resolve but are withheld from the catalogue by an authoring decision.The claim was false in the safe direction — it under-promises, so no author was ever broken by it. Corrected anyway, in the skill's own voice, keeping the sentence that was true and useful: an unknown name still fails
os buildwith a no-matching-overload type error.⛔ No edit to
packages/formula/**, toCEL_STDLIB_FUNCTIONS, or to any other skill. The four withheld names are named as withheld, never added to any list the skill presents as callable.Every occurrence fixed — both in
skills/objectstack-formula/SKILL.md, none left behindCEL_STDLIB_FUNCTIONSis the canonical list, pinned by two tests: every entry resolves at runtime, and this table documents them all.CEL_STDLIB_FUNCTIONSis the advertised bare-callable subset, pinned by two tests: every entry resolves at runtime, and this table documents them all.PRIOR(), a legacyISBLANK(), a typo'disBlnk()— failsos buildwith a "no matching overload" type error, rather than silently no-op'ing the predicate at run time. Useprevious.x(notPRIOR()),isBlank()(notISBLANK()).CEL_STDLIB_FUNCTIONS— the bare-callable public subset: the names you may write asfn(x). Receiver methods (s.split(','),list.map(...)) are called on a value, never bare, and are not in this table; four bare primitives (bytes,dyn,type,uint) resolve but are withheld from the catalogue by an authoring decision — don't reach for them. An UNKNOWN function —PRIOR(), a legacyISBLANK(), a typo'disBlnk()— failsos buildwith a "no matching overload" type error, rather than silently no-op'ing the predicate at run time. Useprevious.x(notPRIOR()),isBlank()(notISBLANK()).Searched the whole published catalogue for the claim family (
only the functions,canonical list,are callable,full/complete/exhaustive list,documents them all). Inside this skill those two sites are all of them.skills/objectstack-formula/references/_index.mdis generator-owned and carries no such claim, so nothing there needed a hand-edit — and none was made.One number deliberately NOT published
The ruling's sentence names 33 receiver methods. That count is not written into the skill, on purpose. The drift pin makes the four withheld names an executable ledger —
expect(withheld).toEqual([...WITHHELD_BARE_CALLABLE_BUILTINS])— so naming them cannot go stale silently. The receiver-only set has no equivalent pin: assertion D asserts onlyexpect(receiverOnly.length).toBeGreaterThan(0)and that none of them leaked into the catalogue. A hard33in customer-facing text would therefore be an unpinned count, free to drift the next time cel-js changes shape. The corrected passage states the rule instead, which cannot go stale.Token ratchet — under the ceiling, no raise
Delta +91 tokens (+364 bytes) for the ruled content — the membership rule, the receiver distinction, and the withheld primitives. ⛔ No ceiling raise; the pinned 6002 is untouched.
✓ check-skills-token-ratchet: skills/objectstack-formula/SKILL.md is 5249 tokens (ceiling 6002; headroom 753).✓ check-skills-token-ratchet: 36 authored bundle file(s) within their ceilings; 10 generator-owned file(s) measured, not ratcheted.Gate verdicts
Gate family derived from the change set by
scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, then reconciled against what was actually run:✓ dispatch-gates --ran: 21 derived famil(ies) accounted for — 21 run, 0 NOT-MEASURED.Run reconciliation — 21 derived, 21 run, 0 NOT-MEASURED, 0 UNRUN.All 21 exit 0, at commit
adfe3a48f. One needed a prerequisite first:check:doc-formula-expressionsexited 3 —PREREQUISITE NOT MET — the workspace package @objectstack/formula is not built, which the gate itself states measures nothing. After building@objectstack/formulaand@objectstack/lintunder the shared verification lock it re-ran at exit 0. Both builds and the gate sweep are recorded as run, not as a failure.Landing regime, asserted rather than assumed:
⛔ GOVERNED — a human merge is the review record for this PR.skills/** ×1 — the published skills catalogscripts/pm/check-governed-merges.mjs --test skills/objectstack-formula/SKILL.mdexits 3. So: this stays a draft. Not flipped ready, not enqueued, no auto-merge armed, no approval from the authoring seat.skip-changesetapplies by the rule rather than by the example list — this PR publishes nothing from any package. Nopackage.jsonin the workspace shipsskills/; the catalogue is not a package artifact.Review notes
Both approvers may want to check the two things a wording change like this can get wrong: that the four names are presented as withheld and not as an invitation (the passage says so and adds "don't reach for them"), and that the corrected text agrees with
validate.tsword for word where it matters — bare-callability as the membership rule, and the withholding as an authoring decision rather than an unavailability.🤖 Generated with Claude Code
https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox
Generated by Claude Code