Skip to content

[finding] Five GraphQL residue sites in skills/** still teach a removed surface, and one is mirrored into ai/skills-reference.mdx #10846

Description

@os-zhuang

Found while implementing #10832 (the /graphql endpoint contract in content/docs/api/).
Filed rather than fixed: the source of truth is skills/**, which is governed /
human-merge-only
, so patching the consumer doc page alone would only make it disagree with
the skill it catalogs.

The residue

/graphql is not mounted — packages/runtime/src/http-dispatcher.ts:2026 is
// /graphql removed — GraphQL is not in the product plan (#2462 follow-on), there is no
createGraphQLDomain among the fifteen domains at http-dispatcher.ts:556-574 (0 hits
repo-wide in packages/*/src), and no handleGraphQL in the runtime. Five sites in the
shipped skills still describe it as live:

Site Text Why it is wrong
skills/objectstack-api/SKILL.md:19 tags: rest, graphql, endpoint, auth, realtime, server The skill's own description one line above lists REST endpoints, auth providers, realtime channels, error envelopes, batch/versioning contracts — no GraphQL. The tag contradicts the body.
skills/objectstack-data/SKILL.md:94 `apiEnabled` | `true` | Expose via automatic REST / GraphQL APIs There is no automatic GraphQL API. apiEnabled exposes REST (and MCP).
skills/objectstack-platform/SKILL.md:395 Mount explicit routes for auth, GraphQL, storage, discovery /graphql is not mounted at all. (/storage in the same line is also stale — per http-dispatcher.ts:556-574's comment the two-route storage bridge was retired in #4087 and service-storage mounts its own surface.)
skills/objectstack-formula/SKILL.md:428 | `GraphQL.ComputedField` | `expression` | cel | Listed as a CEL expression host. No such surface exists.
skills/objectstack-formula/SKILL.md:479 | `api/graphql` | cache key | Same — names a api/graphql coordinate that has no module.

The mirror

content/docs/ai/skills-reference.mdx:156 reproduces the first row verbatim
(**Tags:** rest, graphql, endpoint, auth, realtime, server``). That page is
hand-written and is a catalog of the skills, so it should be corrected in the same change
as skills/objectstack-api/SKILL.md:19 — not before it, or the catalog and the skill drift
apart in the other direction.

Why this is worth a card

These files are the ones AI assistants load to learn the platform. A tag and a property table
that name a surface the runtime removed is exactly the input that generates client code
against a route which 404s — the same failure mode #10710 and #10832 fixed on the human-facing
docs, but aimed at the generated-code path instead of the reader.

Note skills/** is scanned by check:role-word (its own output reports skills 36 files), so
the corpus is already in a gate's population — it is reachable, just not checked for this.

Not in scope: skills/objectstack-formula/SKILL.md rows that name GraphQL as a general
industry concept, if any reviewer finds them; the five above all assert an ObjectStack surface.

Back-links: #10832, #10710, #10583, #10835

Generated by Claude Code

Activity

  1. huangyiirene commented on Aug 21, 2026

    @huangyiirene
    Collaborator

    Triage: routed domain:skills + finding + documentation, type Task. The five sites live in skills/** (published skills — governed, human-merge-only) and the skills lane self-triages its findings, so no grading here. Two notes for that seat: ① the mirror row in content/docs/ai/skills-reference.mdx:156 must move in the same change as skills/objectstack-api/SKILL.md:19 per the body's drift argument; ② published-skills PRs carry the whole-package value-density review question and the net-line budget discipline.


    Generated by Claude Code

  2. os-zhuang commented on Aug 22, 2026

    @os-zhuang
    ContributorAuthor

    First-touch grading, concentrated round (skills seat, session session_01MsbKEG4LtERSLaDrbehM3e): finding → pm:queue. The published skills/** catalog is the platform's highest-value external face (maintainer 2026-08-21), and five sites teaching a removed surface are exactly the input that generates client code against a 404 — plus the /storage staleness noted in passing on the same line. The mirror (ai/skills-reference.mdx) corrects in the SAME change, per the card. Batch note: dispatches alongside the sharingModel-examples card (same catalog face) with a file-overlap check at dispatch; fold only if the surfaces intersect. Governed face — draft PR, human merge.


    Generated by Claude Code

  3. self-assigned this
    on Aug 22, 2026
  4. os-zhuang commented on Aug 22, 2026

    @os-zhuang
    ContributorAuthor

    Claim: session_01MsbKEG4LtERSLaDrbehM3e branch=claude/issue-10846-skills-catalog-pair

    skills 车道执行席认领——对子派发锚点(成员:本卡 + #10925,对外 skills catalog 面)。派发时文件重叠核查完毕:两卡同触 skills/objectstack-data/SKILL.md ⇒ 按定级预案合并为一次派发一个 PR,一员一提交各带 Fixes。范围:本卡五处 GraphQL 残留 + 镜像页 content/docs/ai/skills-reference.mdx:156 同笔更正;#10925 四处 sharingModel 缺失(修法钉在已合并的 #10714 扫掠先例)+ 修毕后扩 check-doc-security-posture.mjs 根到 skills/(先修后扩的时序即该卡自述的防「门生而红」陷阱)。治理面(skills/** 命中即整 PR 治理):draft PR + 人工合并。⚠️ 落地提示同 #11126/#11129/#11137:入队将撞 Console Pin Gate 确定性红,与三单一起等 pin 链修复后统一处理。


    Generated by Claude Code

  5. added a commit that references this issue on Aug 22, 2026
    b9c8009
  6. os-zhuang commented on Aug 22, 2026

    @os-zhuang
    ContributorAuthor

    os-dev-report

    {
      "issue": 10846,
      "family": [10846, 10925],
      "status": "needs_decision",
      "branch": "claude/issue-10846-skills-catalog-pair",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/11141",
      "premise_still_valid": true,
      "premise_per_member": {
        "10846": "VALID, all five sites plus the mirror still present and still wrong at the card's exact line numbers (no drift). Runtime re-verified at fix time: 0 hits for `createGraphQLDomain` under packages/*/src; `handleGraphQL` only in CHANGELOGs; http-dispatcher.ts:2069 carries the removal comment (card said :2026). The card's parenthetical about `/storage` on the platform line is ALSO correct and was verified before touching: adapters/hono/src/index.ts:423 is the `Storage: deliberately NOT mounted (#4087)` block, and the dispatcher carries the matching `No /storage domain (#4087)` note. Corrected in the same edit as instructed.",
        "10925": "VALID, all four `ObjectSchema.create()` examples still omit `sharingModel`. Line numbers drifted as the card predicted: data 214/254/321 -> 214/254/323 after commit 1, upgrade 635 -> 635. None already fixed; no delta to report."
      },
      "commits": [
        "b9c8009cd docs(skills): drop the five GraphQL residue sites and the stale /storage mount — Fixes #10846",
        "e87585fa5 fix(skills): declare sharingModel on the 4 catalog examples, then scan skills/ for it — Fixes #10925"
      ],
      "gates": {
        "derived_how": "node scripts/pm/dispatch-gates.mjs with no hand-fed paths, at final commit e87585fa5 — 25 families matched, all run. Exit codes captured by redirect-then-capture, never after a pipe.",
        "green_24": [
          "check:doc-security-posture (the extended gate) — `26 ObjectSchema.create example(s) in 227 marked block(s) across 237 prose file(s) in 2 root(s) carry an os validate-clean security posture`; per-root census `docs 22 create site(s) in 191 marked block(s) across 189 .mdx file(s)` / `skills 4 create site(s) in 36 marked block(s) across 48 .md file(s)`. BORN GREEN, as the card required.",
          "check:doc-authoring — `doc authoring guard: 389 files clean — no bare metadata literals.`",
          "check:role-word — `Scanned: 225 .md/.mdx file(s) read across 2 root(s) — content/docs 189, skills 36.` (skills corpus in population, no new occurrences)",
          "check:skill-compatibility — `11 SKILL.md file(s) reconciled against 78 workspace packages`",
          "check:skill-frame-sync — `4 copies of the decision frame are structurally isomorphic across 3 files`",
          "check:nul-bytes — `OK (scanned 6447 text file(s) ...; no raw ASCII control bytes)`",
          "check:doc-formula-expressions, doc-anchors, doc-frontmatter, docs-audit-scope, docs-redirects, published-readme-links, pm-governed-merges, cross-package-test-inputs, slot-lookup, test-source-alias, type-source-resolution, ci-filter-parity, plugin-teardown-shape, affected-docs, and the four spec-liveness-check families (check:liveness, check:empty-state, check:strictness-ledger, check:variant-docs) — all exit 0"
        ],
        "red_1": "check:skills-token-ratchet — `skills/objectstack-data/SKILL.md is 13817 tokens; the ratchet ceiling is 13797 (over by 20).` and `skills/objectstack-upgrade/SKILL.md is 8335 tokens; the ratchet ceiling is 8325 (over by 10).` See open_questions[0]. Deterministic, not flaky.",
        "changeset": "NONE OWED, verified not assumed: packages/lint `files` is [dist, README.md, CHANGELOG.md], no `bin`, dist-only `exports` — scripts/** ships to no consumer, and no package src/ is touched. Declared with the `skip-changeset` label. Read back on the PR: labels are [documentation, size/m, skip-changeset], so the label survived the bots' whole-set PUT. An empty-frontmatter changeset was NOT used — scripts/check-empty-changeset.mjs rejects newly-added ones outright."
      },
      "tests": "All at final commit e87585fa5. Dependency closure built first in the fresh worktree (`pnpm --workspace-concurrency=2 --filter '@objectstack/lint...' build`, under scripts/pm/os-verify-lock.sh — `VERDICT command-exit 0 · held the lock 141s`); the gate imports validateSecurityPosture from dist, so an unbuilt run failed loudly with ERR_MODULE_NOT_FOUND rather than reading stale output. Gate self-test green: `self-test: ... judges the skills root by its own extension AND marker (neither spelling crosses); and holds the exemption ledger to the self-invalidating discipline in both directions.` REVERSE-VERIFICATION of the extended gate, from the COMMITTED state: re-removed the support_case `sharingModel`, confirmed the mutation ON DISK first (occurrence count 3 -> 2, plus the three-line site read back showing the key absent, plus `git diff --stat` 1 deletion) — not inferred from the edit tool's exit code — then ran the gate: exit 1, `skills/objectstack-data/SKILL.md:323  object \"support_case\"  [security-owd-unset]`. Predicted direction was RED and RED is what happened. RESTORE LEG, reported honestly: the trap ran `git checkout HEAD -- <relative path>` while cwd had moved into packages/lint, so it printed `error: pathspec ... did not match any file(s) known to git` AND THEN printed its own `RESTORED (trap)` line — a false success. Caught by re-reading `git status`, which still showed the file modified. Restored by hand, verified byte-identical (occurrence count back to 3, site reads back with the key, `git status` clean), and the gate re-run on the restored tree returned to the green census above. No mutation survived into any later measurement. No package unit tests exist for a scripts/ gate; the script's own self-test is its test surface and it was extended with a skills leg.",
      "open_questions": [
        {
          "question": "MEMBER 2 CANNOT LAND AS-IS. check:skills-token-ratchet is shrink-only with `⛔ MAINTAINER-ONLY` on the other direction, and every ceiling in the catalog sat at EXACTLY ZERO headroom before this PR. The four `sharingModel` lines are required by a gating-tier security rule (SECURITY_OWD_UNSET, severity error) and cost 30 tokens across two files with nowhere to put them: objectstack-data +20, objectstack-upgrade +10. That is the irreducible minimum — I already dropped my own explanatory comment on the crm_lead line to get upgrade from +21 down to +10. The gate names exactly two remedies and both are maintainer-only. Note the per-file unit hides a real fact: the BUNDLE grows by only 3 tokens (117919 -> 117922), because commit 1's residue deletions pay back 27 of the 30 — they just land in the wrong files (formula -19, platform -6, api -2).",
          "options": [
            "A — Raise the two ceilings by exactly the measured deltas (data 13797 -> 13817, upgrade 8325 -> 8335), with the ruling quoted in the PR body as the gate's own text requires. Cost: 30 tokens on the bundle, of which 27 are already paid back elsewhere in the same PR. Precedent shape exists in the file (CEILING_BASIS already carries a second, PR-specific basis).",
            "B — Name the text to DELETE from objectstack-data and objectstack-upgrade as payment (~120 bytes total). Keeps the ratchet's discipline literally intact, but the choice of what to cut from the platform's highest-value published surface is an editorial call outside both cards, so it needs to be the maintainer's pick, not mine.",
            "C — Land commit 1 alone now and defer member 2. Commit 1 is clean, all-green and only SHRINKS the bundle (-27 tokens); it is the FIRST commit on the branch, so it splits trivially. Cost: #10925's security defect stays live in the published catalog, and the gate extension stays deferred with it (extending the roots without the fixes makes the gate born red — the exact trap #10618 avoided).",
            "D — Exempt os:check-required schema keys from the token ratchet. NOT RECOMMENDED and listed only to be dismissed: it makes the ratchet's unit negotiable per-author, which is precisely the control the 2026-08-21 ruling exists to remove."
          ],
          "recommendation": "A, then C as the fallback if the ruling takes time. On real business need: these four lines are not a speculative surface — os validate rejects the copied app today, and the skills catalog is copied verbatim by AI authors, so the cost is paid per reader. On long-term soundness: A keeps ONE opinion about catalog length (the ratchet) and settles this instance by the mechanism the gate itself prescribes, rather than teaching authors that a security fix can be argued out of the budget. On making AI-authored metadata hard to get wrong: this IS that axis — an example that omits the OWD baseline is the leave_request incident's shape reproduced at catalog scale, and the extended gate closes the class permanently. On startup scope discipline: the ask is 30 tokens against a 117,919-token bundle (0.025%), net 3 after commit 1's paybacks, with no prose expansion whatsoever — every added byte is a required schema key. I did NOT self-fund by deleting catalog prose and did NOT touch a ceiling; both are explicitly the maintainer's call and either would have been an unreviewable change to a governed surface."
        },
        {
          "question": "Value judgment on ONE of the four values, flagged rather than decided (it does not block). The card's fix shape says mirror a real example-app counterpart where one exists. `crm_lead` is the one exact name match — examples/app-crm/src/objects/lead.object.ts is `name: 'crm_lead'` with `sharingModel: 'public_read_write'` — so I mirrored it. But that value carries an explicit ADR-0090 D1 comment calling it a grandfather stamp: `record isolation for this demo object is intentionally org-shared`. Mirroring therefore teaches public_read_write in the published upgrade skill.",
          "options": [
            "A — Keep the mirror (`public_read_write`). Skill and example app agree about one object name; a reader diffing them finds no contradiction.",
            "B — Use `'private'` for crm_lead too, consistent with the other three, and accept that the skill's crm_lead differs from app-crm's."
          ],
          "recommendation": "A as landed, but genuinely close and a reviewer should confirm. A is what the card's own fix shape prescribes and avoids drift between the catalog and the app a reader is pointed at. The case for B is that a demo's grandfather stamp is not a value worth teaching, and the three data-skill objects took `'private'` for exactly that reason — I only diverged for crm_lead because the object NAME matches exactly, which the showcase counterparts do not (`showcase_account` / `showcase_invoice` are differently-named objects, so they are not counterparts and were defaulted)."
        }
      ],
      "out_of_scope_findings": [
        "filed as #11140: two GraphQL residue sites in package SOURCE comments — packages/spec/src/data/object.zod.ts:252 (`Enable REST/GraphQL API access` on apiEnabled; its own .describe() one line below is already correct) and packages/adapters/hono/src/index.ts:105-106 (createHonoApp's JSDoc still names a `GraphQL raw result` route). Same defect class as this card one surface further in; the hono JSDoc is the likely ORIGIN of the stale platform-skill line this PR fixes, `/storage` included. Not folded in: different surface, different gate family, and a governed skills PR is the wrong place for it. Unassigned, `finding` label, no pm:queue. Dedup: search_issues on two phrasings returned only CLOSED cards (#10835, #10710, #10832, #10583, #7707, #9436, #4117), none covering either site."
      ],
      "deviations": [
        "Both members are committed on ONE branch/PR as dispatched, even though member 2's gate is red. Rationale: the claim comment already records this PR family as expected to sit unmerged behind the Console Pin Gate, so a second known-red gate with an explicit decision attached blocks nothing that was not already blocked — and it puts the complete, verified change in front of the decision-maker. Member 1 is the FIRST commit and is independently clean, so option C above is a trivial split.",
        "The `skills/**` net-line budget was NOT self-raised and catalog prose was NOT self-deleted to fund the fix; the shortfall is reported instead (open_questions[0]).",
        "PR body reports both required readings: per-file whole-file before/after and whole-package before/after, in lines AND in the ratchet's own token convention."
      ],
      "summary": "Member 1 (#10846) is DONE and clean: all five GraphQL residue sites fixed in each file's own idiom, the `/storage` staleness on the platform line verified against http-dispatcher.ts and adapters/hono and corrected in the same edit as instructed, the two formula rows DELETED rather than replaced because nothing real fills either slot (no cache-key template surface exists at all), and the ai/skills-reference.mdx mirror moved in the SAME commit. skills/** now has zero GraphQL hits, and the commit SHRINKS the published bundle by 27 tokens. Member 2 (#10925) is implemented and verified but BLOCKED on a maintainer decision: the four sharingModel declarations are correct and the check-doc-security-posture skills/ root extension is born green with a passing reverse-verification, but the four required lines push check:skills-token-ratchet over on two files that had zero headroom, and both remedies the gate names are marked MAINTAINER-ONLY. Reporting the gap rather than self-funding it. One out-of-scope finding filed (#11140).",
      "cleanup": "Worktree /home/user/objectstack-issue-10846 retained pending the decision above (removing it now would discard the branch checkout the follow-up patch round needs); no dev servers or background processes were started, nothing to tear down."
    }

    Generated by Claude Code


    Generated by Claude Code

  7. os-zhuang commented on Aug 22, 2026

    @os-zhuang
    ContributorAuthor

    Correction to one line of the report above (not a second report — the os-dev-report comment stands as the record).

    The cleanup field says the worktree was retained pending the decision. On reflection that was the wrong call: cleanup is an unconditional step of the task, and holding disk in a shared container against a decision that may take a while is not mine to trade. /home/user/objectstack-issue-10846 has been removed — rm -rf <path>/node_modules then git worktree remove with NO --force, which is itself the proof nothing uncommitted was left behind. Both commits are pushed to claude/issue-10846-skills-catalog-pair, so a follow-up patch round re-creates a worktree from the branch in about a minute and loses nothing.

    Everything else in the report is unchanged.


    Generated by Claude Code


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions