Uh oh!
There was an error while loading. Please reload this page.
skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens) - #14427
Merged
Conversation
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_01LraLgQVGq8egUwfYZpbYt1The 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-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
This was referenced Sep 2, 2026
os-zhuang
approved these changes
Sep 2, 2026
os-zhuang
marked this pull request as ready for review
September 2, 2026 06:41
os-zhuang
enabled auto-merge
September 2, 2026 06:41
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Sep 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #14297
Optimization flight for
skills/objectstack-data, the largest package in the publishedcatalog. 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 PRstays draft;
needs:contract-reviewis on both carriers because INC-01 corrects acontract-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
SKILL.mdreferences/data-hooks.mdrules/hooks.mdrules/indexing.mdrules/validation.mdrules/naming.mdrules/relationships.mdrules/field-types.mdrules/lifecycle.mdrules/datasources.mdevals/README.mdreferences/_index.md(generated, 1,483) untouched.Two rows differ from the card's projection and are called out rather than forced:
rules/field-types.mdnets 0, not −50. DATA-D-14 paid −200; the DATA-E-03Field.*preamble is what it bought. Cross-file payment is not available (the ratchetis per file), so the addition was trimmed twice until it fit inside D-14's payment. The
file does not grow.
evals/README.mdunchanged. DATA-H-01 raises a ceiling and is on the card's DEFERlist.
落点 | before | after
rules/hooks.md(whole file)references/data-hooks.mdis the single hooks file and the catalog's hooks anchor. Ceiling row droppeddata-hooks.md:1-26data-hooks.md:1050-1133functionsmap,packageId, and that programmatic binding gets no declarative condition/retry/timeout/onError/async semanticsdata-hooks.md:1136-1160rules/hooks.mdcarrieduniquevalidation type" stated seven timesvalidation.md+relationships.mddropped;SKILL.md+ theindexing.mdscope table keep itSKILL.md:162-189validation.md:26-36, 313-331data-hooks.md:1209-1275rls,encryptionConfig,tenancy.strategy,softDelete/versioning,type/partial)SKILL.md:858-971data-hooks.md:1279-14440 hooks ~1ms…), plain-JS "Advanced Topics", generic Troubleshooting, a Summary repeating the DO list verbatimrules/hooks.mdcarrieddata-hooks.md:765-1046rules/indexing.mdTable Size → Max Indexes,pg_stat_user_indexesSQL, 10 best practicesnameis a declared key)relationships.md:398-413validation.md:355-438naming.md:15-107SKILL.md:540-555SKILL.md:974-987field-types.md:360-411SKILL.md:1178-1181{/validations: [at statement position (TS parses that as a labelled-statement block)os:checkmarkers added to the two SKILL.md blocks that compilerules/field-types.mdField.*in the file whose job is field authoring; corpus is ~92% factoryField.*preamble with the literal ↔ factory mappingdata-hooks.mdpatternsbody, demonstrated deprecatedhandler10 timesbodywith declared capabilitiesSKILL.md:325-379pluralLabel/description/icon/highlightFieldsadded,indexesdropped (1 of 26 corpus files)SKILL.md:64-84sharingModelon 31/31 real objects, absent from both property tablesSKILL.md:383-403storage.notNullnever mentioned in the packagerequired= write contract,storage.notNull= the DDLSKILL.md:71-84icon/pluralLabel/highlightFieldsundocumentedSKILL.md:1142-1152SKILL.mddefineObjectExtension,readScope/writeScope— zero corpus usageSKILL.md:1129+ frontmatter{object}.seed.ts;find . -name '*.seed.ts'returns 0 repo-widesrc/data/*.tsobjectstack lintandos lintin one file, 60 lines apartosSKILL.md:393required: true → false"dev auto-heals (autoMigrate:'safe')"SKILL.md:398-401Contract-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-798—const expectNullable = field.storage?.notNull !== true;under a comment reading "compared againststorage.notNull, the explicit physical constraint — NOT againstrequired, which isthe write-time contract and implies nothing about the column".
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:10746—const safe = drift.filter((d) => d.category === 'safe');.autoMigrate: 'safe'applies only categorysafe, soit never touches this op.
INC-02.
schema-drift.ts:800-802says that exact configuration means "an omittingwrite 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 listingupdateManyas"also installed". Both are true of different surfaces and neither said which:
ObjectRepository— what ahandler'sctx.api.object()returns(
packages/objectql/src/engine.ts:13563-13600) — has noupdateMany; the sandbox repodoes (
packages/runtime/src/sandbox/quickjs-runner.ts:544-545). The comment now names itssurface. This is why patterns 3 and 6 were converted to
bodyand pattern 8 was left as ahandler.premise_false
None.
git diff --stat a59f78d HEAD -- skills/objectstack-datawas EMPTY at my base909a4417, 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:202points at objectstack-platformrules/plugin-hooks-events.mdand must be re-pointed. At base it already pointed atobjectstack-platform/references/plugin-hooks.md. The file is deleted here anyway, andthat pointer is preserved in the surviving References block.
PM mechanical assumptions — measured
git diff --stat a59f78d HEAD -- skills/objectstack-dataempty;git diff --stat d63c8a25 HEAD -- skills/empty;the ratchet script unchanged since the pin.
check:skill-docsdemand regeneratingskills/README.md?YES, and it runsin CI (
.github/workflows/lint.yml:3986). The frontmatter description changed, thegate failed, and
pnpm --filter @objectstack/spec gen:skill-docsregeneratedskills/README.mdandcontent/docs/ai/skills-reference.mdx— the second file wasnot in the assumption. Both diffs are one data-row each.
check:skill-refsis greenand
references/_index.mdis untouched.rules/hooks.mdreds the ratchet unless its ceiling row goes. TRUE, andverified 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 HEADempty) it exits 0.os:checkrule is in the header ofcheck-skill-examples.ts. TRUE (lines17-23): a marker is
os:checkin 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.
Follow-ups by package
references/plugin-hooks.md:77routes readers to theobjectstack-data skill "(
rules/hooks.md, …)", the file this PR deletes. It is anotherpackage, 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 toreferences/data-hooks.md. No gate reads it (check:published-readme-linksis scoped topackage READMEs, not
skills/**), so nothing is red today.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.
defineHook()is prescribedtwice, but
grep -rln defineHook --include='*.ts'outsidepackages/specandpackages/clireturns 0 files, and both real hook modules use the bare: Hookliteral(
examples/app-crm/src/hooks/opportunity.hook.ts:10,examples/app-todo/src/objects/task.hook.ts:51). Either the examples move todefineHook()or the prescription softens; it is not a doc edit.rules/security.md; would add a file),DATA-H-01 (would raise the
evals/README.mdceiling), DATA-B-06 (moving the routingtable 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:
scripts/check-skill-identifier-liveness.mjs— thehook-lifecycle-events-ruleledgerrow binds the heading
### 8 Lifecycle Eventsinside the deleted file, so the gatewent red. Its message prescribes "Re-point
heading, or delete the row". Re-pointingwould duplicate
hook-lifecycle-events-reference, which already binds the same symbol(
HookEvent) to the surviving canonical file, so the row is dropped. Separately, theDATA-F-05 shrink had incidentally renamed another ledger-bound heading
(
### Access depth (scope-depth) …); there the ledger is right and the rename wasreverted in
SKILL.md.scripts/role-word-baseline.json— the deletions removed two role-word occurrences fromSKILL.md, socheck:role-wordfailed as a ratchet-DOWN: "count improved 4 → 2 —run
node scripts/check-role-word.mjs --updateand commit the baseline". That directionis the author's own remedy (expansion is the maintainer-only one). One line, shrinking.
skills/README.md+content/docs/ai/skills-reference.mdx— generated, regenerated bythe sanctioned generator, as assumption 2 above records.
Gates — head
061e5f4cRun with exit codes captured before any pipe. Heavy builds went through
scripts/pm/os-verify-lock.sh.The four gates named on the card:
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 packagespnpm 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/objectstackderives 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 thelocal reading for this gate is NOT MEASURED. ⛔ It is not a red." It wants a saved
turbo run testlog.node scripts/pm/check-half-states.mjs— needs the GitHub API, which is 403 from thiscontainer.
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-authorityall green on this head.skip-changesetapplies: docs-only, publishing nothing from any package.🤖 Generated with Claude Code
https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1