Skip to content

fix(qa,spec,client): address the metadata write door by its canonical singular type segment - #13011

Merged
os-elon merged 3 commits into
mainfrom
claude/issue-11042-executable-plural-meta-calls
Aug 29, 2026
Merged

fix(qa,spec,client): address the metadata write door by its canonical singular type segment#13011
os-elon merged 3 commits into
mainfrom
claude/issue-11042-executable-plural-meta-calls

Conversation

@os-elon

@os-elon os-elon commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Part of #11042

The QA platform checklist did not merely mention the plural metadata spelling — on four executable steps it told its own operator to send one, on the write door. All seven of the card's sites are now addressed.

Generated by Claude Code, session https://claude.ai/code/session_01CPrUz21stTFhJRUirdc4yw (recorded in prose: a body PATCH eats a trailing rule and the footer after it, per the reading on #12909).

Update — merged main, and the seventh site is now IN

  • Merged origin/main (8f10a79f7a) into the branch — a merge commit, not a rebase, so anyone holding the branch keeps a valid checkout. One conflict, resolved; detail below.
  • Site 7 restored. It was dropped on the first pass because packages/spec/src/api sat inside a declared in-flight surface. That claim has since closed. Re-run of the check, below.

⚠️ Consequence the arming seat needs: the diff now touches packages/spec/src/**, so the clause-② PATH leg fires and this PR is ⛔ not enqueueable without needs:contract-review. CONTENT is comment-only — one docblock line, zero behaviour movement. This seat does not attach the gate label.

The seven sites

# site now
1-4 docs/qa/platform-checklist/areas/attachments-storage.json:27,34,41,84 PUT /api/v1/meta/object/qa_{vault,shared,nofiles,media}
5 packages/spec/liveness/object.json:104 "served on /meta/object/:name. …"
6 packages/client/src/client.hono.test.ts:170 fetch(.../api/v1/meta/object)
7 packages/spec/src/api/http-cache.zod.ts:108 // GET /api/v1/metadata/object/account

4 files, 7 changed lines.

⚠️ Site 5's line has now drifted twice. The card cited :97; the pre-merge tree had :101; the merged tree has :104. Re-derived on the merged tree each time rather than carried forward.

⚠️ Site 7 moves only the plural type segment. The /metadata prefix is a separate axis this card does not scope — the declared default is /meta (rest-server.zod.ts:298) but the sibling example at :188 also uses /metadata, so rewriting the prefix here would split the file's internal consistency for a reason the card never asked for.

The conflict, and how it was resolved

main's #13003 batch 4 (93ea19bcac) re-anchored liveness/object.json from line citations to symbol citations, rewriting the actions entry's evidence and note and adding verifiedAt. Its new note still opened with the plural served on /meta/objects/:name., so this card's change still applied — to different surrounding text.

Resolved by taking main's side wholesale and re-applying only the one word. Nothing of the re-anchoring is reverted; git diff origin/main for that file is exactly one line changed:

-      "note": "served on /meta/objects/:name. 2026-08-28: RE-ANCHORED (#13003) and REPOINTED — …
+      "note": "served on /meta/object/:name. 2026-08-28: RE-ANCHORED (#13003) and REPOINTED — …

In-flight check, re-run (not carried forward)

The card's Unlock-action forbids clearing the block by judging it unlikely to bite, so the check was re-run against the now-current claims, which have turned over almost entirely:

⚠️ One thing the arming seat should know: packages/spec/liveness/object.json (site 5) IS inside #13003's declared surface — packages/spec/liveness/*.json ONLY, a glob, and that card is an in-flight batched worklist with continuation rounds. That collision has already happened once — it is what produced this merge conflict — and it was resolved preserving #13003's work in full. Flagged rather than silently carried, since a later batch could touch this ledger again.

The measurements

The fold is still live, so these rewrites are answer-preserving. check:meta-url-spelling on the merged tree: 34 spellings, 27 registry-declared types; manifest/derived agreement holds. Static dual (an instrument that only ever folds proves nothing): fold("objects")="object" folded, fold("object") passthrough, and negative controls fold("metadata-objects") / fold("bananas") both unfolded. Runtime dual on the hono suite, by temporarily fetching both spellings plus an unmounted control: expect(singular).toBe(plural) passed and expect(bogus).toBe(404) passed, so the assertion distinguishes mounted from unmounted rather than passing vacuously; probe applied to a committed tree and reverted with git checkout HEAD -- ABSOLUTE_PATH, restoration proven by observed state — working blob equal to the HEAD blob, git diff HEAD empty.

Site 6 is incidental, not a fold pin — re-verified on a deepened clone (11,598 commits; git log on the default shallow clone answers wrongly with exit 0). 839982e3d8 (#4018) introduced it to prove a route 404s; e5a4d26901 (#4296) flipped it to not.toBe(404). Neither mentions spelling, plural, or the fold.

⛔ What was deliberately left alone

The card's fence is as much the deliverable as the edit. Untouched, on purpose: the deliberate fold pins (meta-plural-i18n.test.ts, meta-audience-plural.test.ts, meta-state-plural-tolerance.test.ts, protocol-publish-canonical-fold.test.ts, rest-server-meta-org-scope-url-spelling.test.ts and kin — the plural spelling IS the fixture, and rewriting it would leave every assertion green while deleting the coverage); the fold-verification instruction at docs/protocol-upgrade-guide.md:455; the defect narratives at metadata-url-spelling.ts:43, rest-route-ledger.ts:196, runtime/src/route-ledger.ts:356; CHANGELOG.md; content/docs/releases/**; #10178's two files; packages/runtime/src/domains/meta.ts:229 (a deliberate REST/dispatcher asymmetry — #10178's open question, left as is); the sibling /metadata example at http-cache.zod.ts:188; and the test-file and docblock buckets generally.

Finding filed, not fixed

#13010 — a fifth executable plural call at docs/qa/platform-checklist/areas/records-forms.json:35. Not a site the sweep missed: at the card's measurement commit 2866d5f97e that file had zero hits; the call landed in 5737222b89 on 2026-08-26, four days after the card was filed. The class is still being newly introduced and no gate stops the next one, so the finding is written around the missing guard.

Verification

Gate family re-derived from the merged diff (dispatch-gates --repo, exit 0, no STALE TREE, merge base 8f10a79f7). Site 7 added five families: check:authorable-surface (gate source packages/spec/src/api), check:docs, check:skill-refs, check:spec-parsed-alias, check-keyed-text-bounds. All exit codes captured before any pipe — never ${PIPESTATUS[0]}, which reads 0 for a red command when the reader closes the pipe early (#12979).

Green, quoting each gate's own verdict line:

gate exit verdict
check:platform-checklist 0 OK — 15 areas, 221 items (221 active)
check:meta-url-spelling 0 data is current (34 spellings, 27 registry-declared types)
check:authorable-surface 0 authorable-defaults/ verified against upstream 8f10a79f7aef — 1246 default(s) unchanged
check:docs (spec) 0 231 generated files in sync with packages/spec
check:skill-refs 0 9 generated files in sync with packages/spec
check:spec-parsed-alias 0 1528 bare z.input aliases, 837 pinned isomorphic, 691 paired
check-keyed-text-bounds 0 112 *.object.ts files … walk is repo-wide
check:liveness 0 state-counts.md is current — the same 31 row(s)
check:doc-authoring 0 13338 customer-facing string(s) across 672 spec sources clean
check:doc-formula-expressions 0 14 predicate(s) on a statically determinable …
check:skill-examples 0 260 prose examples type-check across 3 surface(s)
check:nul-bytes 0 scanned 7248 text file(s) … no raw ASCII control bytes
check:empty-state / check:strictness-ledger / check:variant-docs 0 all current
check:engine-double-contract 0 704 pinned, 134 in the DEBT ledger, 3 exempt
check:where-matcher 0 313 matcher(s) … correctly or refuse it loudly
plus cross-package-test-inputs, objectql-double-limit, page-declaration-shape, published-files, slot-lookup, test-source-alias, type-source-resolution, merge-driver, query-options-erasure, type-check-coverage, ci-filter-parity, comment-mask-adoption, plugin-teardown-shape, undeclared-dep-imports, affected-docs 0 all green

Tests: pnpm --filter @objectstack/client exec vitest run --maxWorkers=2 src/client.hono.test.ts4 passed (1 file), after building the dependency closure (33 tasks).

Typecheck: @objectstack/client exit 0 and @objectstack/spec exit 0. Stated precisely, because a green half can measure nothing: plain tsc --noEmit for client reads 240 files and not client.hono.test.ts, so site 6 is covered by the chained check:test-typecheck under tsconfig.test.json, whose --listFiles does include it (1 of 639). Site 7 is in spec's own program — --listFiles shows http-cache.zod.ts among 906 files.

Declared narrowings — two, stated rather than quietly skipped:

  1. Repo-wide pnpm lint narrowed to the two changed TypeScript files, with all three evidence items: population read from eslint's own --print-config; count read from --format json (2 files, 0 errors, 0 warnings); and parserOptions.project is null, so type-aware linting is off and this diff cannot move any untouched file's verdict.
  2. check:type-check-debt (the --re-measure ratchet) is NOT MEASURED, reported as such rather than as green — it refuses on an unbuilt closure, and with the closure built the re-run exceeds the container's ~10-minute foreground ceiling. CI runs it on every PR regardless.

⚠️ check:dev-prereqs and (before the build) check:doc-formula-expressions both exited 1 with PREREQUISITE NOT MET — an unbuilt workspace, which each gate's own text says measures nothing and is not a finding. doc-formula-expressions is green above once @objectstack/formula was built.

⚠️ check:platform-checklist is still absent from the derived family even though every area file's own $comment names it as their validator — the under-naming class of #12956. Run by hand; green.

Changeset

None, deliberately — skip-changeset. Re-derived now that the diff reaches published spec source:

  • docs/qa/platform-checklist/** ships in no package's files whitelist.
  • client.hono.test.ts is a test; check:published-files (green) asserts no package publishes test files.
  • liveness/object.json ships, but the changed field is a note — governance prose read only by gate scripts and packages/lint's liveness rule.
  • http-cache.zod.ts ships (src/**/*.zod.ts is in the whitelist), but the changed line is a @example docblock comment. No API, schema, type or behaviour moves, and check:authorable-surface confirms it: 1246 defaults unchanged. Direct in-flight precedent: PR docs(spec): name the real policy-gate runtime symbols in the publish-gate consumer table #13046, a comment-only edit to packages/spec/src/api/endpoint-publish-gate.ts, carries no changeset either.

… singular type segment

The QA platform checklist told its own operator to send a plural item write
(PUT /api/v1/meta/objects/:name) on four executable steps. Those answer 200
only because the boundary fold tolerates the spelling; the /meta type segment
is always singular. Rewrite the four executable call strings plus two
address-stating notes to the canonical spelling.

Part of #11042

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CPrUz21stTFhJRUirdc4yw
@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

2 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. ⚠️ 1 changed file(s) yielded no anchor (packages/spec/liveness/object.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/spec/liveness/object.json) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 126 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 8f10a79f7aef471482fdb4761ae150014a7f355apackageMentionDocs.

Which tree this was computed on

This run read content/docs from 0d6c4f91c9b6cf4aa68cd51ac8ea6b65a810c22a — the merge of head 7d6723e9d248ffacb00bc9a5877285f6944770c2 into base 8f10a79f7aef471482fdb4761ae150014a7f355a, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 0d6c4f91c9b6cf4aa68cd51ac8ea6b65a810c22a && git checkout 0d6c4f91c9b6cf4aa68cd51ac8ea6b65a810c22a
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 8f10a79f7aef471482fdb4761ae150014a7f355a 7d6723e9d248ffacb00bc9a5877285f6944770c2 && git checkout -B drift-repro 8f10a79f7aef471482fdb4761ae150014a7f355a && git merge --no-ff 7d6723e9d248ffacb00bc9a5877285f6944770c2

node scripts/docs-audit/affected-docs.mjs --json 8f10a79f7aef471482fdb4761ae150014a7f355a

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

claude added 2 commits August 29, 2026 01:14
…ecutable-plural-meta-calls

# Conflicts:
#	packages/spec/liveness/object.json
…nt in the http-cache example

The seventh site of the card's slice, held back on the first pass because
packages/spec/src/api was inside a declared in-flight surface (#12522). That
claim has since closed (merged PR #13019), and the re-run check finds the
directory's only current claim (#13040) declared file-precisely at
endpoint-publish-gate.ts with 'Nothing else' -- disjoint from this file, and
its PR touches exactly that one file. No open PR touches http-cache.zod.ts.

Only the plural type segment moves. The /metadata prefix is a separate axis the
card does not scope, and the sibling example at :188 uses it too.

Part of #11042

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CPrUz21stTFhJRUirdc4yw
@github-actions github-actions Bot added the tests label Aug 29, 2026
@os-elon
os-elon marked this pull request as ready for review August 29, 2026 01:41
@os-elon
os-elon enabled auto-merge August 29, 2026 01:41
@os-elon
os-elon added this pull request to the merge queue Aug 29, 2026
Merged via the queue into main with commit 9598f0e Aug 29, 2026
38 checks passed
@os-elon
os-elon deleted the claude/issue-11042-executable-plural-meta-calls branch August 29, 2026 02:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants