skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens) - #14427

Merged
os-zhuang merged 4 commits into
mainfrom
claude/issue-14297-skills-data-optimization
Sep 2, 2026
Merged

skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens)#14427
os-zhuang merged 4 commits into
mainfrom
claude/issue-14297-skills-data-optimization

Conversation

@os-litant

@os-litantos-litant commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Part of #14297

Optimization flight for skills/objectstack-data, the largest package in the published
catalog. Implements the card's IMPLEMENT scope from the 43-row audit record (posted
verbatim as a comment on the card). Governed surface (skills/** markdown) ⇒ this PR
stays draft
; needs:contract-review is on both carriers because INC-01 corrects a
contract-semantics claim.

Net: 45,780 → 36,736 hand-authored tokens (−9,044, −19.8%). One published file
deleted, none added, no ceiling raised, every ratcheted file byte-neutral-or-shrinking.

Per-file token delta

FilebeforeafterΔceilingheadroom
SKILL.md13,89212,553−1,33913,8921,339
references/data-hooks.md12,5849,703−2,88112,6112,908
rules/hooks.md2,195deleted−2,195row dropped
rules/indexing.md3,2402,166−1,0743,2411,075
rules/validation.md3,1092,362−7473,109747
rules/naming.md773248−525773525
rules/relationships.md3,7733,490−2833,778288
rules/field-types.md3,5783,57803,5846
rules/lifecycle.md1,5901,59001,5900
rules/datasources.md90390309118
evals/README.md14314301430
package45,78036,736−9,044

references/_index.md (generated, 1,483) untouched.

Two rows differ from the card's projection and are called out rather than forced:

  • rules/field-types.md nets 0, not −50. DATA-D-14 paid −200; the DATA-E-03
    Field.* preamble is what it bought. Cross-file payment is not available (the ratchet
    is per file), so the addition was trimmed twice until it fit inside D-14's payment. The
    file does not grow.
  • evals/README.md unchanged. DATA-H-01 raises a ceiling and is on the card's DEFER
    list.

落点 | before | after

finding落点beforeafter
DATA-B-01 / I-03rules/hooks.md (whole file)2,195 tok calling itself "a reference pointer", then restating 5 sections of the canonical filedeleted; references/data-hooks.md is the single hooks file and the catalog's hooks anchor. Ceiling row dropped
DATA-B-02data-hooks.md:1-26two H1s, two intros saying the same thing, a "When to Use This Skill" inside a referenceone H1, one intro
DATA-B-038-event table ∥ in both filesstated in full twice (466 + 525 tok)one copy (the canonical file's), via the file deletion
DATA-B-04data-hooks.md:1050-1133three registration methods in 566 tokcompact, 4 load-bearing facts kept: AppPlugin auto-binds, the functions map, packageId, and that programmatic binding gets no declarative condition/retry/timeout/onError/async semantics
DATA-B-05data-hooks.md:1136-116010+10 generic DO/DON'Tthe compact 5+5 rules/hooks.md carried
DATA-B-077 sites"no unique validation type" stated seven timesrestatements in validation.md + relationships.md dropped; SKILL.md + the indexing.md scope table keep it
DATA-C-01SKILL.md:162-189two verbatim CLI/HTTP error transcripts (the 400 text word-for-word in objectstack-query)3 lines naming both refusals; the modelling half (mirror field + two-hook maintenance table) stays — this package is its anchor
DATA-C-02validation.md:26-36, 313-331CEL-vs-SQL prose + a ❌/✅ pairpointer to objectstack-formula (the anchor); the inversion rule stays, it lives nowhere else
DATA-C-03data-hooks.md:1209-1275vitest + LiteKernel harnesses importing 4 unresolvable packagesone-line pointer to objectstack-platform, whose frontmatter claims that surface
DATA-C-045 tombstone sitesstandalone narration of removed keys (rls, encryptionConfig, tenancy.strategy, softDelete/versioning, type/partial)deleted; each key is refused by a parse error carrying its own prescription, and objectstack-upgrade owns in-place upgrades. In-line ❌ markers kept where a wrong key sits beside the right one
DATA-C-05SKILL.md:858-971987 tok: 3 near-identical examples for a 4-value enum + Studio-banner narration + 5-bullet guidanceschema block + 4-row lock table + ONE example + 4 lines of enforcement
DATA-D-01/02/03data-hooks.md:1279-1444invented benchmark table (0 hooks ~1ms…), plain-JS "Advanced Topics", generic Troubleshooting, a Summary repeating the DO list verbatimdeleted; the References block survives and absorbs the two cross-package pointers rules/hooks.md carried
DATA-D-04data-hooks.md:765-104610 patterns, 6 of them plain JavaScriptpatterns 1,2,4,5,7,9 deleted; 3,6,8,10 kept and renumbered
DATA-D-05/06/07rules/indexing.mdRDBMS 101, one textbook fact taught seven ways, unsourced Table Size → Max Indexes, pg_stat_user_indexes SQL, 10 best practicesone paragraph on composite order; naming block kept (name is a declared key)
DATA-D-08relationships.md:398-4137 + 4 items restating the file's own tablesdeleted
DATA-D-09/D-10validation.md:355-4385 patterns restating 4 examples on the same page; 10 best practices + 4 unsourced perf claimsdeleted
DATA-D-11naming.md:15-1076 ❌/✅ pairs + restatements + rationale for a rule the regex already statestable + Critical Rules (773 → 248)
DATA-D-12SKILL.md:540-555"CRM Schema Blueprint" pointing at 6 things covered above itdeleted
DATA-D-13SKILL.md:974-987"Advanced Features Checklist" + tombstone footnotedeleted
DATA-D-14field-types.md:360-4113 ❌/✅ pairs duplicating naming.md, the type table, and a lint ruledeleted (autonumber pair survives) — funds DATA-E-03
DATA-D-15SKILL.md:1178-1181the live model-benchmarking doordeleted (platform benchmarking, not app authoring)
DATA-E-01/E-022 blocksself-contained blocks opening { / validations: [ at statement position (TS parses that as a labelled-statement block)real declarations; os:check markers added to the two SKILL.md blocks that compile
DATA-E-03 / G-02rules/field-types.mdzero Field.* in the file whose job is field authoring; corpus is ~92% factoryField.* preamble with the literal ↔ factory mapping
DATA-E-04data-hooks.md patternsfile prescribed body, demonstrated deprecated handler 10 times2 surviving patterns converted to sandboxed body with declared capabilities
DATA-E-05SKILL.md:325-379the one copy-pasteable object diverged from all 31 real onespluralLabel/description/icon/highlightFields added, indexes dropped (1 of 26 corpus files)
DATA-F-01SKILL.md:64-84sharingModel on 31/31 real objects, absent from both property tablesrequired-table row + 4-row value table
DATA-F-02SKILL.md:383-403storage.notNull never mentioned in the packagerequired = write contract, storage.notNull = the DDL
DATA-F-03SKILL.md:71-84icon/pluralLabel/highlightFields undocumentedthree rows
DATA-F-04SKILL.md:1142-11529 data-model lint rules, 0 security rules4 security rows, 3 of them publish-blocking
DATA-F-05SKILL.mddefineObjectExtension, readScope/writeScope — zero corpus usageshrunk to one schema-pointing row each, not deleted (retirement deferred pending #14296; zero usage in examples is evidence, not proof)
DATA-F-06SKILL.md:1129 + frontmatterprescribed {object}.seed.ts; find . -name '*.seed.ts' returns 0 repo-widerow deleted, trigger aligned to src/data/*.ts
DATA-G-016 sitesobjectstack lint and os lint in one file, 60 lines apartnormalised to os
INC-01SKILL.md:393required: true → false "dev auto-heals (autoMigrate:'safe')"corrected — see below
INC-02SKILL.md:398-401stale NOT NULL produces a clean 400corrected — raw driver error

Contract-semantics corrections (why needs:contract-review)

INC-01. The schema-evolution table named the wrong dial and claimed auto-healing. Both
halves are false against the implementation:

  • packages/drivers/driver-sql/src/schema-drift.ts:795-798const expectNullable = field.storage?.notNull !== true; under a comment reading "compared against
    storage.notNull, the explicit physical constraint — NOT against required, which is
    the write-time contract and implies nothing about the column".
  • The emitted drift is severity: 'warning', category: 'needs_confirm',
    op: { type: 'relax_not_null' } (schema-drift.ts:815-826), above a comment saying
    "never auto-applied".
  • packages/drivers/driver-sql/src/sql-driver.ts:10746const safe = drift.filter((d) => d.category === 'safe');. autoMigrate: 'safe' applies only category safe, so
    it never touches this op.

INC-02.schema-drift.ts:800-802 says that exact configuration means "an omitting
write reaches the DB and dies as a raw driver error instead of a clean validation 400" —
the opposite symptom to the one the tell-tale promised.

INC-03 (new, found while rewriting DATA-D-04 pattern 8). The file asserted "There is
NO updateMany" a few hundred lines below a capability table listing updateMany as
"also installed". Both are true of different surfaces and neither said which:
ObjectRepository — what a handler's ctx.api.object() returns
(packages/objectql/src/engine.ts:13563-13600) — has no updateMany; the sandbox repo
does (packages/runtime/src/sandbox/quickjs-runner.ts:544-545). The comment now names its
surface. This is why patterns 3 and 6 were converted to body and pattern 8 was left as a
handler.

premise_false

None. git diff --stat a59f78d HEAD -- skills/objectstack-data was EMPTY at my base
909a4417, so all 43 spans resolved byte-identically and no finding had to be skipped.

One card-level detail did not hold, and needed no action: the card's ANCHOR RULINGS says
the inbound link at rules/hooks.md:202 points at objectstack-platform
rules/plugin-hooks-events.md and must be re-pointed. At base it already pointed at
objectstack-platform/references/plugin-hooks.md. The file is deleted here anyway, and
that pointer is preserved in the surviving References block.

PM mechanical assumptions — measured

  1. Spans byte-identical at a59f78d. TRUE. git diff --stat a59f78d HEAD -- skills/objectstack-data empty; git diff --stat d63c8a25 HEAD -- skills/ empty;
    the ratchet script unchanged since the pin.
  2. Does check:skill-docs demand regenerating skills/README.md?YES, and it runs
    in CI
    (.github/workflows/lint.yml:3986). The frontmatter description changed, the
    gate failed, and pnpm --filter @objectstack/spec gen:skill-docs regenerated
    skills/README.mdandcontent/docs/ai/skills-reference.mdx — the second file was
    not in the assumption. Both diffs are one data-row each. check:skill-refs is green
    and references/_index.md is untouched.
  3. Deleting rules/hooks.md reds the ratchet unless its ceiling row goes. TRUE, and
    verified in both directions from a committed state with a restore trap: with the row
    re-injected the gate prints ✗ check-skills-token-ratchet: cannot read skills/objectstack-data/rules/hooks.md — red, not a skip (#4690) and exits 1; restored
    (blob hash equal to HEAD, git diff HEAD empty) it exits 0.
  4. The os:check rule is in the header of check-skill-examples.ts. TRUE (lines
    17-23): a marker is os:check in an HTML comment on the line directly above the fence.
    The seven would-fail blocks were handled as the audit proposed — 2 repaired, 2 deleted
    with DATA-C-03, 3 left unmarked (they import unresolvable paths). Markers were added
    only after the gate proved they pass: 261 marked blocks type-check.
  5. A finding whose premise is false is skipped. None were.

Follow-ups by package

  • objectstack-platformreferences/plugin-hooks.md:77 routes readers to the
    objectstack-data skill "(rules/hooks.md, …)", the file this PR deletes. It is another
    package, so it is untouched here; the platform flight (Skills optimization flight — skills/objectstack-platform: RESTRUCTURE (≈ −5,970 tok, −25%) — an orphan rules file with zero inbound links, the canonical hooks reference two hops from the entry file, "When to Use" printed twice, and requires: / engines.protocol / onEnable (every real config) taught nowhere #14299) should re-point it to
    references/data-hooks.md. No gate reads it (check:published-readme-links is scoped to
    package READMEs, not skills/**), so nothing is red today.
  • objectstack-platform — DATA-C-03 removed the LiteKernel/vitest hook harnesses from
    this package and left a pointer. Platform's frontmatter already claims "test harnesses
    via LiteKernel"; it does not yet carry a hook-testing example for the pointer to land on.
  • maintainer decision (DATA-F-07, deferred by the card)defineHook() is prescribed
    twice, but grep -rln defineHook --include='*.ts' outside packages/spec and
    packages/cli returns 0 files, and both real hook modules use the bare : Hook literal
    (examples/app-crm/src/hooks/opportunity.hook.ts:10,
    examples/app-todo/src/objects/task.hook.ts:51). Either the examples move to
    defineHook() or the prescription softens; it is not a doc edit.
  • deferred with the card — DATA-I-04 (a new rules/security.md; would add a file),
    DATA-H-01 (would raise the evals/README.md ceiling), DATA-B-06 (moving the routing
    table up: a MOVE-TO, which is not among the card's three IMPLEMENT verbs, and its only
    named MOVE-TO sibling is deferred). DATA-D-11 is MED confidence with the audit noting a
    maintainer may want one ❌/✅ pair kept — restoring one is a cheap review edit.

Edits outside the declared file surface

The card scoped this to skills/objectstack-data/** plus the one ratchet ceiling row.
Three further files are in the diff. Each is fallout of the mandated deletion, each was
prescribed by the failing gate itself, and each shrinks:

  1. scripts/check-skill-identifier-liveness.mjs — the hook-lifecycle-events-rule ledger
    row binds the heading ### 8 Lifecycle Eventsinside the deleted file, so the gate
    went red. Its message prescribes "Re-point heading, or delete the row". Re-pointing
    would duplicate hook-lifecycle-events-reference, which already binds the same symbol
    (HookEvent) to the surviving canonical file, so the row is dropped. Separately, the
    DATA-F-05 shrink had incidentally renamed another ledger-bound heading
    (### Access depth (scope-depth) …); there the ledger is right and the rename was
    reverted in SKILL.md.
  2. scripts/role-word-baseline.json — the deletions removed two role-word occurrences from
    SKILL.md, so check:role-word failed as a ratchet-DOWN: "count improved 4 → 2 —
    run node scripts/check-role-word.mjs --update and commit the baseline". That direction
    is the author's own remedy (expansion is the maintainer-only one). One line, shrinking.
  3. skills/README.md + content/docs/ai/skills-reference.mdx — generated, regenerated by
    the sanctioned generator, as assumption 2 above records.

Gates — head 061e5f4c

Run with exit codes captured before any pipe. Heavy builds went through
scripts/pm/os-verify-lock.sh.

The four gates named on the card:

gateverdict line
node scripts/check-skills-token-ratchet.mjs✓ 37 authored bundle file(s) within their ceilings (was 38; one file deleted)
pnpm --filter @objectstack/spec check:skill-examples✅ 261 prose examples type-check across 3 surface(s)
pnpm check:skill-compatibility✓ 11 SKILL.md file(s) reconciled against 78 workspace packages
pnpm check:skill-identifier-livenessOK — Leg 1: 492 citation(s) over 47 published file(s); Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s)

Plus the full family node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
derives for the real 13-path change set — 55 gates, re-derived and re-run on this head:
53 exit 0. The two non-zero are exit 3 = NOT MEASURED by the gates' own definition, not
reds:

  • node scripts/check-test-completeness.mjs — "There is no local log to hand it, so the
    local reading for this gate is NOT MEASURED. ⛔ It is not a red." It wants a saved
    turbo run test log.
  • node scripts/pm/check-half-states.mjs — needs the GitHub API, which is 403 from this
    container.

Ratchet self-test green (64 cases pass). check:skill-docs, check:skill-refs,
check:role-word, check:doc-authoring, check:corpus-claim-drift,
check:pm-governed-merges, check:ratchet-remedy-authority all green on this head.

skip-changeset applies: docs-only, publishing nothing from any package.


🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

DATA-B-01 / I-03 — rules/hooks.md called itself "a reference pointer" and then
restated five sections of the canonical file. Delete it; references/data-hooks.md
is the single hooks file and the catalog's hooks anchor. Its ceiling row is
dropped from scripts/check-skills-token-ratchet.mjs (the only edit to that file).
DATA-B-02 second H1 + "When to Use This Skill" inside a reference.
DATA-B-04 three registration methods, compact -- keeping the four load-bearing
facts (AppPlugin auto-binds; the `functions` map; `packageId`; and
that programmatic binding gets NO declarative condition/retry/
timeout/onError/async semantics).
DATA-B-05 10+10 generic DO/DON'T -> the compact 5+5 rules/hooks.md carried.
DATA-C-03 vitest + LiteKernel harnesses -> one-line pointer to
objectstack-platform, which claims that surface in its frontmatter.
DATA-D-01/02/03 invented benchmark table, plain-JS "Advanced Topics", generic
Troubleshooting and the Summary that repeated the DO list verbatim.
The References block survives, and absorbs the two cross-package
pointers rules/hooks.md carried so no routing is lost.
DATA-D-04 patterns 1,2,4,5,7,9 (generic JS) deleted; 3,6,8,10 kept, renumbered.
DATA-E-04 the file prescribed `body` and demonstrated `handler` ten times: two
surviving patterns are now sandboxed `body` with declared capabilities.
INC-03 (found while rewriting pattern 8, evidence pinned): "There is NO
`updateMany`" is true of the HANDLER-side repo -- ObjectRepository, what
ctx.api.object() returns, packages/objectql/src/engine.ts:13575-13600 -- but the
SANDBOX repo does install updateMany/deleteMany
(packages/runtime/src/sandbox/quickjs-runner.ts:544-545), exactly as this file's
own capability table says. The comment now names the surface it is true of.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…01/02, cut restatement
Additions (all paid by deletions in this same file; SKILL.md 13892 -> 12535):
DATA-F-01 `sharingModel` row + the four canonical values. Used by 31/31 real
objects and absent from both property tables. A publish with no
authored sharingModel is refused (`security-owd-unset`, 422) --
maintainer ruling 2026-08-13 recorded at
packages/lint/src/authoring-rules.ts:1293-1296; enum at
packages/spec/src/data/object.zod.ts:2177.
DATA-F-02 `required` (write contract) vs `storage: { notNull: true }` (the DDL),
ADR-0113 -- never mentioned in the package before.
DATA-F-03 `icon` / `pluralLabel` / `highlightFields` rows.
DATA-F-04 four security lint rows; three are publish-blocking errors.
DATA-E-05 the Quick-Start Template now carries the face every real object has
(pluralLabel/description/icon/highlightFields) and drops `indexes`,
which appears in 1 of 26 corpus files.
INC-01 (HIGH) -- the schema-evolution table named `required` as the NOT NULL dial
and claimed dev auto-heals it. Both wrong: schema-drift.ts:795-798 compares
`field.storage?.notNull`, explicitly NOT `required`; the emitted op is
severity 'warning' / category 'needs_confirm' / 'relax_not_null' and the comment
says "never auto-applied"; sql-driver.ts:10746 applies only category 'safe'.
INC-02 (MED) -- the tell-tale promised a clean 400 "<field> is required".
schema-drift.ts:800-802: that configuration dies as a RAW DRIVER ERROR instead.
Deletions: DATA-A-03 (intro + when-to-use restating the frontmatter), DATA-C-01
(two verbatim error transcripts; the query skill carries the same 400 text),
DATA-C-04 (standalone tombstones -- each key is refused by a parse error
carrying its own prescription, and objectstack-upgrade owns that path),
DATA-C-05 (protection: schema + lock table + ONE example survive), DATA-D-12,
DATA-D-13, DATA-D-15, DATA-F-06, DATA-G-01 (one CLI spelling: `os`).
DATA-F-05 is a SHRINK, not a removal (retirement deferred pending #14296):
`defineObjectExtension` and `readScope`/`writeScope` each keep one
schema-pointing row -- zero corpus usage is evidence, not proof.
DATA-A-01/A-02/F-06 rewrite the frontmatter description: it never said
datasource / external / federated though rules/datasources.md is entirely that
surface, never said lifecycle or protection, and fired on `*.seed.ts` -- a
pattern that matches nothing in the repo.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…ips, field-types
DATA-D-11 naming.md six ❌/✅ pairs + Critical Rules restatements + Rationale for a
rule the regex in the table already states. 773 -> 248.
DATA-D-05/06/07 indexing.md: generic RDBMS 101 ("when to add indexes"), four
❌/✅ pairs + three subsections teaching one textbook fact
(left-to-right) collapsed to one paragraph, the unsourced
`Table Size -> Max Indexes` table, the pg_stat_user_indexes /
SHOW INDEX SQL, and a 10-item Best Practices restating the
file. The naming block survives -- `name` is a declared key.
DATA-C-04 indexing.md's standalone `type`/`partial` tombstone clause;
the in-line ❌ block at "Retired and Redundant Keys" stays,
because there a wrong key sits beside the right one.
DATA-C-02 validation CEL-vs-SQL is objectstack-formula's anchor and this package's
description already says to load it alongside. The INVERSION
rule stays -- it is validation-specific and lives nowhere else.
DATA-D-09/D-10 validation.md: five patterns restating four examples already on
the page; 10 best practices + 4 unsourced performance claims
about two rules that lower to the same CEL evaluator.
DATA-B-07 the "no `unique` validation type" rule was stated at 7 sites;
the restatements in validation.md and relationships.md go.
DATA-D-08 relationships.md Best Practices + Performance Considerations.
DATA-D-14/E-03/G-02 field-types.md: three ❌/✅ pairs duplicating naming.md, the type
table and a lint rule (the autonumber pair survives) pay for the
`Field.*` factory preamble -- the corpus is ~92% factory
(~250 calls vs 22 literals) and this file had zero `Field.*`.
DATA-E-02 two blocks carried an `import` and then opened `{` /
`validations: [` at statement position, which TS parses as a
labelled-statement block. Both are now real declarations.
DATA-E-01 `os:check` markers on the two self-contained SKILL.md blocks
that compile (definePermissionSet, the protection example).
Verified: `check:skill-examples` type-checks 261 marked blocks.
Two liveness-ledger bindings needed handling, both fallout of deleting rules/hooks.md
and the F-05 shrink:
- the `### Access depth (scope-depth) …` heading is ledger-bound, so the shrink's
incidental rename is reverted -- the ledger is right.
- `hook-lifecycle-events-rule` binds a heading in the deleted file. The gate's own
message prescribes "Re-point `heading`, or delete the row"; re-pointing would
duplicate `hook-lifecycle-events-reference`, which already binds the same symbol
(HookEvent) to the surviving canonical file, so the row is dropped. This is the
one edit outside the declared file surface and it is reported as such.
`check:skill-docs` DEMANDED regeneration (it runs in CI, lint.yml:3986): the
frontmatter description changed, so `pnpm --filter @objectstack/spec gen:skill-docs`
regenerated skills/README.md and content/docs/ai/skills-reference.mdx. Generated
`references/_index.md` is untouched and `check:skill-refs` is green.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
The DATA-C-04 / D-12 / D-13 deletions removed two role-word occurrences from
skills/objectstack-data/SKILL.md, so `pnpm check:role-word` failed as a
ratchet-DOWN: "role-word count improved 4 -> 2 — run
`node scripts/check-role-word.mjs --update` and commit the baseline". That
remedy is the author's own (baseline EXPANSION is the maintainer-only
direction), so the baseline is updated here. The diff is one line, for this
file only, and it shrinks.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-litantos-litant added skip-changeset PR has no user-facing published change; bypasses the changeset gate needs:contract-review and removed size/xl labels Sep 2, 2026 — with Claude
@github-actionsgithub-actionsBot added the documentation Improvements or additions to documentation label Sep 2, 2026
os-litant pushed a commit that referenced this pull request Sep 2, 2026
…ht's consolidation
`references/plugin-hooks.md` sent readers chasing per-record validation,
defaults and audit trails to `objectstack-data`'s `rules/hooks.md`. The data
flight (PR #14427, head 061e5f4) DELETES that file and consolidates hooks into
`objectstack-data/references/data-hooks.md`, so the reference is repointed
before it can dangle.
Now a real relative link rather than two bare file names:
`../../objectstack-data/references/data-hooks.md`, verified to resolve from
`references/` to skills/objectstack-data/references/data-hooks.md. The old text
named both `rules/hooks.md` and `references/data-hooks.md`; only the surviving
one is named now, so the span is 22 bytes SHORTER — references/plugin-hooks.md
2418 -> 2413 tokens (ceiling 2628, untouched).
`git grep rules/hooks.md` over this package returns nothing further, so this
was the only site.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 06:41
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 940c128Sep 2, 2026
50 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-14297-skills-data-optimization branch September 2, 2026 07:06
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens) - #14427

Merged
os-zhuang merged 4 commits into
mainfrom
claude/issue-14297-skills-data-optimization
Sep 2, 2026
Merged

skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens)#14427
os-zhuang merged 4 commits into
mainfrom
claude/issue-14297-skills-data-optimization

Conversation

@os-litant

@os-litantos-litant commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Part of #14297

Optimization flight for skills/objectstack-data, the largest package in the published
catalog. Implements the card's IMPLEMENT scope from the 43-row audit record (posted
verbatim as a comment on the card). Governed surface (skills/** markdown) ⇒ this PR
stays draft
; needs:contract-review is on both carriers because INC-01 corrects a
contract-semantics claim.

Net: 45,780 → 36,736 hand-authored tokens (−9,044, −19.8%). One published file
deleted, none added, no ceiling raised, every ratcheted file byte-neutral-or-shrinking.

Per-file token delta

FilebeforeafterΔceilingheadroom
SKILL.md13,89212,553−1,33913,8921,339
references/data-hooks.md12,5849,703−2,88112,6112,908
rules/hooks.md2,195deleted−2,195row dropped
rules/indexing.md3,2402,166−1,0743,2411,075
rules/validation.md3,1092,362−7473,109747
rules/naming.md773248−525773525
rules/relationships.md3,7733,490−2833,778288
rules/field-types.md3,5783,57803,5846
rules/lifecycle.md1,5901,59001,5900
rules/datasources.md90390309118
evals/README.md14314301430
package45,78036,736−9,044

references/_index.md (generated, 1,483) untouched.

Two rows differ from the card's projection and are called out rather than forced:

  • rules/field-types.md nets 0, not −50. DATA-D-14 paid −200; the DATA-E-03
    Field.* preamble is what it bought. Cross-file payment is not available (the ratchet
    is per file), so the addition was trimmed twice until it fit inside D-14's payment. The
    file does not grow.
  • evals/README.md unchanged. DATA-H-01 raises a ceiling and is on the card's DEFER
    list.

落点 | before | after

finding落点beforeafter
DATA-B-01 / I-03rules/hooks.md (whole file)2,195 tok calling itself "a reference pointer", then restating 5 sections of the canonical filedeleted; references/data-hooks.md is the single hooks file and the catalog's hooks anchor. Ceiling row dropped
DATA-B-02data-hooks.md:1-26two H1s, two intros saying the same thing, a "When to Use This Skill" inside a referenceone H1, one intro
DATA-B-038-event table ∥ in both filesstated in full twice (466 + 525 tok)one copy (the canonical file's), via the file deletion
DATA-B-04data-hooks.md:1050-1133three registration methods in 566 tokcompact, 4 load-bearing facts kept: AppPlugin auto-binds, the functions map, packageId, and that programmatic binding gets no declarative condition/retry/timeout/onError/async semantics
DATA-B-05data-hooks.md:1136-116010+10 generic DO/DON'Tthe compact 5+5 rules/hooks.md carried
DATA-B-077 sites"no unique validation type" stated seven timesrestatements in validation.md + relationships.md dropped; SKILL.md + the indexing.md scope table keep it
DATA-C-01SKILL.md:162-189two verbatim CLI/HTTP error transcripts (the 400 text word-for-word in objectstack-query)3 lines naming both refusals; the modelling half (mirror field + two-hook maintenance table) stays — this package is its anchor
DATA-C-02validation.md:26-36, 313-331CEL-vs-SQL prose + a ❌/✅ pairpointer to objectstack-formula (the anchor); the inversion rule stays, it lives nowhere else
DATA-C-03data-hooks.md:1209-1275vitest + LiteKernel harnesses importing 4 unresolvable packagesone-line pointer to objectstack-platform, whose frontmatter claims that surface
DATA-C-045 tombstone sitesstandalone narration of removed keys (rls, encryptionConfig, tenancy.strategy, softDelete/versioning, type/partial)deleted; each key is refused by a parse error carrying its own prescription, and objectstack-upgrade owns in-place upgrades. In-line ❌ markers kept where a wrong key sits beside the right one
DATA-C-05SKILL.md:858-971987 tok: 3 near-identical examples for a 4-value enum + Studio-banner narration + 5-bullet guidanceschema block + 4-row lock table + ONE example + 4 lines of enforcement
DATA-D-01/02/03data-hooks.md:1279-1444invented benchmark table (0 hooks ~1ms…), plain-JS "Advanced Topics", generic Troubleshooting, a Summary repeating the DO list verbatimdeleted; the References block survives and absorbs the two cross-package pointers rules/hooks.md carried
DATA-D-04data-hooks.md:765-104610 patterns, 6 of them plain JavaScriptpatterns 1,2,4,5,7,9 deleted; 3,6,8,10 kept and renumbered
DATA-D-05/06/07rules/indexing.mdRDBMS 101, one textbook fact taught seven ways, unsourced Table Size → Max Indexes, pg_stat_user_indexes SQL, 10 best practicesone paragraph on composite order; naming block kept (name is a declared key)
DATA-D-08relationships.md:398-4137 + 4 items restating the file's own tablesdeleted
DATA-D-09/D-10validation.md:355-4385 patterns restating 4 examples on the same page; 10 best practices + 4 unsourced perf claimsdeleted
DATA-D-11naming.md:15-1076 ❌/✅ pairs + restatements + rationale for a rule the regex already statestable + Critical Rules (773 → 248)
DATA-D-12SKILL.md:540-555"CRM Schema Blueprint" pointing at 6 things covered above itdeleted
DATA-D-13SKILL.md:974-987"Advanced Features Checklist" + tombstone footnotedeleted
DATA-D-14field-types.md:360-4113 ❌/✅ pairs duplicating naming.md, the type table, and a lint ruledeleted (autonumber pair survives) — funds DATA-E-03
DATA-D-15SKILL.md:1178-1181the live model-benchmarking doordeleted (platform benchmarking, not app authoring)
DATA-E-01/E-022 blocksself-contained blocks opening { / validations: [ at statement position (TS parses that as a labelled-statement block)real declarations; os:check markers added to the two SKILL.md blocks that compile
DATA-E-03 / G-02rules/field-types.mdzero Field.* in the file whose job is field authoring; corpus is ~92% factoryField.* preamble with the literal ↔ factory mapping
DATA-E-04data-hooks.md patternsfile prescribed body, demonstrated deprecated handler 10 times2 surviving patterns converted to sandboxed body with declared capabilities
DATA-E-05SKILL.md:325-379the one copy-pasteable object diverged from all 31 real onespluralLabel/description/icon/highlightFields added, indexes dropped (1 of 26 corpus files)
DATA-F-01SKILL.md:64-84sharingModel on 31/31 real objects, absent from both property tablesrequired-table row + 4-row value table
DATA-F-02SKILL.md:383-403storage.notNull never mentioned in the packagerequired = write contract, storage.notNull = the DDL
DATA-F-03SKILL.md:71-84icon/pluralLabel/highlightFields undocumentedthree rows
DATA-F-04SKILL.md:1142-11529 data-model lint rules, 0 security rules4 security rows, 3 of them publish-blocking
DATA-F-05SKILL.mddefineObjectExtension, readScope/writeScope — zero corpus usageshrunk to one schema-pointing row each, not deleted (retirement deferred pending #14296; zero usage in examples is evidence, not proof)
DATA-F-06SKILL.md:1129 + frontmatterprescribed {object}.seed.ts; find . -name '*.seed.ts' returns 0 repo-widerow deleted, trigger aligned to src/data/*.ts
DATA-G-016 sitesobjectstack lint and os lint in one file, 60 lines apartnormalised to os
INC-01SKILL.md:393required: true → false "dev auto-heals (autoMigrate:'safe')"corrected — see below
INC-02SKILL.md:398-401stale NOT NULL produces a clean 400corrected — raw driver error

Contract-semantics corrections (why needs:contract-review)

INC-01. The schema-evolution table named the wrong dial and claimed auto-healing. Both
halves are false against the implementation:

  • packages/drivers/driver-sql/src/schema-drift.ts:795-798const expectNullable = field.storage?.notNull !== true; under a comment reading "compared against
    storage.notNull, the explicit physical constraint — NOT against required, which is
    the write-time contract and implies nothing about the column".
  • The emitted drift is severity: 'warning', category: 'needs_confirm',
    op: { type: 'relax_not_null' } (schema-drift.ts:815-826), above a comment saying
    "never auto-applied".
  • packages/drivers/driver-sql/src/sql-driver.ts:10746const safe = drift.filter((d) => d.category === 'safe');. autoMigrate: 'safe' applies only category safe, so
    it never touches this op.

INC-02.schema-drift.ts:800-802 says that exact configuration means "an omitting
write reaches the DB and dies as a raw driver error instead of a clean validation 400" —
the opposite symptom to the one the tell-tale promised.

INC-03 (new, found while rewriting DATA-D-04 pattern 8). The file asserted "There is
NO updateMany" a few hundred lines below a capability table listing updateMany as
"also installed". Both are true of different surfaces and neither said which:
ObjectRepository — what a handler's ctx.api.object() returns
(packages/objectql/src/engine.ts:13563-13600) — has no updateMany; the sandbox repo
does (packages/runtime/src/sandbox/quickjs-runner.ts:544-545). The comment now names its
surface. This is why patterns 3 and 6 were converted to body and pattern 8 was left as a
handler.

premise_false

None. git diff --stat a59f78d HEAD -- skills/objectstack-data was EMPTY at my base
909a4417, so all 43 spans resolved byte-identically and no finding had to be skipped.

One card-level detail did not hold, and needed no action: the card's ANCHOR RULINGS says
the inbound link at rules/hooks.md:202 points at objectstack-platform
rules/plugin-hooks-events.md and must be re-pointed. At base it already pointed at
objectstack-platform/references/plugin-hooks.md. The file is deleted here anyway, and
that pointer is preserved in the surviving References block.

PM mechanical assumptions — measured

  1. Spans byte-identical at a59f78d. TRUE. git diff --stat a59f78d HEAD -- skills/objectstack-data empty; git diff --stat d63c8a25 HEAD -- skills/ empty;
    the ratchet script unchanged since the pin.
  2. Does check:skill-docs demand regenerating skills/README.md?YES, and it runs
    in CI
    (.github/workflows/lint.yml:3986). The frontmatter description changed, the
    gate failed, and pnpm --filter @objectstack/spec gen:skill-docs regenerated
    skills/README.mdandcontent/docs/ai/skills-reference.mdx — the second file was
    not in the assumption. Both diffs are one data-row each. check:skill-refs is green
    and references/_index.md is untouched.
  3. Deleting rules/hooks.md reds the ratchet unless its ceiling row goes. TRUE, and
    verified in both directions from a committed state with a restore trap: with the row
    re-injected the gate prints ✗ check-skills-token-ratchet: cannot read skills/objectstack-data/rules/hooks.md — red, not a skip (#4690) and exits 1; restored
    (blob hash equal to HEAD, git diff HEAD empty) it exits 0.
  4. The os:check rule is in the header of check-skill-examples.ts. TRUE (lines
    17-23): a marker is os:check in an HTML comment on the line directly above the fence.
    The seven would-fail blocks were handled as the audit proposed — 2 repaired, 2 deleted
    with DATA-C-03, 3 left unmarked (they import unresolvable paths). Markers were added
    only after the gate proved they pass: 261 marked blocks type-check.
  5. A finding whose premise is false is skipped. None were.

Follow-ups by package

  • objectstack-platformreferences/plugin-hooks.md:77 routes readers to the
    objectstack-data skill "(rules/hooks.md, …)", the file this PR deletes. It is another
    package, so it is untouched here; the platform flight (Skills optimization flight — skills/objectstack-platform: RESTRUCTURE (≈ −5,970 tok, −25%) — an orphan rules file with zero inbound links, the canonical hooks reference two hops from the entry file, "When to Use" printed twice, and requires: / engines.protocol / onEnable (every real config) taught nowhere #14299) should re-point it to
    references/data-hooks.md. No gate reads it (check:published-readme-links is scoped to
    package READMEs, not skills/**), so nothing is red today.
  • objectstack-platform — DATA-C-03 removed the LiteKernel/vitest hook harnesses from
    this package and left a pointer. Platform's frontmatter already claims "test harnesses
    via LiteKernel"; it does not yet carry a hook-testing example for the pointer to land on.
  • maintainer decision (DATA-F-07, deferred by the card)defineHook() is prescribed
    twice, but grep -rln defineHook --include='*.ts' outside packages/spec and
    packages/cli returns 0 files, and both real hook modules use the bare : Hook literal
    (examples/app-crm/src/hooks/opportunity.hook.ts:10,
    examples/app-todo/src/objects/task.hook.ts:51). Either the examples move to
    defineHook() or the prescription softens; it is not a doc edit.
  • deferred with the card — DATA-I-04 (a new rules/security.md; would add a file),
    DATA-H-01 (would raise the evals/README.md ceiling), DATA-B-06 (moving the routing
    table up: a MOVE-TO, which is not among the card's three IMPLEMENT verbs, and its only
    named MOVE-TO sibling is deferred). DATA-D-11 is MED confidence with the audit noting a
    maintainer may want one ❌/✅ pair kept — restoring one is a cheap review edit.

Edits outside the declared file surface

The card scoped this to skills/objectstack-data/** plus the one ratchet ceiling row.
Three further files are in the diff. Each is fallout of the mandated deletion, each was
prescribed by the failing gate itself, and each shrinks:

  1. scripts/check-skill-identifier-liveness.mjs — the hook-lifecycle-events-rule ledger
    row binds the heading ### 8 Lifecycle Eventsinside the deleted file, so the gate
    went red. Its message prescribes "Re-point heading, or delete the row". Re-pointing
    would duplicate hook-lifecycle-events-reference, which already binds the same symbol
    (HookEvent) to the surviving canonical file, so the row is dropped. Separately, the
    DATA-F-05 shrink had incidentally renamed another ledger-bound heading
    (### Access depth (scope-depth) …); there the ledger is right and the rename was
    reverted in SKILL.md.
  2. scripts/role-word-baseline.json — the deletions removed two role-word occurrences from
    SKILL.md, so check:role-word failed as a ratchet-DOWN: "count improved 4 → 2 —
    run node scripts/check-role-word.mjs --update and commit the baseline". That direction
    is the author's own remedy (expansion is the maintainer-only one). One line, shrinking.
  3. skills/README.md + content/docs/ai/skills-reference.mdx — generated, regenerated by
    the sanctioned generator, as assumption 2 above records.

Gates — head 061e5f4c

Run with exit codes captured before any pipe. Heavy builds went through
scripts/pm/os-verify-lock.sh.

The four gates named on the card:

gateverdict line
node scripts/check-skills-token-ratchet.mjs✓ 37 authored bundle file(s) within their ceilings (was 38; one file deleted)
pnpm --filter @objectstack/spec check:skill-examples✅ 261 prose examples type-check across 3 surface(s)
pnpm check:skill-compatibility✓ 11 SKILL.md file(s) reconciled against 78 workspace packages
pnpm check:skill-identifier-livenessOK — Leg 1: 492 citation(s) over 47 published file(s); Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s)

Plus the full family node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
derives for the real 13-path change set — 55 gates, re-derived and re-run on this head:
53 exit 0. The two non-zero are exit 3 = NOT MEASURED by the gates' own definition, not
reds:

  • node scripts/check-test-completeness.mjs — "There is no local log to hand it, so the
    local reading for this gate is NOT MEASURED. ⛔ It is not a red." It wants a saved
    turbo run test log.
  • node scripts/pm/check-half-states.mjs — needs the GitHub API, which is 403 from this
    container.

Ratchet self-test green (64 cases pass). check:skill-docs, check:skill-refs,
check:role-word, check:doc-authoring, check:corpus-claim-drift,
check:pm-governed-merges, check:ratchet-remedy-authority all green on this head.

skip-changeset applies: docs-only, publishing nothing from any package.


🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

DATA-B-01 / I-03 — rules/hooks.md called itself "a reference pointer" and then
restated five sections of the canonical file. Delete it; references/data-hooks.md
is the single hooks file and the catalog's hooks anchor. Its ceiling row is
dropped from scripts/check-skills-token-ratchet.mjs (the only edit to that file).
DATA-B-02 second H1 + "When to Use This Skill" inside a reference.
DATA-B-04 three registration methods, compact -- keeping the four load-bearing
facts (AppPlugin auto-binds; the `functions` map; `packageId`; and
that programmatic binding gets NO declarative condition/retry/
timeout/onError/async semantics).
DATA-B-05 10+10 generic DO/DON'T -> the compact 5+5 rules/hooks.md carried.
DATA-C-03 vitest + LiteKernel harnesses -> one-line pointer to
objectstack-platform, which claims that surface in its frontmatter.
DATA-D-01/02/03 invented benchmark table, plain-JS "Advanced Topics", generic
Troubleshooting and the Summary that repeated the DO list verbatim.
The References block survives, and absorbs the two cross-package
pointers rules/hooks.md carried so no routing is lost.
DATA-D-04 patterns 1,2,4,5,7,9 (generic JS) deleted; 3,6,8,10 kept, renumbered.
DATA-E-04 the file prescribed `body` and demonstrated `handler` ten times: two
surviving patterns are now sandboxed `body` with declared capabilities.
INC-03 (found while rewriting pattern 8, evidence pinned): "There is NO
`updateMany`" is true of the HANDLER-side repo -- ObjectRepository, what
ctx.api.object() returns, packages/objectql/src/engine.ts:13575-13600 -- but the
SANDBOX repo does install updateMany/deleteMany
(packages/runtime/src/sandbox/quickjs-runner.ts:544-545), exactly as this file's
own capability table says. The comment now names the surface it is true of.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…01/02, cut restatement
Additions (all paid by deletions in this same file; SKILL.md 13892 -> 12535):
DATA-F-01 `sharingModel` row + the four canonical values. Used by 31/31 real
objects and absent from both property tables. A publish with no
authored sharingModel is refused (`security-owd-unset`, 422) --
maintainer ruling 2026-08-13 recorded at
packages/lint/src/authoring-rules.ts:1293-1296; enum at
packages/spec/src/data/object.zod.ts:2177.
DATA-F-02 `required` (write contract) vs `storage: { notNull: true }` (the DDL),
ADR-0113 -- never mentioned in the package before.
DATA-F-03 `icon` / `pluralLabel` / `highlightFields` rows.
DATA-F-04 four security lint rows; three are publish-blocking errors.
DATA-E-05 the Quick-Start Template now carries the face every real object has
(pluralLabel/description/icon/highlightFields) and drops `indexes`,
which appears in 1 of 26 corpus files.
INC-01 (HIGH) -- the schema-evolution table named `required` as the NOT NULL dial
and claimed dev auto-heals it. Both wrong: schema-drift.ts:795-798 compares
`field.storage?.notNull`, explicitly NOT `required`; the emitted op is
severity 'warning' / category 'needs_confirm' / 'relax_not_null' and the comment
says "never auto-applied"; sql-driver.ts:10746 applies only category 'safe'.
INC-02 (MED) -- the tell-tale promised a clean 400 "<field> is required".
schema-drift.ts:800-802: that configuration dies as a RAW DRIVER ERROR instead.
Deletions: DATA-A-03 (intro + when-to-use restating the frontmatter), DATA-C-01
(two verbatim error transcripts; the query skill carries the same 400 text),
DATA-C-04 (standalone tombstones -- each key is refused by a parse error
carrying its own prescription, and objectstack-upgrade owns that path),
DATA-C-05 (protection: schema + lock table + ONE example survive), DATA-D-12,
DATA-D-13, DATA-D-15, DATA-F-06, DATA-G-01 (one CLI spelling: `os`).
DATA-F-05 is a SHRINK, not a removal (retirement deferred pending #14296):
`defineObjectExtension` and `readScope`/`writeScope` each keep one
schema-pointing row -- zero corpus usage is evidence, not proof.
DATA-A-01/A-02/F-06 rewrite the frontmatter description: it never said
datasource / external / federated though rules/datasources.md is entirely that
surface, never said lifecycle or protection, and fired on `*.seed.ts` -- a
pattern that matches nothing in the repo.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…ips, field-types
DATA-D-11 naming.md six ❌/✅ pairs + Critical Rules restatements + Rationale for a
rule the regex in the table already states. 773 -> 248.
DATA-D-05/06/07 indexing.md: generic RDBMS 101 ("when to add indexes"), four
❌/✅ pairs + three subsections teaching one textbook fact
(left-to-right) collapsed to one paragraph, the unsourced
`Table Size -> Max Indexes` table, the pg_stat_user_indexes /
SHOW INDEX SQL, and a 10-item Best Practices restating the
file. The naming block survives -- `name` is a declared key.
DATA-C-04 indexing.md's standalone `type`/`partial` tombstone clause;
the in-line ❌ block at "Retired and Redundant Keys" stays,
because there a wrong key sits beside the right one.
DATA-C-02 validation CEL-vs-SQL is objectstack-formula's anchor and this package's
description already says to load it alongside. The INVERSION
rule stays -- it is validation-specific and lives nowhere else.
DATA-D-09/D-10 validation.md: five patterns restating four examples already on
the page; 10 best practices + 4 unsourced performance claims
about two rules that lower to the same CEL evaluator.
DATA-B-07 the "no `unique` validation type" rule was stated at 7 sites;
the restatements in validation.md and relationships.md go.
DATA-D-08 relationships.md Best Practices + Performance Considerations.
DATA-D-14/E-03/G-02 field-types.md: three ❌/✅ pairs duplicating naming.md, the type
table and a lint rule (the autonumber pair survives) pay for the
`Field.*` factory preamble -- the corpus is ~92% factory
(~250 calls vs 22 literals) and this file had zero `Field.*`.
DATA-E-02 two blocks carried an `import` and then opened `{` /
`validations: [` at statement position, which TS parses as a
labelled-statement block. Both are now real declarations.
DATA-E-01 `os:check` markers on the two self-contained SKILL.md blocks
that compile (definePermissionSet, the protection example).
Verified: `check:skill-examples` type-checks 261 marked blocks.
Two liveness-ledger bindings needed handling, both fallout of deleting rules/hooks.md
and the F-05 shrink:
- the `### Access depth (scope-depth) …` heading is ledger-bound, so the shrink's
incidental rename is reverted -- the ledger is right.
- `hook-lifecycle-events-rule` binds a heading in the deleted file. The gate's own
message prescribes "Re-point `heading`, or delete the row"; re-pointing would
duplicate `hook-lifecycle-events-reference`, which already binds the same symbol
(HookEvent) to the surviving canonical file, so the row is dropped. This is the
one edit outside the declared file surface and it is reported as such.
`check:skill-docs` DEMANDED regeneration (it runs in CI, lint.yml:3986): the
frontmatter description changed, so `pnpm --filter @objectstack/spec gen:skill-docs`
regenerated skills/README.md and content/docs/ai/skills-reference.mdx. Generated
`references/_index.md` is untouched and `check:skill-refs` is green.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
The DATA-C-04 / D-12 / D-13 deletions removed two role-word occurrences from
skills/objectstack-data/SKILL.md, so `pnpm check:role-word` failed as a
ratchet-DOWN: "role-word count improved 4 -> 2 — run
`node scripts/check-role-word.mjs --update` and commit the baseline". That
remedy is the author's own (baseline EXPANSION is the maintainer-only
direction), so the baseline is updated here. The diff is one line, for this
file only, and it shrinks.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-litantos-litant added skip-changeset PR has no user-facing published change; bypasses the changeset gate needs:contract-review and removed size/xl labels Sep 2, 2026 — with Claude
@github-actionsgithub-actionsBot added the documentation Improvements or additions to documentation label Sep 2, 2026
os-litant pushed a commit that referenced this pull request Sep 2, 2026
…ht's consolidation
`references/plugin-hooks.md` sent readers chasing per-record validation,
defaults and audit trails to `objectstack-data`'s `rules/hooks.md`. The data
flight (PR #14427, head 061e5f4) DELETES that file and consolidates hooks into
`objectstack-data/references/data-hooks.md`, so the reference is repointed
before it can dangle.
Now a real relative link rather than two bare file names:
`../../objectstack-data/references/data-hooks.md`, verified to resolve from
`references/` to skills/objectstack-data/references/data-hooks.md. The old text
named both `rules/hooks.md` and `references/data-hooks.md`; only the surviving
one is named now, so the span is 22 bytes SHORTER — references/plugin-hooks.md
2418 -> 2413 tokens (ceiling 2628, untouched).
`git grep rules/hooks.md` over this package returns nothing further, so this
was the only site.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 06:41
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 940c128Sep 2, 2026
50 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-14297-skills-data-optimization branch September 2, 2026 07:06
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens) - #14427

Merged
os-zhuang merged 4 commits into
mainfrom
claude/issue-14297-skills-data-optimization
Sep 2, 2026
Merged

skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens)#14427
os-zhuang merged 4 commits into
mainfrom
claude/issue-14297-skills-data-optimization

Conversation

@os-litant

@os-litantos-litant commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Part of #14297

Optimization flight for skills/objectstack-data, the largest package in the published
catalog. Implements the card's IMPLEMENT scope from the 43-row audit record (posted
verbatim as a comment on the card). Governed surface (skills/** markdown) ⇒ this PR
stays draft
; needs:contract-review is on both carriers because INC-01 corrects a
contract-semantics claim.

Net: 45,780 → 36,736 hand-authored tokens (−9,044, −19.8%). One published file
deleted, none added, no ceiling raised, every ratcheted file byte-neutral-or-shrinking.

Per-file token delta

FilebeforeafterΔceilingheadroom
SKILL.md13,89212,553−1,33913,8921,339
references/data-hooks.md12,5849,703−2,88112,6112,908
rules/hooks.md2,195deleted−2,195row dropped
rules/indexing.md3,2402,166−1,0743,2411,075
rules/validation.md3,1092,362−7473,109747
rules/naming.md773248−525773525
rules/relationships.md3,7733,490−2833,778288
rules/field-types.md3,5783,57803,5846
rules/lifecycle.md1,5901,59001,5900
rules/datasources.md90390309118
evals/README.md14314301430
package45,78036,736−9,044

references/_index.md (generated, 1,483) untouched.

Two rows differ from the card's projection and are called out rather than forced:

  • rules/field-types.md nets 0, not −50. DATA-D-14 paid −200; the DATA-E-03
    Field.* preamble is what it bought. Cross-file payment is not available (the ratchet
    is per file), so the addition was trimmed twice until it fit inside D-14's payment. The
    file does not grow.
  • evals/README.md unchanged. DATA-H-01 raises a ceiling and is on the card's DEFER
    list.

落点 | before | after

finding落点beforeafter
DATA-B-01 / I-03rules/hooks.md (whole file)2,195 tok calling itself "a reference pointer", then restating 5 sections of the canonical filedeleted; references/data-hooks.md is the single hooks file and the catalog's hooks anchor. Ceiling row dropped
DATA-B-02data-hooks.md:1-26two H1s, two intros saying the same thing, a "When to Use This Skill" inside a referenceone H1, one intro
DATA-B-038-event table ∥ in both filesstated in full twice (466 + 525 tok)one copy (the canonical file's), via the file deletion
DATA-B-04data-hooks.md:1050-1133three registration methods in 566 tokcompact, 4 load-bearing facts kept: AppPlugin auto-binds, the functions map, packageId, and that programmatic binding gets no declarative condition/retry/timeout/onError/async semantics
DATA-B-05data-hooks.md:1136-116010+10 generic DO/DON'Tthe compact 5+5 rules/hooks.md carried
DATA-B-077 sites"no unique validation type" stated seven timesrestatements in validation.md + relationships.md dropped; SKILL.md + the indexing.md scope table keep it
DATA-C-01SKILL.md:162-189two verbatim CLI/HTTP error transcripts (the 400 text word-for-word in objectstack-query)3 lines naming both refusals; the modelling half (mirror field + two-hook maintenance table) stays — this package is its anchor
DATA-C-02validation.md:26-36, 313-331CEL-vs-SQL prose + a ❌/✅ pairpointer to objectstack-formula (the anchor); the inversion rule stays, it lives nowhere else
DATA-C-03data-hooks.md:1209-1275vitest + LiteKernel harnesses importing 4 unresolvable packagesone-line pointer to objectstack-platform, whose frontmatter claims that surface
DATA-C-045 tombstone sitesstandalone narration of removed keys (rls, encryptionConfig, tenancy.strategy, softDelete/versioning, type/partial)deleted; each key is refused by a parse error carrying its own prescription, and objectstack-upgrade owns in-place upgrades. In-line ❌ markers kept where a wrong key sits beside the right one
DATA-C-05SKILL.md:858-971987 tok: 3 near-identical examples for a 4-value enum + Studio-banner narration + 5-bullet guidanceschema block + 4-row lock table + ONE example + 4 lines of enforcement
DATA-D-01/02/03data-hooks.md:1279-1444invented benchmark table (0 hooks ~1ms…), plain-JS "Advanced Topics", generic Troubleshooting, a Summary repeating the DO list verbatimdeleted; the References block survives and absorbs the two cross-package pointers rules/hooks.md carried
DATA-D-04data-hooks.md:765-104610 patterns, 6 of them plain JavaScriptpatterns 1,2,4,5,7,9 deleted; 3,6,8,10 kept and renumbered
DATA-D-05/06/07rules/indexing.mdRDBMS 101, one textbook fact taught seven ways, unsourced Table Size → Max Indexes, pg_stat_user_indexes SQL, 10 best practicesone paragraph on composite order; naming block kept (name is a declared key)
DATA-D-08relationships.md:398-4137 + 4 items restating the file's own tablesdeleted
DATA-D-09/D-10validation.md:355-4385 patterns restating 4 examples on the same page; 10 best practices + 4 unsourced perf claimsdeleted
DATA-D-11naming.md:15-1076 ❌/✅ pairs + restatements + rationale for a rule the regex already statestable + Critical Rules (773 → 248)
DATA-D-12SKILL.md:540-555"CRM Schema Blueprint" pointing at 6 things covered above itdeleted
DATA-D-13SKILL.md:974-987"Advanced Features Checklist" + tombstone footnotedeleted
DATA-D-14field-types.md:360-4113 ❌/✅ pairs duplicating naming.md, the type table, and a lint ruledeleted (autonumber pair survives) — funds DATA-E-03
DATA-D-15SKILL.md:1178-1181the live model-benchmarking doordeleted (platform benchmarking, not app authoring)
DATA-E-01/E-022 blocksself-contained blocks opening { / validations: [ at statement position (TS parses that as a labelled-statement block)real declarations; os:check markers added to the two SKILL.md blocks that compile
DATA-E-03 / G-02rules/field-types.mdzero Field.* in the file whose job is field authoring; corpus is ~92% factoryField.* preamble with the literal ↔ factory mapping
DATA-E-04data-hooks.md patternsfile prescribed body, demonstrated deprecated handler 10 times2 surviving patterns converted to sandboxed body with declared capabilities
DATA-E-05SKILL.md:325-379the one copy-pasteable object diverged from all 31 real onespluralLabel/description/icon/highlightFields added, indexes dropped (1 of 26 corpus files)
DATA-F-01SKILL.md:64-84sharingModel on 31/31 real objects, absent from both property tablesrequired-table row + 4-row value table
DATA-F-02SKILL.md:383-403storage.notNull never mentioned in the packagerequired = write contract, storage.notNull = the DDL
DATA-F-03SKILL.md:71-84icon/pluralLabel/highlightFields undocumentedthree rows
DATA-F-04SKILL.md:1142-11529 data-model lint rules, 0 security rules4 security rows, 3 of them publish-blocking
DATA-F-05SKILL.mddefineObjectExtension, readScope/writeScope — zero corpus usageshrunk to one schema-pointing row each, not deleted (retirement deferred pending #14296; zero usage in examples is evidence, not proof)
DATA-F-06SKILL.md:1129 + frontmatterprescribed {object}.seed.ts; find . -name '*.seed.ts' returns 0 repo-widerow deleted, trigger aligned to src/data/*.ts
DATA-G-016 sitesobjectstack lint and os lint in one file, 60 lines apartnormalised to os
INC-01SKILL.md:393required: true → false "dev auto-heals (autoMigrate:'safe')"corrected — see below
INC-02SKILL.md:398-401stale NOT NULL produces a clean 400corrected — raw driver error

Contract-semantics corrections (why needs:contract-review)

INC-01. The schema-evolution table named the wrong dial and claimed auto-healing. Both
halves are false against the implementation:

  • packages/drivers/driver-sql/src/schema-drift.ts:795-798const expectNullable = field.storage?.notNull !== true; under a comment reading "compared against
    storage.notNull, the explicit physical constraint — NOT against required, which is
    the write-time contract and implies nothing about the column".
  • The emitted drift is severity: 'warning', category: 'needs_confirm',
    op: { type: 'relax_not_null' } (schema-drift.ts:815-826), above a comment saying
    "never auto-applied".
  • packages/drivers/driver-sql/src/sql-driver.ts:10746const safe = drift.filter((d) => d.category === 'safe');. autoMigrate: 'safe' applies only category safe, so
    it never touches this op.

INC-02.schema-drift.ts:800-802 says that exact configuration means "an omitting
write reaches the DB and dies as a raw driver error instead of a clean validation 400" —
the opposite symptom to the one the tell-tale promised.

INC-03 (new, found while rewriting DATA-D-04 pattern 8). The file asserted "There is
NO updateMany" a few hundred lines below a capability table listing updateMany as
"also installed". Both are true of different surfaces and neither said which:
ObjectRepository — what a handler's ctx.api.object() returns
(packages/objectql/src/engine.ts:13563-13600) — has no updateMany; the sandbox repo
does (packages/runtime/src/sandbox/quickjs-runner.ts:544-545). The comment now names its
surface. This is why patterns 3 and 6 were converted to body and pattern 8 was left as a
handler.

premise_false

None. git diff --stat a59f78d HEAD -- skills/objectstack-data was EMPTY at my base
909a4417, so all 43 spans resolved byte-identically and no finding had to be skipped.

One card-level detail did not hold, and needed no action: the card's ANCHOR RULINGS says
the inbound link at rules/hooks.md:202 points at objectstack-platform
rules/plugin-hooks-events.md and must be re-pointed. At base it already pointed at
objectstack-platform/references/plugin-hooks.md. The file is deleted here anyway, and
that pointer is preserved in the surviving References block.

PM mechanical assumptions — measured

  1. Spans byte-identical at a59f78d. TRUE. git diff --stat a59f78d HEAD -- skills/objectstack-data empty; git diff --stat d63c8a25 HEAD -- skills/ empty;
    the ratchet script unchanged since the pin.
  2. Does check:skill-docs demand regenerating skills/README.md?YES, and it runs
    in CI
    (.github/workflows/lint.yml:3986). The frontmatter description changed, the
    gate failed, and pnpm --filter @objectstack/spec gen:skill-docs regenerated
    skills/README.mdandcontent/docs/ai/skills-reference.mdx — the second file was
    not in the assumption. Both diffs are one data-row each. check:skill-refs is green
    and references/_index.md is untouched.
  3. Deleting rules/hooks.md reds the ratchet unless its ceiling row goes. TRUE, and
    verified in both directions from a committed state with a restore trap: with the row
    re-injected the gate prints ✗ check-skills-token-ratchet: cannot read skills/objectstack-data/rules/hooks.md — red, not a skip (#4690) and exits 1; restored
    (blob hash equal to HEAD, git diff HEAD empty) it exits 0.
  4. The os:check rule is in the header of check-skill-examples.ts. TRUE (lines
    17-23): a marker is os:check in an HTML comment on the line directly above the fence.
    The seven would-fail blocks were handled as the audit proposed — 2 repaired, 2 deleted
    with DATA-C-03, 3 left unmarked (they import unresolvable paths). Markers were added
    only after the gate proved they pass: 261 marked blocks type-check.
  5. A finding whose premise is false is skipped. None were.

Follow-ups by package

  • objectstack-platformreferences/plugin-hooks.md:77 routes readers to the
    objectstack-data skill "(rules/hooks.md, …)", the file this PR deletes. It is another
    package, so it is untouched here; the platform flight (Skills optimization flight — skills/objectstack-platform: RESTRUCTURE (≈ −5,970 tok, −25%) — an orphan rules file with zero inbound links, the canonical hooks reference two hops from the entry file, "When to Use" printed twice, and requires: / engines.protocol / onEnable (every real config) taught nowhere #14299) should re-point it to
    references/data-hooks.md. No gate reads it (check:published-readme-links is scoped to
    package READMEs, not skills/**), so nothing is red today.
  • objectstack-platform — DATA-C-03 removed the LiteKernel/vitest hook harnesses from
    this package and left a pointer. Platform's frontmatter already claims "test harnesses
    via LiteKernel"; it does not yet carry a hook-testing example for the pointer to land on.
  • maintainer decision (DATA-F-07, deferred by the card)defineHook() is prescribed
    twice, but grep -rln defineHook --include='*.ts' outside packages/spec and
    packages/cli returns 0 files, and both real hook modules use the bare : Hook literal
    (examples/app-crm/src/hooks/opportunity.hook.ts:10,
    examples/app-todo/src/objects/task.hook.ts:51). Either the examples move to
    defineHook() or the prescription softens; it is not a doc edit.
  • deferred with the card — DATA-I-04 (a new rules/security.md; would add a file),
    DATA-H-01 (would raise the evals/README.md ceiling), DATA-B-06 (moving the routing
    table up: a MOVE-TO, which is not among the card's three IMPLEMENT verbs, and its only
    named MOVE-TO sibling is deferred). DATA-D-11 is MED confidence with the audit noting a
    maintainer may want one ❌/✅ pair kept — restoring one is a cheap review edit.

Edits outside the declared file surface

The card scoped this to skills/objectstack-data/** plus the one ratchet ceiling row.
Three further files are in the diff. Each is fallout of the mandated deletion, each was
prescribed by the failing gate itself, and each shrinks:

  1. scripts/check-skill-identifier-liveness.mjs — the hook-lifecycle-events-rule ledger
    row binds the heading ### 8 Lifecycle Eventsinside the deleted file, so the gate
    went red. Its message prescribes "Re-point heading, or delete the row". Re-pointing
    would duplicate hook-lifecycle-events-reference, which already binds the same symbol
    (HookEvent) to the surviving canonical file, so the row is dropped. Separately, the
    DATA-F-05 shrink had incidentally renamed another ledger-bound heading
    (### Access depth (scope-depth) …); there the ledger is right and the rename was
    reverted in SKILL.md.
  2. scripts/role-word-baseline.json — the deletions removed two role-word occurrences from
    SKILL.md, so check:role-word failed as a ratchet-DOWN: "count improved 4 → 2 —
    run node scripts/check-role-word.mjs --update and commit the baseline". That direction
    is the author's own remedy (expansion is the maintainer-only one). One line, shrinking.
  3. skills/README.md + content/docs/ai/skills-reference.mdx — generated, regenerated by
    the sanctioned generator, as assumption 2 above records.

Gates — head 061e5f4c

Run with exit codes captured before any pipe. Heavy builds went through
scripts/pm/os-verify-lock.sh.

The four gates named on the card:

gateverdict line
node scripts/check-skills-token-ratchet.mjs✓ 37 authored bundle file(s) within their ceilings (was 38; one file deleted)
pnpm --filter @objectstack/spec check:skill-examples✅ 261 prose examples type-check across 3 surface(s)
pnpm check:skill-compatibility✓ 11 SKILL.md file(s) reconciled against 78 workspace packages
pnpm check:skill-identifier-livenessOK — Leg 1: 492 citation(s) over 47 published file(s); Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s)

Plus the full family node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
derives for the real 13-path change set — 55 gates, re-derived and re-run on this head:
53 exit 0. The two non-zero are exit 3 = NOT MEASURED by the gates' own definition, not
reds:

  • node scripts/check-test-completeness.mjs — "There is no local log to hand it, so the
    local reading for this gate is NOT MEASURED. ⛔ It is not a red." It wants a saved
    turbo run test log.
  • node scripts/pm/check-half-states.mjs — needs the GitHub API, which is 403 from this
    container.

Ratchet self-test green (64 cases pass). check:skill-docs, check:skill-refs,
check:role-word, check:doc-authoring, check:corpus-claim-drift,
check:pm-governed-merges, check:ratchet-remedy-authority all green on this head.

skip-changeset applies: docs-only, publishing nothing from any package.


🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

DATA-B-01 / I-03 — rules/hooks.md called itself "a reference pointer" and then
restated five sections of the canonical file. Delete it; references/data-hooks.md
is the single hooks file and the catalog's hooks anchor. Its ceiling row is
dropped from scripts/check-skills-token-ratchet.mjs (the only edit to that file).
DATA-B-02 second H1 + "When to Use This Skill" inside a reference.
DATA-B-04 three registration methods, compact -- keeping the four load-bearing
facts (AppPlugin auto-binds; the `functions` map; `packageId`; and
that programmatic binding gets NO declarative condition/retry/
timeout/onError/async semantics).
DATA-B-05 10+10 generic DO/DON'T -> the compact 5+5 rules/hooks.md carried.
DATA-C-03 vitest + LiteKernel harnesses -> one-line pointer to
objectstack-platform, which claims that surface in its frontmatter.
DATA-D-01/02/03 invented benchmark table, plain-JS "Advanced Topics", generic
Troubleshooting and the Summary that repeated the DO list verbatim.
The References block survives, and absorbs the two cross-package
pointers rules/hooks.md carried so no routing is lost.
DATA-D-04 patterns 1,2,4,5,7,9 (generic JS) deleted; 3,6,8,10 kept, renumbered.
DATA-E-04 the file prescribed `body` and demonstrated `handler` ten times: two
surviving patterns are now sandboxed `body` with declared capabilities.
INC-03 (found while rewriting pattern 8, evidence pinned): "There is NO
`updateMany`" is true of the HANDLER-side repo -- ObjectRepository, what
ctx.api.object() returns, packages/objectql/src/engine.ts:13575-13600 -- but the
SANDBOX repo does install updateMany/deleteMany
(packages/runtime/src/sandbox/quickjs-runner.ts:544-545), exactly as this file's
own capability table says. The comment now names the surface it is true of.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…01/02, cut restatement
Additions (all paid by deletions in this same file; SKILL.md 13892 -> 12535):
DATA-F-01 `sharingModel` row + the four canonical values. Used by 31/31 real
objects and absent from both property tables. A publish with no
authored sharingModel is refused (`security-owd-unset`, 422) --
maintainer ruling 2026-08-13 recorded at
packages/lint/src/authoring-rules.ts:1293-1296; enum at
packages/spec/src/data/object.zod.ts:2177.
DATA-F-02 `required` (write contract) vs `storage: { notNull: true }` (the DDL),
ADR-0113 -- never mentioned in the package before.
DATA-F-03 `icon` / `pluralLabel` / `highlightFields` rows.
DATA-F-04 four security lint rows; three are publish-blocking errors.
DATA-E-05 the Quick-Start Template now carries the face every real object has
(pluralLabel/description/icon/highlightFields) and drops `indexes`,
which appears in 1 of 26 corpus files.
INC-01 (HIGH) -- the schema-evolution table named `required` as the NOT NULL dial
and claimed dev auto-heals it. Both wrong: schema-drift.ts:795-798 compares
`field.storage?.notNull`, explicitly NOT `required`; the emitted op is
severity 'warning' / category 'needs_confirm' / 'relax_not_null' and the comment
says "never auto-applied"; sql-driver.ts:10746 applies only category 'safe'.
INC-02 (MED) -- the tell-tale promised a clean 400 "<field> is required".
schema-drift.ts:800-802: that configuration dies as a RAW DRIVER ERROR instead.
Deletions: DATA-A-03 (intro + when-to-use restating the frontmatter), DATA-C-01
(two verbatim error transcripts; the query skill carries the same 400 text),
DATA-C-04 (standalone tombstones -- each key is refused by a parse error
carrying its own prescription, and objectstack-upgrade owns that path),
DATA-C-05 (protection: schema + lock table + ONE example survive), DATA-D-12,
DATA-D-13, DATA-D-15, DATA-F-06, DATA-G-01 (one CLI spelling: `os`).
DATA-F-05 is a SHRINK, not a removal (retirement deferred pending #14296):
`defineObjectExtension` and `readScope`/`writeScope` each keep one
schema-pointing row -- zero corpus usage is evidence, not proof.
DATA-A-01/A-02/F-06 rewrite the frontmatter description: it never said
datasource / external / federated though rules/datasources.md is entirely that
surface, never said lifecycle or protection, and fired on `*.seed.ts` -- a
pattern that matches nothing in the repo.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…ips, field-types
DATA-D-11 naming.md six ❌/✅ pairs + Critical Rules restatements + Rationale for a
rule the regex in the table already states. 773 -> 248.
DATA-D-05/06/07 indexing.md: generic RDBMS 101 ("when to add indexes"), four
❌/✅ pairs + three subsections teaching one textbook fact
(left-to-right) collapsed to one paragraph, the unsourced
`Table Size -> Max Indexes` table, the pg_stat_user_indexes /
SHOW INDEX SQL, and a 10-item Best Practices restating the
file. The naming block survives -- `name` is a declared key.
DATA-C-04 indexing.md's standalone `type`/`partial` tombstone clause;
the in-line ❌ block at "Retired and Redundant Keys" stays,
because there a wrong key sits beside the right one.
DATA-C-02 validation CEL-vs-SQL is objectstack-formula's anchor and this package's
description already says to load it alongside. The INVERSION
rule stays -- it is validation-specific and lives nowhere else.
DATA-D-09/D-10 validation.md: five patterns restating four examples already on
the page; 10 best practices + 4 unsourced performance claims
about two rules that lower to the same CEL evaluator.
DATA-B-07 the "no `unique` validation type" rule was stated at 7 sites;
the restatements in validation.md and relationships.md go.
DATA-D-08 relationships.md Best Practices + Performance Considerations.
DATA-D-14/E-03/G-02 field-types.md: three ❌/✅ pairs duplicating naming.md, the type
table and a lint rule (the autonumber pair survives) pay for the
`Field.*` factory preamble -- the corpus is ~92% factory
(~250 calls vs 22 literals) and this file had zero `Field.*`.
DATA-E-02 two blocks carried an `import` and then opened `{` /
`validations: [` at statement position, which TS parses as a
labelled-statement block. Both are now real declarations.
DATA-E-01 `os:check` markers on the two self-contained SKILL.md blocks
that compile (definePermissionSet, the protection example).
Verified: `check:skill-examples` type-checks 261 marked blocks.
Two liveness-ledger bindings needed handling, both fallout of deleting rules/hooks.md
and the F-05 shrink:
- the `### Access depth (scope-depth) …` heading is ledger-bound, so the shrink's
incidental rename is reverted -- the ledger is right.
- `hook-lifecycle-events-rule` binds a heading in the deleted file. The gate's own
message prescribes "Re-point `heading`, or delete the row"; re-pointing would
duplicate `hook-lifecycle-events-reference`, which already binds the same symbol
(HookEvent) to the surviving canonical file, so the row is dropped. This is the
one edit outside the declared file surface and it is reported as such.
`check:skill-docs` DEMANDED regeneration (it runs in CI, lint.yml:3986): the
frontmatter description changed, so `pnpm --filter @objectstack/spec gen:skill-docs`
regenerated skills/README.md and content/docs/ai/skills-reference.mdx. Generated
`references/_index.md` is untouched and `check:skill-refs` is green.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
The DATA-C-04 / D-12 / D-13 deletions removed two role-word occurrences from
skills/objectstack-data/SKILL.md, so `pnpm check:role-word` failed as a
ratchet-DOWN: "role-word count improved 4 -> 2 — run
`node scripts/check-role-word.mjs --update` and commit the baseline". That
remedy is the author's own (baseline EXPANSION is the maintainer-only
direction), so the baseline is updated here. The diff is one line, for this
file only, and it shrinks.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-litantos-litant added skip-changeset PR has no user-facing published change; bypasses the changeset gate needs:contract-review and removed size/xl labels Sep 2, 2026 — with Claude
@github-actionsgithub-actionsBot added the documentation Improvements or additions to documentation label Sep 2, 2026
os-litant pushed a commit that referenced this pull request Sep 2, 2026
…ht's consolidation
`references/plugin-hooks.md` sent readers chasing per-record validation,
defaults and audit trails to `objectstack-data`'s `rules/hooks.md`. The data
flight (PR #14427, head 061e5f4) DELETES that file and consolidates hooks into
`objectstack-data/references/data-hooks.md`, so the reference is repointed
before it can dangle.
Now a real relative link rather than two bare file names:
`../../objectstack-data/references/data-hooks.md`, verified to resolve from
`references/` to skills/objectstack-data/references/data-hooks.md. The old text
named both `rules/hooks.md` and `references/data-hooks.md`; only the surviving
one is named now, so the span is 22 bytes SHORTER — references/plugin-hooks.md
2418 -> 2413 tokens (ceiling 2628, untouched).
`git grep rules/hooks.md` over this package returns nothing further, so this
was the only site.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 06:41
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 940c128Sep 2, 2026
50 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-14297-skills-data-optimization branch September 2, 2026 07:06
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens) - #14427

Merged
os-zhuang merged 4 commits into
mainfrom
claude/issue-14297-skills-data-optimization
Sep 2, 2026
Merged

skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens)#14427
os-zhuang merged 4 commits into
mainfrom
claude/issue-14297-skills-data-optimization

Conversation

@os-litant

@os-litantos-litant commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Part of #14297

Optimization flight for skills/objectstack-data, the largest package in the published
catalog. Implements the card's IMPLEMENT scope from the 43-row audit record (posted
verbatim as a comment on the card). Governed surface (skills/** markdown) ⇒ this PR
stays draft
; needs:contract-review is on both carriers because INC-01 corrects a
contract-semantics claim.

Net: 45,780 → 36,736 hand-authored tokens (−9,044, −19.8%). One published file
deleted, none added, no ceiling raised, every ratcheted file byte-neutral-or-shrinking.

Per-file token delta

FilebeforeafterΔceilingheadroom
SKILL.md13,89212,553−1,33913,8921,339
references/data-hooks.md12,5849,703−2,88112,6112,908
rules/hooks.md2,195deleted−2,195row dropped
rules/indexing.md3,2402,166−1,0743,2411,075
rules/validation.md3,1092,362−7473,109747
rules/naming.md773248−525773525
rules/relationships.md3,7733,490−2833,778288
rules/field-types.md3,5783,57803,5846
rules/lifecycle.md1,5901,59001,5900
rules/datasources.md90390309118
evals/README.md14314301430
package45,78036,736−9,044

references/_index.md (generated, 1,483) untouched.

Two rows differ from the card's projection and are called out rather than forced:

  • rules/field-types.md nets 0, not −50. DATA-D-14 paid −200; the DATA-E-03
    Field.* preamble is what it bought. Cross-file payment is not available (the ratchet
    is per file), so the addition was trimmed twice until it fit inside D-14's payment. The
    file does not grow.
  • evals/README.md unchanged. DATA-H-01 raises a ceiling and is on the card's DEFER
    list.

落点 | before | after

finding落点beforeafter
DATA-B-01 / I-03rules/hooks.md (whole file)2,195 tok calling itself "a reference pointer", then restating 5 sections of the canonical filedeleted; references/data-hooks.md is the single hooks file and the catalog's hooks anchor. Ceiling row dropped
DATA-B-02data-hooks.md:1-26two H1s, two intros saying the same thing, a "When to Use This Skill" inside a referenceone H1, one intro
DATA-B-038-event table ∥ in both filesstated in full twice (466 + 525 tok)one copy (the canonical file's), via the file deletion
DATA-B-04data-hooks.md:1050-1133three registration methods in 566 tokcompact, 4 load-bearing facts kept: AppPlugin auto-binds, the functions map, packageId, and that programmatic binding gets no declarative condition/retry/timeout/onError/async semantics
DATA-B-05data-hooks.md:1136-116010+10 generic DO/DON'Tthe compact 5+5 rules/hooks.md carried
DATA-B-077 sites"no unique validation type" stated seven timesrestatements in validation.md + relationships.md dropped; SKILL.md + the indexing.md scope table keep it
DATA-C-01SKILL.md:162-189two verbatim CLI/HTTP error transcripts (the 400 text word-for-word in objectstack-query)3 lines naming both refusals; the modelling half (mirror field + two-hook maintenance table) stays — this package is its anchor
DATA-C-02validation.md:26-36, 313-331CEL-vs-SQL prose + a ❌/✅ pairpointer to objectstack-formula (the anchor); the inversion rule stays, it lives nowhere else
DATA-C-03data-hooks.md:1209-1275vitest + LiteKernel harnesses importing 4 unresolvable packagesone-line pointer to objectstack-platform, whose frontmatter claims that surface
DATA-C-045 tombstone sitesstandalone narration of removed keys (rls, encryptionConfig, tenancy.strategy, softDelete/versioning, type/partial)deleted; each key is refused by a parse error carrying its own prescription, and objectstack-upgrade owns in-place upgrades. In-line ❌ markers kept where a wrong key sits beside the right one
DATA-C-05SKILL.md:858-971987 tok: 3 near-identical examples for a 4-value enum + Studio-banner narration + 5-bullet guidanceschema block + 4-row lock table + ONE example + 4 lines of enforcement
DATA-D-01/02/03data-hooks.md:1279-1444invented benchmark table (0 hooks ~1ms…), plain-JS "Advanced Topics", generic Troubleshooting, a Summary repeating the DO list verbatimdeleted; the References block survives and absorbs the two cross-package pointers rules/hooks.md carried
DATA-D-04data-hooks.md:765-104610 patterns, 6 of them plain JavaScriptpatterns 1,2,4,5,7,9 deleted; 3,6,8,10 kept and renumbered
DATA-D-05/06/07rules/indexing.mdRDBMS 101, one textbook fact taught seven ways, unsourced Table Size → Max Indexes, pg_stat_user_indexes SQL, 10 best practicesone paragraph on composite order; naming block kept (name is a declared key)
DATA-D-08relationships.md:398-4137 + 4 items restating the file's own tablesdeleted
DATA-D-09/D-10validation.md:355-4385 patterns restating 4 examples on the same page; 10 best practices + 4 unsourced perf claimsdeleted
DATA-D-11naming.md:15-1076 ❌/✅ pairs + restatements + rationale for a rule the regex already statestable + Critical Rules (773 → 248)
DATA-D-12SKILL.md:540-555"CRM Schema Blueprint" pointing at 6 things covered above itdeleted
DATA-D-13SKILL.md:974-987"Advanced Features Checklist" + tombstone footnotedeleted
DATA-D-14field-types.md:360-4113 ❌/✅ pairs duplicating naming.md, the type table, and a lint ruledeleted (autonumber pair survives) — funds DATA-E-03
DATA-D-15SKILL.md:1178-1181the live model-benchmarking doordeleted (platform benchmarking, not app authoring)
DATA-E-01/E-022 blocksself-contained blocks opening { / validations: [ at statement position (TS parses that as a labelled-statement block)real declarations; os:check markers added to the two SKILL.md blocks that compile
DATA-E-03 / G-02rules/field-types.mdzero Field.* in the file whose job is field authoring; corpus is ~92% factoryField.* preamble with the literal ↔ factory mapping
DATA-E-04data-hooks.md patternsfile prescribed body, demonstrated deprecated handler 10 times2 surviving patterns converted to sandboxed body with declared capabilities
DATA-E-05SKILL.md:325-379the one copy-pasteable object diverged from all 31 real onespluralLabel/description/icon/highlightFields added, indexes dropped (1 of 26 corpus files)
DATA-F-01SKILL.md:64-84sharingModel on 31/31 real objects, absent from both property tablesrequired-table row + 4-row value table
DATA-F-02SKILL.md:383-403storage.notNull never mentioned in the packagerequired = write contract, storage.notNull = the DDL
DATA-F-03SKILL.md:71-84icon/pluralLabel/highlightFields undocumentedthree rows
DATA-F-04SKILL.md:1142-11529 data-model lint rules, 0 security rules4 security rows, 3 of them publish-blocking
DATA-F-05SKILL.mddefineObjectExtension, readScope/writeScope — zero corpus usageshrunk to one schema-pointing row each, not deleted (retirement deferred pending #14296; zero usage in examples is evidence, not proof)
DATA-F-06SKILL.md:1129 + frontmatterprescribed {object}.seed.ts; find . -name '*.seed.ts' returns 0 repo-widerow deleted, trigger aligned to src/data/*.ts
DATA-G-016 sitesobjectstack lint and os lint in one file, 60 lines apartnormalised to os
INC-01SKILL.md:393required: true → false "dev auto-heals (autoMigrate:'safe')"corrected — see below
INC-02SKILL.md:398-401stale NOT NULL produces a clean 400corrected — raw driver error

Contract-semantics corrections (why needs:contract-review)

INC-01. The schema-evolution table named the wrong dial and claimed auto-healing. Both
halves are false against the implementation:

  • packages/drivers/driver-sql/src/schema-drift.ts:795-798const expectNullable = field.storage?.notNull !== true; under a comment reading "compared against
    storage.notNull, the explicit physical constraint — NOT against required, which is
    the write-time contract and implies nothing about the column".
  • The emitted drift is severity: 'warning', category: 'needs_confirm',
    op: { type: 'relax_not_null' } (schema-drift.ts:815-826), above a comment saying
    "never auto-applied".
  • packages/drivers/driver-sql/src/sql-driver.ts:10746const safe = drift.filter((d) => d.category === 'safe');. autoMigrate: 'safe' applies only category safe, so
    it never touches this op.

INC-02.schema-drift.ts:800-802 says that exact configuration means "an omitting
write reaches the DB and dies as a raw driver error instead of a clean validation 400" —
the opposite symptom to the one the tell-tale promised.

INC-03 (new, found while rewriting DATA-D-04 pattern 8). The file asserted "There is
NO updateMany" a few hundred lines below a capability table listing updateMany as
"also installed". Both are true of different surfaces and neither said which:
ObjectRepository — what a handler's ctx.api.object() returns
(packages/objectql/src/engine.ts:13563-13600) — has no updateMany; the sandbox repo
does (packages/runtime/src/sandbox/quickjs-runner.ts:544-545). The comment now names its
surface. This is why patterns 3 and 6 were converted to body and pattern 8 was left as a
handler.

premise_false

None. git diff --stat a59f78d HEAD -- skills/objectstack-data was EMPTY at my base
909a4417, so all 43 spans resolved byte-identically and no finding had to be skipped.

One card-level detail did not hold, and needed no action: the card's ANCHOR RULINGS says
the inbound link at rules/hooks.md:202 points at objectstack-platform
rules/plugin-hooks-events.md and must be re-pointed. At base it already pointed at
objectstack-platform/references/plugin-hooks.md. The file is deleted here anyway, and
that pointer is preserved in the surviving References block.

PM mechanical assumptions — measured

  1. Spans byte-identical at a59f78d. TRUE. git diff --stat a59f78d HEAD -- skills/objectstack-data empty; git diff --stat d63c8a25 HEAD -- skills/ empty;
    the ratchet script unchanged since the pin.
  2. Does check:skill-docs demand regenerating skills/README.md?YES, and it runs
    in CI
    (.github/workflows/lint.yml:3986). The frontmatter description changed, the
    gate failed, and pnpm --filter @objectstack/spec gen:skill-docs regenerated
    skills/README.mdandcontent/docs/ai/skills-reference.mdx — the second file was
    not in the assumption. Both diffs are one data-row each. check:skill-refs is green
    and references/_index.md is untouched.
  3. Deleting rules/hooks.md reds the ratchet unless its ceiling row goes. TRUE, and
    verified in both directions from a committed state with a restore trap: with the row
    re-injected the gate prints ✗ check-skills-token-ratchet: cannot read skills/objectstack-data/rules/hooks.md — red, not a skip (#4690) and exits 1; restored
    (blob hash equal to HEAD, git diff HEAD empty) it exits 0.
  4. The os:check rule is in the header of check-skill-examples.ts. TRUE (lines
    17-23): a marker is os:check in an HTML comment on the line directly above the fence.
    The seven would-fail blocks were handled as the audit proposed — 2 repaired, 2 deleted
    with DATA-C-03, 3 left unmarked (they import unresolvable paths). Markers were added
    only after the gate proved they pass: 261 marked blocks type-check.
  5. A finding whose premise is false is skipped. None were.

Follow-ups by package

  • objectstack-platformreferences/plugin-hooks.md:77 routes readers to the
    objectstack-data skill "(rules/hooks.md, …)", the file this PR deletes. It is another
    package, so it is untouched here; the platform flight (Skills optimization flight — skills/objectstack-platform: RESTRUCTURE (≈ −5,970 tok, −25%) — an orphan rules file with zero inbound links, the canonical hooks reference two hops from the entry file, "When to Use" printed twice, and requires: / engines.protocol / onEnable (every real config) taught nowhere #14299) should re-point it to
    references/data-hooks.md. No gate reads it (check:published-readme-links is scoped to
    package READMEs, not skills/**), so nothing is red today.
  • objectstack-platform — DATA-C-03 removed the LiteKernel/vitest hook harnesses from
    this package and left a pointer. Platform's frontmatter already claims "test harnesses
    via LiteKernel"; it does not yet carry a hook-testing example for the pointer to land on.
  • maintainer decision (DATA-F-07, deferred by the card)defineHook() is prescribed
    twice, but grep -rln defineHook --include='*.ts' outside packages/spec and
    packages/cli returns 0 files, and both real hook modules use the bare : Hook literal
    (examples/app-crm/src/hooks/opportunity.hook.ts:10,
    examples/app-todo/src/objects/task.hook.ts:51). Either the examples move to
    defineHook() or the prescription softens; it is not a doc edit.
  • deferred with the card — DATA-I-04 (a new rules/security.md; would add a file),
    DATA-H-01 (would raise the evals/README.md ceiling), DATA-B-06 (moving the routing
    table up: a MOVE-TO, which is not among the card's three IMPLEMENT verbs, and its only
    named MOVE-TO sibling is deferred). DATA-D-11 is MED confidence with the audit noting a
    maintainer may want one ❌/✅ pair kept — restoring one is a cheap review edit.

Edits outside the declared file surface

The card scoped this to skills/objectstack-data/** plus the one ratchet ceiling row.
Three further files are in the diff. Each is fallout of the mandated deletion, each was
prescribed by the failing gate itself, and each shrinks:

  1. scripts/check-skill-identifier-liveness.mjs — the hook-lifecycle-events-rule ledger
    row binds the heading ### 8 Lifecycle Eventsinside the deleted file, so the gate
    went red. Its message prescribes "Re-point heading, or delete the row". Re-pointing
    would duplicate hook-lifecycle-events-reference, which already binds the same symbol
    (HookEvent) to the surviving canonical file, so the row is dropped. Separately, the
    DATA-F-05 shrink had incidentally renamed another ledger-bound heading
    (### Access depth (scope-depth) …); there the ledger is right and the rename was
    reverted in SKILL.md.
  2. scripts/role-word-baseline.json — the deletions removed two role-word occurrences from
    SKILL.md, so check:role-word failed as a ratchet-DOWN: "count improved 4 → 2 —
    run node scripts/check-role-word.mjs --update and commit the baseline". That direction
    is the author's own remedy (expansion is the maintainer-only one). One line, shrinking.
  3. skills/README.md + content/docs/ai/skills-reference.mdx — generated, regenerated by
    the sanctioned generator, as assumption 2 above records.

Gates — head 061e5f4c

Run with exit codes captured before any pipe. Heavy builds went through
scripts/pm/os-verify-lock.sh.

The four gates named on the card:

gateverdict line
node scripts/check-skills-token-ratchet.mjs✓ 37 authored bundle file(s) within their ceilings (was 38; one file deleted)
pnpm --filter @objectstack/spec check:skill-examples✅ 261 prose examples type-check across 3 surface(s)
pnpm check:skill-compatibility✓ 11 SKILL.md file(s) reconciled against 78 workspace packages
pnpm check:skill-identifier-livenessOK — Leg 1: 492 citation(s) over 47 published file(s); Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s)

Plus the full family node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
derives for the real 13-path change set — 55 gates, re-derived and re-run on this head:
53 exit 0. The two non-zero are exit 3 = NOT MEASURED by the gates' own definition, not
reds:

  • node scripts/check-test-completeness.mjs — "There is no local log to hand it, so the
    local reading for this gate is NOT MEASURED. ⛔ It is not a red." It wants a saved
    turbo run test log.
  • node scripts/pm/check-half-states.mjs — needs the GitHub API, which is 403 from this
    container.

Ratchet self-test green (64 cases pass). check:skill-docs, check:skill-refs,
check:role-word, check:doc-authoring, check:corpus-claim-drift,
check:pm-governed-merges, check:ratchet-remedy-authority all green on this head.

skip-changeset applies: docs-only, publishing nothing from any package.


🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

DATA-B-01 / I-03 — rules/hooks.md called itself "a reference pointer" and then
restated five sections of the canonical file. Delete it; references/data-hooks.md
is the single hooks file and the catalog's hooks anchor. Its ceiling row is
dropped from scripts/check-skills-token-ratchet.mjs (the only edit to that file).
DATA-B-02 second H1 + "When to Use This Skill" inside a reference.
DATA-B-04 three registration methods, compact -- keeping the four load-bearing
facts (AppPlugin auto-binds; the `functions` map; `packageId`; and
that programmatic binding gets NO declarative condition/retry/
timeout/onError/async semantics).
DATA-B-05 10+10 generic DO/DON'T -> the compact 5+5 rules/hooks.md carried.
DATA-C-03 vitest + LiteKernel harnesses -> one-line pointer to
objectstack-platform, which claims that surface in its frontmatter.
DATA-D-01/02/03 invented benchmark table, plain-JS "Advanced Topics", generic
Troubleshooting and the Summary that repeated the DO list verbatim.
The References block survives, and absorbs the two cross-package
pointers rules/hooks.md carried so no routing is lost.
DATA-D-04 patterns 1,2,4,5,7,9 (generic JS) deleted; 3,6,8,10 kept, renumbered.
DATA-E-04 the file prescribed `body` and demonstrated `handler` ten times: two
surviving patterns are now sandboxed `body` with declared capabilities.
INC-03 (found while rewriting pattern 8, evidence pinned): "There is NO
`updateMany`" is true of the HANDLER-side repo -- ObjectRepository, what
ctx.api.object() returns, packages/objectql/src/engine.ts:13575-13600 -- but the
SANDBOX repo does install updateMany/deleteMany
(packages/runtime/src/sandbox/quickjs-runner.ts:544-545), exactly as this file's
own capability table says. The comment now names the surface it is true of.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…01/02, cut restatement
Additions (all paid by deletions in this same file; SKILL.md 13892 -> 12535):
DATA-F-01 `sharingModel` row + the four canonical values. Used by 31/31 real
objects and absent from both property tables. A publish with no
authored sharingModel is refused (`security-owd-unset`, 422) --
maintainer ruling 2026-08-13 recorded at
packages/lint/src/authoring-rules.ts:1293-1296; enum at
packages/spec/src/data/object.zod.ts:2177.
DATA-F-02 `required` (write contract) vs `storage: { notNull: true }` (the DDL),
ADR-0113 -- never mentioned in the package before.
DATA-F-03 `icon` / `pluralLabel` / `highlightFields` rows.
DATA-F-04 four security lint rows; three are publish-blocking errors.
DATA-E-05 the Quick-Start Template now carries the face every real object has
(pluralLabel/description/icon/highlightFields) and drops `indexes`,
which appears in 1 of 26 corpus files.
INC-01 (HIGH) -- the schema-evolution table named `required` as the NOT NULL dial
and claimed dev auto-heals it. Both wrong: schema-drift.ts:795-798 compares
`field.storage?.notNull`, explicitly NOT `required`; the emitted op is
severity 'warning' / category 'needs_confirm' / 'relax_not_null' and the comment
says "never auto-applied"; sql-driver.ts:10746 applies only category 'safe'.
INC-02 (MED) -- the tell-tale promised a clean 400 "<field> is required".
schema-drift.ts:800-802: that configuration dies as a RAW DRIVER ERROR instead.
Deletions: DATA-A-03 (intro + when-to-use restating the frontmatter), DATA-C-01
(two verbatim error transcripts; the query skill carries the same 400 text),
DATA-C-04 (standalone tombstones -- each key is refused by a parse error
carrying its own prescription, and objectstack-upgrade owns that path),
DATA-C-05 (protection: schema + lock table + ONE example survive), DATA-D-12,
DATA-D-13, DATA-D-15, DATA-F-06, DATA-G-01 (one CLI spelling: `os`).
DATA-F-05 is a SHRINK, not a removal (retirement deferred pending #14296):
`defineObjectExtension` and `readScope`/`writeScope` each keep one
schema-pointing row -- zero corpus usage is evidence, not proof.
DATA-A-01/A-02/F-06 rewrite the frontmatter description: it never said
datasource / external / federated though rules/datasources.md is entirely that
surface, never said lifecycle or protection, and fired on `*.seed.ts` -- a
pattern that matches nothing in the repo.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…ips, field-types
DATA-D-11 naming.md six ❌/✅ pairs + Critical Rules restatements + Rationale for a
rule the regex in the table already states. 773 -> 248.
DATA-D-05/06/07 indexing.md: generic RDBMS 101 ("when to add indexes"), four
❌/✅ pairs + three subsections teaching one textbook fact
(left-to-right) collapsed to one paragraph, the unsourced
`Table Size -> Max Indexes` table, the pg_stat_user_indexes /
SHOW INDEX SQL, and a 10-item Best Practices restating the
file. The naming block survives -- `name` is a declared key.
DATA-C-04 indexing.md's standalone `type`/`partial` tombstone clause;
the in-line ❌ block at "Retired and Redundant Keys" stays,
because there a wrong key sits beside the right one.
DATA-C-02 validation CEL-vs-SQL is objectstack-formula's anchor and this package's
description already says to load it alongside. The INVERSION
rule stays -- it is validation-specific and lives nowhere else.
DATA-D-09/D-10 validation.md: five patterns restating four examples already on
the page; 10 best practices + 4 unsourced performance claims
about two rules that lower to the same CEL evaluator.
DATA-B-07 the "no `unique` validation type" rule was stated at 7 sites;
the restatements in validation.md and relationships.md go.
DATA-D-08 relationships.md Best Practices + Performance Considerations.
DATA-D-14/E-03/G-02 field-types.md: three ❌/✅ pairs duplicating naming.md, the type
table and a lint rule (the autonumber pair survives) pay for the
`Field.*` factory preamble -- the corpus is ~92% factory
(~250 calls vs 22 literals) and this file had zero `Field.*`.
DATA-E-02 two blocks carried an `import` and then opened `{` /
`validations: [` at statement position, which TS parses as a
labelled-statement block. Both are now real declarations.
DATA-E-01 `os:check` markers on the two self-contained SKILL.md blocks
that compile (definePermissionSet, the protection example).
Verified: `check:skill-examples` type-checks 261 marked blocks.
Two liveness-ledger bindings needed handling, both fallout of deleting rules/hooks.md
and the F-05 shrink:
- the `### Access depth (scope-depth) …` heading is ledger-bound, so the shrink's
incidental rename is reverted -- the ledger is right.
- `hook-lifecycle-events-rule` binds a heading in the deleted file. The gate's own
message prescribes "Re-point `heading`, or delete the row"; re-pointing would
duplicate `hook-lifecycle-events-reference`, which already binds the same symbol
(HookEvent) to the surviving canonical file, so the row is dropped. This is the
one edit outside the declared file surface and it is reported as such.
`check:skill-docs` DEMANDED regeneration (it runs in CI, lint.yml:3986): the
frontmatter description changed, so `pnpm --filter @objectstack/spec gen:skill-docs`
regenerated skills/README.md and content/docs/ai/skills-reference.mdx. Generated
`references/_index.md` is untouched and `check:skill-refs` is green.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
The DATA-C-04 / D-12 / D-13 deletions removed two role-word occurrences from
skills/objectstack-data/SKILL.md, so `pnpm check:role-word` failed as a
ratchet-DOWN: "role-word count improved 4 -> 2 — run
`node scripts/check-role-word.mjs --update` and commit the baseline". That
remedy is the author's own (baseline EXPANSION is the maintainer-only
direction), so the baseline is updated here. The diff is one line, for this
file only, and it shrinks.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-litantos-litant added skip-changeset PR has no user-facing published change; bypasses the changeset gate needs:contract-review and removed size/xl labels Sep 2, 2026 — with Claude
@github-actionsgithub-actionsBot added the documentation Improvements or additions to documentation label Sep 2, 2026
os-litant pushed a commit that referenced this pull request Sep 2, 2026
…ht's consolidation
`references/plugin-hooks.md` sent readers chasing per-record validation,
defaults and audit trails to `objectstack-data`'s `rules/hooks.md`. The data
flight (PR #14427, head 061e5f4) DELETES that file and consolidates hooks into
`objectstack-data/references/data-hooks.md`, so the reference is repointed
before it can dangle.
Now a real relative link rather than two bare file names:
`../../objectstack-data/references/data-hooks.md`, verified to resolve from
`references/` to skills/objectstack-data/references/data-hooks.md. The old text
named both `rules/hooks.md` and `references/data-hooks.md`; only the surviving
one is named now, so the span is 22 bytes SHORTER — references/plugin-hooks.md
2418 -> 2413 tokens (ceiling 2628, untouched).
`git grep rules/hooks.md` over this package returns nothing further, so this
was the only site.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 06:41
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 940c128Sep 2, 2026
50 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-14297-skills-data-optimization branch September 2, 2026 07:06
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens) - #14427

Merged
os-zhuang merged 4 commits into
mainfrom
claude/issue-14297-skills-data-optimization
Sep 2, 2026
Merged

skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens)#14427
os-zhuang merged 4 commits into
mainfrom
claude/issue-14297-skills-data-optimization

Conversation

@os-litant

@os-litantos-litant commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Part of #14297

Optimization flight for skills/objectstack-data, the largest package in the published
catalog. Implements the card's IMPLEMENT scope from the 43-row audit record (posted
verbatim as a comment on the card). Governed surface (skills/** markdown) ⇒ this PR
stays draft
; needs:contract-review is on both carriers because INC-01 corrects a
contract-semantics claim.

Net: 45,780 → 36,736 hand-authored tokens (−9,044, −19.8%). One published file
deleted, none added, no ceiling raised, every ratcheted file byte-neutral-or-shrinking.

Per-file token delta

FilebeforeafterΔceilingheadroom
SKILL.md13,89212,553−1,33913,8921,339
references/data-hooks.md12,5849,703−2,88112,6112,908
rules/hooks.md2,195deleted−2,195row dropped
rules/indexing.md3,2402,166−1,0743,2411,075
rules/validation.md3,1092,362−7473,109747
rules/naming.md773248−525773525
rules/relationships.md3,7733,490−2833,778288
rules/field-types.md3,5783,57803,5846
rules/lifecycle.md1,5901,59001,5900
rules/datasources.md90390309118
evals/README.md14314301430
package45,78036,736−9,044

references/_index.md (generated, 1,483) untouched.

Two rows differ from the card's projection and are called out rather than forced:

  • rules/field-types.md nets 0, not −50. DATA-D-14 paid −200; the DATA-E-03
    Field.* preamble is what it bought. Cross-file payment is not available (the ratchet
    is per file), so the addition was trimmed twice until it fit inside D-14's payment. The
    file does not grow.
  • evals/README.md unchanged. DATA-H-01 raises a ceiling and is on the card's DEFER
    list.

落点 | before | after

finding落点beforeafter
DATA-B-01 / I-03rules/hooks.md (whole file)2,195 tok calling itself "a reference pointer", then restating 5 sections of the canonical filedeleted; references/data-hooks.md is the single hooks file and the catalog's hooks anchor. Ceiling row dropped
DATA-B-02data-hooks.md:1-26two H1s, two intros saying the same thing, a "When to Use This Skill" inside a referenceone H1, one intro
DATA-B-038-event table ∥ in both filesstated in full twice (466 + 525 tok)one copy (the canonical file's), via the file deletion
DATA-B-04data-hooks.md:1050-1133three registration methods in 566 tokcompact, 4 load-bearing facts kept: AppPlugin auto-binds, the functions map, packageId, and that programmatic binding gets no declarative condition/retry/timeout/onError/async semantics
DATA-B-05data-hooks.md:1136-116010+10 generic DO/DON'Tthe compact 5+5 rules/hooks.md carried
DATA-B-077 sites"no unique validation type" stated seven timesrestatements in validation.md + relationships.md dropped; SKILL.md + the indexing.md scope table keep it
DATA-C-01SKILL.md:162-189two verbatim CLI/HTTP error transcripts (the 400 text word-for-word in objectstack-query)3 lines naming both refusals; the modelling half (mirror field + two-hook maintenance table) stays — this package is its anchor
DATA-C-02validation.md:26-36, 313-331CEL-vs-SQL prose + a ❌/✅ pairpointer to objectstack-formula (the anchor); the inversion rule stays, it lives nowhere else
DATA-C-03data-hooks.md:1209-1275vitest + LiteKernel harnesses importing 4 unresolvable packagesone-line pointer to objectstack-platform, whose frontmatter claims that surface
DATA-C-045 tombstone sitesstandalone narration of removed keys (rls, encryptionConfig, tenancy.strategy, softDelete/versioning, type/partial)deleted; each key is refused by a parse error carrying its own prescription, and objectstack-upgrade owns in-place upgrades. In-line ❌ markers kept where a wrong key sits beside the right one
DATA-C-05SKILL.md:858-971987 tok: 3 near-identical examples for a 4-value enum + Studio-banner narration + 5-bullet guidanceschema block + 4-row lock table + ONE example + 4 lines of enforcement
DATA-D-01/02/03data-hooks.md:1279-1444invented benchmark table (0 hooks ~1ms…), plain-JS "Advanced Topics", generic Troubleshooting, a Summary repeating the DO list verbatimdeleted; the References block survives and absorbs the two cross-package pointers rules/hooks.md carried
DATA-D-04data-hooks.md:765-104610 patterns, 6 of them plain JavaScriptpatterns 1,2,4,5,7,9 deleted; 3,6,8,10 kept and renumbered
DATA-D-05/06/07rules/indexing.mdRDBMS 101, one textbook fact taught seven ways, unsourced Table Size → Max Indexes, pg_stat_user_indexes SQL, 10 best practicesone paragraph on composite order; naming block kept (name is a declared key)
DATA-D-08relationships.md:398-4137 + 4 items restating the file's own tablesdeleted
DATA-D-09/D-10validation.md:355-4385 patterns restating 4 examples on the same page; 10 best practices + 4 unsourced perf claimsdeleted
DATA-D-11naming.md:15-1076 ❌/✅ pairs + restatements + rationale for a rule the regex already statestable + Critical Rules (773 → 248)
DATA-D-12SKILL.md:540-555"CRM Schema Blueprint" pointing at 6 things covered above itdeleted
DATA-D-13SKILL.md:974-987"Advanced Features Checklist" + tombstone footnotedeleted
DATA-D-14field-types.md:360-4113 ❌/✅ pairs duplicating naming.md, the type table, and a lint ruledeleted (autonumber pair survives) — funds DATA-E-03
DATA-D-15SKILL.md:1178-1181the live model-benchmarking doordeleted (platform benchmarking, not app authoring)
DATA-E-01/E-022 blocksself-contained blocks opening { / validations: [ at statement position (TS parses that as a labelled-statement block)real declarations; os:check markers added to the two SKILL.md blocks that compile
DATA-E-03 / G-02rules/field-types.mdzero Field.* in the file whose job is field authoring; corpus is ~92% factoryField.* preamble with the literal ↔ factory mapping
DATA-E-04data-hooks.md patternsfile prescribed body, demonstrated deprecated handler 10 times2 surviving patterns converted to sandboxed body with declared capabilities
DATA-E-05SKILL.md:325-379the one copy-pasteable object diverged from all 31 real onespluralLabel/description/icon/highlightFields added, indexes dropped (1 of 26 corpus files)
DATA-F-01SKILL.md:64-84sharingModel on 31/31 real objects, absent from both property tablesrequired-table row + 4-row value table
DATA-F-02SKILL.md:383-403storage.notNull never mentioned in the packagerequired = write contract, storage.notNull = the DDL
DATA-F-03SKILL.md:71-84icon/pluralLabel/highlightFields undocumentedthree rows
DATA-F-04SKILL.md:1142-11529 data-model lint rules, 0 security rules4 security rows, 3 of them publish-blocking
DATA-F-05SKILL.mddefineObjectExtension, readScope/writeScope — zero corpus usageshrunk to one schema-pointing row each, not deleted (retirement deferred pending #14296; zero usage in examples is evidence, not proof)
DATA-F-06SKILL.md:1129 + frontmatterprescribed {object}.seed.ts; find . -name '*.seed.ts' returns 0 repo-widerow deleted, trigger aligned to src/data/*.ts
DATA-G-016 sitesobjectstack lint and os lint in one file, 60 lines apartnormalised to os
INC-01SKILL.md:393required: true → false "dev auto-heals (autoMigrate:'safe')"corrected — see below
INC-02SKILL.md:398-401stale NOT NULL produces a clean 400corrected — raw driver error

Contract-semantics corrections (why needs:contract-review)

INC-01. The schema-evolution table named the wrong dial and claimed auto-healing. Both
halves are false against the implementation:

  • packages/drivers/driver-sql/src/schema-drift.ts:795-798const expectNullable = field.storage?.notNull !== true; under a comment reading "compared against
    storage.notNull, the explicit physical constraint — NOT against required, which is
    the write-time contract and implies nothing about the column".
  • The emitted drift is severity: 'warning', category: 'needs_confirm',
    op: { type: 'relax_not_null' } (schema-drift.ts:815-826), above a comment saying
    "never auto-applied".
  • packages/drivers/driver-sql/src/sql-driver.ts:10746const safe = drift.filter((d) => d.category === 'safe');. autoMigrate: 'safe' applies only category safe, so
    it never touches this op.

INC-02.schema-drift.ts:800-802 says that exact configuration means "an omitting
write reaches the DB and dies as a raw driver error instead of a clean validation 400" —
the opposite symptom to the one the tell-tale promised.

INC-03 (new, found while rewriting DATA-D-04 pattern 8). The file asserted "There is
NO updateMany" a few hundred lines below a capability table listing updateMany as
"also installed". Both are true of different surfaces and neither said which:
ObjectRepository — what a handler's ctx.api.object() returns
(packages/objectql/src/engine.ts:13563-13600) — has no updateMany; the sandbox repo
does (packages/runtime/src/sandbox/quickjs-runner.ts:544-545). The comment now names its
surface. This is why patterns 3 and 6 were converted to body and pattern 8 was left as a
handler.

premise_false

None. git diff --stat a59f78d HEAD -- skills/objectstack-data was EMPTY at my base
909a4417, so all 43 spans resolved byte-identically and no finding had to be skipped.

One card-level detail did not hold, and needed no action: the card's ANCHOR RULINGS says
the inbound link at rules/hooks.md:202 points at objectstack-platform
rules/plugin-hooks-events.md and must be re-pointed. At base it already pointed at
objectstack-platform/references/plugin-hooks.md. The file is deleted here anyway, and
that pointer is preserved in the surviving References block.

PM mechanical assumptions — measured

  1. Spans byte-identical at a59f78d. TRUE. git diff --stat a59f78d HEAD -- skills/objectstack-data empty; git diff --stat d63c8a25 HEAD -- skills/ empty;
    the ratchet script unchanged since the pin.
  2. Does check:skill-docs demand regenerating skills/README.md?YES, and it runs
    in CI
    (.github/workflows/lint.yml:3986). The frontmatter description changed, the
    gate failed, and pnpm --filter @objectstack/spec gen:skill-docs regenerated
    skills/README.mdandcontent/docs/ai/skills-reference.mdx — the second file was
    not in the assumption. Both diffs are one data-row each. check:skill-refs is green
    and references/_index.md is untouched.
  3. Deleting rules/hooks.md reds the ratchet unless its ceiling row goes. TRUE, and
    verified in both directions from a committed state with a restore trap: with the row
    re-injected the gate prints ✗ check-skills-token-ratchet: cannot read skills/objectstack-data/rules/hooks.md — red, not a skip (#4690) and exits 1; restored
    (blob hash equal to HEAD, git diff HEAD empty) it exits 0.
  4. The os:check rule is in the header of check-skill-examples.ts. TRUE (lines
    17-23): a marker is os:check in an HTML comment on the line directly above the fence.
    The seven would-fail blocks were handled as the audit proposed — 2 repaired, 2 deleted
    with DATA-C-03, 3 left unmarked (they import unresolvable paths). Markers were added
    only after the gate proved they pass: 261 marked blocks type-check.
  5. A finding whose premise is false is skipped. None were.

Follow-ups by package

  • objectstack-platformreferences/plugin-hooks.md:77 routes readers to the
    objectstack-data skill "(rules/hooks.md, …)", the file this PR deletes. It is another
    package, so it is untouched here; the platform flight (Skills optimization flight — skills/objectstack-platform: RESTRUCTURE (≈ −5,970 tok, −25%) — an orphan rules file with zero inbound links, the canonical hooks reference two hops from the entry file, "When to Use" printed twice, and requires: / engines.protocol / onEnable (every real config) taught nowhere #14299) should re-point it to
    references/data-hooks.md. No gate reads it (check:published-readme-links is scoped to
    package READMEs, not skills/**), so nothing is red today.
  • objectstack-platform — DATA-C-03 removed the LiteKernel/vitest hook harnesses from
    this package and left a pointer. Platform's frontmatter already claims "test harnesses
    via LiteKernel"; it does not yet carry a hook-testing example for the pointer to land on.
  • maintainer decision (DATA-F-07, deferred by the card)defineHook() is prescribed
    twice, but grep -rln defineHook --include='*.ts' outside packages/spec and
    packages/cli returns 0 files, and both real hook modules use the bare : Hook literal
    (examples/app-crm/src/hooks/opportunity.hook.ts:10,
    examples/app-todo/src/objects/task.hook.ts:51). Either the examples move to
    defineHook() or the prescription softens; it is not a doc edit.
  • deferred with the card — DATA-I-04 (a new rules/security.md; would add a file),
    DATA-H-01 (would raise the evals/README.md ceiling), DATA-B-06 (moving the routing
    table up: a MOVE-TO, which is not among the card's three IMPLEMENT verbs, and its only
    named MOVE-TO sibling is deferred). DATA-D-11 is MED confidence with the audit noting a
    maintainer may want one ❌/✅ pair kept — restoring one is a cheap review edit.

Edits outside the declared file surface

The card scoped this to skills/objectstack-data/** plus the one ratchet ceiling row.
Three further files are in the diff. Each is fallout of the mandated deletion, each was
prescribed by the failing gate itself, and each shrinks:

  1. scripts/check-skill-identifier-liveness.mjs — the hook-lifecycle-events-rule ledger
    row binds the heading ### 8 Lifecycle Eventsinside the deleted file, so the gate
    went red. Its message prescribes "Re-point heading, or delete the row". Re-pointing
    would duplicate hook-lifecycle-events-reference, which already binds the same symbol
    (HookEvent) to the surviving canonical file, so the row is dropped. Separately, the
    DATA-F-05 shrink had incidentally renamed another ledger-bound heading
    (### Access depth (scope-depth) …); there the ledger is right and the rename was
    reverted in SKILL.md.
  2. scripts/role-word-baseline.json — the deletions removed two role-word occurrences from
    SKILL.md, so check:role-word failed as a ratchet-DOWN: "count improved 4 → 2 —
    run node scripts/check-role-word.mjs --update and commit the baseline". That direction
    is the author's own remedy (expansion is the maintainer-only one). One line, shrinking.
  3. skills/README.md + content/docs/ai/skills-reference.mdx — generated, regenerated by
    the sanctioned generator, as assumption 2 above records.

Gates — head 061e5f4c

Run with exit codes captured before any pipe. Heavy builds went through
scripts/pm/os-verify-lock.sh.

The four gates named on the card:

gateverdict line
node scripts/check-skills-token-ratchet.mjs✓ 37 authored bundle file(s) within their ceilings (was 38; one file deleted)
pnpm --filter @objectstack/spec check:skill-examples✅ 261 prose examples type-check across 3 surface(s)
pnpm check:skill-compatibility✓ 11 SKILL.md file(s) reconciled against 78 workspace packages
pnpm check:skill-identifier-livenessOK — Leg 1: 492 citation(s) over 47 published file(s); Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s)

Plus the full family node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
derives for the real 13-path change set — 55 gates, re-derived and re-run on this head:
53 exit 0. The two non-zero are exit 3 = NOT MEASURED by the gates' own definition, not
reds:

  • node scripts/check-test-completeness.mjs — "There is no local log to hand it, so the
    local reading for this gate is NOT MEASURED. ⛔ It is not a red." It wants a saved
    turbo run test log.
  • node scripts/pm/check-half-states.mjs — needs the GitHub API, which is 403 from this
    container.

Ratchet self-test green (64 cases pass). check:skill-docs, check:skill-refs,
check:role-word, check:doc-authoring, check:corpus-claim-drift,
check:pm-governed-merges, check:ratchet-remedy-authority all green on this head.

skip-changeset applies: docs-only, publishing nothing from any package.


🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

DATA-B-01 / I-03 — rules/hooks.md called itself "a reference pointer" and then
restated five sections of the canonical file. Delete it; references/data-hooks.md
is the single hooks file and the catalog's hooks anchor. Its ceiling row is
dropped from scripts/check-skills-token-ratchet.mjs (the only edit to that file).
DATA-B-02 second H1 + "When to Use This Skill" inside a reference.
DATA-B-04 three registration methods, compact -- keeping the four load-bearing
facts (AppPlugin auto-binds; the `functions` map; `packageId`; and
that programmatic binding gets NO declarative condition/retry/
timeout/onError/async semantics).
DATA-B-05 10+10 generic DO/DON'T -> the compact 5+5 rules/hooks.md carried.
DATA-C-03 vitest + LiteKernel harnesses -> one-line pointer to
objectstack-platform, which claims that surface in its frontmatter.
DATA-D-01/02/03 invented benchmark table, plain-JS "Advanced Topics", generic
Troubleshooting and the Summary that repeated the DO list verbatim.
The References block survives, and absorbs the two cross-package
pointers rules/hooks.md carried so no routing is lost.
DATA-D-04 patterns 1,2,4,5,7,9 (generic JS) deleted; 3,6,8,10 kept, renumbered.
DATA-E-04 the file prescribed `body` and demonstrated `handler` ten times: two
surviving patterns are now sandboxed `body` with declared capabilities.
INC-03 (found while rewriting pattern 8, evidence pinned): "There is NO
`updateMany`" is true of the HANDLER-side repo -- ObjectRepository, what
ctx.api.object() returns, packages/objectql/src/engine.ts:13575-13600 -- but the
SANDBOX repo does install updateMany/deleteMany
(packages/runtime/src/sandbox/quickjs-runner.ts:544-545), exactly as this file's
own capability table says. The comment now names the surface it is true of.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…01/02, cut restatement
Additions (all paid by deletions in this same file; SKILL.md 13892 -> 12535):
DATA-F-01 `sharingModel` row + the four canonical values. Used by 31/31 real
objects and absent from both property tables. A publish with no
authored sharingModel is refused (`security-owd-unset`, 422) --
maintainer ruling 2026-08-13 recorded at
packages/lint/src/authoring-rules.ts:1293-1296; enum at
packages/spec/src/data/object.zod.ts:2177.
DATA-F-02 `required` (write contract) vs `storage: { notNull: true }` (the DDL),
ADR-0113 -- never mentioned in the package before.
DATA-F-03 `icon` / `pluralLabel` / `highlightFields` rows.
DATA-F-04 four security lint rows; three are publish-blocking errors.
DATA-E-05 the Quick-Start Template now carries the face every real object has
(pluralLabel/description/icon/highlightFields) and drops `indexes`,
which appears in 1 of 26 corpus files.
INC-01 (HIGH) -- the schema-evolution table named `required` as the NOT NULL dial
and claimed dev auto-heals it. Both wrong: schema-drift.ts:795-798 compares
`field.storage?.notNull`, explicitly NOT `required`; the emitted op is
severity 'warning' / category 'needs_confirm' / 'relax_not_null' and the comment
says "never auto-applied"; sql-driver.ts:10746 applies only category 'safe'.
INC-02 (MED) -- the tell-tale promised a clean 400 "<field> is required".
schema-drift.ts:800-802: that configuration dies as a RAW DRIVER ERROR instead.
Deletions: DATA-A-03 (intro + when-to-use restating the frontmatter), DATA-C-01
(two verbatim error transcripts; the query skill carries the same 400 text),
DATA-C-04 (standalone tombstones -- each key is refused by a parse error
carrying its own prescription, and objectstack-upgrade owns that path),
DATA-C-05 (protection: schema + lock table + ONE example survive), DATA-D-12,
DATA-D-13, DATA-D-15, DATA-F-06, DATA-G-01 (one CLI spelling: `os`).
DATA-F-05 is a SHRINK, not a removal (retirement deferred pending #14296):
`defineObjectExtension` and `readScope`/`writeScope` each keep one
schema-pointing row -- zero corpus usage is evidence, not proof.
DATA-A-01/A-02/F-06 rewrite the frontmatter description: it never said
datasource / external / federated though rules/datasources.md is entirely that
surface, never said lifecycle or protection, and fired on `*.seed.ts` -- a
pattern that matches nothing in the repo.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…ips, field-types
DATA-D-11 naming.md six ❌/✅ pairs + Critical Rules restatements + Rationale for a
rule the regex in the table already states. 773 -> 248.
DATA-D-05/06/07 indexing.md: generic RDBMS 101 ("when to add indexes"), four
❌/✅ pairs + three subsections teaching one textbook fact
(left-to-right) collapsed to one paragraph, the unsourced
`Table Size -> Max Indexes` table, the pg_stat_user_indexes /
SHOW INDEX SQL, and a 10-item Best Practices restating the
file. The naming block survives -- `name` is a declared key.
DATA-C-04 indexing.md's standalone `type`/`partial` tombstone clause;
the in-line ❌ block at "Retired and Redundant Keys" stays,
because there a wrong key sits beside the right one.
DATA-C-02 validation CEL-vs-SQL is objectstack-formula's anchor and this package's
description already says to load it alongside. The INVERSION
rule stays -- it is validation-specific and lives nowhere else.
DATA-D-09/D-10 validation.md: five patterns restating four examples already on
the page; 10 best practices + 4 unsourced performance claims
about two rules that lower to the same CEL evaluator.
DATA-B-07 the "no `unique` validation type" rule was stated at 7 sites;
the restatements in validation.md and relationships.md go.
DATA-D-08 relationships.md Best Practices + Performance Considerations.
DATA-D-14/E-03/G-02 field-types.md: three ❌/✅ pairs duplicating naming.md, the type
table and a lint rule (the autonumber pair survives) pay for the
`Field.*` factory preamble -- the corpus is ~92% factory
(~250 calls vs 22 literals) and this file had zero `Field.*`.
DATA-E-02 two blocks carried an `import` and then opened `{` /
`validations: [` at statement position, which TS parses as a
labelled-statement block. Both are now real declarations.
DATA-E-01 `os:check` markers on the two self-contained SKILL.md blocks
that compile (definePermissionSet, the protection example).
Verified: `check:skill-examples` type-checks 261 marked blocks.
Two liveness-ledger bindings needed handling, both fallout of deleting rules/hooks.md
and the F-05 shrink:
- the `### Access depth (scope-depth) …` heading is ledger-bound, so the shrink's
incidental rename is reverted -- the ledger is right.
- `hook-lifecycle-events-rule` binds a heading in the deleted file. The gate's own
message prescribes "Re-point `heading`, or delete the row"; re-pointing would
duplicate `hook-lifecycle-events-reference`, which already binds the same symbol
(HookEvent) to the surviving canonical file, so the row is dropped. This is the
one edit outside the declared file surface and it is reported as such.
`check:skill-docs` DEMANDED regeneration (it runs in CI, lint.yml:3986): the
frontmatter description changed, so `pnpm --filter @objectstack/spec gen:skill-docs`
regenerated skills/README.md and content/docs/ai/skills-reference.mdx. Generated
`references/_index.md` is untouched and `check:skill-refs` is green.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
The DATA-C-04 / D-12 / D-13 deletions removed two role-word occurrences from
skills/objectstack-data/SKILL.md, so `pnpm check:role-word` failed as a
ratchet-DOWN: "role-word count improved 4 -> 2 — run
`node scripts/check-role-word.mjs --update` and commit the baseline". That
remedy is the author's own (baseline EXPANSION is the maintainer-only
direction), so the baseline is updated here. The diff is one line, for this
file only, and it shrinks.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-litantos-litant added skip-changeset PR has no user-facing published change; bypasses the changeset gate needs:contract-review and removed size/xl labels Sep 2, 2026 — with Claude
@github-actionsgithub-actionsBot added the documentation Improvements or additions to documentation label Sep 2, 2026
os-litant pushed a commit that referenced this pull request Sep 2, 2026
…ht's consolidation
`references/plugin-hooks.md` sent readers chasing per-record validation,
defaults and audit trails to `objectstack-data`'s `rules/hooks.md`. The data
flight (PR #14427, head 061e5f4) DELETES that file and consolidates hooks into
`objectstack-data/references/data-hooks.md`, so the reference is repointed
before it can dangle.
Now a real relative link rather than two bare file names:
`../../objectstack-data/references/data-hooks.md`, verified to resolve from
`references/` to skills/objectstack-data/references/data-hooks.md. The old text
named both `rules/hooks.md` and `references/data-hooks.md`; only the surviving
one is named now, so the span is 22 bytes SHORTER — references/plugin-hooks.md
2418 -> 2413 tokens (ceiling 2628, untouched).
`git grep rules/hooks.md` over this package returns nothing further, so this
was the only site.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 06:41
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 940c128Sep 2, 2026
50 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-14297-skills-data-optimization branch September 2, 2026 07:06
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens) - #14427

Merged
os-zhuang merged 4 commits into
mainfrom
claude/issue-14297-skills-data-optimization
Sep 2, 2026
Merged

skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens)#14427
os-zhuang merged 4 commits into
mainfrom
claude/issue-14297-skills-data-optimization

Conversation

@os-litant

@os-litantos-litant commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Part of #14297

Optimization flight for skills/objectstack-data, the largest package in the published
catalog. Implements the card's IMPLEMENT scope from the 43-row audit record (posted
verbatim as a comment on the card). Governed surface (skills/** markdown) ⇒ this PR
stays draft
; needs:contract-review is on both carriers because INC-01 corrects a
contract-semantics claim.

Net: 45,780 → 36,736 hand-authored tokens (−9,044, −19.8%). One published file
deleted, none added, no ceiling raised, every ratcheted file byte-neutral-or-shrinking.

Per-file token delta

FilebeforeafterΔceilingheadroom
SKILL.md13,89212,553−1,33913,8921,339
references/data-hooks.md12,5849,703−2,88112,6112,908
rules/hooks.md2,195deleted−2,195row dropped
rules/indexing.md3,2402,166−1,0743,2411,075
rules/validation.md3,1092,362−7473,109747
rules/naming.md773248−525773525
rules/relationships.md3,7733,490−2833,778288
rules/field-types.md3,5783,57803,5846
rules/lifecycle.md1,5901,59001,5900
rules/datasources.md90390309118
evals/README.md14314301430
package45,78036,736−9,044

references/_index.md (generated, 1,483) untouched.

Two rows differ from the card's projection and are called out rather than forced:

  • rules/field-types.md nets 0, not −50. DATA-D-14 paid −200; the DATA-E-03
    Field.* preamble is what it bought. Cross-file payment is not available (the ratchet
    is per file), so the addition was trimmed twice until it fit inside D-14's payment. The
    file does not grow.
  • evals/README.md unchanged. DATA-H-01 raises a ceiling and is on the card's DEFER
    list.

落点 | before | after

finding落点beforeafter
DATA-B-01 / I-03rules/hooks.md (whole file)2,195 tok calling itself "a reference pointer", then restating 5 sections of the canonical filedeleted; references/data-hooks.md is the single hooks file and the catalog's hooks anchor. Ceiling row dropped
DATA-B-02data-hooks.md:1-26two H1s, two intros saying the same thing, a "When to Use This Skill" inside a referenceone H1, one intro
DATA-B-038-event table ∥ in both filesstated in full twice (466 + 525 tok)one copy (the canonical file's), via the file deletion
DATA-B-04data-hooks.md:1050-1133three registration methods in 566 tokcompact, 4 load-bearing facts kept: AppPlugin auto-binds, the functions map, packageId, and that programmatic binding gets no declarative condition/retry/timeout/onError/async semantics
DATA-B-05data-hooks.md:1136-116010+10 generic DO/DON'Tthe compact 5+5 rules/hooks.md carried
DATA-B-077 sites"no unique validation type" stated seven timesrestatements in validation.md + relationships.md dropped; SKILL.md + the indexing.md scope table keep it
DATA-C-01SKILL.md:162-189two verbatim CLI/HTTP error transcripts (the 400 text word-for-word in objectstack-query)3 lines naming both refusals; the modelling half (mirror field + two-hook maintenance table) stays — this package is its anchor
DATA-C-02validation.md:26-36, 313-331CEL-vs-SQL prose + a ❌/✅ pairpointer to objectstack-formula (the anchor); the inversion rule stays, it lives nowhere else
DATA-C-03data-hooks.md:1209-1275vitest + LiteKernel harnesses importing 4 unresolvable packagesone-line pointer to objectstack-platform, whose frontmatter claims that surface
DATA-C-045 tombstone sitesstandalone narration of removed keys (rls, encryptionConfig, tenancy.strategy, softDelete/versioning, type/partial)deleted; each key is refused by a parse error carrying its own prescription, and objectstack-upgrade owns in-place upgrades. In-line ❌ markers kept where a wrong key sits beside the right one
DATA-C-05SKILL.md:858-971987 tok: 3 near-identical examples for a 4-value enum + Studio-banner narration + 5-bullet guidanceschema block + 4-row lock table + ONE example + 4 lines of enforcement
DATA-D-01/02/03data-hooks.md:1279-1444invented benchmark table (0 hooks ~1ms…), plain-JS "Advanced Topics", generic Troubleshooting, a Summary repeating the DO list verbatimdeleted; the References block survives and absorbs the two cross-package pointers rules/hooks.md carried
DATA-D-04data-hooks.md:765-104610 patterns, 6 of them plain JavaScriptpatterns 1,2,4,5,7,9 deleted; 3,6,8,10 kept and renumbered
DATA-D-05/06/07rules/indexing.mdRDBMS 101, one textbook fact taught seven ways, unsourced Table Size → Max Indexes, pg_stat_user_indexes SQL, 10 best practicesone paragraph on composite order; naming block kept (name is a declared key)
DATA-D-08relationships.md:398-4137 + 4 items restating the file's own tablesdeleted
DATA-D-09/D-10validation.md:355-4385 patterns restating 4 examples on the same page; 10 best practices + 4 unsourced perf claimsdeleted
DATA-D-11naming.md:15-1076 ❌/✅ pairs + restatements + rationale for a rule the regex already statestable + Critical Rules (773 → 248)
DATA-D-12SKILL.md:540-555"CRM Schema Blueprint" pointing at 6 things covered above itdeleted
DATA-D-13SKILL.md:974-987"Advanced Features Checklist" + tombstone footnotedeleted
DATA-D-14field-types.md:360-4113 ❌/✅ pairs duplicating naming.md, the type table, and a lint ruledeleted (autonumber pair survives) — funds DATA-E-03
DATA-D-15SKILL.md:1178-1181the live model-benchmarking doordeleted (platform benchmarking, not app authoring)
DATA-E-01/E-022 blocksself-contained blocks opening { / validations: [ at statement position (TS parses that as a labelled-statement block)real declarations; os:check markers added to the two SKILL.md blocks that compile
DATA-E-03 / G-02rules/field-types.mdzero Field.* in the file whose job is field authoring; corpus is ~92% factoryField.* preamble with the literal ↔ factory mapping
DATA-E-04data-hooks.md patternsfile prescribed body, demonstrated deprecated handler 10 times2 surviving patterns converted to sandboxed body with declared capabilities
DATA-E-05SKILL.md:325-379the one copy-pasteable object diverged from all 31 real onespluralLabel/description/icon/highlightFields added, indexes dropped (1 of 26 corpus files)
DATA-F-01SKILL.md:64-84sharingModel on 31/31 real objects, absent from both property tablesrequired-table row + 4-row value table
DATA-F-02SKILL.md:383-403storage.notNull never mentioned in the packagerequired = write contract, storage.notNull = the DDL
DATA-F-03SKILL.md:71-84icon/pluralLabel/highlightFields undocumentedthree rows
DATA-F-04SKILL.md:1142-11529 data-model lint rules, 0 security rules4 security rows, 3 of them publish-blocking
DATA-F-05SKILL.mddefineObjectExtension, readScope/writeScope — zero corpus usageshrunk to one schema-pointing row each, not deleted (retirement deferred pending #14296; zero usage in examples is evidence, not proof)
DATA-F-06SKILL.md:1129 + frontmatterprescribed {object}.seed.ts; find . -name '*.seed.ts' returns 0 repo-widerow deleted, trigger aligned to src/data/*.ts
DATA-G-016 sitesobjectstack lint and os lint in one file, 60 lines apartnormalised to os
INC-01SKILL.md:393required: true → false "dev auto-heals (autoMigrate:'safe')"corrected — see below
INC-02SKILL.md:398-401stale NOT NULL produces a clean 400corrected — raw driver error

Contract-semantics corrections (why needs:contract-review)

INC-01. The schema-evolution table named the wrong dial and claimed auto-healing. Both
halves are false against the implementation:

  • packages/drivers/driver-sql/src/schema-drift.ts:795-798const expectNullable = field.storage?.notNull !== true; under a comment reading "compared against
    storage.notNull, the explicit physical constraint — NOT against required, which is
    the write-time contract and implies nothing about the column".
  • The emitted drift is severity: 'warning', category: 'needs_confirm',
    op: { type: 'relax_not_null' } (schema-drift.ts:815-826), above a comment saying
    "never auto-applied".
  • packages/drivers/driver-sql/src/sql-driver.ts:10746const safe = drift.filter((d) => d.category === 'safe');. autoMigrate: 'safe' applies only category safe, so
    it never touches this op.

INC-02.schema-drift.ts:800-802 says that exact configuration means "an omitting
write reaches the DB and dies as a raw driver error instead of a clean validation 400" —
the opposite symptom to the one the tell-tale promised.

INC-03 (new, found while rewriting DATA-D-04 pattern 8). The file asserted "There is
NO updateMany" a few hundred lines below a capability table listing updateMany as
"also installed". Both are true of different surfaces and neither said which:
ObjectRepository — what a handler's ctx.api.object() returns
(packages/objectql/src/engine.ts:13563-13600) — has no updateMany; the sandbox repo
does (packages/runtime/src/sandbox/quickjs-runner.ts:544-545). The comment now names its
surface. This is why patterns 3 and 6 were converted to body and pattern 8 was left as a
handler.

premise_false

None. git diff --stat a59f78d HEAD -- skills/objectstack-data was EMPTY at my base
909a4417, so all 43 spans resolved byte-identically and no finding had to be skipped.

One card-level detail did not hold, and needed no action: the card's ANCHOR RULINGS says
the inbound link at rules/hooks.md:202 points at objectstack-platform
rules/plugin-hooks-events.md and must be re-pointed. At base it already pointed at
objectstack-platform/references/plugin-hooks.md. The file is deleted here anyway, and
that pointer is preserved in the surviving References block.

PM mechanical assumptions — measured

  1. Spans byte-identical at a59f78d. TRUE. git diff --stat a59f78d HEAD -- skills/objectstack-data empty; git diff --stat d63c8a25 HEAD -- skills/ empty;
    the ratchet script unchanged since the pin.
  2. Does check:skill-docs demand regenerating skills/README.md?YES, and it runs
    in CI
    (.github/workflows/lint.yml:3986). The frontmatter description changed, the
    gate failed, and pnpm --filter @objectstack/spec gen:skill-docs regenerated
    skills/README.mdandcontent/docs/ai/skills-reference.mdx — the second file was
    not in the assumption. Both diffs are one data-row each. check:skill-refs is green
    and references/_index.md is untouched.
  3. Deleting rules/hooks.md reds the ratchet unless its ceiling row goes. TRUE, and
    verified in both directions from a committed state with a restore trap: with the row
    re-injected the gate prints ✗ check-skills-token-ratchet: cannot read skills/objectstack-data/rules/hooks.md — red, not a skip (#4690) and exits 1; restored
    (blob hash equal to HEAD, git diff HEAD empty) it exits 0.
  4. The os:check rule is in the header of check-skill-examples.ts. TRUE (lines
    17-23): a marker is os:check in an HTML comment on the line directly above the fence.
    The seven would-fail blocks were handled as the audit proposed — 2 repaired, 2 deleted
    with DATA-C-03, 3 left unmarked (they import unresolvable paths). Markers were added
    only after the gate proved they pass: 261 marked blocks type-check.
  5. A finding whose premise is false is skipped. None were.

Follow-ups by package

  • objectstack-platformreferences/plugin-hooks.md:77 routes readers to the
    objectstack-data skill "(rules/hooks.md, …)", the file this PR deletes. It is another
    package, so it is untouched here; the platform flight (Skills optimization flight — skills/objectstack-platform: RESTRUCTURE (≈ −5,970 tok, −25%) — an orphan rules file with zero inbound links, the canonical hooks reference two hops from the entry file, "When to Use" printed twice, and requires: / engines.protocol / onEnable (every real config) taught nowhere #14299) should re-point it to
    references/data-hooks.md. No gate reads it (check:published-readme-links is scoped to
    package READMEs, not skills/**), so nothing is red today.
  • objectstack-platform — DATA-C-03 removed the LiteKernel/vitest hook harnesses from
    this package and left a pointer. Platform's frontmatter already claims "test harnesses
    via LiteKernel"; it does not yet carry a hook-testing example for the pointer to land on.
  • maintainer decision (DATA-F-07, deferred by the card)defineHook() is prescribed
    twice, but grep -rln defineHook --include='*.ts' outside packages/spec and
    packages/cli returns 0 files, and both real hook modules use the bare : Hook literal
    (examples/app-crm/src/hooks/opportunity.hook.ts:10,
    examples/app-todo/src/objects/task.hook.ts:51). Either the examples move to
    defineHook() or the prescription softens; it is not a doc edit.
  • deferred with the card — DATA-I-04 (a new rules/security.md; would add a file),
    DATA-H-01 (would raise the evals/README.md ceiling), DATA-B-06 (moving the routing
    table up: a MOVE-TO, which is not among the card's three IMPLEMENT verbs, and its only
    named MOVE-TO sibling is deferred). DATA-D-11 is MED confidence with the audit noting a
    maintainer may want one ❌/✅ pair kept — restoring one is a cheap review edit.

Edits outside the declared file surface

The card scoped this to skills/objectstack-data/** plus the one ratchet ceiling row.
Three further files are in the diff. Each is fallout of the mandated deletion, each was
prescribed by the failing gate itself, and each shrinks:

  1. scripts/check-skill-identifier-liveness.mjs — the hook-lifecycle-events-rule ledger
    row binds the heading ### 8 Lifecycle Eventsinside the deleted file, so the gate
    went red. Its message prescribes "Re-point heading, or delete the row". Re-pointing
    would duplicate hook-lifecycle-events-reference, which already binds the same symbol
    (HookEvent) to the surviving canonical file, so the row is dropped. Separately, the
    DATA-F-05 shrink had incidentally renamed another ledger-bound heading
    (### Access depth (scope-depth) …); there the ledger is right and the rename was
    reverted in SKILL.md.
  2. scripts/role-word-baseline.json — the deletions removed two role-word occurrences from
    SKILL.md, so check:role-word failed as a ratchet-DOWN: "count improved 4 → 2 —
    run node scripts/check-role-word.mjs --update and commit the baseline". That direction
    is the author's own remedy (expansion is the maintainer-only one). One line, shrinking.
  3. skills/README.md + content/docs/ai/skills-reference.mdx — generated, regenerated by
    the sanctioned generator, as assumption 2 above records.

Gates — head 061e5f4c

Run with exit codes captured before any pipe. Heavy builds went through
scripts/pm/os-verify-lock.sh.

The four gates named on the card:

gateverdict line
node scripts/check-skills-token-ratchet.mjs✓ 37 authored bundle file(s) within their ceilings (was 38; one file deleted)
pnpm --filter @objectstack/spec check:skill-examples✅ 261 prose examples type-check across 3 surface(s)
pnpm check:skill-compatibility✓ 11 SKILL.md file(s) reconciled against 78 workspace packages
pnpm check:skill-identifier-livenessOK — Leg 1: 492 citation(s) over 47 published file(s); Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s)

Plus the full family node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
derives for the real 13-path change set — 55 gates, re-derived and re-run on this head:
53 exit 0. The two non-zero are exit 3 = NOT MEASURED by the gates' own definition, not
reds:

  • node scripts/check-test-completeness.mjs — "There is no local log to hand it, so the
    local reading for this gate is NOT MEASURED. ⛔ It is not a red." It wants a saved
    turbo run test log.
  • node scripts/pm/check-half-states.mjs — needs the GitHub API, which is 403 from this
    container.

Ratchet self-test green (64 cases pass). check:skill-docs, check:skill-refs,
check:role-word, check:doc-authoring, check:corpus-claim-drift,
check:pm-governed-merges, check:ratchet-remedy-authority all green on this head.

skip-changeset applies: docs-only, publishing nothing from any package.


🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

DATA-B-01 / I-03 — rules/hooks.md called itself "a reference pointer" and then
restated five sections of the canonical file. Delete it; references/data-hooks.md
is the single hooks file and the catalog's hooks anchor. Its ceiling row is
dropped from scripts/check-skills-token-ratchet.mjs (the only edit to that file).
DATA-B-02 second H1 + "When to Use This Skill" inside a reference.
DATA-B-04 three registration methods, compact -- keeping the four load-bearing
facts (AppPlugin auto-binds; the `functions` map; `packageId`; and
that programmatic binding gets NO declarative condition/retry/
timeout/onError/async semantics).
DATA-B-05 10+10 generic DO/DON'T -> the compact 5+5 rules/hooks.md carried.
DATA-C-03 vitest + LiteKernel harnesses -> one-line pointer to
objectstack-platform, which claims that surface in its frontmatter.
DATA-D-01/02/03 invented benchmark table, plain-JS "Advanced Topics", generic
Troubleshooting and the Summary that repeated the DO list verbatim.
The References block survives, and absorbs the two cross-package
pointers rules/hooks.md carried so no routing is lost.
DATA-D-04 patterns 1,2,4,5,7,9 (generic JS) deleted; 3,6,8,10 kept, renumbered.
DATA-E-04 the file prescribed `body` and demonstrated `handler` ten times: two
surviving patterns are now sandboxed `body` with declared capabilities.
INC-03 (found while rewriting pattern 8, evidence pinned): "There is NO
`updateMany`" is true of the HANDLER-side repo -- ObjectRepository, what
ctx.api.object() returns, packages/objectql/src/engine.ts:13575-13600 -- but the
SANDBOX repo does install updateMany/deleteMany
(packages/runtime/src/sandbox/quickjs-runner.ts:544-545), exactly as this file's
own capability table says. The comment now names the surface it is true of.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…01/02, cut restatement
Additions (all paid by deletions in this same file; SKILL.md 13892 -> 12535):
DATA-F-01 `sharingModel` row + the four canonical values. Used by 31/31 real
objects and absent from both property tables. A publish with no
authored sharingModel is refused (`security-owd-unset`, 422) --
maintainer ruling 2026-08-13 recorded at
packages/lint/src/authoring-rules.ts:1293-1296; enum at
packages/spec/src/data/object.zod.ts:2177.
DATA-F-02 `required` (write contract) vs `storage: { notNull: true }` (the DDL),
ADR-0113 -- never mentioned in the package before.
DATA-F-03 `icon` / `pluralLabel` / `highlightFields` rows.
DATA-F-04 four security lint rows; three are publish-blocking errors.
DATA-E-05 the Quick-Start Template now carries the face every real object has
(pluralLabel/description/icon/highlightFields) and drops `indexes`,
which appears in 1 of 26 corpus files.
INC-01 (HIGH) -- the schema-evolution table named `required` as the NOT NULL dial
and claimed dev auto-heals it. Both wrong: schema-drift.ts:795-798 compares
`field.storage?.notNull`, explicitly NOT `required`; the emitted op is
severity 'warning' / category 'needs_confirm' / 'relax_not_null' and the comment
says "never auto-applied"; sql-driver.ts:10746 applies only category 'safe'.
INC-02 (MED) -- the tell-tale promised a clean 400 "<field> is required".
schema-drift.ts:800-802: that configuration dies as a RAW DRIVER ERROR instead.
Deletions: DATA-A-03 (intro + when-to-use restating the frontmatter), DATA-C-01
(two verbatim error transcripts; the query skill carries the same 400 text),
DATA-C-04 (standalone tombstones -- each key is refused by a parse error
carrying its own prescription, and objectstack-upgrade owns that path),
DATA-C-05 (protection: schema + lock table + ONE example survive), DATA-D-12,
DATA-D-13, DATA-D-15, DATA-F-06, DATA-G-01 (one CLI spelling: `os`).
DATA-F-05 is a SHRINK, not a removal (retirement deferred pending #14296):
`defineObjectExtension` and `readScope`/`writeScope` each keep one
schema-pointing row -- zero corpus usage is evidence, not proof.
DATA-A-01/A-02/F-06 rewrite the frontmatter description: it never said
datasource / external / federated though rules/datasources.md is entirely that
surface, never said lifecycle or protection, and fired on `*.seed.ts` -- a
pattern that matches nothing in the repo.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…ips, field-types
DATA-D-11 naming.md six ❌/✅ pairs + Critical Rules restatements + Rationale for a
rule the regex in the table already states. 773 -> 248.
DATA-D-05/06/07 indexing.md: generic RDBMS 101 ("when to add indexes"), four
❌/✅ pairs + three subsections teaching one textbook fact
(left-to-right) collapsed to one paragraph, the unsourced
`Table Size -> Max Indexes` table, the pg_stat_user_indexes /
SHOW INDEX SQL, and a 10-item Best Practices restating the
file. The naming block survives -- `name` is a declared key.
DATA-C-04 indexing.md's standalone `type`/`partial` tombstone clause;
the in-line ❌ block at "Retired and Redundant Keys" stays,
because there a wrong key sits beside the right one.
DATA-C-02 validation CEL-vs-SQL is objectstack-formula's anchor and this package's
description already says to load it alongside. The INVERSION
rule stays -- it is validation-specific and lives nowhere else.
DATA-D-09/D-10 validation.md: five patterns restating four examples already on
the page; 10 best practices + 4 unsourced performance claims
about two rules that lower to the same CEL evaluator.
DATA-B-07 the "no `unique` validation type" rule was stated at 7 sites;
the restatements in validation.md and relationships.md go.
DATA-D-08 relationships.md Best Practices + Performance Considerations.
DATA-D-14/E-03/G-02 field-types.md: three ❌/✅ pairs duplicating naming.md, the type
table and a lint rule (the autonumber pair survives) pay for the
`Field.*` factory preamble -- the corpus is ~92% factory
(~250 calls vs 22 literals) and this file had zero `Field.*`.
DATA-E-02 two blocks carried an `import` and then opened `{` /
`validations: [` at statement position, which TS parses as a
labelled-statement block. Both are now real declarations.
DATA-E-01 `os:check` markers on the two self-contained SKILL.md blocks
that compile (definePermissionSet, the protection example).
Verified: `check:skill-examples` type-checks 261 marked blocks.
Two liveness-ledger bindings needed handling, both fallout of deleting rules/hooks.md
and the F-05 shrink:
- the `### Access depth (scope-depth) …` heading is ledger-bound, so the shrink's
incidental rename is reverted -- the ledger is right.
- `hook-lifecycle-events-rule` binds a heading in the deleted file. The gate's own
message prescribes "Re-point `heading`, or delete the row"; re-pointing would
duplicate `hook-lifecycle-events-reference`, which already binds the same symbol
(HookEvent) to the surviving canonical file, so the row is dropped. This is the
one edit outside the declared file surface and it is reported as such.
`check:skill-docs` DEMANDED regeneration (it runs in CI, lint.yml:3986): the
frontmatter description changed, so `pnpm --filter @objectstack/spec gen:skill-docs`
regenerated skills/README.md and content/docs/ai/skills-reference.mdx. Generated
`references/_index.md` is untouched and `check:skill-refs` is green.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
The DATA-C-04 / D-12 / D-13 deletions removed two role-word occurrences from
skills/objectstack-data/SKILL.md, so `pnpm check:role-word` failed as a
ratchet-DOWN: "role-word count improved 4 -> 2 — run
`node scripts/check-role-word.mjs --update` and commit the baseline". That
remedy is the author's own (baseline EXPANSION is the maintainer-only
direction), so the baseline is updated here. The diff is one line, for this
file only, and it shrinks.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-litantos-litant added skip-changeset PR has no user-facing published change; bypasses the changeset gate needs:contract-review and removed size/xl labels Sep 2, 2026 — with Claude
@github-actionsgithub-actionsBot added the documentation Improvements or additions to documentation label Sep 2, 2026
os-litant pushed a commit that referenced this pull request Sep 2, 2026
…ht's consolidation
`references/plugin-hooks.md` sent readers chasing per-record validation,
defaults and audit trails to `objectstack-data`'s `rules/hooks.md`. The data
flight (PR #14427, head 061e5f4) DELETES that file and consolidates hooks into
`objectstack-data/references/data-hooks.md`, so the reference is repointed
before it can dangle.
Now a real relative link rather than two bare file names:
`../../objectstack-data/references/data-hooks.md`, verified to resolve from
`references/` to skills/objectstack-data/references/data-hooks.md. The old text
named both `rules/hooks.md` and `references/data-hooks.md`; only the surviving
one is named now, so the span is 22 bytes SHORTER — references/plugin-hooks.md
2418 -> 2413 tokens (ceiling 2628, untouched).
`git grep rules/hooks.md` over this package returns nothing further, so this
was the only site.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 06:41
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 940c128Sep 2, 2026
50 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-14297-skills-data-optimization branch September 2, 2026 07:06
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens) - #14427

Merged
os-zhuang merged 4 commits into
mainfrom
claude/issue-14297-skills-data-optimization
Sep 2, 2026
Merged

skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens)#14427
os-zhuang merged 4 commits into
mainfrom
claude/issue-14297-skills-data-optimization

Conversation

@os-litant

@os-litantos-litant commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Part of #14297

Optimization flight for skills/objectstack-data, the largest package in the published
catalog. Implements the card's IMPLEMENT scope from the 43-row audit record (posted
verbatim as a comment on the card). Governed surface (skills/** markdown) ⇒ this PR
stays draft
; needs:contract-review is on both carriers because INC-01 corrects a
contract-semantics claim.

Net: 45,780 → 36,736 hand-authored tokens (−9,044, −19.8%). One published file
deleted, none added, no ceiling raised, every ratcheted file byte-neutral-or-shrinking.

Per-file token delta

FilebeforeafterΔceilingheadroom
SKILL.md13,89212,553−1,33913,8921,339
references/data-hooks.md12,5849,703−2,88112,6112,908
rules/hooks.md2,195deleted−2,195row dropped
rules/indexing.md3,2402,166−1,0743,2411,075
rules/validation.md3,1092,362−7473,109747
rules/naming.md773248−525773525
rules/relationships.md3,7733,490−2833,778288
rules/field-types.md3,5783,57803,5846
rules/lifecycle.md1,5901,59001,5900
rules/datasources.md90390309118
evals/README.md14314301430
package45,78036,736−9,044

references/_index.md (generated, 1,483) untouched.

Two rows differ from the card's projection and are called out rather than forced:

  • rules/field-types.md nets 0, not −50. DATA-D-14 paid −200; the DATA-E-03
    Field.* preamble is what it bought. Cross-file payment is not available (the ratchet
    is per file), so the addition was trimmed twice until it fit inside D-14's payment. The
    file does not grow.
  • evals/README.md unchanged. DATA-H-01 raises a ceiling and is on the card's DEFER
    list.

落点 | before | after

finding落点beforeafter
DATA-B-01 / I-03rules/hooks.md (whole file)2,195 tok calling itself "a reference pointer", then restating 5 sections of the canonical filedeleted; references/data-hooks.md is the single hooks file and the catalog's hooks anchor. Ceiling row dropped
DATA-B-02data-hooks.md:1-26two H1s, two intros saying the same thing, a "When to Use This Skill" inside a referenceone H1, one intro
DATA-B-038-event table ∥ in both filesstated in full twice (466 + 525 tok)one copy (the canonical file's), via the file deletion
DATA-B-04data-hooks.md:1050-1133three registration methods in 566 tokcompact, 4 load-bearing facts kept: AppPlugin auto-binds, the functions map, packageId, and that programmatic binding gets no declarative condition/retry/timeout/onError/async semantics
DATA-B-05data-hooks.md:1136-116010+10 generic DO/DON'Tthe compact 5+5 rules/hooks.md carried
DATA-B-077 sites"no unique validation type" stated seven timesrestatements in validation.md + relationships.md dropped; SKILL.md + the indexing.md scope table keep it
DATA-C-01SKILL.md:162-189two verbatim CLI/HTTP error transcripts (the 400 text word-for-word in objectstack-query)3 lines naming both refusals; the modelling half (mirror field + two-hook maintenance table) stays — this package is its anchor
DATA-C-02validation.md:26-36, 313-331CEL-vs-SQL prose + a ❌/✅ pairpointer to objectstack-formula (the anchor); the inversion rule stays, it lives nowhere else
DATA-C-03data-hooks.md:1209-1275vitest + LiteKernel harnesses importing 4 unresolvable packagesone-line pointer to objectstack-platform, whose frontmatter claims that surface
DATA-C-045 tombstone sitesstandalone narration of removed keys (rls, encryptionConfig, tenancy.strategy, softDelete/versioning, type/partial)deleted; each key is refused by a parse error carrying its own prescription, and objectstack-upgrade owns in-place upgrades. In-line ❌ markers kept where a wrong key sits beside the right one
DATA-C-05SKILL.md:858-971987 tok: 3 near-identical examples for a 4-value enum + Studio-banner narration + 5-bullet guidanceschema block + 4-row lock table + ONE example + 4 lines of enforcement
DATA-D-01/02/03data-hooks.md:1279-1444invented benchmark table (0 hooks ~1ms…), plain-JS "Advanced Topics", generic Troubleshooting, a Summary repeating the DO list verbatimdeleted; the References block survives and absorbs the two cross-package pointers rules/hooks.md carried
DATA-D-04data-hooks.md:765-104610 patterns, 6 of them plain JavaScriptpatterns 1,2,4,5,7,9 deleted; 3,6,8,10 kept and renumbered
DATA-D-05/06/07rules/indexing.mdRDBMS 101, one textbook fact taught seven ways, unsourced Table Size → Max Indexes, pg_stat_user_indexes SQL, 10 best practicesone paragraph on composite order; naming block kept (name is a declared key)
DATA-D-08relationships.md:398-4137 + 4 items restating the file's own tablesdeleted
DATA-D-09/D-10validation.md:355-4385 patterns restating 4 examples on the same page; 10 best practices + 4 unsourced perf claimsdeleted
DATA-D-11naming.md:15-1076 ❌/✅ pairs + restatements + rationale for a rule the regex already statestable + Critical Rules (773 → 248)
DATA-D-12SKILL.md:540-555"CRM Schema Blueprint" pointing at 6 things covered above itdeleted
DATA-D-13SKILL.md:974-987"Advanced Features Checklist" + tombstone footnotedeleted
DATA-D-14field-types.md:360-4113 ❌/✅ pairs duplicating naming.md, the type table, and a lint ruledeleted (autonumber pair survives) — funds DATA-E-03
DATA-D-15SKILL.md:1178-1181the live model-benchmarking doordeleted (platform benchmarking, not app authoring)
DATA-E-01/E-022 blocksself-contained blocks opening { / validations: [ at statement position (TS parses that as a labelled-statement block)real declarations; os:check markers added to the two SKILL.md blocks that compile
DATA-E-03 / G-02rules/field-types.mdzero Field.* in the file whose job is field authoring; corpus is ~92% factoryField.* preamble with the literal ↔ factory mapping
DATA-E-04data-hooks.md patternsfile prescribed body, demonstrated deprecated handler 10 times2 surviving patterns converted to sandboxed body with declared capabilities
DATA-E-05SKILL.md:325-379the one copy-pasteable object diverged from all 31 real onespluralLabel/description/icon/highlightFields added, indexes dropped (1 of 26 corpus files)
DATA-F-01SKILL.md:64-84sharingModel on 31/31 real objects, absent from both property tablesrequired-table row + 4-row value table
DATA-F-02SKILL.md:383-403storage.notNull never mentioned in the packagerequired = write contract, storage.notNull = the DDL
DATA-F-03SKILL.md:71-84icon/pluralLabel/highlightFields undocumentedthree rows
DATA-F-04SKILL.md:1142-11529 data-model lint rules, 0 security rules4 security rows, 3 of them publish-blocking
DATA-F-05SKILL.mddefineObjectExtension, readScope/writeScope — zero corpus usageshrunk to one schema-pointing row each, not deleted (retirement deferred pending #14296; zero usage in examples is evidence, not proof)
DATA-F-06SKILL.md:1129 + frontmatterprescribed {object}.seed.ts; find . -name '*.seed.ts' returns 0 repo-widerow deleted, trigger aligned to src/data/*.ts
DATA-G-016 sitesobjectstack lint and os lint in one file, 60 lines apartnormalised to os
INC-01SKILL.md:393required: true → false "dev auto-heals (autoMigrate:'safe')"corrected — see below
INC-02SKILL.md:398-401stale NOT NULL produces a clean 400corrected — raw driver error

Contract-semantics corrections (why needs:contract-review)

INC-01. The schema-evolution table named the wrong dial and claimed auto-healing. Both
halves are false against the implementation:

  • packages/drivers/driver-sql/src/schema-drift.ts:795-798const expectNullable = field.storage?.notNull !== true; under a comment reading "compared against
    storage.notNull, the explicit physical constraint — NOT against required, which is
    the write-time contract and implies nothing about the column".
  • The emitted drift is severity: 'warning', category: 'needs_confirm',
    op: { type: 'relax_not_null' } (schema-drift.ts:815-826), above a comment saying
    "never auto-applied".
  • packages/drivers/driver-sql/src/sql-driver.ts:10746const safe = drift.filter((d) => d.category === 'safe');. autoMigrate: 'safe' applies only category safe, so
    it never touches this op.

INC-02.schema-drift.ts:800-802 says that exact configuration means "an omitting
write reaches the DB and dies as a raw driver error instead of a clean validation 400" —
the opposite symptom to the one the tell-tale promised.

INC-03 (new, found while rewriting DATA-D-04 pattern 8). The file asserted "There is
NO updateMany" a few hundred lines below a capability table listing updateMany as
"also installed". Both are true of different surfaces and neither said which:
ObjectRepository — what a handler's ctx.api.object() returns
(packages/objectql/src/engine.ts:13563-13600) — has no updateMany; the sandbox repo
does (packages/runtime/src/sandbox/quickjs-runner.ts:544-545). The comment now names its
surface. This is why patterns 3 and 6 were converted to body and pattern 8 was left as a
handler.

premise_false

None. git diff --stat a59f78d HEAD -- skills/objectstack-data was EMPTY at my base
909a4417, so all 43 spans resolved byte-identically and no finding had to be skipped.

One card-level detail did not hold, and needed no action: the card's ANCHOR RULINGS says
the inbound link at rules/hooks.md:202 points at objectstack-platform
rules/plugin-hooks-events.md and must be re-pointed. At base it already pointed at
objectstack-platform/references/plugin-hooks.md. The file is deleted here anyway, and
that pointer is preserved in the surviving References block.

PM mechanical assumptions — measured

  1. Spans byte-identical at a59f78d. TRUE. git diff --stat a59f78d HEAD -- skills/objectstack-data empty; git diff --stat d63c8a25 HEAD -- skills/ empty;
    the ratchet script unchanged since the pin.
  2. Does check:skill-docs demand regenerating skills/README.md?YES, and it runs
    in CI
    (.github/workflows/lint.yml:3986). The frontmatter description changed, the
    gate failed, and pnpm --filter @objectstack/spec gen:skill-docs regenerated
    skills/README.mdandcontent/docs/ai/skills-reference.mdx — the second file was
    not in the assumption. Both diffs are one data-row each. check:skill-refs is green
    and references/_index.md is untouched.
  3. Deleting rules/hooks.md reds the ratchet unless its ceiling row goes. TRUE, and
    verified in both directions from a committed state with a restore trap: with the row
    re-injected the gate prints ✗ check-skills-token-ratchet: cannot read skills/objectstack-data/rules/hooks.md — red, not a skip (#4690) and exits 1; restored
    (blob hash equal to HEAD, git diff HEAD empty) it exits 0.
  4. The os:check rule is in the header of check-skill-examples.ts. TRUE (lines
    17-23): a marker is os:check in an HTML comment on the line directly above the fence.
    The seven would-fail blocks were handled as the audit proposed — 2 repaired, 2 deleted
    with DATA-C-03, 3 left unmarked (they import unresolvable paths). Markers were added
    only after the gate proved they pass: 261 marked blocks type-check.
  5. A finding whose premise is false is skipped. None were.

Follow-ups by package

  • objectstack-platformreferences/plugin-hooks.md:77 routes readers to the
    objectstack-data skill "(rules/hooks.md, …)", the file this PR deletes. It is another
    package, so it is untouched here; the platform flight (Skills optimization flight — skills/objectstack-platform: RESTRUCTURE (≈ −5,970 tok, −25%) — an orphan rules file with zero inbound links, the canonical hooks reference two hops from the entry file, "When to Use" printed twice, and requires: / engines.protocol / onEnable (every real config) taught nowhere #14299) should re-point it to
    references/data-hooks.md. No gate reads it (check:published-readme-links is scoped to
    package READMEs, not skills/**), so nothing is red today.
  • objectstack-platform — DATA-C-03 removed the LiteKernel/vitest hook harnesses from
    this package and left a pointer. Platform's frontmatter already claims "test harnesses
    via LiteKernel"; it does not yet carry a hook-testing example for the pointer to land on.
  • maintainer decision (DATA-F-07, deferred by the card)defineHook() is prescribed
    twice, but grep -rln defineHook --include='*.ts' outside packages/spec and
    packages/cli returns 0 files, and both real hook modules use the bare : Hook literal
    (examples/app-crm/src/hooks/opportunity.hook.ts:10,
    examples/app-todo/src/objects/task.hook.ts:51). Either the examples move to
    defineHook() or the prescription softens; it is not a doc edit.
  • deferred with the card — DATA-I-04 (a new rules/security.md; would add a file),
    DATA-H-01 (would raise the evals/README.md ceiling), DATA-B-06 (moving the routing
    table up: a MOVE-TO, which is not among the card's three IMPLEMENT verbs, and its only
    named MOVE-TO sibling is deferred). DATA-D-11 is MED confidence with the audit noting a
    maintainer may want one ❌/✅ pair kept — restoring one is a cheap review edit.

Edits outside the declared file surface

The card scoped this to skills/objectstack-data/** plus the one ratchet ceiling row.
Three further files are in the diff. Each is fallout of the mandated deletion, each was
prescribed by the failing gate itself, and each shrinks:

  1. scripts/check-skill-identifier-liveness.mjs — the hook-lifecycle-events-rule ledger
    row binds the heading ### 8 Lifecycle Eventsinside the deleted file, so the gate
    went red. Its message prescribes "Re-point heading, or delete the row". Re-pointing
    would duplicate hook-lifecycle-events-reference, which already binds the same symbol
    (HookEvent) to the surviving canonical file, so the row is dropped. Separately, the
    DATA-F-05 shrink had incidentally renamed another ledger-bound heading
    (### Access depth (scope-depth) …); there the ledger is right and the rename was
    reverted in SKILL.md.
  2. scripts/role-word-baseline.json — the deletions removed two role-word occurrences from
    SKILL.md, so check:role-word failed as a ratchet-DOWN: "count improved 4 → 2 —
    run node scripts/check-role-word.mjs --update and commit the baseline". That direction
    is the author's own remedy (expansion is the maintainer-only one). One line, shrinking.
  3. skills/README.md + content/docs/ai/skills-reference.mdx — generated, regenerated by
    the sanctioned generator, as assumption 2 above records.

Gates — head 061e5f4c

Run with exit codes captured before any pipe. Heavy builds went through
scripts/pm/os-verify-lock.sh.

The four gates named on the card:

gateverdict line
node scripts/check-skills-token-ratchet.mjs✓ 37 authored bundle file(s) within their ceilings (was 38; one file deleted)
pnpm --filter @objectstack/spec check:skill-examples✅ 261 prose examples type-check across 3 surface(s)
pnpm check:skill-compatibility✓ 11 SKILL.md file(s) reconciled against 78 workspace packages
pnpm check:skill-identifier-livenessOK — Leg 1: 492 citation(s) over 47 published file(s); Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s)

Plus the full family node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
derives for the real 13-path change set — 55 gates, re-derived and re-run on this head:
53 exit 0. The two non-zero are exit 3 = NOT MEASURED by the gates' own definition, not
reds:

  • node scripts/check-test-completeness.mjs — "There is no local log to hand it, so the
    local reading for this gate is NOT MEASURED. ⛔ It is not a red." It wants a saved
    turbo run test log.
  • node scripts/pm/check-half-states.mjs — needs the GitHub API, which is 403 from this
    container.

Ratchet self-test green (64 cases pass). check:skill-docs, check:skill-refs,
check:role-word, check:doc-authoring, check:corpus-claim-drift,
check:pm-governed-merges, check:ratchet-remedy-authority all green on this head.

skip-changeset applies: docs-only, publishing nothing from any package.


🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

DATA-B-01 / I-03 — rules/hooks.md called itself "a reference pointer" and then
restated five sections of the canonical file. Delete it; references/data-hooks.md
is the single hooks file and the catalog's hooks anchor. Its ceiling row is
dropped from scripts/check-skills-token-ratchet.mjs (the only edit to that file).
DATA-B-02 second H1 + "When to Use This Skill" inside a reference.
DATA-B-04 three registration methods, compact -- keeping the four load-bearing
facts (AppPlugin auto-binds; the `functions` map; `packageId`; and
that programmatic binding gets NO declarative condition/retry/
timeout/onError/async semantics).
DATA-B-05 10+10 generic DO/DON'T -> the compact 5+5 rules/hooks.md carried.
DATA-C-03 vitest + LiteKernel harnesses -> one-line pointer to
objectstack-platform, which claims that surface in its frontmatter.
DATA-D-01/02/03 invented benchmark table, plain-JS "Advanced Topics", generic
Troubleshooting and the Summary that repeated the DO list verbatim.
The References block survives, and absorbs the two cross-package
pointers rules/hooks.md carried so no routing is lost.
DATA-D-04 patterns 1,2,4,5,7,9 (generic JS) deleted; 3,6,8,10 kept, renumbered.
DATA-E-04 the file prescribed `body` and demonstrated `handler` ten times: two
surviving patterns are now sandboxed `body` with declared capabilities.
INC-03 (found while rewriting pattern 8, evidence pinned): "There is NO
`updateMany`" is true of the HANDLER-side repo -- ObjectRepository, what
ctx.api.object() returns, packages/objectql/src/engine.ts:13575-13600 -- but the
SANDBOX repo does install updateMany/deleteMany
(packages/runtime/src/sandbox/quickjs-runner.ts:544-545), exactly as this file's
own capability table says. The comment now names the surface it is true of.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…01/02, cut restatement
Additions (all paid by deletions in this same file; SKILL.md 13892 -> 12535):
DATA-F-01 `sharingModel` row + the four canonical values. Used by 31/31 real
objects and absent from both property tables. A publish with no
authored sharingModel is refused (`security-owd-unset`, 422) --
maintainer ruling 2026-08-13 recorded at
packages/lint/src/authoring-rules.ts:1293-1296; enum at
packages/spec/src/data/object.zod.ts:2177.
DATA-F-02 `required` (write contract) vs `storage: { notNull: true }` (the DDL),
ADR-0113 -- never mentioned in the package before.
DATA-F-03 `icon` / `pluralLabel` / `highlightFields` rows.
DATA-F-04 four security lint rows; three are publish-blocking errors.
DATA-E-05 the Quick-Start Template now carries the face every real object has
(pluralLabel/description/icon/highlightFields) and drops `indexes`,
which appears in 1 of 26 corpus files.
INC-01 (HIGH) -- the schema-evolution table named `required` as the NOT NULL dial
and claimed dev auto-heals it. Both wrong: schema-drift.ts:795-798 compares
`field.storage?.notNull`, explicitly NOT `required`; the emitted op is
severity 'warning' / category 'needs_confirm' / 'relax_not_null' and the comment
says "never auto-applied"; sql-driver.ts:10746 applies only category 'safe'.
INC-02 (MED) -- the tell-tale promised a clean 400 "<field> is required".
schema-drift.ts:800-802: that configuration dies as a RAW DRIVER ERROR instead.
Deletions: DATA-A-03 (intro + when-to-use restating the frontmatter), DATA-C-01
(two verbatim error transcripts; the query skill carries the same 400 text),
DATA-C-04 (standalone tombstones -- each key is refused by a parse error
carrying its own prescription, and objectstack-upgrade owns that path),
DATA-C-05 (protection: schema + lock table + ONE example survive), DATA-D-12,
DATA-D-13, DATA-D-15, DATA-F-06, DATA-G-01 (one CLI spelling: `os`).
DATA-F-05 is a SHRINK, not a removal (retirement deferred pending #14296):
`defineObjectExtension` and `readScope`/`writeScope` each keep one
schema-pointing row -- zero corpus usage is evidence, not proof.
DATA-A-01/A-02/F-06 rewrite the frontmatter description: it never said
datasource / external / federated though rules/datasources.md is entirely that
surface, never said lifecycle or protection, and fired on `*.seed.ts` -- a
pattern that matches nothing in the repo.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…ips, field-types
DATA-D-11 naming.md six ❌/✅ pairs + Critical Rules restatements + Rationale for a
rule the regex in the table already states. 773 -> 248.
DATA-D-05/06/07 indexing.md: generic RDBMS 101 ("when to add indexes"), four
❌/✅ pairs + three subsections teaching one textbook fact
(left-to-right) collapsed to one paragraph, the unsourced
`Table Size -> Max Indexes` table, the pg_stat_user_indexes /
SHOW INDEX SQL, and a 10-item Best Practices restating the
file. The naming block survives -- `name` is a declared key.
DATA-C-04 indexing.md's standalone `type`/`partial` tombstone clause;
the in-line ❌ block at "Retired and Redundant Keys" stays,
because there a wrong key sits beside the right one.
DATA-C-02 validation CEL-vs-SQL is objectstack-formula's anchor and this package's
description already says to load it alongside. The INVERSION
rule stays -- it is validation-specific and lives nowhere else.
DATA-D-09/D-10 validation.md: five patterns restating four examples already on
the page; 10 best practices + 4 unsourced performance claims
about two rules that lower to the same CEL evaluator.
DATA-B-07 the "no `unique` validation type" rule was stated at 7 sites;
the restatements in validation.md and relationships.md go.
DATA-D-08 relationships.md Best Practices + Performance Considerations.
DATA-D-14/E-03/G-02 field-types.md: three ❌/✅ pairs duplicating naming.md, the type
table and a lint rule (the autonumber pair survives) pay for the
`Field.*` factory preamble -- the corpus is ~92% factory
(~250 calls vs 22 literals) and this file had zero `Field.*`.
DATA-E-02 two blocks carried an `import` and then opened `{` /
`validations: [` at statement position, which TS parses as a
labelled-statement block. Both are now real declarations.
DATA-E-01 `os:check` markers on the two self-contained SKILL.md blocks
that compile (definePermissionSet, the protection example).
Verified: `check:skill-examples` type-checks 261 marked blocks.
Two liveness-ledger bindings needed handling, both fallout of deleting rules/hooks.md
and the F-05 shrink:
- the `### Access depth (scope-depth) …` heading is ledger-bound, so the shrink's
incidental rename is reverted -- the ledger is right.
- `hook-lifecycle-events-rule` binds a heading in the deleted file. The gate's own
message prescribes "Re-point `heading`, or delete the row"; re-pointing would
duplicate `hook-lifecycle-events-reference`, which already binds the same symbol
(HookEvent) to the surviving canonical file, so the row is dropped. This is the
one edit outside the declared file surface and it is reported as such.
`check:skill-docs` DEMANDED regeneration (it runs in CI, lint.yml:3986): the
frontmatter description changed, so `pnpm --filter @objectstack/spec gen:skill-docs`
regenerated skills/README.md and content/docs/ai/skills-reference.mdx. Generated
`references/_index.md` is untouched and `check:skill-refs` is green.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
The DATA-C-04 / D-12 / D-13 deletions removed two role-word occurrences from
skills/objectstack-data/SKILL.md, so `pnpm check:role-word` failed as a
ratchet-DOWN: "role-word count improved 4 -> 2 — run
`node scripts/check-role-word.mjs --update` and commit the baseline". That
remedy is the author's own (baseline EXPANSION is the maintainer-only
direction), so the baseline is updated here. The diff is one line, for this
file only, and it shrinks.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-litantos-litant added skip-changeset PR has no user-facing published change; bypasses the changeset gate needs:contract-review and removed size/xl labels Sep 2, 2026 — with Claude
@github-actionsgithub-actionsBot added the documentation Improvements or additions to documentation label Sep 2, 2026
os-litant pushed a commit that referenced this pull request Sep 2, 2026
…ht's consolidation
`references/plugin-hooks.md` sent readers chasing per-record validation,
defaults and audit trails to `objectstack-data`'s `rules/hooks.md`. The data
flight (PR #14427, head 061e5f4) DELETES that file and consolidates hooks into
`objectstack-data/references/data-hooks.md`, so the reference is repointed
before it can dangle.
Now a real relative link rather than two bare file names:
`../../objectstack-data/references/data-hooks.md`, verified to resolve from
`references/` to skills/objectstack-data/references/data-hooks.md. The old text
named both `rules/hooks.md` and `references/data-hooks.md`; only the surviving
one is named now, so the span is 22 bytes SHORTER — references/plugin-hooks.md
2418 -> 2413 tokens (ceiling 2628, untouched).
`git grep rules/hooks.md` over this package returns nothing further, so this
was the only site.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 06:41
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 940c128Sep 2, 2026
50 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-14297-skills-data-optimization branch September 2, 2026 07:06
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens) - #14427

Merged
os-zhuang merged 4 commits into
mainfrom
claude/issue-14297-skills-data-optimization
Sep 2, 2026
Merged

skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens)#14427
os-zhuang merged 4 commits into
mainfrom
claude/issue-14297-skills-data-optimization

Conversation

@os-litant

@os-litantos-litant commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Part of #14297

Optimization flight for skills/objectstack-data, the largest package in the published
catalog. Implements the card's IMPLEMENT scope from the 43-row audit record (posted
verbatim as a comment on the card). Governed surface (skills/** markdown) ⇒ this PR
stays draft
; needs:contract-review is on both carriers because INC-01 corrects a
contract-semantics claim.

Net: 45,780 → 36,736 hand-authored tokens (−9,044, −19.8%). One published file
deleted, none added, no ceiling raised, every ratcheted file byte-neutral-or-shrinking.

Per-file token delta

FilebeforeafterΔceilingheadroom
SKILL.md13,89212,553−1,33913,8921,339
references/data-hooks.md12,5849,703−2,88112,6112,908
rules/hooks.md2,195deleted−2,195row dropped
rules/indexing.md3,2402,166−1,0743,2411,075
rules/validation.md3,1092,362−7473,109747
rules/naming.md773248−525773525
rules/relationships.md3,7733,490−2833,778288
rules/field-types.md3,5783,57803,5846
rules/lifecycle.md1,5901,59001,5900
rules/datasources.md90390309118
evals/README.md14314301430
package45,78036,736−9,044

references/_index.md (generated, 1,483) untouched.

Two rows differ from the card's projection and are called out rather than forced:

  • rules/field-types.md nets 0, not −50. DATA-D-14 paid −200; the DATA-E-03
    Field.* preamble is what it bought. Cross-file payment is not available (the ratchet
    is per file), so the addition was trimmed twice until it fit inside D-14's payment. The
    file does not grow.
  • evals/README.md unchanged. DATA-H-01 raises a ceiling and is on the card's DEFER
    list.

落点 | before | after

finding落点beforeafter
DATA-B-01 / I-03rules/hooks.md (whole file)2,195 tok calling itself "a reference pointer", then restating 5 sections of the canonical filedeleted; references/data-hooks.md is the single hooks file and the catalog's hooks anchor. Ceiling row dropped
DATA-B-02data-hooks.md:1-26two H1s, two intros saying the same thing, a "When to Use This Skill" inside a referenceone H1, one intro
DATA-B-038-event table ∥ in both filesstated in full twice (466 + 525 tok)one copy (the canonical file's), via the file deletion
DATA-B-04data-hooks.md:1050-1133three registration methods in 566 tokcompact, 4 load-bearing facts kept: AppPlugin auto-binds, the functions map, packageId, and that programmatic binding gets no declarative condition/retry/timeout/onError/async semantics
DATA-B-05data-hooks.md:1136-116010+10 generic DO/DON'Tthe compact 5+5 rules/hooks.md carried
DATA-B-077 sites"no unique validation type" stated seven timesrestatements in validation.md + relationships.md dropped; SKILL.md + the indexing.md scope table keep it
DATA-C-01SKILL.md:162-189two verbatim CLI/HTTP error transcripts (the 400 text word-for-word in objectstack-query)3 lines naming both refusals; the modelling half (mirror field + two-hook maintenance table) stays — this package is its anchor
DATA-C-02validation.md:26-36, 313-331CEL-vs-SQL prose + a ❌/✅ pairpointer to objectstack-formula (the anchor); the inversion rule stays, it lives nowhere else
DATA-C-03data-hooks.md:1209-1275vitest + LiteKernel harnesses importing 4 unresolvable packagesone-line pointer to objectstack-platform, whose frontmatter claims that surface
DATA-C-045 tombstone sitesstandalone narration of removed keys (rls, encryptionConfig, tenancy.strategy, softDelete/versioning, type/partial)deleted; each key is refused by a parse error carrying its own prescription, and objectstack-upgrade owns in-place upgrades. In-line ❌ markers kept where a wrong key sits beside the right one
DATA-C-05SKILL.md:858-971987 tok: 3 near-identical examples for a 4-value enum + Studio-banner narration + 5-bullet guidanceschema block + 4-row lock table + ONE example + 4 lines of enforcement
DATA-D-01/02/03data-hooks.md:1279-1444invented benchmark table (0 hooks ~1ms…), plain-JS "Advanced Topics", generic Troubleshooting, a Summary repeating the DO list verbatimdeleted; the References block survives and absorbs the two cross-package pointers rules/hooks.md carried
DATA-D-04data-hooks.md:765-104610 patterns, 6 of them plain JavaScriptpatterns 1,2,4,5,7,9 deleted; 3,6,8,10 kept and renumbered
DATA-D-05/06/07rules/indexing.mdRDBMS 101, one textbook fact taught seven ways, unsourced Table Size → Max Indexes, pg_stat_user_indexes SQL, 10 best practicesone paragraph on composite order; naming block kept (name is a declared key)
DATA-D-08relationships.md:398-4137 + 4 items restating the file's own tablesdeleted
DATA-D-09/D-10validation.md:355-4385 patterns restating 4 examples on the same page; 10 best practices + 4 unsourced perf claimsdeleted
DATA-D-11naming.md:15-1076 ❌/✅ pairs + restatements + rationale for a rule the regex already statestable + Critical Rules (773 → 248)
DATA-D-12SKILL.md:540-555"CRM Schema Blueprint" pointing at 6 things covered above itdeleted
DATA-D-13SKILL.md:974-987"Advanced Features Checklist" + tombstone footnotedeleted
DATA-D-14field-types.md:360-4113 ❌/✅ pairs duplicating naming.md, the type table, and a lint ruledeleted (autonumber pair survives) — funds DATA-E-03
DATA-D-15SKILL.md:1178-1181the live model-benchmarking doordeleted (platform benchmarking, not app authoring)
DATA-E-01/E-022 blocksself-contained blocks opening { / validations: [ at statement position (TS parses that as a labelled-statement block)real declarations; os:check markers added to the two SKILL.md blocks that compile
DATA-E-03 / G-02rules/field-types.mdzero Field.* in the file whose job is field authoring; corpus is ~92% factoryField.* preamble with the literal ↔ factory mapping
DATA-E-04data-hooks.md patternsfile prescribed body, demonstrated deprecated handler 10 times2 surviving patterns converted to sandboxed body with declared capabilities
DATA-E-05SKILL.md:325-379the one copy-pasteable object diverged from all 31 real onespluralLabel/description/icon/highlightFields added, indexes dropped (1 of 26 corpus files)
DATA-F-01SKILL.md:64-84sharingModel on 31/31 real objects, absent from both property tablesrequired-table row + 4-row value table
DATA-F-02SKILL.md:383-403storage.notNull never mentioned in the packagerequired = write contract, storage.notNull = the DDL
DATA-F-03SKILL.md:71-84icon/pluralLabel/highlightFields undocumentedthree rows
DATA-F-04SKILL.md:1142-11529 data-model lint rules, 0 security rules4 security rows, 3 of them publish-blocking
DATA-F-05SKILL.mddefineObjectExtension, readScope/writeScope — zero corpus usageshrunk to one schema-pointing row each, not deleted (retirement deferred pending #14296; zero usage in examples is evidence, not proof)
DATA-F-06SKILL.md:1129 + frontmatterprescribed {object}.seed.ts; find . -name '*.seed.ts' returns 0 repo-widerow deleted, trigger aligned to src/data/*.ts
DATA-G-016 sitesobjectstack lint and os lint in one file, 60 lines apartnormalised to os
INC-01SKILL.md:393required: true → false "dev auto-heals (autoMigrate:'safe')"corrected — see below
INC-02SKILL.md:398-401stale NOT NULL produces a clean 400corrected — raw driver error

Contract-semantics corrections (why needs:contract-review)

INC-01. The schema-evolution table named the wrong dial and claimed auto-healing. Both
halves are false against the implementation:

  • packages/drivers/driver-sql/src/schema-drift.ts:795-798const expectNullable = field.storage?.notNull !== true; under a comment reading "compared against
    storage.notNull, the explicit physical constraint — NOT against required, which is
    the write-time contract and implies nothing about the column".
  • The emitted drift is severity: 'warning', category: 'needs_confirm',
    op: { type: 'relax_not_null' } (schema-drift.ts:815-826), above a comment saying
    "never auto-applied".
  • packages/drivers/driver-sql/src/sql-driver.ts:10746const safe = drift.filter((d) => d.category === 'safe');. autoMigrate: 'safe' applies only category safe, so
    it never touches this op.

INC-02.schema-drift.ts:800-802 says that exact configuration means "an omitting
write reaches the DB and dies as a raw driver error instead of a clean validation 400" —
the opposite symptom to the one the tell-tale promised.

INC-03 (new, found while rewriting DATA-D-04 pattern 8). The file asserted "There is
NO updateMany" a few hundred lines below a capability table listing updateMany as
"also installed". Both are true of different surfaces and neither said which:
ObjectRepository — what a handler's ctx.api.object() returns
(packages/objectql/src/engine.ts:13563-13600) — has no updateMany; the sandbox repo
does (packages/runtime/src/sandbox/quickjs-runner.ts:544-545). The comment now names its
surface. This is why patterns 3 and 6 were converted to body and pattern 8 was left as a
handler.

premise_false

None. git diff --stat a59f78d HEAD -- skills/objectstack-data was EMPTY at my base
909a4417, so all 43 spans resolved byte-identically and no finding had to be skipped.

One card-level detail did not hold, and needed no action: the card's ANCHOR RULINGS says
the inbound link at rules/hooks.md:202 points at objectstack-platform
rules/plugin-hooks-events.md and must be re-pointed. At base it already pointed at
objectstack-platform/references/plugin-hooks.md. The file is deleted here anyway, and
that pointer is preserved in the surviving References block.

PM mechanical assumptions — measured

  1. Spans byte-identical at a59f78d. TRUE. git diff --stat a59f78d HEAD -- skills/objectstack-data empty; git diff --stat d63c8a25 HEAD -- skills/ empty;
    the ratchet script unchanged since the pin.
  2. Does check:skill-docs demand regenerating skills/README.md?YES, and it runs
    in CI
    (.github/workflows/lint.yml:3986). The frontmatter description changed, the
    gate failed, and pnpm --filter @objectstack/spec gen:skill-docs regenerated
    skills/README.mdandcontent/docs/ai/skills-reference.mdx — the second file was
    not in the assumption. Both diffs are one data-row each. check:skill-refs is green
    and references/_index.md is untouched.
  3. Deleting rules/hooks.md reds the ratchet unless its ceiling row goes. TRUE, and
    verified in both directions from a committed state with a restore trap: with the row
    re-injected the gate prints ✗ check-skills-token-ratchet: cannot read skills/objectstack-data/rules/hooks.md — red, not a skip (#4690) and exits 1; restored
    (blob hash equal to HEAD, git diff HEAD empty) it exits 0.
  4. The os:check rule is in the header of check-skill-examples.ts. TRUE (lines
    17-23): a marker is os:check in an HTML comment on the line directly above the fence.
    The seven would-fail blocks were handled as the audit proposed — 2 repaired, 2 deleted
    with DATA-C-03, 3 left unmarked (they import unresolvable paths). Markers were added
    only after the gate proved they pass: 261 marked blocks type-check.
  5. A finding whose premise is false is skipped. None were.

Follow-ups by package

  • objectstack-platformreferences/plugin-hooks.md:77 routes readers to the
    objectstack-data skill "(rules/hooks.md, …)", the file this PR deletes. It is another
    package, so it is untouched here; the platform flight (Skills optimization flight — skills/objectstack-platform: RESTRUCTURE (≈ −5,970 tok, −25%) — an orphan rules file with zero inbound links, the canonical hooks reference two hops from the entry file, "When to Use" printed twice, and requires: / engines.protocol / onEnable (every real config) taught nowhere #14299) should re-point it to
    references/data-hooks.md. No gate reads it (check:published-readme-links is scoped to
    package READMEs, not skills/**), so nothing is red today.
  • objectstack-platform — DATA-C-03 removed the LiteKernel/vitest hook harnesses from
    this package and left a pointer. Platform's frontmatter already claims "test harnesses
    via LiteKernel"; it does not yet carry a hook-testing example for the pointer to land on.
  • maintainer decision (DATA-F-07, deferred by the card)defineHook() is prescribed
    twice, but grep -rln defineHook --include='*.ts' outside packages/spec and
    packages/cli returns 0 files, and both real hook modules use the bare : Hook literal
    (examples/app-crm/src/hooks/opportunity.hook.ts:10,
    examples/app-todo/src/objects/task.hook.ts:51). Either the examples move to
    defineHook() or the prescription softens; it is not a doc edit.
  • deferred with the card — DATA-I-04 (a new rules/security.md; would add a file),
    DATA-H-01 (would raise the evals/README.md ceiling), DATA-B-06 (moving the routing
    table up: a MOVE-TO, which is not among the card's three IMPLEMENT verbs, and its only
    named MOVE-TO sibling is deferred). DATA-D-11 is MED confidence with the audit noting a
    maintainer may want one ❌/✅ pair kept — restoring one is a cheap review edit.

Edits outside the declared file surface

The card scoped this to skills/objectstack-data/** plus the one ratchet ceiling row.
Three further files are in the diff. Each is fallout of the mandated deletion, each was
prescribed by the failing gate itself, and each shrinks:

  1. scripts/check-skill-identifier-liveness.mjs — the hook-lifecycle-events-rule ledger
    row binds the heading ### 8 Lifecycle Eventsinside the deleted file, so the gate
    went red. Its message prescribes "Re-point heading, or delete the row". Re-pointing
    would duplicate hook-lifecycle-events-reference, which already binds the same symbol
    (HookEvent) to the surviving canonical file, so the row is dropped. Separately, the
    DATA-F-05 shrink had incidentally renamed another ledger-bound heading
    (### Access depth (scope-depth) …); there the ledger is right and the rename was
    reverted in SKILL.md.
  2. scripts/role-word-baseline.json — the deletions removed two role-word occurrences from
    SKILL.md, so check:role-word failed as a ratchet-DOWN: "count improved 4 → 2 —
    run node scripts/check-role-word.mjs --update and commit the baseline". That direction
    is the author's own remedy (expansion is the maintainer-only one). One line, shrinking.
  3. skills/README.md + content/docs/ai/skills-reference.mdx — generated, regenerated by
    the sanctioned generator, as assumption 2 above records.

Gates — head 061e5f4c

Run with exit codes captured before any pipe. Heavy builds went through
scripts/pm/os-verify-lock.sh.

The four gates named on the card:

gateverdict line
node scripts/check-skills-token-ratchet.mjs✓ 37 authored bundle file(s) within their ceilings (was 38; one file deleted)
pnpm --filter @objectstack/spec check:skill-examples✅ 261 prose examples type-check across 3 surface(s)
pnpm check:skill-compatibility✓ 11 SKILL.md file(s) reconciled against 78 workspace packages
pnpm check:skill-identifier-livenessOK — Leg 1: 492 citation(s) over 47 published file(s); Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s)

Plus the full family node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
derives for the real 13-path change set — 55 gates, re-derived and re-run on this head:
53 exit 0. The two non-zero are exit 3 = NOT MEASURED by the gates' own definition, not
reds:

  • node scripts/check-test-completeness.mjs — "There is no local log to hand it, so the
    local reading for this gate is NOT MEASURED. ⛔ It is not a red." It wants a saved
    turbo run test log.
  • node scripts/pm/check-half-states.mjs — needs the GitHub API, which is 403 from this
    container.

Ratchet self-test green (64 cases pass). check:skill-docs, check:skill-refs,
check:role-word, check:doc-authoring, check:corpus-claim-drift,
check:pm-governed-merges, check:ratchet-remedy-authority all green on this head.

skip-changeset applies: docs-only, publishing nothing from any package.


🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

DATA-B-01 / I-03 — rules/hooks.md called itself "a reference pointer" and then
restated five sections of the canonical file. Delete it; references/data-hooks.md
is the single hooks file and the catalog's hooks anchor. Its ceiling row is
dropped from scripts/check-skills-token-ratchet.mjs (the only edit to that file).
DATA-B-02 second H1 + "When to Use This Skill" inside a reference.
DATA-B-04 three registration methods, compact -- keeping the four load-bearing
facts (AppPlugin auto-binds; the `functions` map; `packageId`; and
that programmatic binding gets NO declarative condition/retry/
timeout/onError/async semantics).
DATA-B-05 10+10 generic DO/DON'T -> the compact 5+5 rules/hooks.md carried.
DATA-C-03 vitest + LiteKernel harnesses -> one-line pointer to
objectstack-platform, which claims that surface in its frontmatter.
DATA-D-01/02/03 invented benchmark table, plain-JS "Advanced Topics", generic
Troubleshooting and the Summary that repeated the DO list verbatim.
The References block survives, and absorbs the two cross-package
pointers rules/hooks.md carried so no routing is lost.
DATA-D-04 patterns 1,2,4,5,7,9 (generic JS) deleted; 3,6,8,10 kept, renumbered.
DATA-E-04 the file prescribed `body` and demonstrated `handler` ten times: two
surviving patterns are now sandboxed `body` with declared capabilities.
INC-03 (found while rewriting pattern 8, evidence pinned): "There is NO
`updateMany`" is true of the HANDLER-side repo -- ObjectRepository, what
ctx.api.object() returns, packages/objectql/src/engine.ts:13575-13600 -- but the
SANDBOX repo does install updateMany/deleteMany
(packages/runtime/src/sandbox/quickjs-runner.ts:544-545), exactly as this file's
own capability table says. The comment now names the surface it is true of.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…01/02, cut restatement
Additions (all paid by deletions in this same file; SKILL.md 13892 -> 12535):
DATA-F-01 `sharingModel` row + the four canonical values. Used by 31/31 real
objects and absent from both property tables. A publish with no
authored sharingModel is refused (`security-owd-unset`, 422) --
maintainer ruling 2026-08-13 recorded at
packages/lint/src/authoring-rules.ts:1293-1296; enum at
packages/spec/src/data/object.zod.ts:2177.
DATA-F-02 `required` (write contract) vs `storage: { notNull: true }` (the DDL),
ADR-0113 -- never mentioned in the package before.
DATA-F-03 `icon` / `pluralLabel` / `highlightFields` rows.
DATA-F-04 four security lint rows; three are publish-blocking errors.
DATA-E-05 the Quick-Start Template now carries the face every real object has
(pluralLabel/description/icon/highlightFields) and drops `indexes`,
which appears in 1 of 26 corpus files.
INC-01 (HIGH) -- the schema-evolution table named `required` as the NOT NULL dial
and claimed dev auto-heals it. Both wrong: schema-drift.ts:795-798 compares
`field.storage?.notNull`, explicitly NOT `required`; the emitted op is
severity 'warning' / category 'needs_confirm' / 'relax_not_null' and the comment
says "never auto-applied"; sql-driver.ts:10746 applies only category 'safe'.
INC-02 (MED) -- the tell-tale promised a clean 400 "<field> is required".
schema-drift.ts:800-802: that configuration dies as a RAW DRIVER ERROR instead.
Deletions: DATA-A-03 (intro + when-to-use restating the frontmatter), DATA-C-01
(two verbatim error transcripts; the query skill carries the same 400 text),
DATA-C-04 (standalone tombstones -- each key is refused by a parse error
carrying its own prescription, and objectstack-upgrade owns that path),
DATA-C-05 (protection: schema + lock table + ONE example survive), DATA-D-12,
DATA-D-13, DATA-D-15, DATA-F-06, DATA-G-01 (one CLI spelling: `os`).
DATA-F-05 is a SHRINK, not a removal (retirement deferred pending #14296):
`defineObjectExtension` and `readScope`/`writeScope` each keep one
schema-pointing row -- zero corpus usage is evidence, not proof.
DATA-A-01/A-02/F-06 rewrite the frontmatter description: it never said
datasource / external / federated though rules/datasources.md is entirely that
surface, never said lifecycle or protection, and fired on `*.seed.ts` -- a
pattern that matches nothing in the repo.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…ips, field-types
DATA-D-11 naming.md six ❌/✅ pairs + Critical Rules restatements + Rationale for a
rule the regex in the table already states. 773 -> 248.
DATA-D-05/06/07 indexing.md: generic RDBMS 101 ("when to add indexes"), four
❌/✅ pairs + three subsections teaching one textbook fact
(left-to-right) collapsed to one paragraph, the unsourced
`Table Size -> Max Indexes` table, the pg_stat_user_indexes /
SHOW INDEX SQL, and a 10-item Best Practices restating the
file. The naming block survives -- `name` is a declared key.
DATA-C-04 indexing.md's standalone `type`/`partial` tombstone clause;
the in-line ❌ block at "Retired and Redundant Keys" stays,
because there a wrong key sits beside the right one.
DATA-C-02 validation CEL-vs-SQL is objectstack-formula's anchor and this package's
description already says to load it alongside. The INVERSION
rule stays -- it is validation-specific and lives nowhere else.
DATA-D-09/D-10 validation.md: five patterns restating four examples already on
the page; 10 best practices + 4 unsourced performance claims
about two rules that lower to the same CEL evaluator.
DATA-B-07 the "no `unique` validation type" rule was stated at 7 sites;
the restatements in validation.md and relationships.md go.
DATA-D-08 relationships.md Best Practices + Performance Considerations.
DATA-D-14/E-03/G-02 field-types.md: three ❌/✅ pairs duplicating naming.md, the type
table and a lint rule (the autonumber pair survives) pay for the
`Field.*` factory preamble -- the corpus is ~92% factory
(~250 calls vs 22 literals) and this file had zero `Field.*`.
DATA-E-02 two blocks carried an `import` and then opened `{` /
`validations: [` at statement position, which TS parses as a
labelled-statement block. Both are now real declarations.
DATA-E-01 `os:check` markers on the two self-contained SKILL.md blocks
that compile (definePermissionSet, the protection example).
Verified: `check:skill-examples` type-checks 261 marked blocks.
Two liveness-ledger bindings needed handling, both fallout of deleting rules/hooks.md
and the F-05 shrink:
- the `### Access depth (scope-depth) …` heading is ledger-bound, so the shrink's
incidental rename is reverted -- the ledger is right.
- `hook-lifecycle-events-rule` binds a heading in the deleted file. The gate's own
message prescribes "Re-point `heading`, or delete the row"; re-pointing would
duplicate `hook-lifecycle-events-reference`, which already binds the same symbol
(HookEvent) to the surviving canonical file, so the row is dropped. This is the
one edit outside the declared file surface and it is reported as such.
`check:skill-docs` DEMANDED regeneration (it runs in CI, lint.yml:3986): the
frontmatter description changed, so `pnpm --filter @objectstack/spec gen:skill-docs`
regenerated skills/README.md and content/docs/ai/skills-reference.mdx. Generated
`references/_index.md` is untouched and `check:skill-refs` is green.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
The DATA-C-04 / D-12 / D-13 deletions removed two role-word occurrences from
skills/objectstack-data/SKILL.md, so `pnpm check:role-word` failed as a
ratchet-DOWN: "role-word count improved 4 -> 2 — run
`node scripts/check-role-word.mjs --update` and commit the baseline". That
remedy is the author's own (baseline EXPANSION is the maintainer-only
direction), so the baseline is updated here. The diff is one line, for this
file only, and it shrinks.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-litantos-litant added skip-changeset PR has no user-facing published change; bypasses the changeset gate needs:contract-review and removed size/xl labels Sep 2, 2026 — with Claude
@github-actionsgithub-actionsBot added the documentation Improvements or additions to documentation label Sep 2, 2026
os-litant pushed a commit that referenced this pull request Sep 2, 2026
…ht's consolidation
`references/plugin-hooks.md` sent readers chasing per-record validation,
defaults and audit trails to `objectstack-data`'s `rules/hooks.md`. The data
flight (PR #14427, head 061e5f4) DELETES that file and consolidates hooks into
`objectstack-data/references/data-hooks.md`, so the reference is repointed
before it can dangle.
Now a real relative link rather than two bare file names:
`../../objectstack-data/references/data-hooks.md`, verified to resolve from
`references/` to skills/objectstack-data/references/data-hooks.md. The old text
named both `rules/hooks.md` and `references/data-hooks.md`; only the surviving
one is named now, so the span is 22 bytes SHORTER — references/plugin-hooks.md
2418 -> 2413 tokens (ceiling 2628, untouched).
`git grep rules/hooks.md` over this package returns nothing further, so this
was the only site.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 06:41
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 940c128Sep 2, 2026
50 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-14297-skills-data-optimization branch September 2, 2026 07:06
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@os-litant@os-zhuang@claude