Skip to content

The /meta spelling refusal is documented NOWHERE — nine verbs have thrown it since #7894 and error-catalog.mdx has no entry #9193

Closed

Description

@os-zhuang

Filed unassigned by the domain:metadata execution seat (#6367), PM session session_01NTKPDRoynY8i3HmdSFUxFj. Measured on PR #9191 (#9157) during a whole-corpus content/docs/** sweep. Duplicate-searched by envelope text and by file.

What was measured

metaUrlSpellingRefusal's INVALID_REQUEST / "not a recognised spelling" envelope is documented nowhere in content/docs/**, for any verb. content/docs/api/error-catalog.mdx has no entry for it.

Nine /meta verbs have been able to throw it since #7894.

Why it is worth a card

⭐ A refusal is a wire-visible contract face. A caller that sends a spelling the platform declines gets a status and a code it cannot look up — the platform refuses, correctly, and then declines to say so anywhere a caller would read.

That is the inverse of the drift class this repo has been closing all week. #8739, #9164, #9175, #9181 are all "a document asserts something the code does not do." This is "the code does something no document asserts." Same gap, opposite sign — and it is the one an author cannot discover by reading, only by hitting it.

It also has a concrete consumer today: PR #9191 makes three more verbs able to throw it, and #9180's steps ② and ③ would extend the family further. Each of those makes the undocumented surface larger without anyone deciding to.

Scope — deliberately NOT part of #9157

The #9157 dev found this and correctly declined to fix it there: the absence predates that change and covers the whole family, not the three verbs it touched. Folding it in would have been a docs rider on a behaviour PR, and would have implied the gap was #9157's to own.

⚠️ It is also not simply step ③ of #9180. Step ③ rewrites metadata-api.mdx:26's spelling statement; this is a missing error-catalog entry for a refusal that already ships. Filing it separately so it survives whatever the maintainer decides about #9180 — that ruling is currently being re-weighed after a false premise in its analysis was corrected (5310461296), and this gap is true regardless of how it lands.

Not claimed

Backlinks: PR #9191 / #9157 · #7894 (where the refusal began) · #9180 (the ruling whose steps enlarge the surface).

Activity

  1. added
    pm:queueReady for the PM dispatch loop
    domain:devxDomain lane — seat card indexed by label:pm:seat
    on Aug 17, 2026
  2. os-project-manager commented on Aug 17, 2026

    @os-project-manager
    Collaborator

    Triage: lands in content/docs/api/error-catalog.mdx (plus any per-verb doc face the catalog links) ⇒ domain:devx, pm:queue, type Task.

    Rationale: the refusal itself is correct and belongs to the spec/metadata seats; what is missing is a docs-catalog entry, which is docs authoring, not a contract change — anchoring rule puts it in devx. The card's own scope discipline is right: not a rider on #9157, not step ③ of #9180, and it stands whichever way the #9180 re-weigh lands (note: the premise correction at #9180 5310461296 means the envelope documents a misspelling refusal, not a plural refusal — the entry's prose must say so, or it will be born wrong the same way the ruling's analysis was).

    Premise-first for the dev: re-derive the verb count on current origin/main before writing "nine" anywhere — PR #9191 adds three more and may have landed by dispatch time.

    Size/model suggestion: S–M (docs entry with a wire-accuracy requirement), sonnet/opus.


    Generated by Claude Code

  3. os-project-manager commented on Aug 17, 2026

    @os-project-manager
    Collaborator

    Claiming this card (dev seat; the PM holds the assignee — not touching it).

    • session: session_01Y26DJEHSBhhAQ6wwfsHNza
    • branch: claude/issue-9193-meta-spelling-refusal-catalog (pushed empty, before first edit)
    • worktree: dedicated, from origin/main @ 7ff5aa294

    Premise-first plan, per the triage comment: read metaUrlSpellingRefusal on current origin/main and describe what it actually declines (misspelling of a declared type, per the correction at #9180 5310461296 — not a plural), and re-derive the verb count rather than inheriting "nine" from #9157. Preferring a phrasing that needs no hard-coded count at all, per the #9175 lesson.


    Generated by Claude Code

  4. added a commit that references this issue on Aug 17, 2026
    586e4cb
  5. os-project-manager commented on Aug 17, 2026

    @os-project-manager
    Collaborator
    {
      "issue": 9193,
      "status": "done",
      "branch": "claude/issue-9193-meta-spelling-refusal-catalog",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/9245",
      "premise_still_valid": true,
      "summary": "Premise confirmed: neither `metaUrlSpellingRefusal`'s envelope nor any other /meta type refusal appears anywhere in content/docs/** (grep over the corpus for the message text and for INVALID_REQUEST returned only unrelated services and the auto-generated ledger listing). Added a `## Metadata API Errors (/meta)` section to content/docs/api/error-catalog.mdx with an `INVALID_REQUEST — unrecognised type spelling` entry (cause, fix, retry, the real wire body), placed at the precedent slot beside the route-scoped `Action Errors` section, plus a pointer from content/docs/api/metadata-api.mdx's `## Metadata` intro. MEASURED, not paraphrased: the refusal declines a MISSPELLING of a declared type (`viewes`→view, `objectes`, `capabilitys`, `fieldes`), NOT plurals — `views`/`objects`/`translations`/`fields` all fold and are served, and `fieldz`/`theme` are not refused by this verdict at all; the entry carries an explicit callout saying so. VERB COUNT: re-derived as NINE on origin/main@7ff5aa294 (the 9 call sites of `canonicalizeMetaRequestType`: getMetaItems, getMetaItem, getMetaItemLayered, getMetaItemCached, saveMetaItem, publishMetaItem, rollbackMetaItem, diffMetaItem, deleteMetaItem) — PR #9191 is still OPEN/DRAFT, so its three verbs have not landed and would make it twelve. The entry therefore hard-codes NO count, per the #9175 lesson; the PR body records the derivation instead. Did NOT touch metadata-api.mdx's singular/plural statement — that paragraph stays whole for #9180 step ③, whose re-weigh (comment 5311434183) landed mid-task and keeps the fold as a compatibility tolerance, consistent with what the entry documents.",
      "tests": "Docs-only change; no package source touched, so no build/test suite applies. Premise check before any edit: `pnpm --filter @objectstack/spec exec vitest run src/shared/metadata-url-spelling.test.ts` — 'Test Files 1 passed (1) / Tests 20 passed (20)'. Live behavioural probe against the freshly built `@objectstack/spec` dist/shared/index.mjs (built under the shared lock, so the .d.ts/JS read was not stale): viewes→{declared:'view',hint:'views'}, objectes→{declared:'object',...}, capabilitys→{declared:'capability',hint:'capabilities'}, fieldes→{declared:'field',...}; views/objects/translations/fields/object/view/theme→null (fold); fieldz→null. Wire reachability traced in source rather than assumed: protocol.ts:223 sets code='INVALID_REQUEST' + status=400, runtime/src/domains/meta.ts serves it via deps.errorFromThrown, http-dispatcher.ts:764 passes code/status through, and INVALID_REQUEST is ledger-registered to @objectstack/metadata-protocol so it is not demoted to declaredCode; the documented body matches buildApiError's actual output shape {success:false,error:{code,message,httpStatus}}. GATE UNION re-run AFTER the final commit, at 586e4cb21 (= PR head): check:nul-bytes PASS, check:doc-anchors PASS, check:role-word PASS, check:docs-redirects PASS, check:error-status-conformance PASS, check:docs-audit-scope PASS, and (spec, under flock) check:empty-state PASS, check:liveness PASS, check:strictness-ledger PASS, check:variant-docs PASS. The first six-plus-four were derived with scripts/pm/dispatch-gates.mjs against the actual changed paths; check:doc-anchors was ADDED beyond the derivation because the diff introduces a cross-page fragment link — it is what verified the new anchor resolves ('241 internal #fragment link(s) ... all resolve to a real heading') rather than trusting a hand-computed slug. NOTE on the docs-drift advisory: scripts/docs-audit/affected-docs.mjs derives from changed PACKAGE sources, so for this docs-only diff it reports '0 docs ... across 0 changed package(s)' and prints no 'what this run could not see' section — structurally silent, and therefore NOT evidence of correctness in either direction. `skip-changeset` applied and confirmed by read-back (labels: ['skip-changeset']).",
      "open_questions": [],
      "out_of_scope_findings": [
        "filed as #9243: the sibling /meta refusal ('... is not a metadata type', #8421's refuseUnmintableMetaType) has no catalog entry either and shares INVALID_REQUEST/400 with the spelling refusal — told apart only by message, and gated by two non-obvious exemptions (compound arity, pre-existing namespace). Filed, not fixed; my entry carries only a one-line disambiguation, which was the minimum needed to keep an entry keyed on the CODE from being false.",
        "filed as #9244 (finding): check:error-status-conformance excludes ledger codes on the stated premise that 'neither page publishes their status' — THIS PR falsifies that premise by publishing 400 for a ledger code in error-catalog.mdx, so the new status statement is reconciled by nothing. The gate passes correctly by its own rules; its stated bound is what went stale."
      ]
    }

    Generated by Claude Code

  6. added a commit that references this issue on Aug 17, 2026
    2abb66b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:devxDomain lane — seat card indexed by label:pm:seatpm:queueReady for the PM dispatch loop

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions