Skip to content

docs(skills): objectstack-api teaches the /meta/:type list's ?names= filter and its closed query set - #30844

Merged
os-zhuang merged 5 commits into
mainfrom
claude/project-thread-is2e6b
Nov 6, 2026
Merged

os-zhuang merged 5 commits into
mainfrom
claude/project-thread-is2e6b

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Tesla · project thread

domain:skills#2 · os-tesla · session_01L9qiby5ktwhsqg839UYDQs

Fixes #30710

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:skills/objectstack-api/SKILL.md 的 Metadata API 一节补一段:GET /api/v1/meta/:type 列表支持 ?names=a,b,c 一次按名字读多条(一个逗号分隔值;没有的名字直接缺席;空值返回 400;package 列表拒绝该参数),并且列表只认七个查询参数(package、preview、object、include、id、names、locale),其它参数一律 400 VALIDATION_ERROR,不再静默忽略。评测新增第 7 例(三个对象定义合成一次请求),changeset 一条。
  • 为什么改:这是 Metadata API: no batch by-names read, so the Console roster gate costs one /meta/object request per name #29236 裁决 A 的技能文档半边,服务端已在 PR feat(rest)!: serve ?names= on the /meta/:type list and close its query set #30709 落地。技能不写,读技能的客户 agent 仍会按名字逐个发请求,拼错的过滤参数也不知道会被拒。
  • 风险与回滚:只改技能文本与评测夹具,运行时零改动;行文全部对照 main 上的代码与测试写成。回滚即 revert。
  • 先看:skills/objectstack-api/SKILL.md 的 Metadata API 段(新段落);同文件三处删减(/data 前缀句、Datasources 小节折入 Skill Boundaries 表、RBAC 旁注去掉复述的符号);evals/endpoints-auth-routes.json 第 7 例。
  • 两分钟验证:node scripts/check-skills-token-ratchet.mjs,预期 skills/objectstack-api/SKILL.md is 5141 tokens (ceiling 6314),上限行未动;再看 packages/rest/src/meta-item-read-gate.ts 的 META_LIST_QUERY_PARAMS 七个键与技能段落一致。
  • 需要你做的:本 PR 触 skills/**(Tier H),需要受管审批人在 GitHub 上 Approve 一次;之后席位落地。

What changes

skills/objectstack-api/SKILL.md, section "Metadata API (/meta)": the two-line "read-side query params are client contracts" paragraph becomes one paragraph that states what the list door serves on main since PR #30709:

  • the closed query set package, preview (draft), object, include (content), id, names, locale (META_LIST_QUERY_PARAMS in packages/rest/src/meta-item-read-gate.ts), any other key refused 400 VALIDATION_ERROR instead of ignored;
  • ?names=a,b,c, one comma-separated value, narrowing the list to the named items the caller may see (chain step 2a runs after the per-caller gate); an unknown name simply absent; an empty value refused 400 (metaListNames); the package list refusing the key (NAMES_ON_PACKAGE_LIST_MESSAGE, its items are keyed by id);
  • the closing sentence that these are client contracts, nothing a stack declares, kept.

Not taught, on purpose: the repeated-key arity refusal, the located message texts, the ?id= / ?object= per-type meaning and the runtime dispatcher twin. The skill names the keys and the one behaviour an author or caller must know; the rest is the route's own text.

Growth paid in the same file, by deletion (no re-wrap):

Deleted Why it was restatement
"Data CRUD lives under the /data prefix." and "aggregation goes through POST /api/v1/data/{object}/query with groupBy/aggregations in the body" The route block right above shows every /data path, and the derived-operations table's aggregate row carries the same query + groupBy/aggregations spelling. The negative pins (no /bulk, no GET .../aggregate) stay.
The ## Datasources section Pure routing: every pointer in it has its home in objectstack-data (rules/datasources.md) and objectstack-platform (Driver Selection Guide, which carries the Turso Cloud/EE caveat). The Skill Boundaries table already routed datasources there; it now names the rule file and gains a Pick a driver package row, so no pointer is lost.
(definePermissionSet) and ", not this one" in the auth aside The Skill Boundaries table routes permissions to objectstack-data; the symbol is that skill's to teach.

skills/objectstack-api/evals/endpoints-auth-routes.json: case 7, "three object definitions, one request": expects one GET /api/v1/meta/object?names=account,contact,lead, must contain ?names= / /api/v1/meta/object / VALIDATION_ERROR, must not contain ?name=, ?ids=, ?filter=. Added because case 6 already evaluates a request-shape answer (the import body), so a metadata-read case is inside the fixture's convention. The seat may drop it if the convention is read narrower.

.changeset/30710-meta-list-names-filter.md: '@objectstack/skills': patch, both declaration lines.

Readings (os-dev rule for skills/**):

Reading Before (origin/main b6182249) After (a2f2be9c)
skills/objectstack-api/SKILL.md lines 446 441
skills/objectstack-api/SKILL.md tokens (check-skills-token-ratchet) 5144 5141 (ceiling 6314, unchanged)
Package, all 11 skills/*/SKILL.md, lines 4523 4518
Package, all 11 skills/*/SKILL.md, tokens (gate formula) 56716 56713

No ceiling row moves. The eval fixture is measured, not ratcheted (1234 → 1484 tokens).

Why

#30710, a ruling's owed skills follow-up (#29236, ruling 6580261740 letter A): PR #30709 serves ?names= and closes the list's query set, and its body declares Skills-docs: follow-up #30710. Until the skill says so, an agent reading it sends one request per name and cannot learn that a misspelt filter is refused rather than ignored.

Tests

No runtime code changes. The teaching text was read off main's META_LIST_QUERY_PARAMS, metaListNames, metaListUnknownParamRefusal and the pins in packages/rest/src/meta-query-arity-doors.test.ts and meta-list-names-filter.test.ts at c17719dd; nothing is stated that those do not pin.

Acceptance notes

Verification

Derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack against the three-file diff. Run twice, every line with stdin closed, exit codes landed first:

  • At 36b5c9e6 (before the origin/main merge): 44 derived families, 44 run, 44 exit 0; --ran reconciliation: 0 NOT-MEASURED, 0 UNRUN.
  • At a2f2be9c (the head, after merging origin/main b6182249): 45 derived families (the merge adds scripts/ci/snapshot-next.mjs --self-test), 45 run, 45 exit 0; --ran reconciliation: 0 NOT-MEASURED, 0 UNRUN. Ran lists: skills-seat-2/out/30710-gates-ran-{36b5c9e6,a2f2be9c}.list in the project files.
Gate readings at a2f2be9
  • check-skills-token-ratchet: skills/objectstack-api/SKILL.md is 5141 tokens (ceiling 6314; headroom 1173), exit 0.
  • check:skill-identifier-liveness: Leg 1: 486 citation(s) over 71 published file(s) … Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s), exit 0.
  • check:dual-build-cjs-loads: 116 published require entry point(s) across 71 package(s) load; 2456 emitted CommonJS file(s) parse, exit 0 (declarations build of ./packages/**).
  • check:lean-entry-closure, pnpm --filter @objectstack/spec run check:skill-docs, check:skill-compatibility, check:skill-frame-sync, check:pm-skill-id-lint, check-changeset-no-major --base origin/main, check-empty-changeset --base origin/main, check-adr-0087-registration --base origin/main, check:pm-governed-merges, check:doc-authoring, check:nul-bytes, check:role-word, the rest: exit 0.
  • Tier: dispatch-gates --tier on the three paths: skills/** clause ①, claude-fable-5-1 mandated, no one-line exit; this thread runs on it. check-governed-merges --test skills/objectstack-api/SKILL.md: Tier H.

CI families (Lint & Repo Gates, Test Core, the rest) are the PR's check-runs, not re-run locally.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic.
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint is CI's run (no source file in the diff).
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset.
  • 6. packages/spec not touched.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English.
  • The Before Submitting list in CONTRIBUTING.md is done.

🤖 Generated with Claude Code

https://claude.ai/code/session_01L9qiby5ktwhsqg839UYDQs

objectstack-fleet Bot and others added 2 commits November 6, 2026 05:43
…filter and its closed query set

The Metadata API section states what the list door serves today: `?names=a,b,c`
(one comma-separated value) narrows the list to the named items the caller may
see, an unknown name is absent, an empty value is refused 400, the `package`
list refuses the key, and any key outside the closed set (`package`, `preview`,
`object`, `include`, `id`, `names`, `locale`) is refused 400 VALIDATION_ERROR
instead of ignored. Growth is paid in the same file: the `/data` prefix sentence
and the aggregate spelling restated the route block and the derived-operations
table, the Datasources section folded into the Skill Boundaries table, and the
RBAC aside dropped its restated symbol. Eval case 7 asks for one by-names read.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9qiby5ktwhsqg839UYDQs
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Nov 6, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-tesla · session_01L9qibz5RLVEYDFco93jZ7u

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: a2f2be9c0aee03257f9bef63007426bfebd99c73
Local-runs: none
Scope: skills/objectstack-api/SKILL.md, skills/objectstack-api/evals/endpoints-auth-routes.json + packages/rest/src/meta-item-read-gate.ts (META_LIST_QUERY_PARAMS, metaListUnknownParamRefusal, NAMES_ON_PACKAGE_LIST_MESSAGE, metaListNames, createMetaListAnswer step 2a/8), packages/rest/src/meta-collection-routes.ts (the GET /api/v1/meta/:type handler), packages/rest/src/meta-query-arity-doors.test.ts, packages/rest/src/meta-list-names-filter.test.ts, packages/spec/src/api/protocol.zod.ts (GetMetaItemsRequestSchema.names), skills/objectstack-data/SKILL.md + rules/datasources.md + rules/security.md + references/_index.md, skills/objectstack-platform/SKILL.md (Driver Selection Guide), skills/objectstack-data/evals/README.md (the eval convention), packages/skills/package.json, scripts/check-skills-token-ratchet.mjs (the ceiling row)

Inputs read: card #30710 (body, triage, claim, os-dev-report); PR #30844 body and three-file list; the net diff origin/main...a2f2be9c (merge-base b6182249); the check-runs on the head. The cited code was read on origin/main through git objects, nothing built or run.

① Derived judgments

  • Accept set: no runtime, schema or route file changes. The diff is prose (skills/objectstack-api/SKILL.md), one eval fixture, one changeset. Right: the PR body claims no behaviour change and the tree agrees.
  • Public surface: skills/** ships as @objectstack/skills (packages/skills/package.json, the catalog sync), so the new Metadata API paragraph and the three deletions ARE a published-text change — correctly carried by the changeset. Right.
  • Governed path: skills/** is Tier H (AGENTS.md governed list); the PR is a draft awaiting a governed approver, and Governed Surface Queue Guard is green on the head. Right.
  • Ratchet: check-skills-token-ratchet ceiling row for skills/objectstack-api/SKILL.md (6314) is untouched by the diff; the body's 5144 → 5141 reading is consistent with a 446 → 441-line file, and Lint · repo & tooling gates is green. Right.
  • Dispatch surface respected: only the one skill file, one eval case, one changeset; no other skill, no ceiling moved. Right.
  • Check-runs on the head at review time: every concluded run is success (Lint x8 incl. CI/release/engine gates, Type Check x5, Build Core, Check Changeset, Check PR Size, Dogfood Regression Gate, Governed Surface Queue Guard, PR-body guards, Test Core (2/8), Test UI, Live E2E UI, Auto Label, filter); only Test Core (1/8) was still in_progress at the last read. The diff carries no runtime code, so that shard cannot read it; the adopting seat re-reads it before ACCEPT. No run is red.

② Semver level

  • .changeset/30710-meta-list-names-filter.md: '@objectstack/skills': patch. Right — a documentation change to a published skill text, no API surface of any @objectstack/* runtime package moves. Check Changeset green.
  • Clause-②: no on the PR body and the changeset, no (narrowing) arm. Right — the skill text describes a narrowing that PR feat(rest)!: serve ?names= on the /meta/:type list and close its query set #30709 already declared on its own changeset (ruling 6580261740 letter A: "the seat states it on the changeset"); this PR takes nothing away at any consumer.
  • Metadata-protocol: none. Right — an API query key is not authorable metadata.
  • Face: governed rules text (skills/**) ⇒ CONTRACT_REVIEW_TIER; the record's tier matches --paths.

③ Boundary flags

  • open_questions: [] — nothing to answer.
  • Dev flag "Eval case 7 … the seat may drop it": answered below (④) — keep it, with one should-fix on its assertions; dropping it is also within the dispatch surface ("at most one evals/*.json case").
  • Dev flag "skills/objectstack-api/evals/ has no runner script in this repo": confirmed — the fixtures are population 1b of check-skills-token-ratchet (measured, not ratcheted) and skills/README.md calls them maintainer-scored. Not a defect; no escalation.
  • Dev note "OS_SKIP_DTS=1 reds check:dual-build-cjs-loads": a local-build trap already named in AGENTS.md; no card owed. Not escalated.
  • Serial constraint from the claim (merge origin/main before pushing): the merge-base is b6182249, which was origin/main at push time; origin/main has since moved to 25e1c1ad with no touch to the two hits files. Nothing to redo.

④ Design judgment

skills/objectstack-api/SKILL.md — the new Metadata API paragraph against main's code. Every claim checked and held:

  • Closed query set package, preview, object, include, id, names, locale — equals META_LIST_QUERY_PARAMS (meta-item-read-gate.ts:2659) and the pin SUPPORTED_LIST_PARAMS (meta-query-arity-doors.test.ts:292).
  • "refuses any other key with 400 VALIDATION_ERROR instead of ignoring it" — metaListUnknownParamRefusal (meta-item-read-gate.ts:2705) returns { status: 400, code: 'VALIDATION_ERROR', rule: 'unknown-parameter' }; the RestServer door asks it first, before any protocol read (meta-collection-routes.ts:666; pinned by "an undeclared key answers the nested 400 before any protocol read", and by name, ids, filter, names[] each refused).
  • "?names=a,b,c (one comma-separated value)" — metaListNames splits one string on ,, trims, drops blanks, dedupes (meta-item-read-gate.ts:2750); a repeated key is refused by the arity door (META_QUERY_ARITY_DOORS.list carries names). Matches the ruling's letter A spelling.
  • "narrows the list to the named items the caller may see" — chain step 2a runs after THE per-caller list gate (step 2) and before the mask and translation (meta-item-read-gate.ts:4090–4098); pinned in meta-list-names-filter.test.ts.
  • "an unknown name is simply absent" — names: 'account,nope' → ['account'], names: 'nope' → ok: true, [] (meta-list-names-filter.test.ts); never a 404.
  • "an empty value is refused 400" — '', ',', ' , ' each throw status: 400, code: 'VALIDATION_ERROR', param: 'names' (meta-item-read-gate.ts:2753–2765; pinned); the route asks metaListNames before the store read (meta-collection-routes.ts:729).
  • "the package list (keyed by id) refuses the key" — NAMES_ON_PACKAGE_LIST_MESSAGE, rule: 'names-on-package' (meta-item-read-gate.ts:2712–2714, 2727); pinned on both transports.
  • "These are client contracts — nothing in a stack declares them" — kept from main; still true (no Zod authoring surface declares list query keys; GetMetaItemsRequestSchema.names is the protocol request, not stack metadata).
  • Against the card's eval prompt: an agent reading the paragraph now knows the one-request spelling and that a misspelt filter is refused, which is the exact gap the card names.

The three deletions — does any rule lose its only home?

  • "Data CRUD lives under the /data prefix" + the groupBy/aggregations spelling: the route block directly above (SKILL.md:40–52) lists every /data path, and the derived-operations table row aggregate → POST /data/{object}/query with groupBy/aggregations (SKILL.md:266 in the PR tree) keeps the spelling. The negative pins (no /bulk, no GET .../aggregate) survive, and eval case 5 still has its /batch anchor. Nothing lost.
  • ## Datasources: defineDatasource/schemaMode/external/credentialsRef are taught in skills/objectstack-data/rules/datasources.md (lines 3, 9, 47, 65–71); the Driver Selection Guide with the Turso Cloud/EE caveat is skills/objectstack-platform/SKILL.md:197–207; data/driver/config-registry.zod.ts is skills/objectstack-data/references/_index.md:30. The Skill Boundaries table gains the rule-file name and a Pick a driver package row, so every pointer the section carried still routes. No frame, gate or references/_index.md of objectstack-api names the ## Datasources heading. Nothing lost.
  • (definePermissionSet), ", not this one": definePermissionSet is taught in skills/objectstack-data/rules/security.md:9–11, 77; the routing sentence "RBAC and RLS are objectstack-data's surface" stays. Nothing lost.

Should-fix 1 (SKILL.md:71–72). The parentheticals read as the value set, and include (content) omits grants: the list also reads ?include=grants on the position list (chain step 8, meta-item-read-gate.ts:4041, 4168; describeMetaPositionList). A reader who takes the parenthetical as closed will spell ?include=grants as a refused key. main carried the same omission, so this is not a regression, but the new sentence now asserts a CLOSED set and so invites that reading. Cheapest fix: "include (content, grants)" — three tokens, inside headroom.

skills/objectstack-api/evals/endpoints-auth-routes.json — case 7 against the convention and against main.

  • Shape: id, prompt, expected_output, files: [], assertions.must_contain / must_not_contain — matches cases 1–6 and the objectui shape the data evals README names. JSON parses; check-skills-token-ratchet measures, never ratchets, population 1b.
  • Against main: GET /api/v1/meta/object?names=account,contact,lead is what the route serves (type object is the folded singular the tests drive; the names filter answers ['account','contact','lead'] on the fixture OBJECTS the pin uses). must_not_contain ?name=, ?ids=, ?filter= are the three undeclared spellings the arity-doors test refuses; ?names= does not contain the substring ?name= (the s precedes =), so the negative assertion cannot bite the right answer. A /api/v1/meta/objects?... spelling still contains /api/v1/meta/object, so the plural does not fail the anchor.
  • Should-fix 2 (endpoints-auth-routes.json:68–70). must_contain requires the literal VALIDATION_ERROR, but the prompt asks only to collapse three reads into one request. A correct, complete answer (GET /api/v1/meta/object?names=account,contact,lead, unknown name absent, empty value 400) that never names the misspelt-filter refusal fails the eval. The data evals README's rule is one specific SKILL.md rule per case; case 7 scores two (the filter and the closed set) and anchors the second through a token the prompt gives no reason to produce. Either drop VALIDATION_ERROR from must_contain (keep it in expected_output), or give the prompt the hook (e.g. "our first attempt, ?name=account, came back 400 — why?"). The dev already offered to drop the case; dropping is acceptable too, but the fixed case is worth keeping because it is the only eval that exercises the Metadata API section.

Nit (not a finding). The Skill Boundaries row now reads "datasources (rules/datasources.md)" in the Need column; the deleted section spelled it "objectstack-data → rules/datasources.md". objectstack-api has no rules/ directory, so a reader may look for the file locally; the row's Use-instead cell does name objectstack-data, so the routing survives.

No must-fix. The paragraph states nothing the code does not pin, the deletions orphan no rule, and the eval case is inside the fixture's convention apart from the one over-tight assertion.

Implemented-by: claude/project-thread-is2e6b
Reviewed-by: session_01L9qibz5RLVEYDFco93jZ7u

VERDICT: PASS

…ase 7 its refused-filter hook

Contract review should-fixes: the closed-set sentence now lists `include`
(`content`, `grants`), since the position list reads `?include=grants`; the
growth is paid by dropping the dead `enable.trash` 16.x parenthetical. Eval
case 7's prompt now carries the `?name=` attempt that came back 400, so its
`VALIDATION_ERROR` assertion is reachable from the prompt.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9qiby5ktwhsqg839UYDQs
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-tesla · session_01L9qibz5RLVEYDFco93jZ7u

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 1403468afe798e3c63744bc743e7f4d2f32b287c
Local-runs: none
Scope: skills/objectstack-api/SKILL.md, skills/objectstack-api/evals/endpoints-auth-routes.json + packages/rest/src/meta-item-read-gate.ts (META_LIST_QUERY_PARAMS, chain step 8 ?include=grants), content/docs/releases/v17/17-0.mdx and content/docs/protocol/kernel/http-protocol.mdx (the enable.trash retirement's homes), .changeset/30237-recycle-bin-snapshot-on-delete.md on origin/main (PR #30780, the recycle-bin write side)

Delta review: one commit 1403468a on top of a2f2be9c, applying the two should-fixes of the record at PR comment 6678765634, which this record supersedes. Everything that record judged and the delta does not touch stands as written there (the seven-key set, the ?names= semantics, the three deletions, the changeset, Clause-②: no). Inputs: the delta diff git diff a2f2be9c 1403468a (two files, no changeset change), the check-runs on 1403468a, the cited code on origin/main read through git objects; nothing built or run.

① Derived judgments

  • Accept set: unchanged — still prose and one eval fixture; no runtime, schema or route file.
  • Public surface: the published skill text changes by one added value name (grants) and one dropped parenthetical; still a @objectstack/skills patch. Right.
  • Dispatch surface: still the one skill file and the one eval case; no ceiling row moved; the growth is paid in the same file (the parenthetical is longer than the two added tokens). Right.
  • Check-runs on 1403468a: every concluded run success (Lint x9 incl. Lint & Repo Gates, which carries the token ratchet; Type Check x5; Build Core; Check Changeset; Check PR Size; Dogfood Regression Gate; Governed Surface Queue Guard; PR-body guards; Test Core (2/8); Test UI; Live E2E UI; Auto Label; filter); only Test Core (1/8) still in_progress at the last read. No runtime code in the diff; the adopting seat re-reads that shard before ACCEPT. No run is red.

② Semver level

  • Unchanged: .changeset/30710-meta-list-names-filter.md, '@objectstack/skills': patch, Clause-②: no, Metadata-protocol: none. The delta adds no surface and takes none away. Right.

③ Boundary flags

④ Design judgment

SKILL.md:72 — include (content, grants). Holds: the list chain's step 8 reads ?include=grants on the position list (meta-item-read-gate.ts:4041, 4168) and step 6 reads ?include=content on doc; include is one key of META_LIST_QUERY_PARAMS (meta-item-read-gate.ts:2659). The parenthetical now names both values the list reads, so the closed-set sentence no longer invites a reader to spell a served value as a refused key. Should-fix 1 of 6678765634 is met.

SKILL.md:411–413 — the dropped enable.trash parenthetical. Does the rule lose its only home? No: the retirement is taught in content/docs/releases/v17/17-0.mdx:154–155 (restore / purge never derive — enable.trash retired) and :1045 (object.enable.trash / enable.mru, ADR-0049 close-out, #2377), and in content/docs/protocol/kernel/http-protocol.mdx:798 ("removed in v17"). Both homes say v17; the deleted parenthetical said 16.x, so the deletion removes a mis-dated statement and keeps nothing a reader needs. The pitfall's rule (hard delete; recover through trackHistory or a lifecycle archive policy) stays, and eval case 5's anchors (trackHistory, lifecycle, no 'restore') still read it.

Should-fix 3 (SKILL.md:412, carried from main — not charged to this PR). The re-wrapped sentence now stands alone as "there is no recycle bin." On origin/main since 25e1c1ad (PR #30780, ADR-0148 write side) a by-id delete of a business record writes a sys_recycle_bin entry; the delete is still physical, no read path changed and no restore door ships, so "DELETE is a hard delete" and the recovery advice remain true for a caller, but "there is no recycle bin" is now literally false. #30780's own changeset declares Skills-docs: follow-up owed — skills/objectstack-api/SKILL.md :268, :417 (they teach that there is no recycle bin), so that correction is a separately owed card, not this PR's debt, and this PR's merge-base predates it. Not a must-fix: the delta changes no meaning of the sentence, and the owed follow-up has a declared owner. The seat should make sure that follow-up card exists before this PR's text is read as the newest word on the subject; if the dev prefers, "there is no recycle bin" can be dropped here too (the sentence "ObjectStack DELETE is a hard delete." carries the pitfall alone), which is a one-clause deletion inside the dispatch surface.

endpoints-auth-routes.json:66 — the prompt's refused-filter hook. The prompt now says "our ?name=account,contact,lead attempt came back 400", so a complete answer explains the refusal (closed set, 400 VALIDATION_ERROR) and must_contain: ["VALIDATION_ERROR"] is reachable from the prompt. Against main: ?name= on the object list IS refused 400 VALIDATION_ERROR before any protocol read (meta-query-arity-doors.test.ts: "an undeclared name is refused … with the located sentence"; "RestServer: an undeclared key answers the nested 400"), so the scenario the prompt states is what the server serves. Should-fix 2 of 6678765634 is met.

Should-fix 4 (endpoints-auth-routes.json:66 with :71). The same hook creates a scoring tension: the prompt now contains the literal ?name=, and must_not_contain still forbids ?name= in the output. A natural correct answer quotes the caller's attempt ("your ?name= key is outside the closed set, so it was refused") and would fail the negative assertion while being exactly right. Either (a) drop ?name= from must_not_contain (keep ?ids=, ?filter=, which the prompt never mentions), or (b) phrase the prompt without the literal ("our attempt with a singular name key came back 400"). Not a must-fix: the fixture has no runner in this repo and is maintainer-scored, and the positive anchors are right; but the case should not punish the answer the prompt itself invites.

No must-fix. The two requested fixes land as asked and hold against the code; the dropped parenthetical had two homes that also correct its date; the one carried-over stale clause is #30780's declared follow-up.

Implemented-by: claude/project-thread-is2e6b
Reviewed-by: session_01L9qibz5RLVEYDFco93jZ7u

VERDICT: PASS

objectstack-fleet Bot and others added 2 commits November 6, 2026 06:48
…wn prompt quotes

A correct answer may quote the refused `?name=` attempt the prompt names, so
`must_not_contain` keeps only the spellings a wrong answer writes (`?ids=`,
`?filter=`).

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9qiby5ktwhsqg839UYDQs
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-tesla · session_01L9qibz5RLVEYDFco93jZ7u

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 4138810d643efa39d1f6be0267d27f22900459a2
Local-runs: none
Scope: skills/objectstack-api/SKILL.md, skills/objectstack-api/evals/endpoints-auth-routes.json + packages/rest/src/meta-query-arity-doors.test.ts (the name / ids / filter refusal pins the eval case rests on), the merge-base 677d542a of origin/main (to read the net diff)

Second delta review: two commits on top of 1403468a — fa02fd0f (eval case 7's must_not_contain drops ?name=, keeps ?ids= and ?filter=) and 4138810d, a merge of origin/main 677d542a. This record supersedes the one at PR comment 6679015536 (head 1403468a); everything that record and its predecessor (6678765634) judged and this delta does not touch stands as written there. Inputs: git diff 1403468a 4138810d -- skills/ .changeset/, git diff --name-status origin/main...4138810d, the check-runs on 4138810d, the cited pins on origin/main read through git objects; nothing built or run.

① Derived judgments

  • The two-point delta 1403468a..4138810d under skills/ and .changeset/ holds exactly one PR-authored hunk — the must_not_contain line of eval case 7 — plus three changesets that arrive through the merge (30237-recycle-bin-snapshot-on-delete.md, 30512-plugin-approvals-locales-b.md, 30692-field-group-requires-feature.md), each byte-identical to origin/main's. Right: the merge adds nothing to what the PR publishes.
  • Net diff against origin/main (merge-base 677d542a): .changeset/30710-meta-list-names-filter.md (A), skills/objectstack-api/SKILL.md (M), skills/objectstack-api/evals/endpoints-auth-routes.json (M) — the same three files as every earlier head. Right.
  • Accept set and public surface: unchanged from 6679015536 — prose, one eval fixture, one @objectstack/skills patch changeset; no runtime, schema or route file. Dispatch surface respected. Right.
  • Check-runs on 4138810d: every concluded run success (Lint x9 incl. Lint & Repo Gates, Type Check x5, Build Core, Check Changeset, Check PR Size, Dogfood Regression Gate, Governed Surface Queue Guard, PR-body guards, Test Core (2/8), Test UI, Live E2E UI, Auto Label, filter); only Test Core (1/8) still in_progress at the last read. No runtime code in the diff; the adopting seat re-reads that shard before ACCEPT. No run is red.

② Semver level

  • Unchanged: '@objectstack/skills': patch, Clause-②: no, Metadata-protocol: none. The merged-in changesets belong to their own PRs, already on main, and are not this PR's declaration. Right.

③ Boundary flags

④ Design judgment

endpoints-auth-routes.json:71 — must_not_contain: ["?ids=", "?filter="]. Should-fix 4 is met: the prompt (line 66) quotes the caller's refused ?name=account,contact,lead attempt, and the negative assertions no longer forbid the literal the prompt invites the answer to quote. The two remaining spellings, ?ids= and ?filter=, are names the prompt never mentions and that main refuses as undeclared (meta-query-arity-doors.test.ts: it.each(['name', 'ids', 'filter', …]) refused with the located sentence), so an answer that recommends either is wrong and is caught; an answer that explains why ?name= failed is right and no longer penalised. The positive anchors (?names=, /api/v1/meta/object, VALIDATION_ERROR) are each reachable from the prompt and each pinned on main. The case now tests the one rule the card names (the ?names= filter and the closed set that refuses its misspellings) with the positive and negative patterns the data evals README asks for.

Nothing else in the two hits files moved between 1403468a and 4138810d; the judgments of 6678765634 and 6679015536 on the Metadata API paragraph, the three same-file deletions, the include (content, grants) fix and the dropped enable.trash parenthetical stand.

No must-fix. No new should-fix. Should-fix 3 remains an owed follow-up of #30780, not a finding against this diff.

Implemented-by: claude/project-thread-is2e6b
Reviewed-by: session_01L9qibz5RLVEYDFco93jZ7u

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-tesla · session_01L9qibz5RLVEYDFco93jZ7u

维护者速读

  • 改了什么:objectstack-api 技能的 Metadata API 一段补上 /api/v1/meta/:type 列表的两点:?names=a,b,c 只返回点名的条目(一个逗号分隔的值;不存在的名字不返回;空值 400;?package= 包列表不接受它),以及列表只认七个查询参数(package、preview、object、include(content、grants)、id、names、locale),其他任何键都 400 VALIDATION_ERROR。测试题加第 7 题(一次 ?names= 读三个对象)。
  • 为什么改:PR feat(rest)!: serve ?names= on the /meta/:type list and close its query set #30709 已在 main 上提供 ?names= 并关闭了查询参数集,但技能没写,AI 会按名字逐个请求,或拼错参数后以为拿到了全量列表。
  • 风险与回滚:只改技能文本、一道测试题和 changeset,不碰运行时。篇幅靠同文件删重复/过时内容换来(/data 前缀一句、Datasources 一节并入 Skill Boundaries 表、definePermissionSet 旁注、一个写错版本号的 enable.trash 括注),token 5144→5131,上限 6314 未动。回滚即 revert。
  • 先看:skills/objectstack-api/SKILL.md 第 71–72 行。
  • 两分钟验证:git grep -n "names=" skills/objectstack-api/SKILL.md packages/rest/src/meta-list-names-filter.test.ts。
  • 需要你做的:改的是 skills/**,属于 Tier H,需要 os-zhuang(或 hotlong)批准后才能合并。契约复审 PASS 记录 6679200681,Head-sha 4138810d。

席位意见:契约复审三轮都 PASS,四条建议修改里三条已改,第四条(SKILL.md 第 412 行“没有回收站”已过时)是 #30780 留下的欠账,已有卡 #30847 跟进。可以批准。

席位核对

ACCEPT · seat domain:skills#2 · head 4138810d · 2026-11-06T07:05Z

  1. Shape: Fixes #30710, draft, base main, 3 files (skills/objectstack-api/SKILL.md, skills/objectstack-api/evals/endpoints-auth-routes.json case 7, .changeset/30710-meta-list-names-filter.md '@objectstack/skills': patch), +33/−20, five commits (two fix commits, merges of origin/main).
  2. Ruling: Metadata API: no batch by-names read, so the Console roster gate costs one /meta/object request per name #29236 ruling 6580261740 letter A (the served change, PR feat(rest)!: serve ?names= on the /meta/:type list and close its query set #30709 merged); triage 6672683921 (p3). Claim 6677888510. No ceiling raised.
  3. Contract review: PASS 6679200681 at this head (Fable, delta; supersedes PASS 6679015536 at 1403468a and PASS 6678765634 at a2f2be9c). Should-fixes 1 (include names grants), 2 (eval 7 prompt hook), 4 (eval 7 must_not_contain no longer forbids the quoted attempt) applied and verified; should-fix 3 (L412 "no recycle bin", stale since feat(objectql,platform-objects): keep a by-id delete's rows in the recycle bin (ADR-0148) #30780) is not this card's debt and is carried by skills: objectstack-api still teaches that DELETE is unrecoverable and that there is no recycle bin (#30237, ADR-0148) #30847. Clause-②: no, Metadata-protocol: none.
  4. Gates / check-runs: dev reports 45/45 derived gates exit 0 at 4138810d, 0 NOT MEASURED (ran-list skills-seat-2/out/30710-gates-ran-4138810d.list). On head 4138810d: 41 check-runs, 28 success, 13 skipped, 0 failed; mergeable_state clean.
  5. Accepted deviations: the PR body describes a2f2be9c and is not patched (the dev writes it once). Where it differs, this record holds: include is content, grants; SKILL.md reads 5131 tokens (not 5141), still 441 lines; the enable.trash parenthetical is also deleted; eval 7's prompt carries the 400 ?name= attempt and its must_not_contain is ?ids= / ?filter=. Report 6678954717 stands except head and the eval reading (1498 tokens).
  6. Landing: check-governed-merges --pr 30844: GOVERNED, Tier H (skills/**). The seat readies the PR and the relay's governed-review leg requests the approvers; no auto-merge is armed by the seat. After an authorized approval the seat lands it, or the approver enqueues it.

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

Labels

documentation Improvements or additions to documentation size/s tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

skills/objectstack-api: teach the /meta/:type list door's ?names= filter and its closed query set (follow-up of #29236)

1 participant