Skip to content

[finding] Catalog anatomy drift: hand-authored per-topic files live under references/ (reserved for generated pointers) in objectstack-platform and objectstack-data, unlinked or linked only by path — PLAT-G-02 / the data-hooks.md shape, catalog-wide #14655

Description

@os-litant

Recorded by the skills lane seat (session session_01LraLgQVGq8egUwfYZpbYt1) from the optimization program's per-package audits (program anchor #14292): the platform audit's PLAT-G-02 (deferred on #14299 as "the catalog follow-up" in the seat's ACCEPT on PR #14351) and the same shape measured on objectstack-data in the data flight (references/data-hooks.md, now the canonical hooks anchor after rules/hooks.md was deleted in PR #14427). Filed so that #14299 can close on its last in-scope item; the placement question is catalog-wide and belongs to one pass, not to a per-package flight.

What

skills/README.md (the catalog anatomy, generator-owned) reserves references/ for the generated _index.md ("generated pointers … do not hand-edit") and assigns hand-authored per-topic files to rules/ ("(optional) detailed per-topic rule files linked from SKILL.md"). Two packages violate that on origin/main today:

package file measured
objectstack-platform references/plugin-hooks.md hand-authored; 2,413 tokens after PR #14351; the platform flight linked it directly from SKILL.md (the "two hops" finding), but its location still contradicts the anatomy
objectstack-data references/data-hooks.md hand-authored; the canonical hooks anchor since PR #14427 deleted rules/hooks.md; objectstack-ui, objectstack-automation and objectstack-platform now point at it by path

Both are load-bearing anchors that other packages cite by path (references/data-hooks.md from ui/automation/platform; references/plugin-hooks.md from data's References block), so a move is a multi-package rename with pointer updates, a check:skill-identifier-liveness Leg-2 binding check (bindings are keyed by file path + heading) and ceiling-row renames in scripts/check-skills-token-ratchet.mjs — one pass, after the in-flight splits (#14298, #14300 r2, #14297 r2) land, so the rows do not race.

Two honest resolutions, both need a lane decision, not a dev's guess

  1. Move both files to rules/ and update every cross-package pointer in one PR (governed skills/**, draft, human merge) — the anatomy stays as written.
  2. Amend the anatomy (the generator's source for skills/README.md) so references/ may also hold hand-authored reference material that is linked from SKILL.md, and require the link — the files stay where three packages already point.

Option 2 is cheaper and matches what the flights converged on (both files are now linked directly); option 1 matches the text. Either way the generator-owned skills/README.md is regenerated, never hand-edited.

Not this card

The content of either file (audited and trimmed in PR #14351 / #14427); the check-skill-examples.ts SURFACES gap (platform fences unreachable — separate ledger item); the token re-lock pass.

Dedupe: the lane's 46 open domain:skills cards were listed by the seat at 16:4xZ — none records the placement question; PLAT-G-02 exists only as a row in #14299's audit record and a line in the seat post's ledger.

Refs: #14292 · #14299 (PLAT-G-02) · #14297 (data hooks anchor) · PR #14351 · PR #14427.

Activity

  1. self-assigned this
    on Sep 3, 2026
  2. os-litant commented on Sep 3, 2026

    @os-litant
    CollaboratorAuthor

    Claim: PM loop round 8, slot 5 (the slot freed when objectui#7405 delivered)
    Session: session_01LraLgQVGq8egUwfYZpbYt1
    Branch: claude/issue-14655-references-anatomy
    Worktree: objectstack-issue-14655
    Domain: skills (the seat grades its own programme's follow-up cards)

    Lane decision: option 2 — amend the anatomy, keep the files where three packages already point. Reasons, measured at origin/main df657d9df (01:01Z 09-03):

    • Both files are already linked directly from their package's SKILL.md (objectstack-data/SKILL.md:50, :173, :522; objectstack-platform/SKILL.md:657, :790) and cited by path from automation (SKILL.md:705), data's rules/validation.md (:24, :279) and each other. Option 1 is a multi-package rename with Leg-2 binding checks and ceiling-row renames in the ratchet script for zero reader value — the reader reaches the same text either way.
    • ⚠️ One premise of this card is corrected at dispatch: the "Skill anatomy" block is hand-authored prose outside the generated markers — packages/spec/scripts/build-skill-docs.ts:12-14 rewrites only between <!-- BEGIN/END GENERATED: skills --> and preserves everything else, and the block sits after <!-- END GENERATED: skills --> (skills/README.md:44-58). So there is no generator source to amend; the change is the block itself, and check:skill-docs --check must stay green to prove the generated region was not touched.
    • skills/README.md is outside the token-ratchet population (scripts/check-skills-token-ratchet.mjs:133, self-test :790), so no ceiling row moves; the lane's shrink-or-neutral rule still applies to the file.

    Scope is the anatomy block only: references/ may hold hand-authored reference files linked from SKILL.md, rules/ keeps its per-topic rule role, _index.md stays "do not hand-edit". No file moves, no pointer edits, no gate added, no other README sentence touched (the README's other ledger items — :100 and :104-105 — are the seat's and are not this card's). Governed skills/** ⇒ draft PR, Fixes #14655, review requests are the seat's step.


    Generated by Claude Code

  3. os-litant commented on Sep 3, 2026

    @os-litant
    CollaboratorAuthor

    Claim: dev seat (os-dev subagent of the dispatching PM session — same session id, distinct seat)
    Session: session_01LraLgQVGq8egUwfYZpbYt1
    Branch: claude/issue-14655-references-anatomy
    Worktree: objectstack-issue-14655
    Branch point: df657d9df1fac5a2222f183008532613a1df585f — identical to the seat's measurement point, so no drift to report there.

    Scope taken as dispatched: the "Skill anatomy" block in skills/README.md only (lane decision option 2). No file moves, no pointer edits, no new gate, no other README sentence.


    Generated by Claude Code

  4. os-litant commented on Sep 3, 2026

    @os-litant
    CollaboratorAuthor

    os-dev-report

    {
      "issue": 14655,
      "status": "done",
      "branch": "claude/issue-14655-references-anatomy",
      "head_sha": "3b9bf943535b0a8f98742eabf41503ffecb2e356",
      "branch_point": "df657d9df1fac5a2222f183008532613a1df585f",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/14786",
      "pr_state": "draft, stays draft (governed skills/**); labels documentation, size/xs, skip-changeset",
      "summary": "Lane decision option 2 implemented as one changed line in skills/README.md: the anatomy tree's `references/` entry now carries the comment 'may also hold hand-authored reference files linked from SKILL.md'. The `_index.md` child keeps both of its comment lines byte-identical (generated pointers, do not hand-edit, full gen:skill-refs command), and SKILL.md / rules/ / contracts/ / evals/ are byte-identical. No file moved, no pointer edited, no gate added, no other README sentence touched. The card's illustrative examples for the new comment (event lists, payload tables, hook references) were deliberately omitted as flavour rather than contract, under the shrink-or-neutral budget; the requirement itself (optional, hand-authored, linked from SKILL.md) is stated in full. Diff: 1 file, +1/-1.",
      "premise_false": [
        "The card's 'the generator-owned skills/README.md is regenerated, never hand-edited' is false for this block, exactly as the seat corrected at dispatch: packages/spec/scripts/build-skill-docs.ts:12-13 rewrites only between the BEGIN/END GENERATED: skills markers and preserves prose outside them; the END marker is skills/README.md:44 and the anatomy block is :50-62. The block is hand-authored and was edited by hand.",
        "Minor drift from the seat's claim comment: the block is at :50-62 at this branch point (heading :50, tree :52-62), not :44-58 — :44 is the END marker line. No effect on the decision.",
        "Anchor links re-verified at the branch point and unchanged: objectstack-data/SKILL.md:50, :173, :522 and objectstack-platform/SKILL.md:657, :790.",
        "Branch point equals the seat's measurement point df657d9df, so no other binding fact drifted."
      ],
      "token_delta": {
        "file": "skills/README.md",
        "metric": "ceil(utf8_bytes/4)",
        "before": {"bytes": 7941, "tokens": 1986},
        "after": {"bytes": 8018, "tokens": 2005},
        "delta": {"bytes": 77, "tokens": 19},
        "note": "Net +19, not neutral. The only in-block way to pay for it was folding the two _index.md comment lines into one, which would have deleted the runnable 'pnpm --filter @objectstack/spec gen:skill-refs' command the dispatch told me to keep. Reported honestly rather than bought. skills/README.md is outside the ratchet population (check-skills-token-ratchet.mjs:133, self-test :790); the ratchet run confirms no ceiling row exists or moved."
      },
      "gates": [
        {"cmd": "node scripts/check-ci-filter-parity.mjs", "exit": 0, "verdict": "OK: all 130 declared cross-package glob(s) (92 unique) are covered by core or crosspkg, every crosspkg entry still covers one, and the test job's if: still names both filters."},
        {"cmd": "node scripts/check-cross-package-test-inputs.mjs", "exit": 0, "verdict": "OK: 25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob."},
        {"cmd": "node scripts/check-shard-attestation.mjs", "exit": 0, "verdict": "check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s)."},
        {"cmd": "node scripts/check-test-completeness.mjs", "exit": 3, "verdict": "NOT MEASURED — 'PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named.' Its own text: 'the local reading for this gate is NOT MEASURED. It is not a red, and there is nothing here to fix.'"},
        {"cmd": "pnpm --filter @objectstack/lint run check:doc-formula-expressions", "exit": 0, "verdict": "check:doc-formula-expressions: 22 record-scoped formula example(s) across 426 files / 1365 TS blocks judged clean by @objectstack/formula. (First run exited 3 on unbuilt prerequisites; converted into a real reading by building @objectstack/formula then @objectstack/lint, both under the lock.)"},
        {"cmd": "pnpm --filter @objectstack/spec run check:skill-docs", "exit": 0, "verdict": "skills/README.md OK · content/docs/ai/skills-reference.mdx OK · 'Skill docs in sync'"},
        {"cmd": "pnpm check:agent-test-spelling", "exit": 0, "verdict": "check-agent-test-spelling: 0 violations — 430 file(s), 5698 bare separator token(s), 1382 launcher-rooted run(s)."},
        {"cmd": "pnpm check:corpus-claim-drift", "exit": 0, "verdict": "check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling."},
        {"cmd": "pnpm check:cross-package-test-inputs", "exit": 0, "verdict": "All 117 self-test cases passed. OK: 25 package(s) read outside themselves, all declared."},
        {"cmd": "pnpm check:doc-authoring", "exit": 0, "verdict": "doc authoring guard: 46 published skill files clean — no internal issue-id references."},
        {"cmd": "pnpm check:merge-driver", "exit": 0, "verdict": "check-regen-pending self-test passed."},
        {"cmd": "pnpm check:pm-governed-merges", "exit": 0, "verdict": "check-governed-merges --self-test: 243 assertions pass."},
        {"cmd": "pnpm check:role-word", "exit": 0, "verdict": "check-role-word: OK, no new occurrences of the reserved word."},
        {"cmd": "pnpm check:skill-compatibility", "exit": 0, "verdict": "check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 79 workspace packages."},
        {"cmd": "pnpm check:skill-frame-sync", "exit": 0, "verdict": "check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files."},
        {"cmd": "pnpm check:skill-identifier-liveness", "exit": 0, "verdict": "check-skill-identifier-liveness OK — Leg 1: 465 citation(s) over 46 published file(s); Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s)."},
        {"cmd": "node scripts/check-skills-token-ratchet.mjs", "exit": 0, "verdict": "check-skills-token-ratchet: 36 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted."},
        {"cmd": "node scripts/check-skills-token-ratchet.mjs --self-test", "exit": 0, "verdict": "check-skills-token-ratchet self-test: 64 cases pass."},
        {"cmd": "node scripts/check-nul-bytes.mjs", "exit": 0, "verdict": "check-nul-bytes: OK (scanned 8053 text file(s); no raw ASCII control bytes)."}
      ],
      "gates_note": "18 measured green, 1 NOT MEASURED (CI-only input), 0 red. The list is the union re-derived AFTER the last edit by 'node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands' at head 3b9bf9435 (16 families, every one matched via skills/README.md), byte-identical to the pre-ablation derivation, plus the three the dispatch named directly (token ratchet, its self-test, nul-bytes). Every run went through scripts/pm/os-verify-lock.sh; exit codes captured by redirect before any pipe. Note for the seat: the lock takes no --slot flag as the dispatch spelled it — the mechanism is the env var OS_VERIFY_LOCK_SLOT, which I set to issue-14655 before the first acquisition.",
      "reverse_verification": {
        "gate": "pnpm --filter @objectstack/spec run check:skill-docs",
        "rebuild": "none owed — the gate is 'tsx scripts/build-skill-docs.ts --check', reading the markdown sources from disk; no compiled artifact sits between mutation and measurement",
        "mutated_leg": {"mutation": "one character inserted INSIDE the generated region (the Formula row's domain cell)", "on_disk_proof": "anchor count 1 to 0, injected count 0 to 1; blob 2940ce52 to e023126d", "exit": 1, "verdict": "skills/README.md is out of date — run pnpm --filter @objectstack/spec gen:skill-docs"},
        "restored_leg": {"how": "git checkout HEAD -- skills/README.md, inside a trap on EXIT INT TERM with absolute paths", "on_disk_proof": "blob back to 2940ce52 = the HEAD blob; git diff HEAD 0 bytes; git status --porcelain 0 lines", "exit": 0, "verdict": "Skill docs in sync"},
        "predicted_direction": "red naming skills/README.md — observed"
      },
      "eslint_narrowing": "Declared narrowing, all three pieces present. (1) Population read from eslint.config.mjs itself: base block :971 is files ['**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}'] and every later block (:1015, :1054, :1103, :1172, :1212, :1238) narrows within those extensions; no block admits .md. (2) --format json count: one entry for skills/README.md, 0 errors, 1 warning, the warning being 'File ignored because no matching configuration was supplied'; eslint exited 0. (3) Invariance: no parserOptions.project and no projectService anywhere (the config's own comment at :328 says so), so no file's verdict is a function of another file's contents and a markdown-only diff cannot move a lint result anywhere.",
      "changeset": "none; skip-changeset applied. scripts/check-empty-changeset.mjs:359-361 enumerates 'releases nothing (.github/, .claude/, skills/, docs/, content/, examples/, tests-only, and the like)' and routes it to this label. The diff is exactly one file inside skills/.",
      "channel_notes": [
        "REST is 403 for this seat: both a repo-scoped read (GET /repos/objectstack-ai/objectstack) and an issue read returned 403 with the token in env, and gh is absent. Declared channel switch: labels went through MCP — read current set (documentation, size/xs), union with skip-changeset, whole-set write, then a comparative read-back returning exactly documentation, size/xs, skip-changeset. Nothing stripped, nothing missing.",
        "mcp__github__issue_read method get_labels cannot resolve a PR number ('Could not resolve to an Issue with the number of 14786'), twice. The working label read is list_pull_requests filtered by head branch with fields ['labels'] — worth recording in the lane's platform readings.",
        "GitHub's body sanitizer ate the angle-bracket placeholder in the PR body's before/after blocks on the first write, leaving 'skills//'. Caught by the full read-back, repaired by spelling the placeholder SKILL-NAME with the substitution declared in the body itself; the second read-back is clean end to end. The PATCH also dropped the platform's session-URL footer to nothing, as measured behaviour predicts — the session URL survives in the body's own prose."
      ],
      "out_of_scope_findings": [
        "skills/objectstack-ui/references/react-blocks.md is a GENERATED file (its own header: 'GENERATED by packages/spec/scripts/build-react-blocks-contract.ts — do not edit') sitting under references/ beside _index.md, and grep finds no link to it from objectstack-ui/SKILL.md. It is neither the generated _index.md the anatomy names nor the hand-authored linked material this PR admits, so the amended sentence does not cover it. Likely overlaps the contracts/ line the dispatch assigned to #14559 — recorded here for the seat to dedup and file, not filed from this seat.",
        "The 'linked from SKILL.md' requirement is text only, with no gate. Out of scope by dispatch. If the lane wants one, the shape is: every non-_index.md file under a published skills/*/references/ is referenced by that skill's SKILL.md — but the react-blocks.md triage above has to land first, or the gate reds on a generated file on day one."
      ],
      "mcp_calls": 12
    }

    Generated by Claude Code

  5. os-litant commented on Sep 3, 2026

    @os-litant
    CollaboratorAuthor

    ACCEPT — skills-lane seat (session session_01LraLgQVGq8egUwfYZpbYt1), reviewer of record, verified against GitHub and the seat's own checkout, not the report.

    • PR docs(skills): admit hand-authored reference files under references/ in the catalog anatomy #14786 exists, is DRAFT, head 3b9bf943, one file, +1 −1; labels documentation · size/xs · skip-changeset; no needs:contract-review (catalog anatomy text, no contract claim).
    • Diff read by the seat: skills/README.md:55 ├── references/ gains the trailing comment # may also hold hand-authored reference files linked from SKILL.md; the _index.md child keeps both of its comment lines byte-identical (generated pointers, do not hand-edit, the runnable gen:skill-refs command); the SKILL.md / rules/ / contracts/ / evals/ lines byte-identical; the generated region between the markers untouched — proven by the check:skill-docs ablation (a one-character edit inside the region went red naming skills/README.md; restore proven by blob hash and an empty git diff HEAD).
    • Option 2 is stated in full: references/ may hold hand-authored reference material, optional, linked from SKILL.md; rules/ keeps its per-topic role. The card's illustrative examples (event lists, payload tables) were omitted as flavour — the seat agrees; the requirement is the contract, the examples were not.
    • Budget, accepted with the reason on record: 7,941 → 8,018 bytes = 1,986 → 2,005 tokens (+19). skills/README.md is outside the ratchet population (check-skills-token-ratchet.mjs:133, self-test :790) and outside every published skill bundle; the only in-block payment would have deleted the runnable gen:skill-refs command the brief said to keep. The seat takes +19 on the catalog front page over losing a command an author runs.
    • Premise corrections accepted: the anatomy block is hand-authored prose outside the generated markers (build-skill-docs.ts:12-13); the seat's claim comment placed it at :44-58 — it is at :50-62, :44 being the END marker line; no effect on the decision. Anchor links re-verified unchanged (data SKILL.md:50, :173, :522; platform SKILL.md:657, :790).
    • CI at 3b9bf943: every one of the 37 check runs is success or skipped, read at 2026-09-03T01:32Z — Lint & Repo Gates success (completed 01:28:28Z), all six Test Core shards, the four Type Check legs, Check Changeset success, Governed Surface Queue Guard (draft — correct), Check Documentation Links, the three claim guards.
    • Two findings recorded on the seat ledger, not filed: skills/objectstack-ui/references/react-blocks.md is a generated file under references/ that neither clause of the amended anatomy names and that objectstack-ui/SKILL.md does not link — it overlaps Seam (spec lane, ruled): gen:react-blocks stops emitting skills/objectstack-ui/contracts/react-blocks.contract.json — the markdown rendering becomes the single AI-facing output (#14296 item 3 = A) #14559's contracts/ line and is dedup'd there before any filing; a "linked from SKILL.md" gate is text-only by dispatch, and would red on that generated file on day one, so the react-blocks question lands first.
    • Platform notes for the lane's table: the verify lock's slot is the environment variable OS_VERIFY_LOCK_SLOT, not a --slot flag — the seat's brief spelled it wrong; PR labels are read via list_pull_requests with fields: [labels]; GitHub's sanitizer eats angle-bracket placeholders in PR bodies.
    • Governed skills/** ⇒ stays DRAFT; review requested from os-zhuang + hotlong; human merge is the record. At MERGED the seat strips pm:dispatched (Fixes ⇒ the card closes).

    Generated by Claude Code

  6. os-litant commented on Sep 3, 2026

    @os-litant
    CollaboratorAuthor

    Merge patrol reading 2026-09-03T09:10Z (git fetch origin main, then git log origin/main --grep '(#14786)' in the same minute): PR #14786 merged as 2d40f91468 at 02:35:11Z; this card was closed by os-zhuang at 04:12:18Z. The seat's patrols between 02:35Z and 08:31Z kept listing PR #14786 as a draft at the governed terminal — wrong from 02:35Z on; corrected here and in seat post #7623 at this refresh. pm:dispatched removed at 09:12Z; labels now documentation, domain:skills, priority:p3, read back 09:13Z. Nothing else moves.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions