skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens) - #14351

Merged
os-zhuang merged 7 commits into
mainfrom
claude/issue-14299-skills-platform-optimization
Sep 2, 2026
Merged

skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens)#14351
os-zhuang merged 7 commits into
mainfrom
claude/issue-14299-skills-platform-optimization

Conversation

@os-litant

@os-litantos-litant commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Part of #14299

Skills catalog optimization flight for skills/objectstack-platform (program #14292, maintainer mandate 2026-09-02 「审核所有的 skills,进行全面的优化。」). The 50-finding audit record is posted verbatim on the card. Governed face — stays draft; needs:contract-review on both carriers.

Why Part of and not a closing keyword: only the implementable half of the card landed. PLAT-H-01 is deferred to decision card #14296 item 2 and PLAT-G-02 to the catalog follow-up below, so merging this must not close the card while its deferred half is still undecided. The card stays open; pm:dispatched is stripped by hand at merge.

Per-file token delta

Token unit is the ratchet's own: ceil(utf8 bytes / 4).

Filebeforeafterceilingnote
SKILL.md129841287112984−113; every addition paid in-file. Review round 1 spent 175 of the freed headroom on the corrected requires: table
references/plugin-hooks.md262824132628−215; absorbed the deleted pointer's DO/DON'T, plus the cross-flight link repair
rules/plugin-lifecycle.md240417772408−627
rules/service-registry.md232917542331−575
rules/bootstrap-patterns.md1093deletedrow droppedorphan, zero inbound links
rules/plugin-hooks-events.md985deletedrow droppedself-declared pointer that restated its target
evals/README.md514514514untouched — DEFERRED per #14296 item 2
references/_index.md13441344generateduntouched

Package 24,281 → 20,673 = −3,608 (−14.9%). Bundle total 187,854 → 184,246. No ceiling was raised; no file grew; scripts/check-skills-token-ratchet.mjs was touched only to drop the two deleted files' rows.

The audit's package total of 24,278 is 3 tokens off — the measured base is 24,281 (sum of the eight rows above).

Why −3,608 and not the projected −5,970

Four of the projected reductions were withdrawn by evidence or by ruling, not skipped:

The five funded additions also cost more than the projected +355, because they were written against the measured facts (the requires: table carries all 20 provider-backed tokens plus the five rules that change what an author writes) rather than against the projection.

Per-item: 落点 | before | after

Deleted files

id落点beforeafter
PLAT-B-01rules/bootstrap-patterns.md1,093 tokens with zero inbound links repo-wide — the only mention of its path was its own ceiling row. Content already carried by SKILL.md (driver table, HTTP-layer table, the "no driver: key, refused at load" block, manifest required fields); its own last line pointed back at SKILL.mddeleted, with its ceiling row
PLAT-B-02rules/plugin-hooks-events.md + SKILL.md:717,865The file opened "This document is a compact pointer. Complete documentation lives in the canonical reference" and then reproduced it. SKILL.md linked only the pointer, so the 2,628-token canonical file sat two hops from the entry filedeleted; SKILL.md links references/plugin-hooks.md directly at both sites. Path unchanged on purposeskills/objectstack-data/rules/hooks.md:202 links to it across packages; verified still resolving

Checked before deleting the pointer: it carried no fact absent from the canonical reference or SKILL.md. Its one non-hooks item ("no circular dependencies between plugins, both kernels throw") is already the Dependency resolution row of the ObjectKernel-vs-LiteKernel table.

references/plugin-hooks.md

id落点beforeafter
PLAT-D-04:312-3277-item "Best Practices", every item restating a span of the same filereplaced by the compact DO/DON'T folded in from the deleted pointer
PLAT-D-05:238-251"Hook Naming Conventions", 4 good / 2 bad names; the convention was already given at :80-82 and demonstrated at :225-232deleted; its only new rule (lower-case) folded into the Custom Hooks convention line
PLAT-D-06:252-311two near-identical 25-line vitest blocks; the second differed only by asserting receivedData instead of hookCalledsecond block deleted

rules/plugin-lifecycle.md and rules/service-registry.md

id落点beforeafter
PLAT-B-07service-registry.md:145-158the same table as SKILL.md:1008-1024 with inverted columns and only 6 of its 13 rows; both then repeated "the REST plugin registers no service"one table, in SKILL.md; the rules file points at it
PLAT-D-03service-registry.md:270-319"Service Naming Conventions" (generic: "use descriptive names", "avoid abbreviations") + a test block asserting only toBeDefined()/toThrow() + a 10-item Best Practices restating the file's own sectionsdeleted
PLAT-D-08plugin-lifecycle.md:201-230the same ❌/✅ lesson as service-registry.md:193-223, differing only in names, closing on the same null-placeholder paragraphreplaced by the rule plus a link to the one worked pair
PLAT-D-02plugin-lifecycle.md:293-34010-item Best Practices (1-7 restate the file's own Phase headings; 8-10 generic: "version your plugin", "use reverse domain names") + two vitest blocks asserting only toBeDefined()/isConnected()deleted
PLAT-C-05plugin-lifecycle.md:110-113, SKILL.md:944-948the data:* boundary was stated five times in-packagein-package statements down to three; SKILL.md keeps exactly one (the one explaining the silent registration), per the anchor ruling; canonical statement stays in references/plugin-hooks.md

SKILL.md — structure

id落点beforeafter
PLAT-B-05section order1,441 tokens preceded defineStack() — the core construct sat 12% down the filedefineStack() (with the Manifest Reference it needs) is the first section after the title
PLAT-B-03:39-49, :699-708"When to Use This Skill" appeared twice, 650 lines apart, both restating the frontmatterboth deleted — a loaded package is already selected
PLAT-B-06:25-35narrated the package's own edit history ("the original 'quickstart' skill", "which is why they live in one skill")one sentence naming the two concerns
PLAT-D-07:142-158"CRM Blueprint": rows 2-3 restated the directory tree 18 lines above; rows 5-6 pointed at data / i18n territorydeleted; its only platform-specific row (requires:) is now taught properly under the Boot Sequence
PLAT-D-01:735-758ASCII "Decision Guide" restating the table two lines above; its gloss changed no branchdeleted, table survives
PLAT-B-04:1277-1279"see Health Monitoring earlier in this skill" — that section documents an in-process TS API and contains no HTTP routecross-reference dropped

SKILL.md — truthfulness

id落点beforeafter
PLAT-F-06:347-381driver-as-a-plugins:-entry taught as the canonical bootstrap. Zero example configs do it: app-showcase and the blank template list connector plugins, app-crm and app-todo have no plugins: key, and the CLI wires the driver itself from the resolved DB URL (serve.ts:2687-2745)selection table kept; the code reframed as embedding/tests only, with "pick a driver by setting the DB URL, not by writing code"
PLAT-F-05:498-522composeStacks() had a section plus a 3-row strategies table and zero usages outside packages/spec and its own testsreduced to a pointer at stack.zod.ts. Live surface with zero measured usage ⇒ one row, never delete the last mention
PLAT-C-01:548-576taught a raw data: [{ object: 'task', … }] literal — writing object: by hand, which objectstack-data/SKILL.md:1036 forbids verbatim ("Auto-set from objectDef.name — never write manually"); 24 real defineSeed( sites, 0 raw literalsliteral deleted, defineSeed() pointer added, mode table kept (see premise_false) and given the ⚠️ Data-loss flag on replace it was missing
PLAT-C-02:626-663re-taught field types in a shape 0 of 7 real object files use (export default {} vs ObjectSchema.create({…}))one line pointing at objectstack-data and the scaffolder's own note.object.ts
PLAT-G-01:303,319,322-323,1035five spans used the retired v5.0 word for the runtime workspace ("project runtime", "Project revisions", "isolated project kernel") against skills/README.md:88 and the os environments CLI surfaceall five now environment. Uses of "project" for the local source tree left alone — those are correct
imprecision:79-80the blank template "ships One example object, in-memory driver, Hono server" — the template config has neither; its plugins: array holds three connector executors and both arrive from CLI auto-registrationstates what is in the file, and that the driver and server come from the CLI
PLAT-A-01:5,9-10,20 and the section headingfrontmatter sold "drivers, adapters" while :394-397 answers "There are no@objectstack/adapter-* packages" — promise and truth 385 lines apartdescription and heading now name the Hono HTTP layer
PLAT-G-03:307-310 vs :1109the os / objectstack alias was declared 800 lines after first usestated at first use
PLAT-C-04:1299a 60-token restatement of the very rule it delegates to objectstack-datasymptom plus the one-line cause

SKILL.md — examples that could not compile

id落点beforeafter
PLAT-E-01:527-542"Host Pattern" read as a complete config file but had ≥4 errors on paste: defineStack and SqlDriver used un-imported, CrmApp/TodoApp undefined, and new SqlDriver({ ... }) is TS1109folded into the Multi-App Composition prose; no un-compilable block
PLAT-E-02:1059-1073typed the literal as a Plugin intersection then read this.pool.query(...) (TS2339) and err.message on a catch binding (TS18046); PluginHealthStatus never importedthe opt-in contract in prose plus the three real kernel call sites
PLAT-E-03:954-969kernel.getService with a type argument naming a non-exported class from a different fence (TS2304)type argument dropped
PLAT-E-04:296-298defineStack({ ... }, { strict: false }) — TS1109 by constructiondefineStack(config, { strict: false })

The funded additions — each paid by a deletion in the same file

id落点beforeafter
PLAT-F-01Manifest Referencemanifest.engines: { protocol: '^17' } has 4 real usages including every project the scaffolder emits, and grep engines skills/objectstack-platform/ returned 0one manifest row plus why the runtime checks it before it loads anything
PLAT-F-02Boot Sequencerequires: [...] decides which service plugins boot; taught as one CRM-blueprint cell and one bare word, while the Boot Sequence narrated a fixed auto-register list and never said requires: drives itall 20 provider-backed tokens against their real pkg values, the two other resolution mechanisms kept separate from them, and five rules that change what you write: precedence, declaring-is-a-demand (declared-but-absent is a hard boot error, auto-injected-but-absent stays best-effort), auth implies email, keep automation whenever plugins: lists a connector, and pair triggers with job
PLAT-F-03Boot Sequencethe onEnable export — the seam where an app binds runtime code — has 4 real sites and was documented only in objectstack-dataits own subsection with the AppPlugin invocation and a worked export
PLAT-F-04Part 3plugin authoring stopped at kernel.use(plugin) with no path to a distributable plugin; the ADR-0025 §3.4 pipeline was mentioned nowhere in skills/a 3-row `os plugin build
PLAT-F-07kernel decisionthe guide offered two answers and routed serverless/edge to LiteKernel, while the repo's own example for that shape uses neither kernela third branch naming @objectstack/objectql/core and examples/embed-objectql (ADR-0076)
PLAT-A-02frontmatterthe description never named capabilities / requires:, the key that decides which service plugins bootone clause added, paid by A-01

Facts re-read against source before writing, per the card's assumption 5: blank/objectstack.config.ts:22,30; serve.tsCAPABILITY_PROVIDERS and the auth ⇒ email implication at :2281-2321; onEnable at app-showcase :283, app-crm :127, app-todo :33; PLATFORM_CAPABILITY_TOKENS in packages/spec/src/kernel/platform-capabilities.ts.

CAPABILITY_PROVIDERS holds 20 entries — the audit's "~20" was right. An earlier revision of this PR claimed 14 and offered that as a correction to the audit; that claim was itself wrong and is retracted. See Review round 1.

premise_false

  • PLAT-E-05 — premise false; not implemented. The audit proposed adding an os:check marker to the Complete Plugin Example so plugin/kernel examples would finally be type-checked. Measured: the gate's "skills + docs" surface resolves from packages/spec only (SURFACES in packages/spec/scripts/check-skill-examples.ts, resolutionDir: SPEC_DIR, selfPackages: [SPEC_DIR]), and @objectstack/core is not a dependency of packages/spec — that package's node_modules has no @objectstack scope at all. Marking the block produced skills/objectstack-platform/SKILL.md:804:44 error TS2307: Cannot find module '@objectstack/core'. Every plugin/kernel example in this package imports Plugin / PluginContext / ObjectKernel / LiteKernel from there, so no such example can be gated without a new SURFACES entry — another package, which this flight may not edit. The marker was reverted; check:skill-examples is green with 258 marked blocks. Filed as follow-up below.
  • PLAT-C-01 — premise partly false. "DELETE the mode table → one pointer line" is not available: check:skill-identifier-liveness registers ## Seed Data as exhaustive over SeedMode, and deleting the table turned five live members (insert, update, upsert, replace, ignore) into capabilities no AI author reading the catalog can reach. The gate caught it. Fixed the author's way — the table stays, and gained the ⚠️ Data-loss flag on replace the audit noted was missing. The shrink-only gap ledger is maintainer-only and was not touched.
  • PLAT-C-03 — not applied, by ruling. The card's ANCHOR RULINGS keep SKILL.md:59-70 because the pm-dispatch flight points there. The overlap the audit identified is real but is the anchor's to settle.
  • PLAT-G-02 — not applied, by ruling. Moving references/plugin-hooks.md to rules/ is exactly what the card forbids (the path is pinned stable for objectstack-data's inbound link). The catalog-wide drift it names is real and is listed as follow-up.

Card assumptions verified rather than assumed: (1) skills/objectstack-platform/** is byte-identical at a59f78d, d63c8a25 and this branch's actual base 909a4417git diff --stat empty for both; note origin/main had moved past the d63c8a25 named in the card. (2) bootstrap-patterns has zero inbound links, with plugin-lifecycle as a positive control that hits abundantly. (3) check:skill-docsis the drift gate, it is in the derived family, and the frontmatter edit did force regeneration — of two files, not one (below). (4) the ratchet reds on a deleted file whose row remains — probed directly: re-adding the row gave exit 1 and "cannot read … — red, not a skip (#4690)", then the script was restored and the restore confirmed by hash match.

Files outside the card's literal list

  • skills/README.md — regenerated, as the card anticipated for a frontmatter edit.
  • content/docs/ai/skills-reference.mdxalso regenerated, because one generator writes both and check:skill-docs fails on both. Not anticipated by the card; flagged here. Both diffs are frontmatter-derived only, confined to this package's row. Not content/docs/releases/.

follow-up for packages/spec

  • Extend SURFACES in packages/spec/scripts/check-skill-examples.ts with a resolution root that can see @objectstack/core, so plugin / kernel / service examples across the catalog become type-checkable. Today 78 of this package's 80 TypeScript fences are unchecked and the two checked ones both teach data authoring — the least proprietary content in the package. This is PLAT-E-05's real blocker.

follow-up for the catalog

  • PLAT-G-02: hand-authored per-topic files live under the generated references/ directory, which skills/README.md:55-58 reserves for generated pointers. This package and objectstack-data (references/data-hooks.md) both do it — a catalog-wide placement decision, not a lone slip, and one this flight is explicitly forbidden to settle by moving the file.

Review round 1

Contract review failed one span — the requires: table added for PLAT-F-02. Three defects, all from reading a bounded slice of CAPABILITY_PROVIDERS instead of reading it to its closing brace. Fixed in 224d5d9a; the cross-flight link repair below landed in 25012189:

#defecttruth at sourcefix
1audit row named @objectstack/service-audit@objectstack/plugin-audit (AuditPlugin), serve.ts:1473-1475row corrected
2triggers row named @objectstack/service-triggers, which does not exist@objectstack/trigger-record-change (RecordChangeTriggerPlugin), extras @objectstack/trigger-schedule (ScheduleTriggerPlugin, TimeRelativeTriggerPlugin) and @objectstack/trigger-api (ApiTriggerPlugin), serve.ts:1506-1537row corrected; the entry's own comment ("so pair triggers with job") became a row note and the fifth rule
3"the remaining vocabulary … resolve the same way", and the claim that the map holds 14 entriesthe map holds 20; the other eight tokens resolve by two different mechanismstable lists all 20 against their real pkg; the eight are split into tier-gated (no map entry, opened by dedicated run() blocks per the CAPABILITY_TO_TIER docblock at serve.ts:1166-1171) and enterprise/cloud (no open-edition provider: hierarchy-security ships in @objectstack/security-enterprise via plugins[], ai-seat and governance are cloud-runtime only, platform-capabilities.ts:57-66)

20 + 5 + 3 = the 28 tokens in PLATFORM_CAPABILITY_TOKENS, counted from the frozen array rather than asserted. Defect 3 is the one worth naming plainly: the "14 entries" figure was published as a correction to the audit when the audit was right and the correction was the error — a truncated read reported as a finding.

Cross-flight link repair

references/plugin-hooks.md routed readers to objectstack-data's rules/hooks.md for per-record validation, defaults and audit trails. The data flight (PR #14427, head 061e5f4c, delivered) DELETES that file and consolidates hooks into objectstack-data/references/data-hooks.md, so the reference was repointed before it could dangle — now a real relative link, ../../objectstack-data/references/data-hooks.md, verified to resolve from references/. The old text named both the doomed rules/hooks.md and the surviving references/data-hooks.md; naming only the survivor makes the span 22 bytes shorter. git grep rules/hooks.md over this package returns nothing further, so that was the only site.

The PR title still carries the pre-patch figure (−3,778); the accurate net is −3,608. Left alone deliberately — the patch instruction was not to retitle.

Gates

Head sha 25012189. Command list derived from the real change set by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (9 paths; re-derived after regeneration added the two generated files, which pulled in 20 further docs-family gates). The full 46 were run on 15b4ac79: 45 exit 0, 1 NOT MEASURED. Review round 1 touched only SKILL.md and references/plugin-hooks.md, so the change set and therefore the derived family are unchanged; the card-named gates were re-run on 25012189 and are listed below.

The one non-green in that full run is NOT MEASURED by its own verdict text — node scripts/check-test-completeness.mjs exits 3, not 1: "PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named… the local reading for this gate is NOT MEASURED." CI tees the log and passes the path, so this branch is unreachable there. Not a finding, and not read as green.

Card-named gates on 25012189, every exit captured before any pipe, all exit 0:

gateverdict line
check-skills-token-ratchet"36 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted" — SKILL.md 12871 / 12984, plugin-hooks.md 2413 / 2628
check:skill-examples"258 marked example(s) across 100 file(s), 3 surface(s)"
check:skill-identifier-liveness"OK — Leg 1: 493 citation(s) over 46 published file(s) … Leg 2: 9 registered exhaustive section(s), 0 ledgered gap(s)" — 493, up from 491: the corrected package names are themselves live-checked citations
check:skill-docsexit 0 with no regeneration needed (round 1 touched no frontmatter)
check:skill-compatibility"11 SKILL.md file(s) reconciled against 78 workspace packages"
check:published-readme-linksexit 0 — run additionally to prove the repointed cross-package link resolves

Two gates initially reported exit 3 for missing local build prerequisites and were re-run properly rather than recorded as failures: check:doc-formula-expressions (needed @objectstack/formula built) and check:skill-examples (needed @objectstack/client-react built — it refuses rather than false-greening, #7122). Both green afterwards.

Control bytes: node scripts/check-nul-bytes.mjs green, plus a direct scan of all changed files for the wider control-byte range — no hits.

skip-changeset applies and is on the PR: this diff releases nothing from any package. skills/ is named in the changeset gate's own release-nothing enumeration (scripts/check-empty-changeset.mjs), which pins a "skills/**-only PR carrying NO changeset" as a green fixture, and scripts/check-skills-token-ratchet.mjs is a CI-internal gate script — the workflow calls that the textbook case.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

…-B-01)
`rules/bootstrap-patterns.md` had ZERO inbound links repo-wide — the only
reference to its path anywhere in the tree was its own ceiling row in
`scripts/check-skills-token-ratchet.mjs`. `SKILL.md:715-717` links only
lifecycle / service-registry / hooks-events, so nothing ever routed a reader
to it; verified with `git grep -n bootstrap-patterns` against a positive
control (`git grep -n plugin-lifecycle` hits abundantly).
Its content was already carried by SKILL.md: the driver table (:66-74 =
SKILL.md:351-357), the HTTP-layer table (:76-83 = :389-397), the "no `driver:`
key, refused at load" block plus the `defineStack validation failed` sample
(:7-31,87-105 = :209-234), and manifest required fields (:29-31,107-130 =
:327-339). Its own last line pointed back at SKILL.md.
1,093 tokens of the published bundle that no customer agent could reach.
The ceiling row goes with the file: the gate treats an unreadable ratcheted
path as RED, not as a skip (#4690) — verified by a controlled probe that
re-added the row (exit 1, "cannot read ... — red, not a skip"), then restored
the script and confirmed the restore by hash match.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
… the pointer file (PLAT-B-02, D-04, D-05, D-06)
`rules/plugin-hooks-events.md` opened by declaring itself "a compact pointer.
Complete documentation lives in the canonical reference" and then reproduced
that reference: the event table, the `data:*` warning, the custom-hook
convention, execution order, and a DO/DON'T list. SKILL.md linked only the
pointer, so the 2,628-token canonical file sat TWO hops from the entry file
behind 985 tokens that restated it.
SKILL.md now links `references/plugin-hooks.md` directly at both sites
(`:717` and `:865`) and the pointer file is deleted with its ceiling row.
Checked before deleting: the pointer carried no fact absent from the
canonical reference or from SKILL.md — its one non-hooks item ("no circular
dependencies between plugins, both kernels throw") is already the
`Dependency resolution` row of the ObjectKernel-vs-LiteKernel table. So the
merge is a relink plus a deletion, and the compact DO/DON'T shape it had is
what now closes the canonical file.
`references/plugin-hooks.md` PATH IS UNCHANGED on purpose:
`skills/objectstack-data/rules/hooks.md:202` links to it across packages, and
that link is verified still resolving.
Paid inside `references/plugin-hooks.md`, per the shrink-only ratchet:
- PLAT-D-04 — the 7-item "Best Practices" list, every item of which
restated a span of the same file, is replaced by the compact DO/DON'T
rules-of-thumb folded in from the deleted pointer.
- PLAT-D-05 — "Hook Naming Conventions" deleted; its only new rule
(lower-case) folded into the Custom Hooks convention line.
- PLAT-D-06 — the second of two near-identical vitest blocks deleted; it
differed only in asserting `receivedData` instead of `hookCalled`.
Token deltas: references/plugin-hooks.md 2628 -> 2418 (ceiling 2628);
SKILL.md 12984 -> 12982 (ceiling 12984 — the relinked paths are shorter than
the deleted ones); rules/plugin-hooks-events.md 985 -> deleted with its row.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…07, C-05)
`rules/service-registry.md` 2329 -> 1754 tokens (ceiling 2331):
- PLAT-B-07 — "Well-Known Service Keys" was the SAME table as
`SKILL.md:1008-1024` with the columns inverted and only 6 of its 13 rows,
and both then repeated "the REST plugin registers no service". One table
now, in SKILL.md; this file points at it.
- PLAT-D-03 — deleted "Service Naming Conventions" (generic advice: "use
descriptive names", "avoid abbreviations"), a "Testing Service
Registration" block whose only assertions were `toBeDefined()` and
`toThrow()`, and a 10-item "Best Practices" list restating this file's own
Registration Patterns section and its `null`-placeholder paragraph.
`rules/plugin-lifecycle.md` 2404 -> 1777 tokens (ceiling 2408):
- PLAT-D-08 — the ❌/✅ "getService() in init() without a declared
dependency" lesson was already in `service-registry.md:193-223`,
differing only in the names used (CachePlugin/db-pool vs
AnalyticsPlugin/objectql) and closing on the SAME paragraph about never
registering `null`. Replaced with the rule plus a link to the one worked
pair.
- PLAT-D-02 — deleted a 10-item "Best Practices" list (items 1-7 restate
this file's own Phase 1/2/3 headings; 8-10 are generic: "version your
plugin", "use reverse domain names") and a "Testing Lifecycle" section of
two vitest blocks whose only assertions were `toBeDefined()` and
`isConnected()`.
- PLAT-C-05 — dropped this file's copy of the `data:*`-boundary warning.
The boundary was stated five times in-package; the canonical statement
stays in `references/plugin-hooks.md` and SKILL.md keeps exactly one.
No content was moved to another package: each deletion either had a surviving
in-package statement or was generic advice that changed no decision.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…B/C/D/E/F/G)
Deletions and rewrites (SKILL.md 12984 -> 12696 tokens, ceiling 12984):
- PLAT-B-05 — `defineStack()` was 12% down the file behind 1,441 tokens of
preamble. It (with the Manifest Reference it needs) is now the first
section after the title.
- PLAT-B-03 — "When to Use This Skill" appeared TWICE, 650 lines apart,
both restating the frontmatter. A loaded package is already selected.
- PLAT-B-06 — the package narrated its own edit history ("the original
'quickstart' skill"). A customer agent never chose between two former
skills.
- PLAT-D-07 — the CRM Blueprint restated the directory tree 18 lines above
and pointed at data / i18n territory; only its `requires:` row was
platform-specific, and that is now taught properly (F-02).
- PLAT-D-01 — the ASCII Decision Guide restated the table two lines above.
- PLAT-F-05 — `composeStacks()` had a section plus a strategies table and
ZERO usages outside `packages/spec` and its own tests; real multi-app
composition is AppPlugin registration. Reduced to a pointer at the schema,
not deleted (live surface, zero measured usage).
- PLAT-F-06 — driver-as-a-`plugins:`-entry was taught as THE canonical
bootstrap; no example config does it and the CLI wires the driver itself
from the resolved DB URL. Reframed as embedding/tests only.
- PLAT-C-01 — seeds are objectstack-data's; the copy here taught a raw
literal writing `object:` by hand, which that skill forbids verbatim.
Now a pointer PLUS the `mode` table (see below).
- PLAT-C-02 — the example object file re-taught field types in a spelling
7 of 7 real object files do not use (`export default {}` vs
`ObjectSchema.create({...})`).
- PLAT-C-04, B-04 — a restatement of the rule it delegates, and a
cross-reference to a section that documents an in-process TS API and
contains no HTTP route.
- PLAT-C-05 — SKILL.md stated the `data:*` boundary twice; one statement
remains (the one that explains the silent registration).
- PLAT-E-01, E-02, E-03, E-04 — four blocks that could not compile:
`defineStack`/`SqlDriver` used un-imported with `CrmApp`/`TodoApp`
undefined; `this.pool` on a plain object literal plus `err.message` on a
`catch` binding; a type argument naming a non-exported class from another
fence; and `{ ... }` / `{ … }` ellipsis placeholders (TS1109).
- PLAT-G-01 — v5.0 vocabulary: the runtime workspace is `environment`, not
`project`, in all five spans (skills/README.md:88; the CLI surface is
`os environments`).
- PLAT-G-03 — the `os` / `objectstack` binary alias is now stated at first
use instead of 800 lines later.
- PLAT-A-01 — the frontmatter sold "adapters" and the body refutes it 385
lines in ("There are no `@objectstack/adapter-*` packages"). Both the
description and the section heading now name the Hono HTTP layer.
- The `blank` template's "in-memory driver, Hono server" was true of the
RUNNING APP and false of the file a reader opens: the template config has
neither; both arrive from CLI auto-registration.
Additions, each paid by a deletion in this same file:
- PLAT-F-01 — `manifest.engines.protocol`, stamped into every project
`create-objectstack` emits and carried by all three example apps, was
mentioned NOWHERE in this package. One manifest row + why it is checked
before anything loads.
- PLAT-F-02 — `requires: [...]` decides which service plugins boot and was
taught as one blueprint cell and one bare word. Now a token table plus the
four rules that change what you write: precedence, declaring-is-a-demand
(hard boot error vs best-effort), `auth` implies `email`, and keep
`automation` whenever `plugins:` lists a connector.
- PLAT-F-03 — the `onEnable` export, the seam where an app binds runtime
code, used by all three example apps and documented only in
objectstack-data.
- PLAT-F-04 — `os plugin build|sign|publish`: authoring stopped at
`kernel.use(plugin)` with no path to a distributable plugin.
- PLAT-F-07 — a third answer to the kernel question: `examples/embed-objectql`
uses NEITHER kernel (`@objectstack/objectql/core`, ADR-0076).
- PLAT-A-02 — the description now names the capability key.
Generated files regenerated because the frontmatter changed, as the drift gate
demands: `skills/README.md` AND `content/docs/ai/skills-reference.mdx` (one
generator writes both; `pnpm --filter @objectstack/spec gen:skill-docs`). Both
diffs are frontmatter-derived only.
`## Seed Data` keeps its `mode` table: `check:skill-identifier-liveness`
registers that section as exhaustive over `SeedMode`, and deleting the table
made five live members unreachable (caught by the gate, fixed the author's
way — the shrink-only gap ledger is maintainer-only and was not touched). The
table now also carries the Data-loss flag on `replace` that it was missing.
PLAT-E-05 is NOT implemented — its premise is false; see the PR body.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…al registry (review round 1)
Contract review round 1 failed the `requires:` table I added in the previous
commit. Three defects, all mine, all from reading a bounded slice of
`CAPABILITY_PROVIDERS` instead of reading it to its closing brace:
1. `audit` named `@objectstack/service-audit`. The real entry is
`@objectstack/plugin-audit` (`AuditPlugin`), serve.ts:1473-1475.
2. `triggers` named `@objectstack/service-triggers`, which does not exist. The
entry is `@objectstack/trigger-record-change` (`RecordChangeTriggerPlugin`)
with extras `@objectstack/trigger-schedule` (`ScheduleTriggerPlugin`,
`TimeRelativeTriggerPlugin`) and `@objectstack/trigger-api`
(`ApiTriggerPlugin`), serve.ts:1506-1537.
3. "the remaining vocabulary resolves the same way" was false, and so was the
claim that the map holds 14 entries. It holds TWENTY — I bounded an `awk`
range by guess and stopped at `sms`, then reported the truncation as a
correction to the audit. The audit's "~20" was right and my correction was
the error.
The table now lists all 20 provider-backed tokens against their real `pkg`
values, and the eight remaining tokens are separated into the two mechanisms
that actually resolve them: five tier-gated tokens with NO map entry, opened by
dedicated blocks in `serve.ts` `run()` (CAPABILITY_TO_TIER docblock,
serve.ts:1166-1171), and three enterprise/cloud tokens with no open-edition
provider at all — `hierarchy-security` ships in
`@objectstack/security-enterprise` via `plugins[]`, `ai-seat` and `governance`
are cloud-runtime only (platform-capabilities.ts:57-66). 20 + 5 + 3 = the 28
tokens in `PLATFORM_CAPABILITY_TOKENS`, counted from the frozen array rather
than asserted.
The `triggers` entry's own comment carries a rule an author needs — schedule
triggers run on the job service, "so pair `triggers` with `job`" — so that is
now both a row note and the fifth rule: `triggers` alone arms record-change
triggers, and autolaunched scheduled flows stay silent without `job`.
SKILL.md 12696 -> 12871 tokens, ceiling 12984 unchanged and not raised; the
growth is paid from the headroom this flight's own deletions created.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…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-litantos-litant changed the title skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,778 tokens)skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens)Sep 2, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 06:53
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to a conflict with the base branch Sep 2, 2026
Nine sibling skills flights landed on main after this branch's base. Both
conflicts fell inside the BEGIN/END GENERATED: skills region of the two mixed
generated files (skills/README.md, content/docs/ai/skills-reference.mdx);
resolved by clearing the markers in place — preserving main's text-merged prose
outside the region — and regenerating both wholesale with
`pnpm --filter @objectstack/spec gen:skill-docs` on the merged tree.
scripts/check-skills-token-ratchet.mjs auto-merged (each flight edited its own
package's ceiling rows). No behaviour or content change to the platform package.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01489YWhZEoHT9oXshiyywQy
@claude
claudeBot requested a review from os-zhuangSeptember 2, 2026 14:54
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/xlskip-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(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens) - #14351

Merged
os-zhuang merged 7 commits into
mainfrom
claude/issue-14299-skills-platform-optimization
Sep 2, 2026
Merged

skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens)#14351
os-zhuang merged 7 commits into
mainfrom
claude/issue-14299-skills-platform-optimization

Conversation

@os-litant

@os-litantos-litant commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Part of #14299

Skills catalog optimization flight for skills/objectstack-platform (program #14292, maintainer mandate 2026-09-02 「审核所有的 skills,进行全面的优化。」). The 50-finding audit record is posted verbatim on the card. Governed face — stays draft; needs:contract-review on both carriers.

Why Part of and not a closing keyword: only the implementable half of the card landed. PLAT-H-01 is deferred to decision card #14296 item 2 and PLAT-G-02 to the catalog follow-up below, so merging this must not close the card while its deferred half is still undecided. The card stays open; pm:dispatched is stripped by hand at merge.

Per-file token delta

Token unit is the ratchet's own: ceil(utf8 bytes / 4).

Filebeforeafterceilingnote
SKILL.md129841287112984−113; every addition paid in-file. Review round 1 spent 175 of the freed headroom on the corrected requires: table
references/plugin-hooks.md262824132628−215; absorbed the deleted pointer's DO/DON'T, plus the cross-flight link repair
rules/plugin-lifecycle.md240417772408−627
rules/service-registry.md232917542331−575
rules/bootstrap-patterns.md1093deletedrow droppedorphan, zero inbound links
rules/plugin-hooks-events.md985deletedrow droppedself-declared pointer that restated its target
evals/README.md514514514untouched — DEFERRED per #14296 item 2
references/_index.md13441344generateduntouched

Package 24,281 → 20,673 = −3,608 (−14.9%). Bundle total 187,854 → 184,246. No ceiling was raised; no file grew; scripts/check-skills-token-ratchet.mjs was touched only to drop the two deleted files' rows.

The audit's package total of 24,278 is 3 tokens off — the measured base is 24,281 (sum of the eight rows above).

Why −3,608 and not the projected −5,970

Four of the projected reductions were withdrawn by evidence or by ruling, not skipped:

The five funded additions also cost more than the projected +355, because they were written against the measured facts (the requires: table carries all 20 provider-backed tokens plus the five rules that change what an author writes) rather than against the projection.

Per-item: 落点 | before | after

Deleted files

id落点beforeafter
PLAT-B-01rules/bootstrap-patterns.md1,093 tokens with zero inbound links repo-wide — the only mention of its path was its own ceiling row. Content already carried by SKILL.md (driver table, HTTP-layer table, the "no driver: key, refused at load" block, manifest required fields); its own last line pointed back at SKILL.mddeleted, with its ceiling row
PLAT-B-02rules/plugin-hooks-events.md + SKILL.md:717,865The file opened "This document is a compact pointer. Complete documentation lives in the canonical reference" and then reproduced it. SKILL.md linked only the pointer, so the 2,628-token canonical file sat two hops from the entry filedeleted; SKILL.md links references/plugin-hooks.md directly at both sites. Path unchanged on purposeskills/objectstack-data/rules/hooks.md:202 links to it across packages; verified still resolving

Checked before deleting the pointer: it carried no fact absent from the canonical reference or SKILL.md. Its one non-hooks item ("no circular dependencies between plugins, both kernels throw") is already the Dependency resolution row of the ObjectKernel-vs-LiteKernel table.

references/plugin-hooks.md

id落点beforeafter
PLAT-D-04:312-3277-item "Best Practices", every item restating a span of the same filereplaced by the compact DO/DON'T folded in from the deleted pointer
PLAT-D-05:238-251"Hook Naming Conventions", 4 good / 2 bad names; the convention was already given at :80-82 and demonstrated at :225-232deleted; its only new rule (lower-case) folded into the Custom Hooks convention line
PLAT-D-06:252-311two near-identical 25-line vitest blocks; the second differed only by asserting receivedData instead of hookCalledsecond block deleted

rules/plugin-lifecycle.md and rules/service-registry.md

id落点beforeafter
PLAT-B-07service-registry.md:145-158the same table as SKILL.md:1008-1024 with inverted columns and only 6 of its 13 rows; both then repeated "the REST plugin registers no service"one table, in SKILL.md; the rules file points at it
PLAT-D-03service-registry.md:270-319"Service Naming Conventions" (generic: "use descriptive names", "avoid abbreviations") + a test block asserting only toBeDefined()/toThrow() + a 10-item Best Practices restating the file's own sectionsdeleted
PLAT-D-08plugin-lifecycle.md:201-230the same ❌/✅ lesson as service-registry.md:193-223, differing only in names, closing on the same null-placeholder paragraphreplaced by the rule plus a link to the one worked pair
PLAT-D-02plugin-lifecycle.md:293-34010-item Best Practices (1-7 restate the file's own Phase headings; 8-10 generic: "version your plugin", "use reverse domain names") + two vitest blocks asserting only toBeDefined()/isConnected()deleted
PLAT-C-05plugin-lifecycle.md:110-113, SKILL.md:944-948the data:* boundary was stated five times in-packagein-package statements down to three; SKILL.md keeps exactly one (the one explaining the silent registration), per the anchor ruling; canonical statement stays in references/plugin-hooks.md

SKILL.md — structure

id落点beforeafter
PLAT-B-05section order1,441 tokens preceded defineStack() — the core construct sat 12% down the filedefineStack() (with the Manifest Reference it needs) is the first section after the title
PLAT-B-03:39-49, :699-708"When to Use This Skill" appeared twice, 650 lines apart, both restating the frontmatterboth deleted — a loaded package is already selected
PLAT-B-06:25-35narrated the package's own edit history ("the original 'quickstart' skill", "which is why they live in one skill")one sentence naming the two concerns
PLAT-D-07:142-158"CRM Blueprint": rows 2-3 restated the directory tree 18 lines above; rows 5-6 pointed at data / i18n territorydeleted; its only platform-specific row (requires:) is now taught properly under the Boot Sequence
PLAT-D-01:735-758ASCII "Decision Guide" restating the table two lines above; its gloss changed no branchdeleted, table survives
PLAT-B-04:1277-1279"see Health Monitoring earlier in this skill" — that section documents an in-process TS API and contains no HTTP routecross-reference dropped

SKILL.md — truthfulness

id落点beforeafter
PLAT-F-06:347-381driver-as-a-plugins:-entry taught as the canonical bootstrap. Zero example configs do it: app-showcase and the blank template list connector plugins, app-crm and app-todo have no plugins: key, and the CLI wires the driver itself from the resolved DB URL (serve.ts:2687-2745)selection table kept; the code reframed as embedding/tests only, with "pick a driver by setting the DB URL, not by writing code"
PLAT-F-05:498-522composeStacks() had a section plus a 3-row strategies table and zero usages outside packages/spec and its own testsreduced to a pointer at stack.zod.ts. Live surface with zero measured usage ⇒ one row, never delete the last mention
PLAT-C-01:548-576taught a raw data: [{ object: 'task', … }] literal — writing object: by hand, which objectstack-data/SKILL.md:1036 forbids verbatim ("Auto-set from objectDef.name — never write manually"); 24 real defineSeed( sites, 0 raw literalsliteral deleted, defineSeed() pointer added, mode table kept (see premise_false) and given the ⚠️ Data-loss flag on replace it was missing
PLAT-C-02:626-663re-taught field types in a shape 0 of 7 real object files use (export default {} vs ObjectSchema.create({…}))one line pointing at objectstack-data and the scaffolder's own note.object.ts
PLAT-G-01:303,319,322-323,1035five spans used the retired v5.0 word for the runtime workspace ("project runtime", "Project revisions", "isolated project kernel") against skills/README.md:88 and the os environments CLI surfaceall five now environment. Uses of "project" for the local source tree left alone — those are correct
imprecision:79-80the blank template "ships One example object, in-memory driver, Hono server" — the template config has neither; its plugins: array holds three connector executors and both arrive from CLI auto-registrationstates what is in the file, and that the driver and server come from the CLI
PLAT-A-01:5,9-10,20 and the section headingfrontmatter sold "drivers, adapters" while :394-397 answers "There are no@objectstack/adapter-* packages" — promise and truth 385 lines apartdescription and heading now name the Hono HTTP layer
PLAT-G-03:307-310 vs :1109the os / objectstack alias was declared 800 lines after first usestated at first use
PLAT-C-04:1299a 60-token restatement of the very rule it delegates to objectstack-datasymptom plus the one-line cause

SKILL.md — examples that could not compile

id落点beforeafter
PLAT-E-01:527-542"Host Pattern" read as a complete config file but had ≥4 errors on paste: defineStack and SqlDriver used un-imported, CrmApp/TodoApp undefined, and new SqlDriver({ ... }) is TS1109folded into the Multi-App Composition prose; no un-compilable block
PLAT-E-02:1059-1073typed the literal as a Plugin intersection then read this.pool.query(...) (TS2339) and err.message on a catch binding (TS18046); PluginHealthStatus never importedthe opt-in contract in prose plus the three real kernel call sites
PLAT-E-03:954-969kernel.getService with a type argument naming a non-exported class from a different fence (TS2304)type argument dropped
PLAT-E-04:296-298defineStack({ ... }, { strict: false }) — TS1109 by constructiondefineStack(config, { strict: false })

The funded additions — each paid by a deletion in the same file

id落点beforeafter
PLAT-F-01Manifest Referencemanifest.engines: { protocol: '^17' } has 4 real usages including every project the scaffolder emits, and grep engines skills/objectstack-platform/ returned 0one manifest row plus why the runtime checks it before it loads anything
PLAT-F-02Boot Sequencerequires: [...] decides which service plugins boot; taught as one CRM-blueprint cell and one bare word, while the Boot Sequence narrated a fixed auto-register list and never said requires: drives itall 20 provider-backed tokens against their real pkg values, the two other resolution mechanisms kept separate from them, and five rules that change what you write: precedence, declaring-is-a-demand (declared-but-absent is a hard boot error, auto-injected-but-absent stays best-effort), auth implies email, keep automation whenever plugins: lists a connector, and pair triggers with job
PLAT-F-03Boot Sequencethe onEnable export — the seam where an app binds runtime code — has 4 real sites and was documented only in objectstack-dataits own subsection with the AppPlugin invocation and a worked export
PLAT-F-04Part 3plugin authoring stopped at kernel.use(plugin) with no path to a distributable plugin; the ADR-0025 §3.4 pipeline was mentioned nowhere in skills/a 3-row `os plugin build
PLAT-F-07kernel decisionthe guide offered two answers and routed serverless/edge to LiteKernel, while the repo's own example for that shape uses neither kernela third branch naming @objectstack/objectql/core and examples/embed-objectql (ADR-0076)
PLAT-A-02frontmatterthe description never named capabilities / requires:, the key that decides which service plugins bootone clause added, paid by A-01

Facts re-read against source before writing, per the card's assumption 5: blank/objectstack.config.ts:22,30; serve.tsCAPABILITY_PROVIDERS and the auth ⇒ email implication at :2281-2321; onEnable at app-showcase :283, app-crm :127, app-todo :33; PLATFORM_CAPABILITY_TOKENS in packages/spec/src/kernel/platform-capabilities.ts.

CAPABILITY_PROVIDERS holds 20 entries — the audit's "~20" was right. An earlier revision of this PR claimed 14 and offered that as a correction to the audit; that claim was itself wrong and is retracted. See Review round 1.

premise_false

  • PLAT-E-05 — premise false; not implemented. The audit proposed adding an os:check marker to the Complete Plugin Example so plugin/kernel examples would finally be type-checked. Measured: the gate's "skills + docs" surface resolves from packages/spec only (SURFACES in packages/spec/scripts/check-skill-examples.ts, resolutionDir: SPEC_DIR, selfPackages: [SPEC_DIR]), and @objectstack/core is not a dependency of packages/spec — that package's node_modules has no @objectstack scope at all. Marking the block produced skills/objectstack-platform/SKILL.md:804:44 error TS2307: Cannot find module '@objectstack/core'. Every plugin/kernel example in this package imports Plugin / PluginContext / ObjectKernel / LiteKernel from there, so no such example can be gated without a new SURFACES entry — another package, which this flight may not edit. The marker was reverted; check:skill-examples is green with 258 marked blocks. Filed as follow-up below.
  • PLAT-C-01 — premise partly false. "DELETE the mode table → one pointer line" is not available: check:skill-identifier-liveness registers ## Seed Data as exhaustive over SeedMode, and deleting the table turned five live members (insert, update, upsert, replace, ignore) into capabilities no AI author reading the catalog can reach. The gate caught it. Fixed the author's way — the table stays, and gained the ⚠️ Data-loss flag on replace the audit noted was missing. The shrink-only gap ledger is maintainer-only and was not touched.
  • PLAT-C-03 — not applied, by ruling. The card's ANCHOR RULINGS keep SKILL.md:59-70 because the pm-dispatch flight points there. The overlap the audit identified is real but is the anchor's to settle.
  • PLAT-G-02 — not applied, by ruling. Moving references/plugin-hooks.md to rules/ is exactly what the card forbids (the path is pinned stable for objectstack-data's inbound link). The catalog-wide drift it names is real and is listed as follow-up.

Card assumptions verified rather than assumed: (1) skills/objectstack-platform/** is byte-identical at a59f78d, d63c8a25 and this branch's actual base 909a4417git diff --stat empty for both; note origin/main had moved past the d63c8a25 named in the card. (2) bootstrap-patterns has zero inbound links, with plugin-lifecycle as a positive control that hits abundantly. (3) check:skill-docsis the drift gate, it is in the derived family, and the frontmatter edit did force regeneration — of two files, not one (below). (4) the ratchet reds on a deleted file whose row remains — probed directly: re-adding the row gave exit 1 and "cannot read … — red, not a skip (#4690)", then the script was restored and the restore confirmed by hash match.

Files outside the card's literal list

  • skills/README.md — regenerated, as the card anticipated for a frontmatter edit.
  • content/docs/ai/skills-reference.mdxalso regenerated, because one generator writes both and check:skill-docs fails on both. Not anticipated by the card; flagged here. Both diffs are frontmatter-derived only, confined to this package's row. Not content/docs/releases/.

follow-up for packages/spec

  • Extend SURFACES in packages/spec/scripts/check-skill-examples.ts with a resolution root that can see @objectstack/core, so plugin / kernel / service examples across the catalog become type-checkable. Today 78 of this package's 80 TypeScript fences are unchecked and the two checked ones both teach data authoring — the least proprietary content in the package. This is PLAT-E-05's real blocker.

follow-up for the catalog

  • PLAT-G-02: hand-authored per-topic files live under the generated references/ directory, which skills/README.md:55-58 reserves for generated pointers. This package and objectstack-data (references/data-hooks.md) both do it — a catalog-wide placement decision, not a lone slip, and one this flight is explicitly forbidden to settle by moving the file.

Review round 1

Contract review failed one span — the requires: table added for PLAT-F-02. Three defects, all from reading a bounded slice of CAPABILITY_PROVIDERS instead of reading it to its closing brace. Fixed in 224d5d9a; the cross-flight link repair below landed in 25012189:

#defecttruth at sourcefix
1audit row named @objectstack/service-audit@objectstack/plugin-audit (AuditPlugin), serve.ts:1473-1475row corrected
2triggers row named @objectstack/service-triggers, which does not exist@objectstack/trigger-record-change (RecordChangeTriggerPlugin), extras @objectstack/trigger-schedule (ScheduleTriggerPlugin, TimeRelativeTriggerPlugin) and @objectstack/trigger-api (ApiTriggerPlugin), serve.ts:1506-1537row corrected; the entry's own comment ("so pair triggers with job") became a row note and the fifth rule
3"the remaining vocabulary … resolve the same way", and the claim that the map holds 14 entriesthe map holds 20; the other eight tokens resolve by two different mechanismstable lists all 20 against their real pkg; the eight are split into tier-gated (no map entry, opened by dedicated run() blocks per the CAPABILITY_TO_TIER docblock at serve.ts:1166-1171) and enterprise/cloud (no open-edition provider: hierarchy-security ships in @objectstack/security-enterprise via plugins[], ai-seat and governance are cloud-runtime only, platform-capabilities.ts:57-66)

20 + 5 + 3 = the 28 tokens in PLATFORM_CAPABILITY_TOKENS, counted from the frozen array rather than asserted. Defect 3 is the one worth naming plainly: the "14 entries" figure was published as a correction to the audit when the audit was right and the correction was the error — a truncated read reported as a finding.

Cross-flight link repair

references/plugin-hooks.md routed readers to objectstack-data's rules/hooks.md for per-record validation, defaults and audit trails. The data flight (PR #14427, head 061e5f4c, delivered) DELETES that file and consolidates hooks into objectstack-data/references/data-hooks.md, so the reference was repointed before it could dangle — now a real relative link, ../../objectstack-data/references/data-hooks.md, verified to resolve from references/. The old text named both the doomed rules/hooks.md and the surviving references/data-hooks.md; naming only the survivor makes the span 22 bytes shorter. git grep rules/hooks.md over this package returns nothing further, so that was the only site.

The PR title still carries the pre-patch figure (−3,778); the accurate net is −3,608. Left alone deliberately — the patch instruction was not to retitle.

Gates

Head sha 25012189. Command list derived from the real change set by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (9 paths; re-derived after regeneration added the two generated files, which pulled in 20 further docs-family gates). The full 46 were run on 15b4ac79: 45 exit 0, 1 NOT MEASURED. Review round 1 touched only SKILL.md and references/plugin-hooks.md, so the change set and therefore the derived family are unchanged; the card-named gates were re-run on 25012189 and are listed below.

The one non-green in that full run is NOT MEASURED by its own verdict text — node scripts/check-test-completeness.mjs exits 3, not 1: "PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named… the local reading for this gate is NOT MEASURED." CI tees the log and passes the path, so this branch is unreachable there. Not a finding, and not read as green.

Card-named gates on 25012189, every exit captured before any pipe, all exit 0:

gateverdict line
check-skills-token-ratchet"36 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted" — SKILL.md 12871 / 12984, plugin-hooks.md 2413 / 2628
check:skill-examples"258 marked example(s) across 100 file(s), 3 surface(s)"
check:skill-identifier-liveness"OK — Leg 1: 493 citation(s) over 46 published file(s) … Leg 2: 9 registered exhaustive section(s), 0 ledgered gap(s)" — 493, up from 491: the corrected package names are themselves live-checked citations
check:skill-docsexit 0 with no regeneration needed (round 1 touched no frontmatter)
check:skill-compatibility"11 SKILL.md file(s) reconciled against 78 workspace packages"
check:published-readme-linksexit 0 — run additionally to prove the repointed cross-package link resolves

Two gates initially reported exit 3 for missing local build prerequisites and were re-run properly rather than recorded as failures: check:doc-formula-expressions (needed @objectstack/formula built) and check:skill-examples (needed @objectstack/client-react built — it refuses rather than false-greening, #7122). Both green afterwards.

Control bytes: node scripts/check-nul-bytes.mjs green, plus a direct scan of all changed files for the wider control-byte range — no hits.

skip-changeset applies and is on the PR: this diff releases nothing from any package. skills/ is named in the changeset gate's own release-nothing enumeration (scripts/check-empty-changeset.mjs), which pins a "skills/**-only PR carrying NO changeset" as a green fixture, and scripts/check-skills-token-ratchet.mjs is a CI-internal gate script — the workflow calls that the textbook case.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

…-B-01)
`rules/bootstrap-patterns.md` had ZERO inbound links repo-wide — the only
reference to its path anywhere in the tree was its own ceiling row in
`scripts/check-skills-token-ratchet.mjs`. `SKILL.md:715-717` links only
lifecycle / service-registry / hooks-events, so nothing ever routed a reader
to it; verified with `git grep -n bootstrap-patterns` against a positive
control (`git grep -n plugin-lifecycle` hits abundantly).
Its content was already carried by SKILL.md: the driver table (:66-74 =
SKILL.md:351-357), the HTTP-layer table (:76-83 = :389-397), the "no `driver:`
key, refused at load" block plus the `defineStack validation failed` sample
(:7-31,87-105 = :209-234), and manifest required fields (:29-31,107-130 =
:327-339). Its own last line pointed back at SKILL.md.
1,093 tokens of the published bundle that no customer agent could reach.
The ceiling row goes with the file: the gate treats an unreadable ratcheted
path as RED, not as a skip (#4690) — verified by a controlled probe that
re-added the row (exit 1, "cannot read ... — red, not a skip"), then restored
the script and confirmed the restore by hash match.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
… the pointer file (PLAT-B-02, D-04, D-05, D-06)
`rules/plugin-hooks-events.md` opened by declaring itself "a compact pointer.
Complete documentation lives in the canonical reference" and then reproduced
that reference: the event table, the `data:*` warning, the custom-hook
convention, execution order, and a DO/DON'T list. SKILL.md linked only the
pointer, so the 2,628-token canonical file sat TWO hops from the entry file
behind 985 tokens that restated it.
SKILL.md now links `references/plugin-hooks.md` directly at both sites
(`:717` and `:865`) and the pointer file is deleted with its ceiling row.
Checked before deleting: the pointer carried no fact absent from the
canonical reference or from SKILL.md — its one non-hooks item ("no circular
dependencies between plugins, both kernels throw") is already the
`Dependency resolution` row of the ObjectKernel-vs-LiteKernel table. So the
merge is a relink plus a deletion, and the compact DO/DON'T shape it had is
what now closes the canonical file.
`references/plugin-hooks.md` PATH IS UNCHANGED on purpose:
`skills/objectstack-data/rules/hooks.md:202` links to it across packages, and
that link is verified still resolving.
Paid inside `references/plugin-hooks.md`, per the shrink-only ratchet:
- PLAT-D-04 — the 7-item "Best Practices" list, every item of which
restated a span of the same file, is replaced by the compact DO/DON'T
rules-of-thumb folded in from the deleted pointer.
- PLAT-D-05 — "Hook Naming Conventions" deleted; its only new rule
(lower-case) folded into the Custom Hooks convention line.
- PLAT-D-06 — the second of two near-identical vitest blocks deleted; it
differed only in asserting `receivedData` instead of `hookCalled`.
Token deltas: references/plugin-hooks.md 2628 -> 2418 (ceiling 2628);
SKILL.md 12984 -> 12982 (ceiling 12984 — the relinked paths are shorter than
the deleted ones); rules/plugin-hooks-events.md 985 -> deleted with its row.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…07, C-05)
`rules/service-registry.md` 2329 -> 1754 tokens (ceiling 2331):
- PLAT-B-07 — "Well-Known Service Keys" was the SAME table as
`SKILL.md:1008-1024` with the columns inverted and only 6 of its 13 rows,
and both then repeated "the REST plugin registers no service". One table
now, in SKILL.md; this file points at it.
- PLAT-D-03 — deleted "Service Naming Conventions" (generic advice: "use
descriptive names", "avoid abbreviations"), a "Testing Service
Registration" block whose only assertions were `toBeDefined()` and
`toThrow()`, and a 10-item "Best Practices" list restating this file's own
Registration Patterns section and its `null`-placeholder paragraph.
`rules/plugin-lifecycle.md` 2404 -> 1777 tokens (ceiling 2408):
- PLAT-D-08 — the ❌/✅ "getService() in init() without a declared
dependency" lesson was already in `service-registry.md:193-223`,
differing only in the names used (CachePlugin/db-pool vs
AnalyticsPlugin/objectql) and closing on the SAME paragraph about never
registering `null`. Replaced with the rule plus a link to the one worked
pair.
- PLAT-D-02 — deleted a 10-item "Best Practices" list (items 1-7 restate
this file's own Phase 1/2/3 headings; 8-10 are generic: "version your
plugin", "use reverse domain names") and a "Testing Lifecycle" section of
two vitest blocks whose only assertions were `toBeDefined()` and
`isConnected()`.
- PLAT-C-05 — dropped this file's copy of the `data:*`-boundary warning.
The boundary was stated five times in-package; the canonical statement
stays in `references/plugin-hooks.md` and SKILL.md keeps exactly one.
No content was moved to another package: each deletion either had a surviving
in-package statement or was generic advice that changed no decision.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…B/C/D/E/F/G)
Deletions and rewrites (SKILL.md 12984 -> 12696 tokens, ceiling 12984):
- PLAT-B-05 — `defineStack()` was 12% down the file behind 1,441 tokens of
preamble. It (with the Manifest Reference it needs) is now the first
section after the title.
- PLAT-B-03 — "When to Use This Skill" appeared TWICE, 650 lines apart,
both restating the frontmatter. A loaded package is already selected.
- PLAT-B-06 — the package narrated its own edit history ("the original
'quickstart' skill"). A customer agent never chose between two former
skills.
- PLAT-D-07 — the CRM Blueprint restated the directory tree 18 lines above
and pointed at data / i18n territory; only its `requires:` row was
platform-specific, and that is now taught properly (F-02).
- PLAT-D-01 — the ASCII Decision Guide restated the table two lines above.
- PLAT-F-05 — `composeStacks()` had a section plus a strategies table and
ZERO usages outside `packages/spec` and its own tests; real multi-app
composition is AppPlugin registration. Reduced to a pointer at the schema,
not deleted (live surface, zero measured usage).
- PLAT-F-06 — driver-as-a-`plugins:`-entry was taught as THE canonical
bootstrap; no example config does it and the CLI wires the driver itself
from the resolved DB URL. Reframed as embedding/tests only.
- PLAT-C-01 — seeds are objectstack-data's; the copy here taught a raw
literal writing `object:` by hand, which that skill forbids verbatim.
Now a pointer PLUS the `mode` table (see below).
- PLAT-C-02 — the example object file re-taught field types in a spelling
7 of 7 real object files do not use (`export default {}` vs
`ObjectSchema.create({...})`).
- PLAT-C-04, B-04 — a restatement of the rule it delegates, and a
cross-reference to a section that documents an in-process TS API and
contains no HTTP route.
- PLAT-C-05 — SKILL.md stated the `data:*` boundary twice; one statement
remains (the one that explains the silent registration).
- PLAT-E-01, E-02, E-03, E-04 — four blocks that could not compile:
`defineStack`/`SqlDriver` used un-imported with `CrmApp`/`TodoApp`
undefined; `this.pool` on a plain object literal plus `err.message` on a
`catch` binding; a type argument naming a non-exported class from another
fence; and `{ ... }` / `{ … }` ellipsis placeholders (TS1109).
- PLAT-G-01 — v5.0 vocabulary: the runtime workspace is `environment`, not
`project`, in all five spans (skills/README.md:88; the CLI surface is
`os environments`).
- PLAT-G-03 — the `os` / `objectstack` binary alias is now stated at first
use instead of 800 lines later.
- PLAT-A-01 — the frontmatter sold "adapters" and the body refutes it 385
lines in ("There are no `@objectstack/adapter-*` packages"). Both the
description and the section heading now name the Hono HTTP layer.
- The `blank` template's "in-memory driver, Hono server" was true of the
RUNNING APP and false of the file a reader opens: the template config has
neither; both arrive from CLI auto-registration.
Additions, each paid by a deletion in this same file:
- PLAT-F-01 — `manifest.engines.protocol`, stamped into every project
`create-objectstack` emits and carried by all three example apps, was
mentioned NOWHERE in this package. One manifest row + why it is checked
before anything loads.
- PLAT-F-02 — `requires: [...]` decides which service plugins boot and was
taught as one blueprint cell and one bare word. Now a token table plus the
four rules that change what you write: precedence, declaring-is-a-demand
(hard boot error vs best-effort), `auth` implies `email`, and keep
`automation` whenever `plugins:` lists a connector.
- PLAT-F-03 — the `onEnable` export, the seam where an app binds runtime
code, used by all three example apps and documented only in
objectstack-data.
- PLAT-F-04 — `os plugin build|sign|publish`: authoring stopped at
`kernel.use(plugin)` with no path to a distributable plugin.
- PLAT-F-07 — a third answer to the kernel question: `examples/embed-objectql`
uses NEITHER kernel (`@objectstack/objectql/core`, ADR-0076).
- PLAT-A-02 — the description now names the capability key.
Generated files regenerated because the frontmatter changed, as the drift gate
demands: `skills/README.md` AND `content/docs/ai/skills-reference.mdx` (one
generator writes both; `pnpm --filter @objectstack/spec gen:skill-docs`). Both
diffs are frontmatter-derived only.
`## Seed Data` keeps its `mode` table: `check:skill-identifier-liveness`
registers that section as exhaustive over `SeedMode`, and deleting the table
made five live members unreachable (caught by the gate, fixed the author's
way — the shrink-only gap ledger is maintainer-only and was not touched). The
table now also carries the Data-loss flag on `replace` that it was missing.
PLAT-E-05 is NOT implemented — its premise is false; see the PR body.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…al registry (review round 1)
Contract review round 1 failed the `requires:` table I added in the previous
commit. Three defects, all mine, all from reading a bounded slice of
`CAPABILITY_PROVIDERS` instead of reading it to its closing brace:
1. `audit` named `@objectstack/service-audit`. The real entry is
`@objectstack/plugin-audit` (`AuditPlugin`), serve.ts:1473-1475.
2. `triggers` named `@objectstack/service-triggers`, which does not exist. The
entry is `@objectstack/trigger-record-change` (`RecordChangeTriggerPlugin`)
with extras `@objectstack/trigger-schedule` (`ScheduleTriggerPlugin`,
`TimeRelativeTriggerPlugin`) and `@objectstack/trigger-api`
(`ApiTriggerPlugin`), serve.ts:1506-1537.
3. "the remaining vocabulary resolves the same way" was false, and so was the
claim that the map holds 14 entries. It holds TWENTY — I bounded an `awk`
range by guess and stopped at `sms`, then reported the truncation as a
correction to the audit. The audit's "~20" was right and my correction was
the error.
The table now lists all 20 provider-backed tokens against their real `pkg`
values, and the eight remaining tokens are separated into the two mechanisms
that actually resolve them: five tier-gated tokens with NO map entry, opened by
dedicated blocks in `serve.ts` `run()` (CAPABILITY_TO_TIER docblock,
serve.ts:1166-1171), and three enterprise/cloud tokens with no open-edition
provider at all — `hierarchy-security` ships in
`@objectstack/security-enterprise` via `plugins[]`, `ai-seat` and `governance`
are cloud-runtime only (platform-capabilities.ts:57-66). 20 + 5 + 3 = the 28
tokens in `PLATFORM_CAPABILITY_TOKENS`, counted from the frozen array rather
than asserted.
The `triggers` entry's own comment carries a rule an author needs — schedule
triggers run on the job service, "so pair `triggers` with `job`" — so that is
now both a row note and the fifth rule: `triggers` alone arms record-change
triggers, and autolaunched scheduled flows stay silent without `job`.
SKILL.md 12696 -> 12871 tokens, ceiling 12984 unchanged and not raised; the
growth is paid from the headroom this flight's own deletions created.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…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-litantos-litant changed the title skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,778 tokens)skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens)Sep 2, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 06:53
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to a conflict with the base branch Sep 2, 2026
Nine sibling skills flights landed on main after this branch's base. Both
conflicts fell inside the BEGIN/END GENERATED: skills region of the two mixed
generated files (skills/README.md, content/docs/ai/skills-reference.mdx);
resolved by clearing the markers in place — preserving main's text-merged prose
outside the region — and regenerating both wholesale with
`pnpm --filter @objectstack/spec gen:skill-docs` on the merged tree.
scripts/check-skills-token-ratchet.mjs auto-merged (each flight edited its own
package's ceiling rows). No behaviour or content change to the platform package.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01489YWhZEoHT9oXshiyywQy
@claude
claudeBot requested a review from os-zhuangSeptember 2, 2026 14:54
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/xlskip-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(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens) - #14351

Merged
os-zhuang merged 7 commits into
mainfrom
claude/issue-14299-skills-platform-optimization
Sep 2, 2026
Merged

skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens)#14351
os-zhuang merged 7 commits into
mainfrom
claude/issue-14299-skills-platform-optimization

Conversation

@os-litant

@os-litantos-litant commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Part of #14299

Skills catalog optimization flight for skills/objectstack-platform (program #14292, maintainer mandate 2026-09-02 「审核所有的 skills,进行全面的优化。」). The 50-finding audit record is posted verbatim on the card. Governed face — stays draft; needs:contract-review on both carriers.

Why Part of and not a closing keyword: only the implementable half of the card landed. PLAT-H-01 is deferred to decision card #14296 item 2 and PLAT-G-02 to the catalog follow-up below, so merging this must not close the card while its deferred half is still undecided. The card stays open; pm:dispatched is stripped by hand at merge.

Per-file token delta

Token unit is the ratchet's own: ceil(utf8 bytes / 4).

Filebeforeafterceilingnote
SKILL.md129841287112984−113; every addition paid in-file. Review round 1 spent 175 of the freed headroom on the corrected requires: table
references/plugin-hooks.md262824132628−215; absorbed the deleted pointer's DO/DON'T, plus the cross-flight link repair
rules/plugin-lifecycle.md240417772408−627
rules/service-registry.md232917542331−575
rules/bootstrap-patterns.md1093deletedrow droppedorphan, zero inbound links
rules/plugin-hooks-events.md985deletedrow droppedself-declared pointer that restated its target
evals/README.md514514514untouched — DEFERRED per #14296 item 2
references/_index.md13441344generateduntouched

Package 24,281 → 20,673 = −3,608 (−14.9%). Bundle total 187,854 → 184,246. No ceiling was raised; no file grew; scripts/check-skills-token-ratchet.mjs was touched only to drop the two deleted files' rows.

The audit's package total of 24,278 is 3 tokens off — the measured base is 24,281 (sum of the eight rows above).

Why −3,608 and not the projected −5,970

Four of the projected reductions were withdrawn by evidence or by ruling, not skipped:

The five funded additions also cost more than the projected +355, because they were written against the measured facts (the requires: table carries all 20 provider-backed tokens plus the five rules that change what an author writes) rather than against the projection.

Per-item: 落点 | before | after

Deleted files

id落点beforeafter
PLAT-B-01rules/bootstrap-patterns.md1,093 tokens with zero inbound links repo-wide — the only mention of its path was its own ceiling row. Content already carried by SKILL.md (driver table, HTTP-layer table, the "no driver: key, refused at load" block, manifest required fields); its own last line pointed back at SKILL.mddeleted, with its ceiling row
PLAT-B-02rules/plugin-hooks-events.md + SKILL.md:717,865The file opened "This document is a compact pointer. Complete documentation lives in the canonical reference" and then reproduced it. SKILL.md linked only the pointer, so the 2,628-token canonical file sat two hops from the entry filedeleted; SKILL.md links references/plugin-hooks.md directly at both sites. Path unchanged on purposeskills/objectstack-data/rules/hooks.md:202 links to it across packages; verified still resolving

Checked before deleting the pointer: it carried no fact absent from the canonical reference or SKILL.md. Its one non-hooks item ("no circular dependencies between plugins, both kernels throw") is already the Dependency resolution row of the ObjectKernel-vs-LiteKernel table.

references/plugin-hooks.md

id落点beforeafter
PLAT-D-04:312-3277-item "Best Practices", every item restating a span of the same filereplaced by the compact DO/DON'T folded in from the deleted pointer
PLAT-D-05:238-251"Hook Naming Conventions", 4 good / 2 bad names; the convention was already given at :80-82 and demonstrated at :225-232deleted; its only new rule (lower-case) folded into the Custom Hooks convention line
PLAT-D-06:252-311two near-identical 25-line vitest blocks; the second differed only by asserting receivedData instead of hookCalledsecond block deleted

rules/plugin-lifecycle.md and rules/service-registry.md

id落点beforeafter
PLAT-B-07service-registry.md:145-158the same table as SKILL.md:1008-1024 with inverted columns and only 6 of its 13 rows; both then repeated "the REST plugin registers no service"one table, in SKILL.md; the rules file points at it
PLAT-D-03service-registry.md:270-319"Service Naming Conventions" (generic: "use descriptive names", "avoid abbreviations") + a test block asserting only toBeDefined()/toThrow() + a 10-item Best Practices restating the file's own sectionsdeleted
PLAT-D-08plugin-lifecycle.md:201-230the same ❌/✅ lesson as service-registry.md:193-223, differing only in names, closing on the same null-placeholder paragraphreplaced by the rule plus a link to the one worked pair
PLAT-D-02plugin-lifecycle.md:293-34010-item Best Practices (1-7 restate the file's own Phase headings; 8-10 generic: "version your plugin", "use reverse domain names") + two vitest blocks asserting only toBeDefined()/isConnected()deleted
PLAT-C-05plugin-lifecycle.md:110-113, SKILL.md:944-948the data:* boundary was stated five times in-packagein-package statements down to three; SKILL.md keeps exactly one (the one explaining the silent registration), per the anchor ruling; canonical statement stays in references/plugin-hooks.md

SKILL.md — structure

id落点beforeafter
PLAT-B-05section order1,441 tokens preceded defineStack() — the core construct sat 12% down the filedefineStack() (with the Manifest Reference it needs) is the first section after the title
PLAT-B-03:39-49, :699-708"When to Use This Skill" appeared twice, 650 lines apart, both restating the frontmatterboth deleted — a loaded package is already selected
PLAT-B-06:25-35narrated the package's own edit history ("the original 'quickstart' skill", "which is why they live in one skill")one sentence naming the two concerns
PLAT-D-07:142-158"CRM Blueprint": rows 2-3 restated the directory tree 18 lines above; rows 5-6 pointed at data / i18n territorydeleted; its only platform-specific row (requires:) is now taught properly under the Boot Sequence
PLAT-D-01:735-758ASCII "Decision Guide" restating the table two lines above; its gloss changed no branchdeleted, table survives
PLAT-B-04:1277-1279"see Health Monitoring earlier in this skill" — that section documents an in-process TS API and contains no HTTP routecross-reference dropped

SKILL.md — truthfulness

id落点beforeafter
PLAT-F-06:347-381driver-as-a-plugins:-entry taught as the canonical bootstrap. Zero example configs do it: app-showcase and the blank template list connector plugins, app-crm and app-todo have no plugins: key, and the CLI wires the driver itself from the resolved DB URL (serve.ts:2687-2745)selection table kept; the code reframed as embedding/tests only, with "pick a driver by setting the DB URL, not by writing code"
PLAT-F-05:498-522composeStacks() had a section plus a 3-row strategies table and zero usages outside packages/spec and its own testsreduced to a pointer at stack.zod.ts. Live surface with zero measured usage ⇒ one row, never delete the last mention
PLAT-C-01:548-576taught a raw data: [{ object: 'task', … }] literal — writing object: by hand, which objectstack-data/SKILL.md:1036 forbids verbatim ("Auto-set from objectDef.name — never write manually"); 24 real defineSeed( sites, 0 raw literalsliteral deleted, defineSeed() pointer added, mode table kept (see premise_false) and given the ⚠️ Data-loss flag on replace it was missing
PLAT-C-02:626-663re-taught field types in a shape 0 of 7 real object files use (export default {} vs ObjectSchema.create({…}))one line pointing at objectstack-data and the scaffolder's own note.object.ts
PLAT-G-01:303,319,322-323,1035five spans used the retired v5.0 word for the runtime workspace ("project runtime", "Project revisions", "isolated project kernel") against skills/README.md:88 and the os environments CLI surfaceall five now environment. Uses of "project" for the local source tree left alone — those are correct
imprecision:79-80the blank template "ships One example object, in-memory driver, Hono server" — the template config has neither; its plugins: array holds three connector executors and both arrive from CLI auto-registrationstates what is in the file, and that the driver and server come from the CLI
PLAT-A-01:5,9-10,20 and the section headingfrontmatter sold "drivers, adapters" while :394-397 answers "There are no@objectstack/adapter-* packages" — promise and truth 385 lines apartdescription and heading now name the Hono HTTP layer
PLAT-G-03:307-310 vs :1109the os / objectstack alias was declared 800 lines after first usestated at first use
PLAT-C-04:1299a 60-token restatement of the very rule it delegates to objectstack-datasymptom plus the one-line cause

SKILL.md — examples that could not compile

id落点beforeafter
PLAT-E-01:527-542"Host Pattern" read as a complete config file but had ≥4 errors on paste: defineStack and SqlDriver used un-imported, CrmApp/TodoApp undefined, and new SqlDriver({ ... }) is TS1109folded into the Multi-App Composition prose; no un-compilable block
PLAT-E-02:1059-1073typed the literal as a Plugin intersection then read this.pool.query(...) (TS2339) and err.message on a catch binding (TS18046); PluginHealthStatus never importedthe opt-in contract in prose plus the three real kernel call sites
PLAT-E-03:954-969kernel.getService with a type argument naming a non-exported class from a different fence (TS2304)type argument dropped
PLAT-E-04:296-298defineStack({ ... }, { strict: false }) — TS1109 by constructiondefineStack(config, { strict: false })

The funded additions — each paid by a deletion in the same file

id落点beforeafter
PLAT-F-01Manifest Referencemanifest.engines: { protocol: '^17' } has 4 real usages including every project the scaffolder emits, and grep engines skills/objectstack-platform/ returned 0one manifest row plus why the runtime checks it before it loads anything
PLAT-F-02Boot Sequencerequires: [...] decides which service plugins boot; taught as one CRM-blueprint cell and one bare word, while the Boot Sequence narrated a fixed auto-register list and never said requires: drives itall 20 provider-backed tokens against their real pkg values, the two other resolution mechanisms kept separate from them, and five rules that change what you write: precedence, declaring-is-a-demand (declared-but-absent is a hard boot error, auto-injected-but-absent stays best-effort), auth implies email, keep automation whenever plugins: lists a connector, and pair triggers with job
PLAT-F-03Boot Sequencethe onEnable export — the seam where an app binds runtime code — has 4 real sites and was documented only in objectstack-dataits own subsection with the AppPlugin invocation and a worked export
PLAT-F-04Part 3plugin authoring stopped at kernel.use(plugin) with no path to a distributable plugin; the ADR-0025 §3.4 pipeline was mentioned nowhere in skills/a 3-row `os plugin build
PLAT-F-07kernel decisionthe guide offered two answers and routed serverless/edge to LiteKernel, while the repo's own example for that shape uses neither kernela third branch naming @objectstack/objectql/core and examples/embed-objectql (ADR-0076)
PLAT-A-02frontmatterthe description never named capabilities / requires:, the key that decides which service plugins bootone clause added, paid by A-01

Facts re-read against source before writing, per the card's assumption 5: blank/objectstack.config.ts:22,30; serve.tsCAPABILITY_PROVIDERS and the auth ⇒ email implication at :2281-2321; onEnable at app-showcase :283, app-crm :127, app-todo :33; PLATFORM_CAPABILITY_TOKENS in packages/spec/src/kernel/platform-capabilities.ts.

CAPABILITY_PROVIDERS holds 20 entries — the audit's "~20" was right. An earlier revision of this PR claimed 14 and offered that as a correction to the audit; that claim was itself wrong and is retracted. See Review round 1.

premise_false

  • PLAT-E-05 — premise false; not implemented. The audit proposed adding an os:check marker to the Complete Plugin Example so plugin/kernel examples would finally be type-checked. Measured: the gate's "skills + docs" surface resolves from packages/spec only (SURFACES in packages/spec/scripts/check-skill-examples.ts, resolutionDir: SPEC_DIR, selfPackages: [SPEC_DIR]), and @objectstack/core is not a dependency of packages/spec — that package's node_modules has no @objectstack scope at all. Marking the block produced skills/objectstack-platform/SKILL.md:804:44 error TS2307: Cannot find module '@objectstack/core'. Every plugin/kernel example in this package imports Plugin / PluginContext / ObjectKernel / LiteKernel from there, so no such example can be gated without a new SURFACES entry — another package, which this flight may not edit. The marker was reverted; check:skill-examples is green with 258 marked blocks. Filed as follow-up below.
  • PLAT-C-01 — premise partly false. "DELETE the mode table → one pointer line" is not available: check:skill-identifier-liveness registers ## Seed Data as exhaustive over SeedMode, and deleting the table turned five live members (insert, update, upsert, replace, ignore) into capabilities no AI author reading the catalog can reach. The gate caught it. Fixed the author's way — the table stays, and gained the ⚠️ Data-loss flag on replace the audit noted was missing. The shrink-only gap ledger is maintainer-only and was not touched.
  • PLAT-C-03 — not applied, by ruling. The card's ANCHOR RULINGS keep SKILL.md:59-70 because the pm-dispatch flight points there. The overlap the audit identified is real but is the anchor's to settle.
  • PLAT-G-02 — not applied, by ruling. Moving references/plugin-hooks.md to rules/ is exactly what the card forbids (the path is pinned stable for objectstack-data's inbound link). The catalog-wide drift it names is real and is listed as follow-up.

Card assumptions verified rather than assumed: (1) skills/objectstack-platform/** is byte-identical at a59f78d, d63c8a25 and this branch's actual base 909a4417git diff --stat empty for both; note origin/main had moved past the d63c8a25 named in the card. (2) bootstrap-patterns has zero inbound links, with plugin-lifecycle as a positive control that hits abundantly. (3) check:skill-docsis the drift gate, it is in the derived family, and the frontmatter edit did force regeneration — of two files, not one (below). (4) the ratchet reds on a deleted file whose row remains — probed directly: re-adding the row gave exit 1 and "cannot read … — red, not a skip (#4690)", then the script was restored and the restore confirmed by hash match.

Files outside the card's literal list

  • skills/README.md — regenerated, as the card anticipated for a frontmatter edit.
  • content/docs/ai/skills-reference.mdxalso regenerated, because one generator writes both and check:skill-docs fails on both. Not anticipated by the card; flagged here. Both diffs are frontmatter-derived only, confined to this package's row. Not content/docs/releases/.

follow-up for packages/spec

  • Extend SURFACES in packages/spec/scripts/check-skill-examples.ts with a resolution root that can see @objectstack/core, so plugin / kernel / service examples across the catalog become type-checkable. Today 78 of this package's 80 TypeScript fences are unchecked and the two checked ones both teach data authoring — the least proprietary content in the package. This is PLAT-E-05's real blocker.

follow-up for the catalog

  • PLAT-G-02: hand-authored per-topic files live under the generated references/ directory, which skills/README.md:55-58 reserves for generated pointers. This package and objectstack-data (references/data-hooks.md) both do it — a catalog-wide placement decision, not a lone slip, and one this flight is explicitly forbidden to settle by moving the file.

Review round 1

Contract review failed one span — the requires: table added for PLAT-F-02. Three defects, all from reading a bounded slice of CAPABILITY_PROVIDERS instead of reading it to its closing brace. Fixed in 224d5d9a; the cross-flight link repair below landed in 25012189:

#defecttruth at sourcefix
1audit row named @objectstack/service-audit@objectstack/plugin-audit (AuditPlugin), serve.ts:1473-1475row corrected
2triggers row named @objectstack/service-triggers, which does not exist@objectstack/trigger-record-change (RecordChangeTriggerPlugin), extras @objectstack/trigger-schedule (ScheduleTriggerPlugin, TimeRelativeTriggerPlugin) and @objectstack/trigger-api (ApiTriggerPlugin), serve.ts:1506-1537row corrected; the entry's own comment ("so pair triggers with job") became a row note and the fifth rule
3"the remaining vocabulary … resolve the same way", and the claim that the map holds 14 entriesthe map holds 20; the other eight tokens resolve by two different mechanismstable lists all 20 against their real pkg; the eight are split into tier-gated (no map entry, opened by dedicated run() blocks per the CAPABILITY_TO_TIER docblock at serve.ts:1166-1171) and enterprise/cloud (no open-edition provider: hierarchy-security ships in @objectstack/security-enterprise via plugins[], ai-seat and governance are cloud-runtime only, platform-capabilities.ts:57-66)

20 + 5 + 3 = the 28 tokens in PLATFORM_CAPABILITY_TOKENS, counted from the frozen array rather than asserted. Defect 3 is the one worth naming plainly: the "14 entries" figure was published as a correction to the audit when the audit was right and the correction was the error — a truncated read reported as a finding.

Cross-flight link repair

references/plugin-hooks.md routed readers to objectstack-data's rules/hooks.md for per-record validation, defaults and audit trails. The data flight (PR #14427, head 061e5f4c, delivered) DELETES that file and consolidates hooks into objectstack-data/references/data-hooks.md, so the reference was repointed before it could dangle — now a real relative link, ../../objectstack-data/references/data-hooks.md, verified to resolve from references/. The old text named both the doomed rules/hooks.md and the surviving references/data-hooks.md; naming only the survivor makes the span 22 bytes shorter. git grep rules/hooks.md over this package returns nothing further, so that was the only site.

The PR title still carries the pre-patch figure (−3,778); the accurate net is −3,608. Left alone deliberately — the patch instruction was not to retitle.

Gates

Head sha 25012189. Command list derived from the real change set by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (9 paths; re-derived after regeneration added the two generated files, which pulled in 20 further docs-family gates). The full 46 were run on 15b4ac79: 45 exit 0, 1 NOT MEASURED. Review round 1 touched only SKILL.md and references/plugin-hooks.md, so the change set and therefore the derived family are unchanged; the card-named gates were re-run on 25012189 and are listed below.

The one non-green in that full run is NOT MEASURED by its own verdict text — node scripts/check-test-completeness.mjs exits 3, not 1: "PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named… the local reading for this gate is NOT MEASURED." CI tees the log and passes the path, so this branch is unreachable there. Not a finding, and not read as green.

Card-named gates on 25012189, every exit captured before any pipe, all exit 0:

gateverdict line
check-skills-token-ratchet"36 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted" — SKILL.md 12871 / 12984, plugin-hooks.md 2413 / 2628
check:skill-examples"258 marked example(s) across 100 file(s), 3 surface(s)"
check:skill-identifier-liveness"OK — Leg 1: 493 citation(s) over 46 published file(s) … Leg 2: 9 registered exhaustive section(s), 0 ledgered gap(s)" — 493, up from 491: the corrected package names are themselves live-checked citations
check:skill-docsexit 0 with no regeneration needed (round 1 touched no frontmatter)
check:skill-compatibility"11 SKILL.md file(s) reconciled against 78 workspace packages"
check:published-readme-linksexit 0 — run additionally to prove the repointed cross-package link resolves

Two gates initially reported exit 3 for missing local build prerequisites and were re-run properly rather than recorded as failures: check:doc-formula-expressions (needed @objectstack/formula built) and check:skill-examples (needed @objectstack/client-react built — it refuses rather than false-greening, #7122). Both green afterwards.

Control bytes: node scripts/check-nul-bytes.mjs green, plus a direct scan of all changed files for the wider control-byte range — no hits.

skip-changeset applies and is on the PR: this diff releases nothing from any package. skills/ is named in the changeset gate's own release-nothing enumeration (scripts/check-empty-changeset.mjs), which pins a "skills/**-only PR carrying NO changeset" as a green fixture, and scripts/check-skills-token-ratchet.mjs is a CI-internal gate script — the workflow calls that the textbook case.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

…-B-01)
`rules/bootstrap-patterns.md` had ZERO inbound links repo-wide — the only
reference to its path anywhere in the tree was its own ceiling row in
`scripts/check-skills-token-ratchet.mjs`. `SKILL.md:715-717` links only
lifecycle / service-registry / hooks-events, so nothing ever routed a reader
to it; verified with `git grep -n bootstrap-patterns` against a positive
control (`git grep -n plugin-lifecycle` hits abundantly).
Its content was already carried by SKILL.md: the driver table (:66-74 =
SKILL.md:351-357), the HTTP-layer table (:76-83 = :389-397), the "no `driver:`
key, refused at load" block plus the `defineStack validation failed` sample
(:7-31,87-105 = :209-234), and manifest required fields (:29-31,107-130 =
:327-339). Its own last line pointed back at SKILL.md.
1,093 tokens of the published bundle that no customer agent could reach.
The ceiling row goes with the file: the gate treats an unreadable ratcheted
path as RED, not as a skip (#4690) — verified by a controlled probe that
re-added the row (exit 1, "cannot read ... — red, not a skip"), then restored
the script and confirmed the restore by hash match.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
… the pointer file (PLAT-B-02, D-04, D-05, D-06)
`rules/plugin-hooks-events.md` opened by declaring itself "a compact pointer.
Complete documentation lives in the canonical reference" and then reproduced
that reference: the event table, the `data:*` warning, the custom-hook
convention, execution order, and a DO/DON'T list. SKILL.md linked only the
pointer, so the 2,628-token canonical file sat TWO hops from the entry file
behind 985 tokens that restated it.
SKILL.md now links `references/plugin-hooks.md` directly at both sites
(`:717` and `:865`) and the pointer file is deleted with its ceiling row.
Checked before deleting: the pointer carried no fact absent from the
canonical reference or from SKILL.md — its one non-hooks item ("no circular
dependencies between plugins, both kernels throw") is already the
`Dependency resolution` row of the ObjectKernel-vs-LiteKernel table. So the
merge is a relink plus a deletion, and the compact DO/DON'T shape it had is
what now closes the canonical file.
`references/plugin-hooks.md` PATH IS UNCHANGED on purpose:
`skills/objectstack-data/rules/hooks.md:202` links to it across packages, and
that link is verified still resolving.
Paid inside `references/plugin-hooks.md`, per the shrink-only ratchet:
- PLAT-D-04 — the 7-item "Best Practices" list, every item of which
restated a span of the same file, is replaced by the compact DO/DON'T
rules-of-thumb folded in from the deleted pointer.
- PLAT-D-05 — "Hook Naming Conventions" deleted; its only new rule
(lower-case) folded into the Custom Hooks convention line.
- PLAT-D-06 — the second of two near-identical vitest blocks deleted; it
differed only in asserting `receivedData` instead of `hookCalled`.
Token deltas: references/plugin-hooks.md 2628 -> 2418 (ceiling 2628);
SKILL.md 12984 -> 12982 (ceiling 12984 — the relinked paths are shorter than
the deleted ones); rules/plugin-hooks-events.md 985 -> deleted with its row.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…07, C-05)
`rules/service-registry.md` 2329 -> 1754 tokens (ceiling 2331):
- PLAT-B-07 — "Well-Known Service Keys" was the SAME table as
`SKILL.md:1008-1024` with the columns inverted and only 6 of its 13 rows,
and both then repeated "the REST plugin registers no service". One table
now, in SKILL.md; this file points at it.
- PLAT-D-03 — deleted "Service Naming Conventions" (generic advice: "use
descriptive names", "avoid abbreviations"), a "Testing Service
Registration" block whose only assertions were `toBeDefined()` and
`toThrow()`, and a 10-item "Best Practices" list restating this file's own
Registration Patterns section and its `null`-placeholder paragraph.
`rules/plugin-lifecycle.md` 2404 -> 1777 tokens (ceiling 2408):
- PLAT-D-08 — the ❌/✅ "getService() in init() without a declared
dependency" lesson was already in `service-registry.md:193-223`,
differing only in the names used (CachePlugin/db-pool vs
AnalyticsPlugin/objectql) and closing on the SAME paragraph about never
registering `null`. Replaced with the rule plus a link to the one worked
pair.
- PLAT-D-02 — deleted a 10-item "Best Practices" list (items 1-7 restate
this file's own Phase 1/2/3 headings; 8-10 are generic: "version your
plugin", "use reverse domain names") and a "Testing Lifecycle" section of
two vitest blocks whose only assertions were `toBeDefined()` and
`isConnected()`.
- PLAT-C-05 — dropped this file's copy of the `data:*`-boundary warning.
The boundary was stated five times in-package; the canonical statement
stays in `references/plugin-hooks.md` and SKILL.md keeps exactly one.
No content was moved to another package: each deletion either had a surviving
in-package statement or was generic advice that changed no decision.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…B/C/D/E/F/G)
Deletions and rewrites (SKILL.md 12984 -> 12696 tokens, ceiling 12984):
- PLAT-B-05 — `defineStack()` was 12% down the file behind 1,441 tokens of
preamble. It (with the Manifest Reference it needs) is now the first
section after the title.
- PLAT-B-03 — "When to Use This Skill" appeared TWICE, 650 lines apart,
both restating the frontmatter. A loaded package is already selected.
- PLAT-B-06 — the package narrated its own edit history ("the original
'quickstart' skill"). A customer agent never chose between two former
skills.
- PLAT-D-07 — the CRM Blueprint restated the directory tree 18 lines above
and pointed at data / i18n territory; only its `requires:` row was
platform-specific, and that is now taught properly (F-02).
- PLAT-D-01 — the ASCII Decision Guide restated the table two lines above.
- PLAT-F-05 — `composeStacks()` had a section plus a strategies table and
ZERO usages outside `packages/spec` and its own tests; real multi-app
composition is AppPlugin registration. Reduced to a pointer at the schema,
not deleted (live surface, zero measured usage).
- PLAT-F-06 — driver-as-a-`plugins:`-entry was taught as THE canonical
bootstrap; no example config does it and the CLI wires the driver itself
from the resolved DB URL. Reframed as embedding/tests only.
- PLAT-C-01 — seeds are objectstack-data's; the copy here taught a raw
literal writing `object:` by hand, which that skill forbids verbatim.
Now a pointer PLUS the `mode` table (see below).
- PLAT-C-02 — the example object file re-taught field types in a spelling
7 of 7 real object files do not use (`export default {}` vs
`ObjectSchema.create({...})`).
- PLAT-C-04, B-04 — a restatement of the rule it delegates, and a
cross-reference to a section that documents an in-process TS API and
contains no HTTP route.
- PLAT-C-05 — SKILL.md stated the `data:*` boundary twice; one statement
remains (the one that explains the silent registration).
- PLAT-E-01, E-02, E-03, E-04 — four blocks that could not compile:
`defineStack`/`SqlDriver` used un-imported with `CrmApp`/`TodoApp`
undefined; `this.pool` on a plain object literal plus `err.message` on a
`catch` binding; a type argument naming a non-exported class from another
fence; and `{ ... }` / `{ … }` ellipsis placeholders (TS1109).
- PLAT-G-01 — v5.0 vocabulary: the runtime workspace is `environment`, not
`project`, in all five spans (skills/README.md:88; the CLI surface is
`os environments`).
- PLAT-G-03 — the `os` / `objectstack` binary alias is now stated at first
use instead of 800 lines later.
- PLAT-A-01 — the frontmatter sold "adapters" and the body refutes it 385
lines in ("There are no `@objectstack/adapter-*` packages"). Both the
description and the section heading now name the Hono HTTP layer.
- The `blank` template's "in-memory driver, Hono server" was true of the
RUNNING APP and false of the file a reader opens: the template config has
neither; both arrive from CLI auto-registration.
Additions, each paid by a deletion in this same file:
- PLAT-F-01 — `manifest.engines.protocol`, stamped into every project
`create-objectstack` emits and carried by all three example apps, was
mentioned NOWHERE in this package. One manifest row + why it is checked
before anything loads.
- PLAT-F-02 — `requires: [...]` decides which service plugins boot and was
taught as one blueprint cell and one bare word. Now a token table plus the
four rules that change what you write: precedence, declaring-is-a-demand
(hard boot error vs best-effort), `auth` implies `email`, and keep
`automation` whenever `plugins:` lists a connector.
- PLAT-F-03 — the `onEnable` export, the seam where an app binds runtime
code, used by all three example apps and documented only in
objectstack-data.
- PLAT-F-04 — `os plugin build|sign|publish`: authoring stopped at
`kernel.use(plugin)` with no path to a distributable plugin.
- PLAT-F-07 — a third answer to the kernel question: `examples/embed-objectql`
uses NEITHER kernel (`@objectstack/objectql/core`, ADR-0076).
- PLAT-A-02 — the description now names the capability key.
Generated files regenerated because the frontmatter changed, as the drift gate
demands: `skills/README.md` AND `content/docs/ai/skills-reference.mdx` (one
generator writes both; `pnpm --filter @objectstack/spec gen:skill-docs`). Both
diffs are frontmatter-derived only.
`## Seed Data` keeps its `mode` table: `check:skill-identifier-liveness`
registers that section as exhaustive over `SeedMode`, and deleting the table
made five live members unreachable (caught by the gate, fixed the author's
way — the shrink-only gap ledger is maintainer-only and was not touched). The
table now also carries the Data-loss flag on `replace` that it was missing.
PLAT-E-05 is NOT implemented — its premise is false; see the PR body.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…al registry (review round 1)
Contract review round 1 failed the `requires:` table I added in the previous
commit. Three defects, all mine, all from reading a bounded slice of
`CAPABILITY_PROVIDERS` instead of reading it to its closing brace:
1. `audit` named `@objectstack/service-audit`. The real entry is
`@objectstack/plugin-audit` (`AuditPlugin`), serve.ts:1473-1475.
2. `triggers` named `@objectstack/service-triggers`, which does not exist. The
entry is `@objectstack/trigger-record-change` (`RecordChangeTriggerPlugin`)
with extras `@objectstack/trigger-schedule` (`ScheduleTriggerPlugin`,
`TimeRelativeTriggerPlugin`) and `@objectstack/trigger-api`
(`ApiTriggerPlugin`), serve.ts:1506-1537.
3. "the remaining vocabulary resolves the same way" was false, and so was the
claim that the map holds 14 entries. It holds TWENTY — I bounded an `awk`
range by guess and stopped at `sms`, then reported the truncation as a
correction to the audit. The audit's "~20" was right and my correction was
the error.
The table now lists all 20 provider-backed tokens against their real `pkg`
values, and the eight remaining tokens are separated into the two mechanisms
that actually resolve them: five tier-gated tokens with NO map entry, opened by
dedicated blocks in `serve.ts` `run()` (CAPABILITY_TO_TIER docblock,
serve.ts:1166-1171), and three enterprise/cloud tokens with no open-edition
provider at all — `hierarchy-security` ships in
`@objectstack/security-enterprise` via `plugins[]`, `ai-seat` and `governance`
are cloud-runtime only (platform-capabilities.ts:57-66). 20 + 5 + 3 = the 28
tokens in `PLATFORM_CAPABILITY_TOKENS`, counted from the frozen array rather
than asserted.
The `triggers` entry's own comment carries a rule an author needs — schedule
triggers run on the job service, "so pair `triggers` with `job`" — so that is
now both a row note and the fifth rule: `triggers` alone arms record-change
triggers, and autolaunched scheduled flows stay silent without `job`.
SKILL.md 12696 -> 12871 tokens, ceiling 12984 unchanged and not raised; the
growth is paid from the headroom this flight's own deletions created.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…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-litantos-litant changed the title skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,778 tokens)skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens)Sep 2, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 06:53
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to a conflict with the base branch Sep 2, 2026
Nine sibling skills flights landed on main after this branch's base. Both
conflicts fell inside the BEGIN/END GENERATED: skills region of the two mixed
generated files (skills/README.md, content/docs/ai/skills-reference.mdx);
resolved by clearing the markers in place — preserving main's text-merged prose
outside the region — and regenerating both wholesale with
`pnpm --filter @objectstack/spec gen:skill-docs` on the merged tree.
scripts/check-skills-token-ratchet.mjs auto-merged (each flight edited its own
package's ceiling rows). No behaviour or content change to the platform package.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01489YWhZEoHT9oXshiyywQy
@claude
claudeBot requested a review from os-zhuangSeptember 2, 2026 14:54
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/xlskip-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(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens) - #14351

Merged
os-zhuang merged 7 commits into
mainfrom
claude/issue-14299-skills-platform-optimization
Sep 2, 2026
Merged

skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens)#14351
os-zhuang merged 7 commits into
mainfrom
claude/issue-14299-skills-platform-optimization

Conversation

@os-litant

@os-litantos-litant commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Part of #14299

Skills catalog optimization flight for skills/objectstack-platform (program #14292, maintainer mandate 2026-09-02 「审核所有的 skills,进行全面的优化。」). The 50-finding audit record is posted verbatim on the card. Governed face — stays draft; needs:contract-review on both carriers.

Why Part of and not a closing keyword: only the implementable half of the card landed. PLAT-H-01 is deferred to decision card #14296 item 2 and PLAT-G-02 to the catalog follow-up below, so merging this must not close the card while its deferred half is still undecided. The card stays open; pm:dispatched is stripped by hand at merge.

Per-file token delta

Token unit is the ratchet's own: ceil(utf8 bytes / 4).

Filebeforeafterceilingnote
SKILL.md129841287112984−113; every addition paid in-file. Review round 1 spent 175 of the freed headroom on the corrected requires: table
references/plugin-hooks.md262824132628−215; absorbed the deleted pointer's DO/DON'T, plus the cross-flight link repair
rules/plugin-lifecycle.md240417772408−627
rules/service-registry.md232917542331−575
rules/bootstrap-patterns.md1093deletedrow droppedorphan, zero inbound links
rules/plugin-hooks-events.md985deletedrow droppedself-declared pointer that restated its target
evals/README.md514514514untouched — DEFERRED per #14296 item 2
references/_index.md13441344generateduntouched

Package 24,281 → 20,673 = −3,608 (−14.9%). Bundle total 187,854 → 184,246. No ceiling was raised; no file grew; scripts/check-skills-token-ratchet.mjs was touched only to drop the two deleted files' rows.

The audit's package total of 24,278 is 3 tokens off — the measured base is 24,281 (sum of the eight rows above).

Why −3,608 and not the projected −5,970

Four of the projected reductions were withdrawn by evidence or by ruling, not skipped:

The five funded additions also cost more than the projected +355, because they were written against the measured facts (the requires: table carries all 20 provider-backed tokens plus the five rules that change what an author writes) rather than against the projection.

Per-item: 落点 | before | after

Deleted files

id落点beforeafter
PLAT-B-01rules/bootstrap-patterns.md1,093 tokens with zero inbound links repo-wide — the only mention of its path was its own ceiling row. Content already carried by SKILL.md (driver table, HTTP-layer table, the "no driver: key, refused at load" block, manifest required fields); its own last line pointed back at SKILL.mddeleted, with its ceiling row
PLAT-B-02rules/plugin-hooks-events.md + SKILL.md:717,865The file opened "This document is a compact pointer. Complete documentation lives in the canonical reference" and then reproduced it. SKILL.md linked only the pointer, so the 2,628-token canonical file sat two hops from the entry filedeleted; SKILL.md links references/plugin-hooks.md directly at both sites. Path unchanged on purposeskills/objectstack-data/rules/hooks.md:202 links to it across packages; verified still resolving

Checked before deleting the pointer: it carried no fact absent from the canonical reference or SKILL.md. Its one non-hooks item ("no circular dependencies between plugins, both kernels throw") is already the Dependency resolution row of the ObjectKernel-vs-LiteKernel table.

references/plugin-hooks.md

id落点beforeafter
PLAT-D-04:312-3277-item "Best Practices", every item restating a span of the same filereplaced by the compact DO/DON'T folded in from the deleted pointer
PLAT-D-05:238-251"Hook Naming Conventions", 4 good / 2 bad names; the convention was already given at :80-82 and demonstrated at :225-232deleted; its only new rule (lower-case) folded into the Custom Hooks convention line
PLAT-D-06:252-311two near-identical 25-line vitest blocks; the second differed only by asserting receivedData instead of hookCalledsecond block deleted

rules/plugin-lifecycle.md and rules/service-registry.md

id落点beforeafter
PLAT-B-07service-registry.md:145-158the same table as SKILL.md:1008-1024 with inverted columns and only 6 of its 13 rows; both then repeated "the REST plugin registers no service"one table, in SKILL.md; the rules file points at it
PLAT-D-03service-registry.md:270-319"Service Naming Conventions" (generic: "use descriptive names", "avoid abbreviations") + a test block asserting only toBeDefined()/toThrow() + a 10-item Best Practices restating the file's own sectionsdeleted
PLAT-D-08plugin-lifecycle.md:201-230the same ❌/✅ lesson as service-registry.md:193-223, differing only in names, closing on the same null-placeholder paragraphreplaced by the rule plus a link to the one worked pair
PLAT-D-02plugin-lifecycle.md:293-34010-item Best Practices (1-7 restate the file's own Phase headings; 8-10 generic: "version your plugin", "use reverse domain names") + two vitest blocks asserting only toBeDefined()/isConnected()deleted
PLAT-C-05plugin-lifecycle.md:110-113, SKILL.md:944-948the data:* boundary was stated five times in-packagein-package statements down to three; SKILL.md keeps exactly one (the one explaining the silent registration), per the anchor ruling; canonical statement stays in references/plugin-hooks.md

SKILL.md — structure

id落点beforeafter
PLAT-B-05section order1,441 tokens preceded defineStack() — the core construct sat 12% down the filedefineStack() (with the Manifest Reference it needs) is the first section after the title
PLAT-B-03:39-49, :699-708"When to Use This Skill" appeared twice, 650 lines apart, both restating the frontmatterboth deleted — a loaded package is already selected
PLAT-B-06:25-35narrated the package's own edit history ("the original 'quickstart' skill", "which is why they live in one skill")one sentence naming the two concerns
PLAT-D-07:142-158"CRM Blueprint": rows 2-3 restated the directory tree 18 lines above; rows 5-6 pointed at data / i18n territorydeleted; its only platform-specific row (requires:) is now taught properly under the Boot Sequence
PLAT-D-01:735-758ASCII "Decision Guide" restating the table two lines above; its gloss changed no branchdeleted, table survives
PLAT-B-04:1277-1279"see Health Monitoring earlier in this skill" — that section documents an in-process TS API and contains no HTTP routecross-reference dropped

SKILL.md — truthfulness

id落点beforeafter
PLAT-F-06:347-381driver-as-a-plugins:-entry taught as the canonical bootstrap. Zero example configs do it: app-showcase and the blank template list connector plugins, app-crm and app-todo have no plugins: key, and the CLI wires the driver itself from the resolved DB URL (serve.ts:2687-2745)selection table kept; the code reframed as embedding/tests only, with "pick a driver by setting the DB URL, not by writing code"
PLAT-F-05:498-522composeStacks() had a section plus a 3-row strategies table and zero usages outside packages/spec and its own testsreduced to a pointer at stack.zod.ts. Live surface with zero measured usage ⇒ one row, never delete the last mention
PLAT-C-01:548-576taught a raw data: [{ object: 'task', … }] literal — writing object: by hand, which objectstack-data/SKILL.md:1036 forbids verbatim ("Auto-set from objectDef.name — never write manually"); 24 real defineSeed( sites, 0 raw literalsliteral deleted, defineSeed() pointer added, mode table kept (see premise_false) and given the ⚠️ Data-loss flag on replace it was missing
PLAT-C-02:626-663re-taught field types in a shape 0 of 7 real object files use (export default {} vs ObjectSchema.create({…}))one line pointing at objectstack-data and the scaffolder's own note.object.ts
PLAT-G-01:303,319,322-323,1035five spans used the retired v5.0 word for the runtime workspace ("project runtime", "Project revisions", "isolated project kernel") against skills/README.md:88 and the os environments CLI surfaceall five now environment. Uses of "project" for the local source tree left alone — those are correct
imprecision:79-80the blank template "ships One example object, in-memory driver, Hono server" — the template config has neither; its plugins: array holds three connector executors and both arrive from CLI auto-registrationstates what is in the file, and that the driver and server come from the CLI
PLAT-A-01:5,9-10,20 and the section headingfrontmatter sold "drivers, adapters" while :394-397 answers "There are no@objectstack/adapter-* packages" — promise and truth 385 lines apartdescription and heading now name the Hono HTTP layer
PLAT-G-03:307-310 vs :1109the os / objectstack alias was declared 800 lines after first usestated at first use
PLAT-C-04:1299a 60-token restatement of the very rule it delegates to objectstack-datasymptom plus the one-line cause

SKILL.md — examples that could not compile

id落点beforeafter
PLAT-E-01:527-542"Host Pattern" read as a complete config file but had ≥4 errors on paste: defineStack and SqlDriver used un-imported, CrmApp/TodoApp undefined, and new SqlDriver({ ... }) is TS1109folded into the Multi-App Composition prose; no un-compilable block
PLAT-E-02:1059-1073typed the literal as a Plugin intersection then read this.pool.query(...) (TS2339) and err.message on a catch binding (TS18046); PluginHealthStatus never importedthe opt-in contract in prose plus the three real kernel call sites
PLAT-E-03:954-969kernel.getService with a type argument naming a non-exported class from a different fence (TS2304)type argument dropped
PLAT-E-04:296-298defineStack({ ... }, { strict: false }) — TS1109 by constructiondefineStack(config, { strict: false })

The funded additions — each paid by a deletion in the same file

id落点beforeafter
PLAT-F-01Manifest Referencemanifest.engines: { protocol: '^17' } has 4 real usages including every project the scaffolder emits, and grep engines skills/objectstack-platform/ returned 0one manifest row plus why the runtime checks it before it loads anything
PLAT-F-02Boot Sequencerequires: [...] decides which service plugins boot; taught as one CRM-blueprint cell and one bare word, while the Boot Sequence narrated a fixed auto-register list and never said requires: drives itall 20 provider-backed tokens against their real pkg values, the two other resolution mechanisms kept separate from them, and five rules that change what you write: precedence, declaring-is-a-demand (declared-but-absent is a hard boot error, auto-injected-but-absent stays best-effort), auth implies email, keep automation whenever plugins: lists a connector, and pair triggers with job
PLAT-F-03Boot Sequencethe onEnable export — the seam where an app binds runtime code — has 4 real sites and was documented only in objectstack-dataits own subsection with the AppPlugin invocation and a worked export
PLAT-F-04Part 3plugin authoring stopped at kernel.use(plugin) with no path to a distributable plugin; the ADR-0025 §3.4 pipeline was mentioned nowhere in skills/a 3-row `os plugin build
PLAT-F-07kernel decisionthe guide offered two answers and routed serverless/edge to LiteKernel, while the repo's own example for that shape uses neither kernela third branch naming @objectstack/objectql/core and examples/embed-objectql (ADR-0076)
PLAT-A-02frontmatterthe description never named capabilities / requires:, the key that decides which service plugins bootone clause added, paid by A-01

Facts re-read against source before writing, per the card's assumption 5: blank/objectstack.config.ts:22,30; serve.tsCAPABILITY_PROVIDERS and the auth ⇒ email implication at :2281-2321; onEnable at app-showcase :283, app-crm :127, app-todo :33; PLATFORM_CAPABILITY_TOKENS in packages/spec/src/kernel/platform-capabilities.ts.

CAPABILITY_PROVIDERS holds 20 entries — the audit's "~20" was right. An earlier revision of this PR claimed 14 and offered that as a correction to the audit; that claim was itself wrong and is retracted. See Review round 1.

premise_false

  • PLAT-E-05 — premise false; not implemented. The audit proposed adding an os:check marker to the Complete Plugin Example so plugin/kernel examples would finally be type-checked. Measured: the gate's "skills + docs" surface resolves from packages/spec only (SURFACES in packages/spec/scripts/check-skill-examples.ts, resolutionDir: SPEC_DIR, selfPackages: [SPEC_DIR]), and @objectstack/core is not a dependency of packages/spec — that package's node_modules has no @objectstack scope at all. Marking the block produced skills/objectstack-platform/SKILL.md:804:44 error TS2307: Cannot find module '@objectstack/core'. Every plugin/kernel example in this package imports Plugin / PluginContext / ObjectKernel / LiteKernel from there, so no such example can be gated without a new SURFACES entry — another package, which this flight may not edit. The marker was reverted; check:skill-examples is green with 258 marked blocks. Filed as follow-up below.
  • PLAT-C-01 — premise partly false. "DELETE the mode table → one pointer line" is not available: check:skill-identifier-liveness registers ## Seed Data as exhaustive over SeedMode, and deleting the table turned five live members (insert, update, upsert, replace, ignore) into capabilities no AI author reading the catalog can reach. The gate caught it. Fixed the author's way — the table stays, and gained the ⚠️ Data-loss flag on replace the audit noted was missing. The shrink-only gap ledger is maintainer-only and was not touched.
  • PLAT-C-03 — not applied, by ruling. The card's ANCHOR RULINGS keep SKILL.md:59-70 because the pm-dispatch flight points there. The overlap the audit identified is real but is the anchor's to settle.
  • PLAT-G-02 — not applied, by ruling. Moving references/plugin-hooks.md to rules/ is exactly what the card forbids (the path is pinned stable for objectstack-data's inbound link). The catalog-wide drift it names is real and is listed as follow-up.

Card assumptions verified rather than assumed: (1) skills/objectstack-platform/** is byte-identical at a59f78d, d63c8a25 and this branch's actual base 909a4417git diff --stat empty for both; note origin/main had moved past the d63c8a25 named in the card. (2) bootstrap-patterns has zero inbound links, with plugin-lifecycle as a positive control that hits abundantly. (3) check:skill-docsis the drift gate, it is in the derived family, and the frontmatter edit did force regeneration — of two files, not one (below). (4) the ratchet reds on a deleted file whose row remains — probed directly: re-adding the row gave exit 1 and "cannot read … — red, not a skip (#4690)", then the script was restored and the restore confirmed by hash match.

Files outside the card's literal list

  • skills/README.md — regenerated, as the card anticipated for a frontmatter edit.
  • content/docs/ai/skills-reference.mdxalso regenerated, because one generator writes both and check:skill-docs fails on both. Not anticipated by the card; flagged here. Both diffs are frontmatter-derived only, confined to this package's row. Not content/docs/releases/.

follow-up for packages/spec

  • Extend SURFACES in packages/spec/scripts/check-skill-examples.ts with a resolution root that can see @objectstack/core, so plugin / kernel / service examples across the catalog become type-checkable. Today 78 of this package's 80 TypeScript fences are unchecked and the two checked ones both teach data authoring — the least proprietary content in the package. This is PLAT-E-05's real blocker.

follow-up for the catalog

  • PLAT-G-02: hand-authored per-topic files live under the generated references/ directory, which skills/README.md:55-58 reserves for generated pointers. This package and objectstack-data (references/data-hooks.md) both do it — a catalog-wide placement decision, not a lone slip, and one this flight is explicitly forbidden to settle by moving the file.

Review round 1

Contract review failed one span — the requires: table added for PLAT-F-02. Three defects, all from reading a bounded slice of CAPABILITY_PROVIDERS instead of reading it to its closing brace. Fixed in 224d5d9a; the cross-flight link repair below landed in 25012189:

#defecttruth at sourcefix
1audit row named @objectstack/service-audit@objectstack/plugin-audit (AuditPlugin), serve.ts:1473-1475row corrected
2triggers row named @objectstack/service-triggers, which does not exist@objectstack/trigger-record-change (RecordChangeTriggerPlugin), extras @objectstack/trigger-schedule (ScheduleTriggerPlugin, TimeRelativeTriggerPlugin) and @objectstack/trigger-api (ApiTriggerPlugin), serve.ts:1506-1537row corrected; the entry's own comment ("so pair triggers with job") became a row note and the fifth rule
3"the remaining vocabulary … resolve the same way", and the claim that the map holds 14 entriesthe map holds 20; the other eight tokens resolve by two different mechanismstable lists all 20 against their real pkg; the eight are split into tier-gated (no map entry, opened by dedicated run() blocks per the CAPABILITY_TO_TIER docblock at serve.ts:1166-1171) and enterprise/cloud (no open-edition provider: hierarchy-security ships in @objectstack/security-enterprise via plugins[], ai-seat and governance are cloud-runtime only, platform-capabilities.ts:57-66)

20 + 5 + 3 = the 28 tokens in PLATFORM_CAPABILITY_TOKENS, counted from the frozen array rather than asserted. Defect 3 is the one worth naming plainly: the "14 entries" figure was published as a correction to the audit when the audit was right and the correction was the error — a truncated read reported as a finding.

Cross-flight link repair

references/plugin-hooks.md routed readers to objectstack-data's rules/hooks.md for per-record validation, defaults and audit trails. The data flight (PR #14427, head 061e5f4c, delivered) DELETES that file and consolidates hooks into objectstack-data/references/data-hooks.md, so the reference was repointed before it could dangle — now a real relative link, ../../objectstack-data/references/data-hooks.md, verified to resolve from references/. The old text named both the doomed rules/hooks.md and the surviving references/data-hooks.md; naming only the survivor makes the span 22 bytes shorter. git grep rules/hooks.md over this package returns nothing further, so that was the only site.

The PR title still carries the pre-patch figure (−3,778); the accurate net is −3,608. Left alone deliberately — the patch instruction was not to retitle.

Gates

Head sha 25012189. Command list derived from the real change set by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (9 paths; re-derived after regeneration added the two generated files, which pulled in 20 further docs-family gates). The full 46 were run on 15b4ac79: 45 exit 0, 1 NOT MEASURED. Review round 1 touched only SKILL.md and references/plugin-hooks.md, so the change set and therefore the derived family are unchanged; the card-named gates were re-run on 25012189 and are listed below.

The one non-green in that full run is NOT MEASURED by its own verdict text — node scripts/check-test-completeness.mjs exits 3, not 1: "PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named… the local reading for this gate is NOT MEASURED." CI tees the log and passes the path, so this branch is unreachable there. Not a finding, and not read as green.

Card-named gates on 25012189, every exit captured before any pipe, all exit 0:

gateverdict line
check-skills-token-ratchet"36 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted" — SKILL.md 12871 / 12984, plugin-hooks.md 2413 / 2628
check:skill-examples"258 marked example(s) across 100 file(s), 3 surface(s)"
check:skill-identifier-liveness"OK — Leg 1: 493 citation(s) over 46 published file(s) … Leg 2: 9 registered exhaustive section(s), 0 ledgered gap(s)" — 493, up from 491: the corrected package names are themselves live-checked citations
check:skill-docsexit 0 with no regeneration needed (round 1 touched no frontmatter)
check:skill-compatibility"11 SKILL.md file(s) reconciled against 78 workspace packages"
check:published-readme-linksexit 0 — run additionally to prove the repointed cross-package link resolves

Two gates initially reported exit 3 for missing local build prerequisites and were re-run properly rather than recorded as failures: check:doc-formula-expressions (needed @objectstack/formula built) and check:skill-examples (needed @objectstack/client-react built — it refuses rather than false-greening, #7122). Both green afterwards.

Control bytes: node scripts/check-nul-bytes.mjs green, plus a direct scan of all changed files for the wider control-byte range — no hits.

skip-changeset applies and is on the PR: this diff releases nothing from any package. skills/ is named in the changeset gate's own release-nothing enumeration (scripts/check-empty-changeset.mjs), which pins a "skills/**-only PR carrying NO changeset" as a green fixture, and scripts/check-skills-token-ratchet.mjs is a CI-internal gate script — the workflow calls that the textbook case.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

…-B-01)
`rules/bootstrap-patterns.md` had ZERO inbound links repo-wide — the only
reference to its path anywhere in the tree was its own ceiling row in
`scripts/check-skills-token-ratchet.mjs`. `SKILL.md:715-717` links only
lifecycle / service-registry / hooks-events, so nothing ever routed a reader
to it; verified with `git grep -n bootstrap-patterns` against a positive
control (`git grep -n plugin-lifecycle` hits abundantly).
Its content was already carried by SKILL.md: the driver table (:66-74 =
SKILL.md:351-357), the HTTP-layer table (:76-83 = :389-397), the "no `driver:`
key, refused at load" block plus the `defineStack validation failed` sample
(:7-31,87-105 = :209-234), and manifest required fields (:29-31,107-130 =
:327-339). Its own last line pointed back at SKILL.md.
1,093 tokens of the published bundle that no customer agent could reach.
The ceiling row goes with the file: the gate treats an unreadable ratcheted
path as RED, not as a skip (#4690) — verified by a controlled probe that
re-added the row (exit 1, "cannot read ... — red, not a skip"), then restored
the script and confirmed the restore by hash match.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
… the pointer file (PLAT-B-02, D-04, D-05, D-06)
`rules/plugin-hooks-events.md` opened by declaring itself "a compact pointer.
Complete documentation lives in the canonical reference" and then reproduced
that reference: the event table, the `data:*` warning, the custom-hook
convention, execution order, and a DO/DON'T list. SKILL.md linked only the
pointer, so the 2,628-token canonical file sat TWO hops from the entry file
behind 985 tokens that restated it.
SKILL.md now links `references/plugin-hooks.md` directly at both sites
(`:717` and `:865`) and the pointer file is deleted with its ceiling row.
Checked before deleting: the pointer carried no fact absent from the
canonical reference or from SKILL.md — its one non-hooks item ("no circular
dependencies between plugins, both kernels throw") is already the
`Dependency resolution` row of the ObjectKernel-vs-LiteKernel table. So the
merge is a relink plus a deletion, and the compact DO/DON'T shape it had is
what now closes the canonical file.
`references/plugin-hooks.md` PATH IS UNCHANGED on purpose:
`skills/objectstack-data/rules/hooks.md:202` links to it across packages, and
that link is verified still resolving.
Paid inside `references/plugin-hooks.md`, per the shrink-only ratchet:
- PLAT-D-04 — the 7-item "Best Practices" list, every item of which
restated a span of the same file, is replaced by the compact DO/DON'T
rules-of-thumb folded in from the deleted pointer.
- PLAT-D-05 — "Hook Naming Conventions" deleted; its only new rule
(lower-case) folded into the Custom Hooks convention line.
- PLAT-D-06 — the second of two near-identical vitest blocks deleted; it
differed only in asserting `receivedData` instead of `hookCalled`.
Token deltas: references/plugin-hooks.md 2628 -> 2418 (ceiling 2628);
SKILL.md 12984 -> 12982 (ceiling 12984 — the relinked paths are shorter than
the deleted ones); rules/plugin-hooks-events.md 985 -> deleted with its row.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…07, C-05)
`rules/service-registry.md` 2329 -> 1754 tokens (ceiling 2331):
- PLAT-B-07 — "Well-Known Service Keys" was the SAME table as
`SKILL.md:1008-1024` with the columns inverted and only 6 of its 13 rows,
and both then repeated "the REST plugin registers no service". One table
now, in SKILL.md; this file points at it.
- PLAT-D-03 — deleted "Service Naming Conventions" (generic advice: "use
descriptive names", "avoid abbreviations"), a "Testing Service
Registration" block whose only assertions were `toBeDefined()` and
`toThrow()`, and a 10-item "Best Practices" list restating this file's own
Registration Patterns section and its `null`-placeholder paragraph.
`rules/plugin-lifecycle.md` 2404 -> 1777 tokens (ceiling 2408):
- PLAT-D-08 — the ❌/✅ "getService() in init() without a declared
dependency" lesson was already in `service-registry.md:193-223`,
differing only in the names used (CachePlugin/db-pool vs
AnalyticsPlugin/objectql) and closing on the SAME paragraph about never
registering `null`. Replaced with the rule plus a link to the one worked
pair.
- PLAT-D-02 — deleted a 10-item "Best Practices" list (items 1-7 restate
this file's own Phase 1/2/3 headings; 8-10 are generic: "version your
plugin", "use reverse domain names") and a "Testing Lifecycle" section of
two vitest blocks whose only assertions were `toBeDefined()` and
`isConnected()`.
- PLAT-C-05 — dropped this file's copy of the `data:*`-boundary warning.
The boundary was stated five times in-package; the canonical statement
stays in `references/plugin-hooks.md` and SKILL.md keeps exactly one.
No content was moved to another package: each deletion either had a surviving
in-package statement or was generic advice that changed no decision.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…B/C/D/E/F/G)
Deletions and rewrites (SKILL.md 12984 -> 12696 tokens, ceiling 12984):
- PLAT-B-05 — `defineStack()` was 12% down the file behind 1,441 tokens of
preamble. It (with the Manifest Reference it needs) is now the first
section after the title.
- PLAT-B-03 — "When to Use This Skill" appeared TWICE, 650 lines apart,
both restating the frontmatter. A loaded package is already selected.
- PLAT-B-06 — the package narrated its own edit history ("the original
'quickstart' skill"). A customer agent never chose between two former
skills.
- PLAT-D-07 — the CRM Blueprint restated the directory tree 18 lines above
and pointed at data / i18n territory; only its `requires:` row was
platform-specific, and that is now taught properly (F-02).
- PLAT-D-01 — the ASCII Decision Guide restated the table two lines above.
- PLAT-F-05 — `composeStacks()` had a section plus a strategies table and
ZERO usages outside `packages/spec` and its own tests; real multi-app
composition is AppPlugin registration. Reduced to a pointer at the schema,
not deleted (live surface, zero measured usage).
- PLAT-F-06 — driver-as-a-`plugins:`-entry was taught as THE canonical
bootstrap; no example config does it and the CLI wires the driver itself
from the resolved DB URL. Reframed as embedding/tests only.
- PLAT-C-01 — seeds are objectstack-data's; the copy here taught a raw
literal writing `object:` by hand, which that skill forbids verbatim.
Now a pointer PLUS the `mode` table (see below).
- PLAT-C-02 — the example object file re-taught field types in a spelling
7 of 7 real object files do not use (`export default {}` vs
`ObjectSchema.create({...})`).
- PLAT-C-04, B-04 — a restatement of the rule it delegates, and a
cross-reference to a section that documents an in-process TS API and
contains no HTTP route.
- PLAT-C-05 — SKILL.md stated the `data:*` boundary twice; one statement
remains (the one that explains the silent registration).
- PLAT-E-01, E-02, E-03, E-04 — four blocks that could not compile:
`defineStack`/`SqlDriver` used un-imported with `CrmApp`/`TodoApp`
undefined; `this.pool` on a plain object literal plus `err.message` on a
`catch` binding; a type argument naming a non-exported class from another
fence; and `{ ... }` / `{ … }` ellipsis placeholders (TS1109).
- PLAT-G-01 — v5.0 vocabulary: the runtime workspace is `environment`, not
`project`, in all five spans (skills/README.md:88; the CLI surface is
`os environments`).
- PLAT-G-03 — the `os` / `objectstack` binary alias is now stated at first
use instead of 800 lines later.
- PLAT-A-01 — the frontmatter sold "adapters" and the body refutes it 385
lines in ("There are no `@objectstack/adapter-*` packages"). Both the
description and the section heading now name the Hono HTTP layer.
- The `blank` template's "in-memory driver, Hono server" was true of the
RUNNING APP and false of the file a reader opens: the template config has
neither; both arrive from CLI auto-registration.
Additions, each paid by a deletion in this same file:
- PLAT-F-01 — `manifest.engines.protocol`, stamped into every project
`create-objectstack` emits and carried by all three example apps, was
mentioned NOWHERE in this package. One manifest row + why it is checked
before anything loads.
- PLAT-F-02 — `requires: [...]` decides which service plugins boot and was
taught as one blueprint cell and one bare word. Now a token table plus the
four rules that change what you write: precedence, declaring-is-a-demand
(hard boot error vs best-effort), `auth` implies `email`, and keep
`automation` whenever `plugins:` lists a connector.
- PLAT-F-03 — the `onEnable` export, the seam where an app binds runtime
code, used by all three example apps and documented only in
objectstack-data.
- PLAT-F-04 — `os plugin build|sign|publish`: authoring stopped at
`kernel.use(plugin)` with no path to a distributable plugin.
- PLAT-F-07 — a third answer to the kernel question: `examples/embed-objectql`
uses NEITHER kernel (`@objectstack/objectql/core`, ADR-0076).
- PLAT-A-02 — the description now names the capability key.
Generated files regenerated because the frontmatter changed, as the drift gate
demands: `skills/README.md` AND `content/docs/ai/skills-reference.mdx` (one
generator writes both; `pnpm --filter @objectstack/spec gen:skill-docs`). Both
diffs are frontmatter-derived only.
`## Seed Data` keeps its `mode` table: `check:skill-identifier-liveness`
registers that section as exhaustive over `SeedMode`, and deleting the table
made five live members unreachable (caught by the gate, fixed the author's
way — the shrink-only gap ledger is maintainer-only and was not touched). The
table now also carries the Data-loss flag on `replace` that it was missing.
PLAT-E-05 is NOT implemented — its premise is false; see the PR body.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…al registry (review round 1)
Contract review round 1 failed the `requires:` table I added in the previous
commit. Three defects, all mine, all from reading a bounded slice of
`CAPABILITY_PROVIDERS` instead of reading it to its closing brace:
1. `audit` named `@objectstack/service-audit`. The real entry is
`@objectstack/plugin-audit` (`AuditPlugin`), serve.ts:1473-1475.
2. `triggers` named `@objectstack/service-triggers`, which does not exist. The
entry is `@objectstack/trigger-record-change` (`RecordChangeTriggerPlugin`)
with extras `@objectstack/trigger-schedule` (`ScheduleTriggerPlugin`,
`TimeRelativeTriggerPlugin`) and `@objectstack/trigger-api`
(`ApiTriggerPlugin`), serve.ts:1506-1537.
3. "the remaining vocabulary resolves the same way" was false, and so was the
claim that the map holds 14 entries. It holds TWENTY — I bounded an `awk`
range by guess and stopped at `sms`, then reported the truncation as a
correction to the audit. The audit's "~20" was right and my correction was
the error.
The table now lists all 20 provider-backed tokens against their real `pkg`
values, and the eight remaining tokens are separated into the two mechanisms
that actually resolve them: five tier-gated tokens with NO map entry, opened by
dedicated blocks in `serve.ts` `run()` (CAPABILITY_TO_TIER docblock,
serve.ts:1166-1171), and three enterprise/cloud tokens with no open-edition
provider at all — `hierarchy-security` ships in
`@objectstack/security-enterprise` via `plugins[]`, `ai-seat` and `governance`
are cloud-runtime only (platform-capabilities.ts:57-66). 20 + 5 + 3 = the 28
tokens in `PLATFORM_CAPABILITY_TOKENS`, counted from the frozen array rather
than asserted.
The `triggers` entry's own comment carries a rule an author needs — schedule
triggers run on the job service, "so pair `triggers` with `job`" — so that is
now both a row note and the fifth rule: `triggers` alone arms record-change
triggers, and autolaunched scheduled flows stay silent without `job`.
SKILL.md 12696 -> 12871 tokens, ceiling 12984 unchanged and not raised; the
growth is paid from the headroom this flight's own deletions created.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…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-litantos-litant changed the title skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,778 tokens)skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens)Sep 2, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 06:53
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to a conflict with the base branch Sep 2, 2026
Nine sibling skills flights landed on main after this branch's base. Both
conflicts fell inside the BEGIN/END GENERATED: skills region of the two mixed
generated files (skills/README.md, content/docs/ai/skills-reference.mdx);
resolved by clearing the markers in place — preserving main's text-merged prose
outside the region — and regenerating both wholesale with
`pnpm --filter @objectstack/spec gen:skill-docs` on the merged tree.
scripts/check-skills-token-ratchet.mjs auto-merged (each flight edited its own
package's ceiling rows). No behaviour or content change to the platform package.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01489YWhZEoHT9oXshiyywQy
@claude
claudeBot requested a review from os-zhuangSeptember 2, 2026 14:54
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/xlskip-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(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens) - #14351

Merged
os-zhuang merged 7 commits into
mainfrom
claude/issue-14299-skills-platform-optimization
Sep 2, 2026
Merged

skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens)#14351
os-zhuang merged 7 commits into
mainfrom
claude/issue-14299-skills-platform-optimization

Conversation

@os-litant

@os-litantos-litant commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Part of #14299

Skills catalog optimization flight for skills/objectstack-platform (program #14292, maintainer mandate 2026-09-02 「审核所有的 skills,进行全面的优化。」). The 50-finding audit record is posted verbatim on the card. Governed face — stays draft; needs:contract-review on both carriers.

Why Part of and not a closing keyword: only the implementable half of the card landed. PLAT-H-01 is deferred to decision card #14296 item 2 and PLAT-G-02 to the catalog follow-up below, so merging this must not close the card while its deferred half is still undecided. The card stays open; pm:dispatched is stripped by hand at merge.

Per-file token delta

Token unit is the ratchet's own: ceil(utf8 bytes / 4).

Filebeforeafterceilingnote
SKILL.md129841287112984−113; every addition paid in-file. Review round 1 spent 175 of the freed headroom on the corrected requires: table
references/plugin-hooks.md262824132628−215; absorbed the deleted pointer's DO/DON'T, plus the cross-flight link repair
rules/plugin-lifecycle.md240417772408−627
rules/service-registry.md232917542331−575
rules/bootstrap-patterns.md1093deletedrow droppedorphan, zero inbound links
rules/plugin-hooks-events.md985deletedrow droppedself-declared pointer that restated its target
evals/README.md514514514untouched — DEFERRED per #14296 item 2
references/_index.md13441344generateduntouched

Package 24,281 → 20,673 = −3,608 (−14.9%). Bundle total 187,854 → 184,246. No ceiling was raised; no file grew; scripts/check-skills-token-ratchet.mjs was touched only to drop the two deleted files' rows.

The audit's package total of 24,278 is 3 tokens off — the measured base is 24,281 (sum of the eight rows above).

Why −3,608 and not the projected −5,970

Four of the projected reductions were withdrawn by evidence or by ruling, not skipped:

The five funded additions also cost more than the projected +355, because they were written against the measured facts (the requires: table carries all 20 provider-backed tokens plus the five rules that change what an author writes) rather than against the projection.

Per-item: 落点 | before | after

Deleted files

id落点beforeafter
PLAT-B-01rules/bootstrap-patterns.md1,093 tokens with zero inbound links repo-wide — the only mention of its path was its own ceiling row. Content already carried by SKILL.md (driver table, HTTP-layer table, the "no driver: key, refused at load" block, manifest required fields); its own last line pointed back at SKILL.mddeleted, with its ceiling row
PLAT-B-02rules/plugin-hooks-events.md + SKILL.md:717,865The file opened "This document is a compact pointer. Complete documentation lives in the canonical reference" and then reproduced it. SKILL.md linked only the pointer, so the 2,628-token canonical file sat two hops from the entry filedeleted; SKILL.md links references/plugin-hooks.md directly at both sites. Path unchanged on purposeskills/objectstack-data/rules/hooks.md:202 links to it across packages; verified still resolving

Checked before deleting the pointer: it carried no fact absent from the canonical reference or SKILL.md. Its one non-hooks item ("no circular dependencies between plugins, both kernels throw") is already the Dependency resolution row of the ObjectKernel-vs-LiteKernel table.

references/plugin-hooks.md

id落点beforeafter
PLAT-D-04:312-3277-item "Best Practices", every item restating a span of the same filereplaced by the compact DO/DON'T folded in from the deleted pointer
PLAT-D-05:238-251"Hook Naming Conventions", 4 good / 2 bad names; the convention was already given at :80-82 and demonstrated at :225-232deleted; its only new rule (lower-case) folded into the Custom Hooks convention line
PLAT-D-06:252-311two near-identical 25-line vitest blocks; the second differed only by asserting receivedData instead of hookCalledsecond block deleted

rules/plugin-lifecycle.md and rules/service-registry.md

id落点beforeafter
PLAT-B-07service-registry.md:145-158the same table as SKILL.md:1008-1024 with inverted columns and only 6 of its 13 rows; both then repeated "the REST plugin registers no service"one table, in SKILL.md; the rules file points at it
PLAT-D-03service-registry.md:270-319"Service Naming Conventions" (generic: "use descriptive names", "avoid abbreviations") + a test block asserting only toBeDefined()/toThrow() + a 10-item Best Practices restating the file's own sectionsdeleted
PLAT-D-08plugin-lifecycle.md:201-230the same ❌/✅ lesson as service-registry.md:193-223, differing only in names, closing on the same null-placeholder paragraphreplaced by the rule plus a link to the one worked pair
PLAT-D-02plugin-lifecycle.md:293-34010-item Best Practices (1-7 restate the file's own Phase headings; 8-10 generic: "version your plugin", "use reverse domain names") + two vitest blocks asserting only toBeDefined()/isConnected()deleted
PLAT-C-05plugin-lifecycle.md:110-113, SKILL.md:944-948the data:* boundary was stated five times in-packagein-package statements down to three; SKILL.md keeps exactly one (the one explaining the silent registration), per the anchor ruling; canonical statement stays in references/plugin-hooks.md

SKILL.md — structure

id落点beforeafter
PLAT-B-05section order1,441 tokens preceded defineStack() — the core construct sat 12% down the filedefineStack() (with the Manifest Reference it needs) is the first section after the title
PLAT-B-03:39-49, :699-708"When to Use This Skill" appeared twice, 650 lines apart, both restating the frontmatterboth deleted — a loaded package is already selected
PLAT-B-06:25-35narrated the package's own edit history ("the original 'quickstart' skill", "which is why they live in one skill")one sentence naming the two concerns
PLAT-D-07:142-158"CRM Blueprint": rows 2-3 restated the directory tree 18 lines above; rows 5-6 pointed at data / i18n territorydeleted; its only platform-specific row (requires:) is now taught properly under the Boot Sequence
PLAT-D-01:735-758ASCII "Decision Guide" restating the table two lines above; its gloss changed no branchdeleted, table survives
PLAT-B-04:1277-1279"see Health Monitoring earlier in this skill" — that section documents an in-process TS API and contains no HTTP routecross-reference dropped

SKILL.md — truthfulness

id落点beforeafter
PLAT-F-06:347-381driver-as-a-plugins:-entry taught as the canonical bootstrap. Zero example configs do it: app-showcase and the blank template list connector plugins, app-crm and app-todo have no plugins: key, and the CLI wires the driver itself from the resolved DB URL (serve.ts:2687-2745)selection table kept; the code reframed as embedding/tests only, with "pick a driver by setting the DB URL, not by writing code"
PLAT-F-05:498-522composeStacks() had a section plus a 3-row strategies table and zero usages outside packages/spec and its own testsreduced to a pointer at stack.zod.ts. Live surface with zero measured usage ⇒ one row, never delete the last mention
PLAT-C-01:548-576taught a raw data: [{ object: 'task', … }] literal — writing object: by hand, which objectstack-data/SKILL.md:1036 forbids verbatim ("Auto-set from objectDef.name — never write manually"); 24 real defineSeed( sites, 0 raw literalsliteral deleted, defineSeed() pointer added, mode table kept (see premise_false) and given the ⚠️ Data-loss flag on replace it was missing
PLAT-C-02:626-663re-taught field types in a shape 0 of 7 real object files use (export default {} vs ObjectSchema.create({…}))one line pointing at objectstack-data and the scaffolder's own note.object.ts
PLAT-G-01:303,319,322-323,1035five spans used the retired v5.0 word for the runtime workspace ("project runtime", "Project revisions", "isolated project kernel") against skills/README.md:88 and the os environments CLI surfaceall five now environment. Uses of "project" for the local source tree left alone — those are correct
imprecision:79-80the blank template "ships One example object, in-memory driver, Hono server" — the template config has neither; its plugins: array holds three connector executors and both arrive from CLI auto-registrationstates what is in the file, and that the driver and server come from the CLI
PLAT-A-01:5,9-10,20 and the section headingfrontmatter sold "drivers, adapters" while :394-397 answers "There are no@objectstack/adapter-* packages" — promise and truth 385 lines apartdescription and heading now name the Hono HTTP layer
PLAT-G-03:307-310 vs :1109the os / objectstack alias was declared 800 lines after first usestated at first use
PLAT-C-04:1299a 60-token restatement of the very rule it delegates to objectstack-datasymptom plus the one-line cause

SKILL.md — examples that could not compile

id落点beforeafter
PLAT-E-01:527-542"Host Pattern" read as a complete config file but had ≥4 errors on paste: defineStack and SqlDriver used un-imported, CrmApp/TodoApp undefined, and new SqlDriver({ ... }) is TS1109folded into the Multi-App Composition prose; no un-compilable block
PLAT-E-02:1059-1073typed the literal as a Plugin intersection then read this.pool.query(...) (TS2339) and err.message on a catch binding (TS18046); PluginHealthStatus never importedthe opt-in contract in prose plus the three real kernel call sites
PLAT-E-03:954-969kernel.getService with a type argument naming a non-exported class from a different fence (TS2304)type argument dropped
PLAT-E-04:296-298defineStack({ ... }, { strict: false }) — TS1109 by constructiondefineStack(config, { strict: false })

The funded additions — each paid by a deletion in the same file

id落点beforeafter
PLAT-F-01Manifest Referencemanifest.engines: { protocol: '^17' } has 4 real usages including every project the scaffolder emits, and grep engines skills/objectstack-platform/ returned 0one manifest row plus why the runtime checks it before it loads anything
PLAT-F-02Boot Sequencerequires: [...] decides which service plugins boot; taught as one CRM-blueprint cell and one bare word, while the Boot Sequence narrated a fixed auto-register list and never said requires: drives itall 20 provider-backed tokens against their real pkg values, the two other resolution mechanisms kept separate from them, and five rules that change what you write: precedence, declaring-is-a-demand (declared-but-absent is a hard boot error, auto-injected-but-absent stays best-effort), auth implies email, keep automation whenever plugins: lists a connector, and pair triggers with job
PLAT-F-03Boot Sequencethe onEnable export — the seam where an app binds runtime code — has 4 real sites and was documented only in objectstack-dataits own subsection with the AppPlugin invocation and a worked export
PLAT-F-04Part 3plugin authoring stopped at kernel.use(plugin) with no path to a distributable plugin; the ADR-0025 §3.4 pipeline was mentioned nowhere in skills/a 3-row `os plugin build
PLAT-F-07kernel decisionthe guide offered two answers and routed serverless/edge to LiteKernel, while the repo's own example for that shape uses neither kernela third branch naming @objectstack/objectql/core and examples/embed-objectql (ADR-0076)
PLAT-A-02frontmatterthe description never named capabilities / requires:, the key that decides which service plugins bootone clause added, paid by A-01

Facts re-read against source before writing, per the card's assumption 5: blank/objectstack.config.ts:22,30; serve.tsCAPABILITY_PROVIDERS and the auth ⇒ email implication at :2281-2321; onEnable at app-showcase :283, app-crm :127, app-todo :33; PLATFORM_CAPABILITY_TOKENS in packages/spec/src/kernel/platform-capabilities.ts.

CAPABILITY_PROVIDERS holds 20 entries — the audit's "~20" was right. An earlier revision of this PR claimed 14 and offered that as a correction to the audit; that claim was itself wrong and is retracted. See Review round 1.

premise_false

  • PLAT-E-05 — premise false; not implemented. The audit proposed adding an os:check marker to the Complete Plugin Example so plugin/kernel examples would finally be type-checked. Measured: the gate's "skills + docs" surface resolves from packages/spec only (SURFACES in packages/spec/scripts/check-skill-examples.ts, resolutionDir: SPEC_DIR, selfPackages: [SPEC_DIR]), and @objectstack/core is not a dependency of packages/spec — that package's node_modules has no @objectstack scope at all. Marking the block produced skills/objectstack-platform/SKILL.md:804:44 error TS2307: Cannot find module '@objectstack/core'. Every plugin/kernel example in this package imports Plugin / PluginContext / ObjectKernel / LiteKernel from there, so no such example can be gated without a new SURFACES entry — another package, which this flight may not edit. The marker was reverted; check:skill-examples is green with 258 marked blocks. Filed as follow-up below.
  • PLAT-C-01 — premise partly false. "DELETE the mode table → one pointer line" is not available: check:skill-identifier-liveness registers ## Seed Data as exhaustive over SeedMode, and deleting the table turned five live members (insert, update, upsert, replace, ignore) into capabilities no AI author reading the catalog can reach. The gate caught it. Fixed the author's way — the table stays, and gained the ⚠️ Data-loss flag on replace the audit noted was missing. The shrink-only gap ledger is maintainer-only and was not touched.
  • PLAT-C-03 — not applied, by ruling. The card's ANCHOR RULINGS keep SKILL.md:59-70 because the pm-dispatch flight points there. The overlap the audit identified is real but is the anchor's to settle.
  • PLAT-G-02 — not applied, by ruling. Moving references/plugin-hooks.md to rules/ is exactly what the card forbids (the path is pinned stable for objectstack-data's inbound link). The catalog-wide drift it names is real and is listed as follow-up.

Card assumptions verified rather than assumed: (1) skills/objectstack-platform/** is byte-identical at a59f78d, d63c8a25 and this branch's actual base 909a4417git diff --stat empty for both; note origin/main had moved past the d63c8a25 named in the card. (2) bootstrap-patterns has zero inbound links, with plugin-lifecycle as a positive control that hits abundantly. (3) check:skill-docsis the drift gate, it is in the derived family, and the frontmatter edit did force regeneration — of two files, not one (below). (4) the ratchet reds on a deleted file whose row remains — probed directly: re-adding the row gave exit 1 and "cannot read … — red, not a skip (#4690)", then the script was restored and the restore confirmed by hash match.

Files outside the card's literal list

  • skills/README.md — regenerated, as the card anticipated for a frontmatter edit.
  • content/docs/ai/skills-reference.mdxalso regenerated, because one generator writes both and check:skill-docs fails on both. Not anticipated by the card; flagged here. Both diffs are frontmatter-derived only, confined to this package's row. Not content/docs/releases/.

follow-up for packages/spec

  • Extend SURFACES in packages/spec/scripts/check-skill-examples.ts with a resolution root that can see @objectstack/core, so plugin / kernel / service examples across the catalog become type-checkable. Today 78 of this package's 80 TypeScript fences are unchecked and the two checked ones both teach data authoring — the least proprietary content in the package. This is PLAT-E-05's real blocker.

follow-up for the catalog

  • PLAT-G-02: hand-authored per-topic files live under the generated references/ directory, which skills/README.md:55-58 reserves for generated pointers. This package and objectstack-data (references/data-hooks.md) both do it — a catalog-wide placement decision, not a lone slip, and one this flight is explicitly forbidden to settle by moving the file.

Review round 1

Contract review failed one span — the requires: table added for PLAT-F-02. Three defects, all from reading a bounded slice of CAPABILITY_PROVIDERS instead of reading it to its closing brace. Fixed in 224d5d9a; the cross-flight link repair below landed in 25012189:

#defecttruth at sourcefix
1audit row named @objectstack/service-audit@objectstack/plugin-audit (AuditPlugin), serve.ts:1473-1475row corrected
2triggers row named @objectstack/service-triggers, which does not exist@objectstack/trigger-record-change (RecordChangeTriggerPlugin), extras @objectstack/trigger-schedule (ScheduleTriggerPlugin, TimeRelativeTriggerPlugin) and @objectstack/trigger-api (ApiTriggerPlugin), serve.ts:1506-1537row corrected; the entry's own comment ("so pair triggers with job") became a row note and the fifth rule
3"the remaining vocabulary … resolve the same way", and the claim that the map holds 14 entriesthe map holds 20; the other eight tokens resolve by two different mechanismstable lists all 20 against their real pkg; the eight are split into tier-gated (no map entry, opened by dedicated run() blocks per the CAPABILITY_TO_TIER docblock at serve.ts:1166-1171) and enterprise/cloud (no open-edition provider: hierarchy-security ships in @objectstack/security-enterprise via plugins[], ai-seat and governance are cloud-runtime only, platform-capabilities.ts:57-66)

20 + 5 + 3 = the 28 tokens in PLATFORM_CAPABILITY_TOKENS, counted from the frozen array rather than asserted. Defect 3 is the one worth naming plainly: the "14 entries" figure was published as a correction to the audit when the audit was right and the correction was the error — a truncated read reported as a finding.

Cross-flight link repair

references/plugin-hooks.md routed readers to objectstack-data's rules/hooks.md for per-record validation, defaults and audit trails. The data flight (PR #14427, head 061e5f4c, delivered) DELETES that file and consolidates hooks into objectstack-data/references/data-hooks.md, so the reference was repointed before it could dangle — now a real relative link, ../../objectstack-data/references/data-hooks.md, verified to resolve from references/. The old text named both the doomed rules/hooks.md and the surviving references/data-hooks.md; naming only the survivor makes the span 22 bytes shorter. git grep rules/hooks.md over this package returns nothing further, so that was the only site.

The PR title still carries the pre-patch figure (−3,778); the accurate net is −3,608. Left alone deliberately — the patch instruction was not to retitle.

Gates

Head sha 25012189. Command list derived from the real change set by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (9 paths; re-derived after regeneration added the two generated files, which pulled in 20 further docs-family gates). The full 46 were run on 15b4ac79: 45 exit 0, 1 NOT MEASURED. Review round 1 touched only SKILL.md and references/plugin-hooks.md, so the change set and therefore the derived family are unchanged; the card-named gates were re-run on 25012189 and are listed below.

The one non-green in that full run is NOT MEASURED by its own verdict text — node scripts/check-test-completeness.mjs exits 3, not 1: "PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named… the local reading for this gate is NOT MEASURED." CI tees the log and passes the path, so this branch is unreachable there. Not a finding, and not read as green.

Card-named gates on 25012189, every exit captured before any pipe, all exit 0:

gateverdict line
check-skills-token-ratchet"36 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted" — SKILL.md 12871 / 12984, plugin-hooks.md 2413 / 2628
check:skill-examples"258 marked example(s) across 100 file(s), 3 surface(s)"
check:skill-identifier-liveness"OK — Leg 1: 493 citation(s) over 46 published file(s) … Leg 2: 9 registered exhaustive section(s), 0 ledgered gap(s)" — 493, up from 491: the corrected package names are themselves live-checked citations
check:skill-docsexit 0 with no regeneration needed (round 1 touched no frontmatter)
check:skill-compatibility"11 SKILL.md file(s) reconciled against 78 workspace packages"
check:published-readme-linksexit 0 — run additionally to prove the repointed cross-package link resolves

Two gates initially reported exit 3 for missing local build prerequisites and were re-run properly rather than recorded as failures: check:doc-formula-expressions (needed @objectstack/formula built) and check:skill-examples (needed @objectstack/client-react built — it refuses rather than false-greening, #7122). Both green afterwards.

Control bytes: node scripts/check-nul-bytes.mjs green, plus a direct scan of all changed files for the wider control-byte range — no hits.

skip-changeset applies and is on the PR: this diff releases nothing from any package. skills/ is named in the changeset gate's own release-nothing enumeration (scripts/check-empty-changeset.mjs), which pins a "skills/**-only PR carrying NO changeset" as a green fixture, and scripts/check-skills-token-ratchet.mjs is a CI-internal gate script — the workflow calls that the textbook case.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

…-B-01)
`rules/bootstrap-patterns.md` had ZERO inbound links repo-wide — the only
reference to its path anywhere in the tree was its own ceiling row in
`scripts/check-skills-token-ratchet.mjs`. `SKILL.md:715-717` links only
lifecycle / service-registry / hooks-events, so nothing ever routed a reader
to it; verified with `git grep -n bootstrap-patterns` against a positive
control (`git grep -n plugin-lifecycle` hits abundantly).
Its content was already carried by SKILL.md: the driver table (:66-74 =
SKILL.md:351-357), the HTTP-layer table (:76-83 = :389-397), the "no `driver:`
key, refused at load" block plus the `defineStack validation failed` sample
(:7-31,87-105 = :209-234), and manifest required fields (:29-31,107-130 =
:327-339). Its own last line pointed back at SKILL.md.
1,093 tokens of the published bundle that no customer agent could reach.
The ceiling row goes with the file: the gate treats an unreadable ratcheted
path as RED, not as a skip (#4690) — verified by a controlled probe that
re-added the row (exit 1, "cannot read ... — red, not a skip"), then restored
the script and confirmed the restore by hash match.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
… the pointer file (PLAT-B-02, D-04, D-05, D-06)
`rules/plugin-hooks-events.md` opened by declaring itself "a compact pointer.
Complete documentation lives in the canonical reference" and then reproduced
that reference: the event table, the `data:*` warning, the custom-hook
convention, execution order, and a DO/DON'T list. SKILL.md linked only the
pointer, so the 2,628-token canonical file sat TWO hops from the entry file
behind 985 tokens that restated it.
SKILL.md now links `references/plugin-hooks.md` directly at both sites
(`:717` and `:865`) and the pointer file is deleted with its ceiling row.
Checked before deleting: the pointer carried no fact absent from the
canonical reference or from SKILL.md — its one non-hooks item ("no circular
dependencies between plugins, both kernels throw") is already the
`Dependency resolution` row of the ObjectKernel-vs-LiteKernel table. So the
merge is a relink plus a deletion, and the compact DO/DON'T shape it had is
what now closes the canonical file.
`references/plugin-hooks.md` PATH IS UNCHANGED on purpose:
`skills/objectstack-data/rules/hooks.md:202` links to it across packages, and
that link is verified still resolving.
Paid inside `references/plugin-hooks.md`, per the shrink-only ratchet:
- PLAT-D-04 — the 7-item "Best Practices" list, every item of which
restated a span of the same file, is replaced by the compact DO/DON'T
rules-of-thumb folded in from the deleted pointer.
- PLAT-D-05 — "Hook Naming Conventions" deleted; its only new rule
(lower-case) folded into the Custom Hooks convention line.
- PLAT-D-06 — the second of two near-identical vitest blocks deleted; it
differed only in asserting `receivedData` instead of `hookCalled`.
Token deltas: references/plugin-hooks.md 2628 -> 2418 (ceiling 2628);
SKILL.md 12984 -> 12982 (ceiling 12984 — the relinked paths are shorter than
the deleted ones); rules/plugin-hooks-events.md 985 -> deleted with its row.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…07, C-05)
`rules/service-registry.md` 2329 -> 1754 tokens (ceiling 2331):
- PLAT-B-07 — "Well-Known Service Keys" was the SAME table as
`SKILL.md:1008-1024` with the columns inverted and only 6 of its 13 rows,
and both then repeated "the REST plugin registers no service". One table
now, in SKILL.md; this file points at it.
- PLAT-D-03 — deleted "Service Naming Conventions" (generic advice: "use
descriptive names", "avoid abbreviations"), a "Testing Service
Registration" block whose only assertions were `toBeDefined()` and
`toThrow()`, and a 10-item "Best Practices" list restating this file's own
Registration Patterns section and its `null`-placeholder paragraph.
`rules/plugin-lifecycle.md` 2404 -> 1777 tokens (ceiling 2408):
- PLAT-D-08 — the ❌/✅ "getService() in init() without a declared
dependency" lesson was already in `service-registry.md:193-223`,
differing only in the names used (CachePlugin/db-pool vs
AnalyticsPlugin/objectql) and closing on the SAME paragraph about never
registering `null`. Replaced with the rule plus a link to the one worked
pair.
- PLAT-D-02 — deleted a 10-item "Best Practices" list (items 1-7 restate
this file's own Phase 1/2/3 headings; 8-10 are generic: "version your
plugin", "use reverse domain names") and a "Testing Lifecycle" section of
two vitest blocks whose only assertions were `toBeDefined()` and
`isConnected()`.
- PLAT-C-05 — dropped this file's copy of the `data:*`-boundary warning.
The boundary was stated five times in-package; the canonical statement
stays in `references/plugin-hooks.md` and SKILL.md keeps exactly one.
No content was moved to another package: each deletion either had a surviving
in-package statement or was generic advice that changed no decision.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…B/C/D/E/F/G)
Deletions and rewrites (SKILL.md 12984 -> 12696 tokens, ceiling 12984):
- PLAT-B-05 — `defineStack()` was 12% down the file behind 1,441 tokens of
preamble. It (with the Manifest Reference it needs) is now the first
section after the title.
- PLAT-B-03 — "When to Use This Skill" appeared TWICE, 650 lines apart,
both restating the frontmatter. A loaded package is already selected.
- PLAT-B-06 — the package narrated its own edit history ("the original
'quickstart' skill"). A customer agent never chose between two former
skills.
- PLAT-D-07 — the CRM Blueprint restated the directory tree 18 lines above
and pointed at data / i18n territory; only its `requires:` row was
platform-specific, and that is now taught properly (F-02).
- PLAT-D-01 — the ASCII Decision Guide restated the table two lines above.
- PLAT-F-05 — `composeStacks()` had a section plus a strategies table and
ZERO usages outside `packages/spec` and its own tests; real multi-app
composition is AppPlugin registration. Reduced to a pointer at the schema,
not deleted (live surface, zero measured usage).
- PLAT-F-06 — driver-as-a-`plugins:`-entry was taught as THE canonical
bootstrap; no example config does it and the CLI wires the driver itself
from the resolved DB URL. Reframed as embedding/tests only.
- PLAT-C-01 — seeds are objectstack-data's; the copy here taught a raw
literal writing `object:` by hand, which that skill forbids verbatim.
Now a pointer PLUS the `mode` table (see below).
- PLAT-C-02 — the example object file re-taught field types in a spelling
7 of 7 real object files do not use (`export default {}` vs
`ObjectSchema.create({...})`).
- PLAT-C-04, B-04 — a restatement of the rule it delegates, and a
cross-reference to a section that documents an in-process TS API and
contains no HTTP route.
- PLAT-C-05 — SKILL.md stated the `data:*` boundary twice; one statement
remains (the one that explains the silent registration).
- PLAT-E-01, E-02, E-03, E-04 — four blocks that could not compile:
`defineStack`/`SqlDriver` used un-imported with `CrmApp`/`TodoApp`
undefined; `this.pool` on a plain object literal plus `err.message` on a
`catch` binding; a type argument naming a non-exported class from another
fence; and `{ ... }` / `{ … }` ellipsis placeholders (TS1109).
- PLAT-G-01 — v5.0 vocabulary: the runtime workspace is `environment`, not
`project`, in all five spans (skills/README.md:88; the CLI surface is
`os environments`).
- PLAT-G-03 — the `os` / `objectstack` binary alias is now stated at first
use instead of 800 lines later.
- PLAT-A-01 — the frontmatter sold "adapters" and the body refutes it 385
lines in ("There are no `@objectstack/adapter-*` packages"). Both the
description and the section heading now name the Hono HTTP layer.
- The `blank` template's "in-memory driver, Hono server" was true of the
RUNNING APP and false of the file a reader opens: the template config has
neither; both arrive from CLI auto-registration.
Additions, each paid by a deletion in this same file:
- PLAT-F-01 — `manifest.engines.protocol`, stamped into every project
`create-objectstack` emits and carried by all three example apps, was
mentioned NOWHERE in this package. One manifest row + why it is checked
before anything loads.
- PLAT-F-02 — `requires: [...]` decides which service plugins boot and was
taught as one blueprint cell and one bare word. Now a token table plus the
four rules that change what you write: precedence, declaring-is-a-demand
(hard boot error vs best-effort), `auth` implies `email`, and keep
`automation` whenever `plugins:` lists a connector.
- PLAT-F-03 — the `onEnable` export, the seam where an app binds runtime
code, used by all three example apps and documented only in
objectstack-data.
- PLAT-F-04 — `os plugin build|sign|publish`: authoring stopped at
`kernel.use(plugin)` with no path to a distributable plugin.
- PLAT-F-07 — a third answer to the kernel question: `examples/embed-objectql`
uses NEITHER kernel (`@objectstack/objectql/core`, ADR-0076).
- PLAT-A-02 — the description now names the capability key.
Generated files regenerated because the frontmatter changed, as the drift gate
demands: `skills/README.md` AND `content/docs/ai/skills-reference.mdx` (one
generator writes both; `pnpm --filter @objectstack/spec gen:skill-docs`). Both
diffs are frontmatter-derived only.
`## Seed Data` keeps its `mode` table: `check:skill-identifier-liveness`
registers that section as exhaustive over `SeedMode`, and deleting the table
made five live members unreachable (caught by the gate, fixed the author's
way — the shrink-only gap ledger is maintainer-only and was not touched). The
table now also carries the Data-loss flag on `replace` that it was missing.
PLAT-E-05 is NOT implemented — its premise is false; see the PR body.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…al registry (review round 1)
Contract review round 1 failed the `requires:` table I added in the previous
commit. Three defects, all mine, all from reading a bounded slice of
`CAPABILITY_PROVIDERS` instead of reading it to its closing brace:
1. `audit` named `@objectstack/service-audit`. The real entry is
`@objectstack/plugin-audit` (`AuditPlugin`), serve.ts:1473-1475.
2. `triggers` named `@objectstack/service-triggers`, which does not exist. The
entry is `@objectstack/trigger-record-change` (`RecordChangeTriggerPlugin`)
with extras `@objectstack/trigger-schedule` (`ScheduleTriggerPlugin`,
`TimeRelativeTriggerPlugin`) and `@objectstack/trigger-api`
(`ApiTriggerPlugin`), serve.ts:1506-1537.
3. "the remaining vocabulary resolves the same way" was false, and so was the
claim that the map holds 14 entries. It holds TWENTY — I bounded an `awk`
range by guess and stopped at `sms`, then reported the truncation as a
correction to the audit. The audit's "~20" was right and my correction was
the error.
The table now lists all 20 provider-backed tokens against their real `pkg`
values, and the eight remaining tokens are separated into the two mechanisms
that actually resolve them: five tier-gated tokens with NO map entry, opened by
dedicated blocks in `serve.ts` `run()` (CAPABILITY_TO_TIER docblock,
serve.ts:1166-1171), and three enterprise/cloud tokens with no open-edition
provider at all — `hierarchy-security` ships in
`@objectstack/security-enterprise` via `plugins[]`, `ai-seat` and `governance`
are cloud-runtime only (platform-capabilities.ts:57-66). 20 + 5 + 3 = the 28
tokens in `PLATFORM_CAPABILITY_TOKENS`, counted from the frozen array rather
than asserted.
The `triggers` entry's own comment carries a rule an author needs — schedule
triggers run on the job service, "so pair `triggers` with `job`" — so that is
now both a row note and the fifth rule: `triggers` alone arms record-change
triggers, and autolaunched scheduled flows stay silent without `job`.
SKILL.md 12696 -> 12871 tokens, ceiling 12984 unchanged and not raised; the
growth is paid from the headroom this flight's own deletions created.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…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-litantos-litant changed the title skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,778 tokens)skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens)Sep 2, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 06:53
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to a conflict with the base branch Sep 2, 2026
Nine sibling skills flights landed on main after this branch's base. Both
conflicts fell inside the BEGIN/END GENERATED: skills region of the two mixed
generated files (skills/README.md, content/docs/ai/skills-reference.mdx);
resolved by clearing the markers in place — preserving main's text-merged prose
outside the region — and regenerating both wholesale with
`pnpm --filter @objectstack/spec gen:skill-docs` on the merged tree.
scripts/check-skills-token-ratchet.mjs auto-merged (each flight edited its own
package's ceiling rows). No behaviour or content change to the platform package.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01489YWhZEoHT9oXshiyywQy
@claude
claudeBot requested a review from os-zhuangSeptember 2, 2026 14:54
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/xlskip-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(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens) - #14351

Merged
os-zhuang merged 7 commits into
mainfrom
claude/issue-14299-skills-platform-optimization
Sep 2, 2026
Merged

skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens)#14351
os-zhuang merged 7 commits into
mainfrom
claude/issue-14299-skills-platform-optimization

Conversation

@os-litant

@os-litantos-litant commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Part of #14299

Skills catalog optimization flight for skills/objectstack-platform (program #14292, maintainer mandate 2026-09-02 「审核所有的 skills,进行全面的优化。」). The 50-finding audit record is posted verbatim on the card. Governed face — stays draft; needs:contract-review on both carriers.

Why Part of and not a closing keyword: only the implementable half of the card landed. PLAT-H-01 is deferred to decision card #14296 item 2 and PLAT-G-02 to the catalog follow-up below, so merging this must not close the card while its deferred half is still undecided. The card stays open; pm:dispatched is stripped by hand at merge.

Per-file token delta

Token unit is the ratchet's own: ceil(utf8 bytes / 4).

Filebeforeafterceilingnote
SKILL.md129841287112984−113; every addition paid in-file. Review round 1 spent 175 of the freed headroom on the corrected requires: table
references/plugin-hooks.md262824132628−215; absorbed the deleted pointer's DO/DON'T, plus the cross-flight link repair
rules/plugin-lifecycle.md240417772408−627
rules/service-registry.md232917542331−575
rules/bootstrap-patterns.md1093deletedrow droppedorphan, zero inbound links
rules/plugin-hooks-events.md985deletedrow droppedself-declared pointer that restated its target
evals/README.md514514514untouched — DEFERRED per #14296 item 2
references/_index.md13441344generateduntouched

Package 24,281 → 20,673 = −3,608 (−14.9%). Bundle total 187,854 → 184,246. No ceiling was raised; no file grew; scripts/check-skills-token-ratchet.mjs was touched only to drop the two deleted files' rows.

The audit's package total of 24,278 is 3 tokens off — the measured base is 24,281 (sum of the eight rows above).

Why −3,608 and not the projected −5,970

Four of the projected reductions were withdrawn by evidence or by ruling, not skipped:

The five funded additions also cost more than the projected +355, because they were written against the measured facts (the requires: table carries all 20 provider-backed tokens plus the five rules that change what an author writes) rather than against the projection.

Per-item: 落点 | before | after

Deleted files

id落点beforeafter
PLAT-B-01rules/bootstrap-patterns.md1,093 tokens with zero inbound links repo-wide — the only mention of its path was its own ceiling row. Content already carried by SKILL.md (driver table, HTTP-layer table, the "no driver: key, refused at load" block, manifest required fields); its own last line pointed back at SKILL.mddeleted, with its ceiling row
PLAT-B-02rules/plugin-hooks-events.md + SKILL.md:717,865The file opened "This document is a compact pointer. Complete documentation lives in the canonical reference" and then reproduced it. SKILL.md linked only the pointer, so the 2,628-token canonical file sat two hops from the entry filedeleted; SKILL.md links references/plugin-hooks.md directly at both sites. Path unchanged on purposeskills/objectstack-data/rules/hooks.md:202 links to it across packages; verified still resolving

Checked before deleting the pointer: it carried no fact absent from the canonical reference or SKILL.md. Its one non-hooks item ("no circular dependencies between plugins, both kernels throw") is already the Dependency resolution row of the ObjectKernel-vs-LiteKernel table.

references/plugin-hooks.md

id落点beforeafter
PLAT-D-04:312-3277-item "Best Practices", every item restating a span of the same filereplaced by the compact DO/DON'T folded in from the deleted pointer
PLAT-D-05:238-251"Hook Naming Conventions", 4 good / 2 bad names; the convention was already given at :80-82 and demonstrated at :225-232deleted; its only new rule (lower-case) folded into the Custom Hooks convention line
PLAT-D-06:252-311two near-identical 25-line vitest blocks; the second differed only by asserting receivedData instead of hookCalledsecond block deleted

rules/plugin-lifecycle.md and rules/service-registry.md

id落点beforeafter
PLAT-B-07service-registry.md:145-158the same table as SKILL.md:1008-1024 with inverted columns and only 6 of its 13 rows; both then repeated "the REST plugin registers no service"one table, in SKILL.md; the rules file points at it
PLAT-D-03service-registry.md:270-319"Service Naming Conventions" (generic: "use descriptive names", "avoid abbreviations") + a test block asserting only toBeDefined()/toThrow() + a 10-item Best Practices restating the file's own sectionsdeleted
PLAT-D-08plugin-lifecycle.md:201-230the same ❌/✅ lesson as service-registry.md:193-223, differing only in names, closing on the same null-placeholder paragraphreplaced by the rule plus a link to the one worked pair
PLAT-D-02plugin-lifecycle.md:293-34010-item Best Practices (1-7 restate the file's own Phase headings; 8-10 generic: "version your plugin", "use reverse domain names") + two vitest blocks asserting only toBeDefined()/isConnected()deleted
PLAT-C-05plugin-lifecycle.md:110-113, SKILL.md:944-948the data:* boundary was stated five times in-packagein-package statements down to three; SKILL.md keeps exactly one (the one explaining the silent registration), per the anchor ruling; canonical statement stays in references/plugin-hooks.md

SKILL.md — structure

id落点beforeafter
PLAT-B-05section order1,441 tokens preceded defineStack() — the core construct sat 12% down the filedefineStack() (with the Manifest Reference it needs) is the first section after the title
PLAT-B-03:39-49, :699-708"When to Use This Skill" appeared twice, 650 lines apart, both restating the frontmatterboth deleted — a loaded package is already selected
PLAT-B-06:25-35narrated the package's own edit history ("the original 'quickstart' skill", "which is why they live in one skill")one sentence naming the two concerns
PLAT-D-07:142-158"CRM Blueprint": rows 2-3 restated the directory tree 18 lines above; rows 5-6 pointed at data / i18n territorydeleted; its only platform-specific row (requires:) is now taught properly under the Boot Sequence
PLAT-D-01:735-758ASCII "Decision Guide" restating the table two lines above; its gloss changed no branchdeleted, table survives
PLAT-B-04:1277-1279"see Health Monitoring earlier in this skill" — that section documents an in-process TS API and contains no HTTP routecross-reference dropped

SKILL.md — truthfulness

id落点beforeafter
PLAT-F-06:347-381driver-as-a-plugins:-entry taught as the canonical bootstrap. Zero example configs do it: app-showcase and the blank template list connector plugins, app-crm and app-todo have no plugins: key, and the CLI wires the driver itself from the resolved DB URL (serve.ts:2687-2745)selection table kept; the code reframed as embedding/tests only, with "pick a driver by setting the DB URL, not by writing code"
PLAT-F-05:498-522composeStacks() had a section plus a 3-row strategies table and zero usages outside packages/spec and its own testsreduced to a pointer at stack.zod.ts. Live surface with zero measured usage ⇒ one row, never delete the last mention
PLAT-C-01:548-576taught a raw data: [{ object: 'task', … }] literal — writing object: by hand, which objectstack-data/SKILL.md:1036 forbids verbatim ("Auto-set from objectDef.name — never write manually"); 24 real defineSeed( sites, 0 raw literalsliteral deleted, defineSeed() pointer added, mode table kept (see premise_false) and given the ⚠️ Data-loss flag on replace it was missing
PLAT-C-02:626-663re-taught field types in a shape 0 of 7 real object files use (export default {} vs ObjectSchema.create({…}))one line pointing at objectstack-data and the scaffolder's own note.object.ts
PLAT-G-01:303,319,322-323,1035five spans used the retired v5.0 word for the runtime workspace ("project runtime", "Project revisions", "isolated project kernel") against skills/README.md:88 and the os environments CLI surfaceall five now environment. Uses of "project" for the local source tree left alone — those are correct
imprecision:79-80the blank template "ships One example object, in-memory driver, Hono server" — the template config has neither; its plugins: array holds three connector executors and both arrive from CLI auto-registrationstates what is in the file, and that the driver and server come from the CLI
PLAT-A-01:5,9-10,20 and the section headingfrontmatter sold "drivers, adapters" while :394-397 answers "There are no@objectstack/adapter-* packages" — promise and truth 385 lines apartdescription and heading now name the Hono HTTP layer
PLAT-G-03:307-310 vs :1109the os / objectstack alias was declared 800 lines after first usestated at first use
PLAT-C-04:1299a 60-token restatement of the very rule it delegates to objectstack-datasymptom plus the one-line cause

SKILL.md — examples that could not compile

id落点beforeafter
PLAT-E-01:527-542"Host Pattern" read as a complete config file but had ≥4 errors on paste: defineStack and SqlDriver used un-imported, CrmApp/TodoApp undefined, and new SqlDriver({ ... }) is TS1109folded into the Multi-App Composition prose; no un-compilable block
PLAT-E-02:1059-1073typed the literal as a Plugin intersection then read this.pool.query(...) (TS2339) and err.message on a catch binding (TS18046); PluginHealthStatus never importedthe opt-in contract in prose plus the three real kernel call sites
PLAT-E-03:954-969kernel.getService with a type argument naming a non-exported class from a different fence (TS2304)type argument dropped
PLAT-E-04:296-298defineStack({ ... }, { strict: false }) — TS1109 by constructiondefineStack(config, { strict: false })

The funded additions — each paid by a deletion in the same file

id落点beforeafter
PLAT-F-01Manifest Referencemanifest.engines: { protocol: '^17' } has 4 real usages including every project the scaffolder emits, and grep engines skills/objectstack-platform/ returned 0one manifest row plus why the runtime checks it before it loads anything
PLAT-F-02Boot Sequencerequires: [...] decides which service plugins boot; taught as one CRM-blueprint cell and one bare word, while the Boot Sequence narrated a fixed auto-register list and never said requires: drives itall 20 provider-backed tokens against their real pkg values, the two other resolution mechanisms kept separate from them, and five rules that change what you write: precedence, declaring-is-a-demand (declared-but-absent is a hard boot error, auto-injected-but-absent stays best-effort), auth implies email, keep automation whenever plugins: lists a connector, and pair triggers with job
PLAT-F-03Boot Sequencethe onEnable export — the seam where an app binds runtime code — has 4 real sites and was documented only in objectstack-dataits own subsection with the AppPlugin invocation and a worked export
PLAT-F-04Part 3plugin authoring stopped at kernel.use(plugin) with no path to a distributable plugin; the ADR-0025 §3.4 pipeline was mentioned nowhere in skills/a 3-row `os plugin build
PLAT-F-07kernel decisionthe guide offered two answers and routed serverless/edge to LiteKernel, while the repo's own example for that shape uses neither kernela third branch naming @objectstack/objectql/core and examples/embed-objectql (ADR-0076)
PLAT-A-02frontmatterthe description never named capabilities / requires:, the key that decides which service plugins bootone clause added, paid by A-01

Facts re-read against source before writing, per the card's assumption 5: blank/objectstack.config.ts:22,30; serve.tsCAPABILITY_PROVIDERS and the auth ⇒ email implication at :2281-2321; onEnable at app-showcase :283, app-crm :127, app-todo :33; PLATFORM_CAPABILITY_TOKENS in packages/spec/src/kernel/platform-capabilities.ts.

CAPABILITY_PROVIDERS holds 20 entries — the audit's "~20" was right. An earlier revision of this PR claimed 14 and offered that as a correction to the audit; that claim was itself wrong and is retracted. See Review round 1.

premise_false

  • PLAT-E-05 — premise false; not implemented. The audit proposed adding an os:check marker to the Complete Plugin Example so plugin/kernel examples would finally be type-checked. Measured: the gate's "skills + docs" surface resolves from packages/spec only (SURFACES in packages/spec/scripts/check-skill-examples.ts, resolutionDir: SPEC_DIR, selfPackages: [SPEC_DIR]), and @objectstack/core is not a dependency of packages/spec — that package's node_modules has no @objectstack scope at all. Marking the block produced skills/objectstack-platform/SKILL.md:804:44 error TS2307: Cannot find module '@objectstack/core'. Every plugin/kernel example in this package imports Plugin / PluginContext / ObjectKernel / LiteKernel from there, so no such example can be gated without a new SURFACES entry — another package, which this flight may not edit. The marker was reverted; check:skill-examples is green with 258 marked blocks. Filed as follow-up below.
  • PLAT-C-01 — premise partly false. "DELETE the mode table → one pointer line" is not available: check:skill-identifier-liveness registers ## Seed Data as exhaustive over SeedMode, and deleting the table turned five live members (insert, update, upsert, replace, ignore) into capabilities no AI author reading the catalog can reach. The gate caught it. Fixed the author's way — the table stays, and gained the ⚠️ Data-loss flag on replace the audit noted was missing. The shrink-only gap ledger is maintainer-only and was not touched.
  • PLAT-C-03 — not applied, by ruling. The card's ANCHOR RULINGS keep SKILL.md:59-70 because the pm-dispatch flight points there. The overlap the audit identified is real but is the anchor's to settle.
  • PLAT-G-02 — not applied, by ruling. Moving references/plugin-hooks.md to rules/ is exactly what the card forbids (the path is pinned stable for objectstack-data's inbound link). The catalog-wide drift it names is real and is listed as follow-up.

Card assumptions verified rather than assumed: (1) skills/objectstack-platform/** is byte-identical at a59f78d, d63c8a25 and this branch's actual base 909a4417git diff --stat empty for both; note origin/main had moved past the d63c8a25 named in the card. (2) bootstrap-patterns has zero inbound links, with plugin-lifecycle as a positive control that hits abundantly. (3) check:skill-docsis the drift gate, it is in the derived family, and the frontmatter edit did force regeneration — of two files, not one (below). (4) the ratchet reds on a deleted file whose row remains — probed directly: re-adding the row gave exit 1 and "cannot read … — red, not a skip (#4690)", then the script was restored and the restore confirmed by hash match.

Files outside the card's literal list

  • skills/README.md — regenerated, as the card anticipated for a frontmatter edit.
  • content/docs/ai/skills-reference.mdxalso regenerated, because one generator writes both and check:skill-docs fails on both. Not anticipated by the card; flagged here. Both diffs are frontmatter-derived only, confined to this package's row. Not content/docs/releases/.

follow-up for packages/spec

  • Extend SURFACES in packages/spec/scripts/check-skill-examples.ts with a resolution root that can see @objectstack/core, so plugin / kernel / service examples across the catalog become type-checkable. Today 78 of this package's 80 TypeScript fences are unchecked and the two checked ones both teach data authoring — the least proprietary content in the package. This is PLAT-E-05's real blocker.

follow-up for the catalog

  • PLAT-G-02: hand-authored per-topic files live under the generated references/ directory, which skills/README.md:55-58 reserves for generated pointers. This package and objectstack-data (references/data-hooks.md) both do it — a catalog-wide placement decision, not a lone slip, and one this flight is explicitly forbidden to settle by moving the file.

Review round 1

Contract review failed one span — the requires: table added for PLAT-F-02. Three defects, all from reading a bounded slice of CAPABILITY_PROVIDERS instead of reading it to its closing brace. Fixed in 224d5d9a; the cross-flight link repair below landed in 25012189:

#defecttruth at sourcefix
1audit row named @objectstack/service-audit@objectstack/plugin-audit (AuditPlugin), serve.ts:1473-1475row corrected
2triggers row named @objectstack/service-triggers, which does not exist@objectstack/trigger-record-change (RecordChangeTriggerPlugin), extras @objectstack/trigger-schedule (ScheduleTriggerPlugin, TimeRelativeTriggerPlugin) and @objectstack/trigger-api (ApiTriggerPlugin), serve.ts:1506-1537row corrected; the entry's own comment ("so pair triggers with job") became a row note and the fifth rule
3"the remaining vocabulary … resolve the same way", and the claim that the map holds 14 entriesthe map holds 20; the other eight tokens resolve by two different mechanismstable lists all 20 against their real pkg; the eight are split into tier-gated (no map entry, opened by dedicated run() blocks per the CAPABILITY_TO_TIER docblock at serve.ts:1166-1171) and enterprise/cloud (no open-edition provider: hierarchy-security ships in @objectstack/security-enterprise via plugins[], ai-seat and governance are cloud-runtime only, platform-capabilities.ts:57-66)

20 + 5 + 3 = the 28 tokens in PLATFORM_CAPABILITY_TOKENS, counted from the frozen array rather than asserted. Defect 3 is the one worth naming plainly: the "14 entries" figure was published as a correction to the audit when the audit was right and the correction was the error — a truncated read reported as a finding.

Cross-flight link repair

references/plugin-hooks.md routed readers to objectstack-data's rules/hooks.md for per-record validation, defaults and audit trails. The data flight (PR #14427, head 061e5f4c, delivered) DELETES that file and consolidates hooks into objectstack-data/references/data-hooks.md, so the reference was repointed before it could dangle — now a real relative link, ../../objectstack-data/references/data-hooks.md, verified to resolve from references/. The old text named both the doomed rules/hooks.md and the surviving references/data-hooks.md; naming only the survivor makes the span 22 bytes shorter. git grep rules/hooks.md over this package returns nothing further, so that was the only site.

The PR title still carries the pre-patch figure (−3,778); the accurate net is −3,608. Left alone deliberately — the patch instruction was not to retitle.

Gates

Head sha 25012189. Command list derived from the real change set by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (9 paths; re-derived after regeneration added the two generated files, which pulled in 20 further docs-family gates). The full 46 were run on 15b4ac79: 45 exit 0, 1 NOT MEASURED. Review round 1 touched only SKILL.md and references/plugin-hooks.md, so the change set and therefore the derived family are unchanged; the card-named gates were re-run on 25012189 and are listed below.

The one non-green in that full run is NOT MEASURED by its own verdict text — node scripts/check-test-completeness.mjs exits 3, not 1: "PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named… the local reading for this gate is NOT MEASURED." CI tees the log and passes the path, so this branch is unreachable there. Not a finding, and not read as green.

Card-named gates on 25012189, every exit captured before any pipe, all exit 0:

gateverdict line
check-skills-token-ratchet"36 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted" — SKILL.md 12871 / 12984, plugin-hooks.md 2413 / 2628
check:skill-examples"258 marked example(s) across 100 file(s), 3 surface(s)"
check:skill-identifier-liveness"OK — Leg 1: 493 citation(s) over 46 published file(s) … Leg 2: 9 registered exhaustive section(s), 0 ledgered gap(s)" — 493, up from 491: the corrected package names are themselves live-checked citations
check:skill-docsexit 0 with no regeneration needed (round 1 touched no frontmatter)
check:skill-compatibility"11 SKILL.md file(s) reconciled against 78 workspace packages"
check:published-readme-linksexit 0 — run additionally to prove the repointed cross-package link resolves

Two gates initially reported exit 3 for missing local build prerequisites and were re-run properly rather than recorded as failures: check:doc-formula-expressions (needed @objectstack/formula built) and check:skill-examples (needed @objectstack/client-react built — it refuses rather than false-greening, #7122). Both green afterwards.

Control bytes: node scripts/check-nul-bytes.mjs green, plus a direct scan of all changed files for the wider control-byte range — no hits.

skip-changeset applies and is on the PR: this diff releases nothing from any package. skills/ is named in the changeset gate's own release-nothing enumeration (scripts/check-empty-changeset.mjs), which pins a "skills/**-only PR carrying NO changeset" as a green fixture, and scripts/check-skills-token-ratchet.mjs is a CI-internal gate script — the workflow calls that the textbook case.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

…-B-01)
`rules/bootstrap-patterns.md` had ZERO inbound links repo-wide — the only
reference to its path anywhere in the tree was its own ceiling row in
`scripts/check-skills-token-ratchet.mjs`. `SKILL.md:715-717` links only
lifecycle / service-registry / hooks-events, so nothing ever routed a reader
to it; verified with `git grep -n bootstrap-patterns` against a positive
control (`git grep -n plugin-lifecycle` hits abundantly).
Its content was already carried by SKILL.md: the driver table (:66-74 =
SKILL.md:351-357), the HTTP-layer table (:76-83 = :389-397), the "no `driver:`
key, refused at load" block plus the `defineStack validation failed` sample
(:7-31,87-105 = :209-234), and manifest required fields (:29-31,107-130 =
:327-339). Its own last line pointed back at SKILL.md.
1,093 tokens of the published bundle that no customer agent could reach.
The ceiling row goes with the file: the gate treats an unreadable ratcheted
path as RED, not as a skip (#4690) — verified by a controlled probe that
re-added the row (exit 1, "cannot read ... — red, not a skip"), then restored
the script and confirmed the restore by hash match.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
… the pointer file (PLAT-B-02, D-04, D-05, D-06)
`rules/plugin-hooks-events.md` opened by declaring itself "a compact pointer.
Complete documentation lives in the canonical reference" and then reproduced
that reference: the event table, the `data:*` warning, the custom-hook
convention, execution order, and a DO/DON'T list. SKILL.md linked only the
pointer, so the 2,628-token canonical file sat TWO hops from the entry file
behind 985 tokens that restated it.
SKILL.md now links `references/plugin-hooks.md` directly at both sites
(`:717` and `:865`) and the pointer file is deleted with its ceiling row.
Checked before deleting: the pointer carried no fact absent from the
canonical reference or from SKILL.md — its one non-hooks item ("no circular
dependencies between plugins, both kernels throw") is already the
`Dependency resolution` row of the ObjectKernel-vs-LiteKernel table. So the
merge is a relink plus a deletion, and the compact DO/DON'T shape it had is
what now closes the canonical file.
`references/plugin-hooks.md` PATH IS UNCHANGED on purpose:
`skills/objectstack-data/rules/hooks.md:202` links to it across packages, and
that link is verified still resolving.
Paid inside `references/plugin-hooks.md`, per the shrink-only ratchet:
- PLAT-D-04 — the 7-item "Best Practices" list, every item of which
restated a span of the same file, is replaced by the compact DO/DON'T
rules-of-thumb folded in from the deleted pointer.
- PLAT-D-05 — "Hook Naming Conventions" deleted; its only new rule
(lower-case) folded into the Custom Hooks convention line.
- PLAT-D-06 — the second of two near-identical vitest blocks deleted; it
differed only in asserting `receivedData` instead of `hookCalled`.
Token deltas: references/plugin-hooks.md 2628 -> 2418 (ceiling 2628);
SKILL.md 12984 -> 12982 (ceiling 12984 — the relinked paths are shorter than
the deleted ones); rules/plugin-hooks-events.md 985 -> deleted with its row.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…07, C-05)
`rules/service-registry.md` 2329 -> 1754 tokens (ceiling 2331):
- PLAT-B-07 — "Well-Known Service Keys" was the SAME table as
`SKILL.md:1008-1024` with the columns inverted and only 6 of its 13 rows,
and both then repeated "the REST plugin registers no service". One table
now, in SKILL.md; this file points at it.
- PLAT-D-03 — deleted "Service Naming Conventions" (generic advice: "use
descriptive names", "avoid abbreviations"), a "Testing Service
Registration" block whose only assertions were `toBeDefined()` and
`toThrow()`, and a 10-item "Best Practices" list restating this file's own
Registration Patterns section and its `null`-placeholder paragraph.
`rules/plugin-lifecycle.md` 2404 -> 1777 tokens (ceiling 2408):
- PLAT-D-08 — the ❌/✅ "getService() in init() without a declared
dependency" lesson was already in `service-registry.md:193-223`,
differing only in the names used (CachePlugin/db-pool vs
AnalyticsPlugin/objectql) and closing on the SAME paragraph about never
registering `null`. Replaced with the rule plus a link to the one worked
pair.
- PLAT-D-02 — deleted a 10-item "Best Practices" list (items 1-7 restate
this file's own Phase 1/2/3 headings; 8-10 are generic: "version your
plugin", "use reverse domain names") and a "Testing Lifecycle" section of
two vitest blocks whose only assertions were `toBeDefined()` and
`isConnected()`.
- PLAT-C-05 — dropped this file's copy of the `data:*`-boundary warning.
The boundary was stated five times in-package; the canonical statement
stays in `references/plugin-hooks.md` and SKILL.md keeps exactly one.
No content was moved to another package: each deletion either had a surviving
in-package statement or was generic advice that changed no decision.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…B/C/D/E/F/G)
Deletions and rewrites (SKILL.md 12984 -> 12696 tokens, ceiling 12984):
- PLAT-B-05 — `defineStack()` was 12% down the file behind 1,441 tokens of
preamble. It (with the Manifest Reference it needs) is now the first
section after the title.
- PLAT-B-03 — "When to Use This Skill" appeared TWICE, 650 lines apart,
both restating the frontmatter. A loaded package is already selected.
- PLAT-B-06 — the package narrated its own edit history ("the original
'quickstart' skill"). A customer agent never chose between two former
skills.
- PLAT-D-07 — the CRM Blueprint restated the directory tree 18 lines above
and pointed at data / i18n territory; only its `requires:` row was
platform-specific, and that is now taught properly (F-02).
- PLAT-D-01 — the ASCII Decision Guide restated the table two lines above.
- PLAT-F-05 — `composeStacks()` had a section plus a strategies table and
ZERO usages outside `packages/spec` and its own tests; real multi-app
composition is AppPlugin registration. Reduced to a pointer at the schema,
not deleted (live surface, zero measured usage).
- PLAT-F-06 — driver-as-a-`plugins:`-entry was taught as THE canonical
bootstrap; no example config does it and the CLI wires the driver itself
from the resolved DB URL. Reframed as embedding/tests only.
- PLAT-C-01 — seeds are objectstack-data's; the copy here taught a raw
literal writing `object:` by hand, which that skill forbids verbatim.
Now a pointer PLUS the `mode` table (see below).
- PLAT-C-02 — the example object file re-taught field types in a spelling
7 of 7 real object files do not use (`export default {}` vs
`ObjectSchema.create({...})`).
- PLAT-C-04, B-04 — a restatement of the rule it delegates, and a
cross-reference to a section that documents an in-process TS API and
contains no HTTP route.
- PLAT-C-05 — SKILL.md stated the `data:*` boundary twice; one statement
remains (the one that explains the silent registration).
- PLAT-E-01, E-02, E-03, E-04 — four blocks that could not compile:
`defineStack`/`SqlDriver` used un-imported with `CrmApp`/`TodoApp`
undefined; `this.pool` on a plain object literal plus `err.message` on a
`catch` binding; a type argument naming a non-exported class from another
fence; and `{ ... }` / `{ … }` ellipsis placeholders (TS1109).
- PLAT-G-01 — v5.0 vocabulary: the runtime workspace is `environment`, not
`project`, in all five spans (skills/README.md:88; the CLI surface is
`os environments`).
- PLAT-G-03 — the `os` / `objectstack` binary alias is now stated at first
use instead of 800 lines later.
- PLAT-A-01 — the frontmatter sold "adapters" and the body refutes it 385
lines in ("There are no `@objectstack/adapter-*` packages"). Both the
description and the section heading now name the Hono HTTP layer.
- The `blank` template's "in-memory driver, Hono server" was true of the
RUNNING APP and false of the file a reader opens: the template config has
neither; both arrive from CLI auto-registration.
Additions, each paid by a deletion in this same file:
- PLAT-F-01 — `manifest.engines.protocol`, stamped into every project
`create-objectstack` emits and carried by all three example apps, was
mentioned NOWHERE in this package. One manifest row + why it is checked
before anything loads.
- PLAT-F-02 — `requires: [...]` decides which service plugins boot and was
taught as one blueprint cell and one bare word. Now a token table plus the
four rules that change what you write: precedence, declaring-is-a-demand
(hard boot error vs best-effort), `auth` implies `email`, and keep
`automation` whenever `plugins:` lists a connector.
- PLAT-F-03 — the `onEnable` export, the seam where an app binds runtime
code, used by all three example apps and documented only in
objectstack-data.
- PLAT-F-04 — `os plugin build|sign|publish`: authoring stopped at
`kernel.use(plugin)` with no path to a distributable plugin.
- PLAT-F-07 — a third answer to the kernel question: `examples/embed-objectql`
uses NEITHER kernel (`@objectstack/objectql/core`, ADR-0076).
- PLAT-A-02 — the description now names the capability key.
Generated files regenerated because the frontmatter changed, as the drift gate
demands: `skills/README.md` AND `content/docs/ai/skills-reference.mdx` (one
generator writes both; `pnpm --filter @objectstack/spec gen:skill-docs`). Both
diffs are frontmatter-derived only.
`## Seed Data` keeps its `mode` table: `check:skill-identifier-liveness`
registers that section as exhaustive over `SeedMode`, and deleting the table
made five live members unreachable (caught by the gate, fixed the author's
way — the shrink-only gap ledger is maintainer-only and was not touched). The
table now also carries the Data-loss flag on `replace` that it was missing.
PLAT-E-05 is NOT implemented — its premise is false; see the PR body.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…al registry (review round 1)
Contract review round 1 failed the `requires:` table I added in the previous
commit. Three defects, all mine, all from reading a bounded slice of
`CAPABILITY_PROVIDERS` instead of reading it to its closing brace:
1. `audit` named `@objectstack/service-audit`. The real entry is
`@objectstack/plugin-audit` (`AuditPlugin`), serve.ts:1473-1475.
2. `triggers` named `@objectstack/service-triggers`, which does not exist. The
entry is `@objectstack/trigger-record-change` (`RecordChangeTriggerPlugin`)
with extras `@objectstack/trigger-schedule` (`ScheduleTriggerPlugin`,
`TimeRelativeTriggerPlugin`) and `@objectstack/trigger-api`
(`ApiTriggerPlugin`), serve.ts:1506-1537.
3. "the remaining vocabulary resolves the same way" was false, and so was the
claim that the map holds 14 entries. It holds TWENTY — I bounded an `awk`
range by guess and stopped at `sms`, then reported the truncation as a
correction to the audit. The audit's "~20" was right and my correction was
the error.
The table now lists all 20 provider-backed tokens against their real `pkg`
values, and the eight remaining tokens are separated into the two mechanisms
that actually resolve them: five tier-gated tokens with NO map entry, opened by
dedicated blocks in `serve.ts` `run()` (CAPABILITY_TO_TIER docblock,
serve.ts:1166-1171), and three enterprise/cloud tokens with no open-edition
provider at all — `hierarchy-security` ships in
`@objectstack/security-enterprise` via `plugins[]`, `ai-seat` and `governance`
are cloud-runtime only (platform-capabilities.ts:57-66). 20 + 5 + 3 = the 28
tokens in `PLATFORM_CAPABILITY_TOKENS`, counted from the frozen array rather
than asserted.
The `triggers` entry's own comment carries a rule an author needs — schedule
triggers run on the job service, "so pair `triggers` with `job`" — so that is
now both a row note and the fifth rule: `triggers` alone arms record-change
triggers, and autolaunched scheduled flows stay silent without `job`.
SKILL.md 12696 -> 12871 tokens, ceiling 12984 unchanged and not raised; the
growth is paid from the headroom this flight's own deletions created.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…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-litantos-litant changed the title skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,778 tokens)skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens)Sep 2, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 06:53
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to a conflict with the base branch Sep 2, 2026
Nine sibling skills flights landed on main after this branch's base. Both
conflicts fell inside the BEGIN/END GENERATED: skills region of the two mixed
generated files (skills/README.md, content/docs/ai/skills-reference.mdx);
resolved by clearing the markers in place — preserving main's text-merged prose
outside the region — and regenerating both wholesale with
`pnpm --filter @objectstack/spec gen:skill-docs` on the merged tree.
scripts/check-skills-token-ratchet.mjs auto-merged (each flight edited its own
package's ceiling rows). No behaviour or content change to the platform package.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01489YWhZEoHT9oXshiyywQy
@claude
claudeBot requested a review from os-zhuangSeptember 2, 2026 14:54
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/xlskip-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(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens) - #14351

Merged
os-zhuang merged 7 commits into
mainfrom
claude/issue-14299-skills-platform-optimization
Sep 2, 2026
Merged

skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens)#14351
os-zhuang merged 7 commits into
mainfrom
claude/issue-14299-skills-platform-optimization

Conversation

@os-litant

@os-litantos-litant commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Part of #14299

Skills catalog optimization flight for skills/objectstack-platform (program #14292, maintainer mandate 2026-09-02 「审核所有的 skills,进行全面的优化。」). The 50-finding audit record is posted verbatim on the card. Governed face — stays draft; needs:contract-review on both carriers.

Why Part of and not a closing keyword: only the implementable half of the card landed. PLAT-H-01 is deferred to decision card #14296 item 2 and PLAT-G-02 to the catalog follow-up below, so merging this must not close the card while its deferred half is still undecided. The card stays open; pm:dispatched is stripped by hand at merge.

Per-file token delta

Token unit is the ratchet's own: ceil(utf8 bytes / 4).

Filebeforeafterceilingnote
SKILL.md129841287112984−113; every addition paid in-file. Review round 1 spent 175 of the freed headroom on the corrected requires: table
references/plugin-hooks.md262824132628−215; absorbed the deleted pointer's DO/DON'T, plus the cross-flight link repair
rules/plugin-lifecycle.md240417772408−627
rules/service-registry.md232917542331−575
rules/bootstrap-patterns.md1093deletedrow droppedorphan, zero inbound links
rules/plugin-hooks-events.md985deletedrow droppedself-declared pointer that restated its target
evals/README.md514514514untouched — DEFERRED per #14296 item 2
references/_index.md13441344generateduntouched

Package 24,281 → 20,673 = −3,608 (−14.9%). Bundle total 187,854 → 184,246. No ceiling was raised; no file grew; scripts/check-skills-token-ratchet.mjs was touched only to drop the two deleted files' rows.

The audit's package total of 24,278 is 3 tokens off — the measured base is 24,281 (sum of the eight rows above).

Why −3,608 and not the projected −5,970

Four of the projected reductions were withdrawn by evidence or by ruling, not skipped:

The five funded additions also cost more than the projected +355, because they were written against the measured facts (the requires: table carries all 20 provider-backed tokens plus the five rules that change what an author writes) rather than against the projection.

Per-item: 落点 | before | after

Deleted files

id落点beforeafter
PLAT-B-01rules/bootstrap-patterns.md1,093 tokens with zero inbound links repo-wide — the only mention of its path was its own ceiling row. Content already carried by SKILL.md (driver table, HTTP-layer table, the "no driver: key, refused at load" block, manifest required fields); its own last line pointed back at SKILL.mddeleted, with its ceiling row
PLAT-B-02rules/plugin-hooks-events.md + SKILL.md:717,865The file opened "This document is a compact pointer. Complete documentation lives in the canonical reference" and then reproduced it. SKILL.md linked only the pointer, so the 2,628-token canonical file sat two hops from the entry filedeleted; SKILL.md links references/plugin-hooks.md directly at both sites. Path unchanged on purposeskills/objectstack-data/rules/hooks.md:202 links to it across packages; verified still resolving

Checked before deleting the pointer: it carried no fact absent from the canonical reference or SKILL.md. Its one non-hooks item ("no circular dependencies between plugins, both kernels throw") is already the Dependency resolution row of the ObjectKernel-vs-LiteKernel table.

references/plugin-hooks.md

id落点beforeafter
PLAT-D-04:312-3277-item "Best Practices", every item restating a span of the same filereplaced by the compact DO/DON'T folded in from the deleted pointer
PLAT-D-05:238-251"Hook Naming Conventions", 4 good / 2 bad names; the convention was already given at :80-82 and demonstrated at :225-232deleted; its only new rule (lower-case) folded into the Custom Hooks convention line
PLAT-D-06:252-311two near-identical 25-line vitest blocks; the second differed only by asserting receivedData instead of hookCalledsecond block deleted

rules/plugin-lifecycle.md and rules/service-registry.md

id落点beforeafter
PLAT-B-07service-registry.md:145-158the same table as SKILL.md:1008-1024 with inverted columns and only 6 of its 13 rows; both then repeated "the REST plugin registers no service"one table, in SKILL.md; the rules file points at it
PLAT-D-03service-registry.md:270-319"Service Naming Conventions" (generic: "use descriptive names", "avoid abbreviations") + a test block asserting only toBeDefined()/toThrow() + a 10-item Best Practices restating the file's own sectionsdeleted
PLAT-D-08plugin-lifecycle.md:201-230the same ❌/✅ lesson as service-registry.md:193-223, differing only in names, closing on the same null-placeholder paragraphreplaced by the rule plus a link to the one worked pair
PLAT-D-02plugin-lifecycle.md:293-34010-item Best Practices (1-7 restate the file's own Phase headings; 8-10 generic: "version your plugin", "use reverse domain names") + two vitest blocks asserting only toBeDefined()/isConnected()deleted
PLAT-C-05plugin-lifecycle.md:110-113, SKILL.md:944-948the data:* boundary was stated five times in-packagein-package statements down to three; SKILL.md keeps exactly one (the one explaining the silent registration), per the anchor ruling; canonical statement stays in references/plugin-hooks.md

SKILL.md — structure

id落点beforeafter
PLAT-B-05section order1,441 tokens preceded defineStack() — the core construct sat 12% down the filedefineStack() (with the Manifest Reference it needs) is the first section after the title
PLAT-B-03:39-49, :699-708"When to Use This Skill" appeared twice, 650 lines apart, both restating the frontmatterboth deleted — a loaded package is already selected
PLAT-B-06:25-35narrated the package's own edit history ("the original 'quickstart' skill", "which is why they live in one skill")one sentence naming the two concerns
PLAT-D-07:142-158"CRM Blueprint": rows 2-3 restated the directory tree 18 lines above; rows 5-6 pointed at data / i18n territorydeleted; its only platform-specific row (requires:) is now taught properly under the Boot Sequence
PLAT-D-01:735-758ASCII "Decision Guide" restating the table two lines above; its gloss changed no branchdeleted, table survives
PLAT-B-04:1277-1279"see Health Monitoring earlier in this skill" — that section documents an in-process TS API and contains no HTTP routecross-reference dropped

SKILL.md — truthfulness

id落点beforeafter
PLAT-F-06:347-381driver-as-a-plugins:-entry taught as the canonical bootstrap. Zero example configs do it: app-showcase and the blank template list connector plugins, app-crm and app-todo have no plugins: key, and the CLI wires the driver itself from the resolved DB URL (serve.ts:2687-2745)selection table kept; the code reframed as embedding/tests only, with "pick a driver by setting the DB URL, not by writing code"
PLAT-F-05:498-522composeStacks() had a section plus a 3-row strategies table and zero usages outside packages/spec and its own testsreduced to a pointer at stack.zod.ts. Live surface with zero measured usage ⇒ one row, never delete the last mention
PLAT-C-01:548-576taught a raw data: [{ object: 'task', … }] literal — writing object: by hand, which objectstack-data/SKILL.md:1036 forbids verbatim ("Auto-set from objectDef.name — never write manually"); 24 real defineSeed( sites, 0 raw literalsliteral deleted, defineSeed() pointer added, mode table kept (see premise_false) and given the ⚠️ Data-loss flag on replace it was missing
PLAT-C-02:626-663re-taught field types in a shape 0 of 7 real object files use (export default {} vs ObjectSchema.create({…}))one line pointing at objectstack-data and the scaffolder's own note.object.ts
PLAT-G-01:303,319,322-323,1035five spans used the retired v5.0 word for the runtime workspace ("project runtime", "Project revisions", "isolated project kernel") against skills/README.md:88 and the os environments CLI surfaceall five now environment. Uses of "project" for the local source tree left alone — those are correct
imprecision:79-80the blank template "ships One example object, in-memory driver, Hono server" — the template config has neither; its plugins: array holds three connector executors and both arrive from CLI auto-registrationstates what is in the file, and that the driver and server come from the CLI
PLAT-A-01:5,9-10,20 and the section headingfrontmatter sold "drivers, adapters" while :394-397 answers "There are no@objectstack/adapter-* packages" — promise and truth 385 lines apartdescription and heading now name the Hono HTTP layer
PLAT-G-03:307-310 vs :1109the os / objectstack alias was declared 800 lines after first usestated at first use
PLAT-C-04:1299a 60-token restatement of the very rule it delegates to objectstack-datasymptom plus the one-line cause

SKILL.md — examples that could not compile

id落点beforeafter
PLAT-E-01:527-542"Host Pattern" read as a complete config file but had ≥4 errors on paste: defineStack and SqlDriver used un-imported, CrmApp/TodoApp undefined, and new SqlDriver({ ... }) is TS1109folded into the Multi-App Composition prose; no un-compilable block
PLAT-E-02:1059-1073typed the literal as a Plugin intersection then read this.pool.query(...) (TS2339) and err.message on a catch binding (TS18046); PluginHealthStatus never importedthe opt-in contract in prose plus the three real kernel call sites
PLAT-E-03:954-969kernel.getService with a type argument naming a non-exported class from a different fence (TS2304)type argument dropped
PLAT-E-04:296-298defineStack({ ... }, { strict: false }) — TS1109 by constructiondefineStack(config, { strict: false })

The funded additions — each paid by a deletion in the same file

id落点beforeafter
PLAT-F-01Manifest Referencemanifest.engines: { protocol: '^17' } has 4 real usages including every project the scaffolder emits, and grep engines skills/objectstack-platform/ returned 0one manifest row plus why the runtime checks it before it loads anything
PLAT-F-02Boot Sequencerequires: [...] decides which service plugins boot; taught as one CRM-blueprint cell and one bare word, while the Boot Sequence narrated a fixed auto-register list and never said requires: drives itall 20 provider-backed tokens against their real pkg values, the two other resolution mechanisms kept separate from them, and five rules that change what you write: precedence, declaring-is-a-demand (declared-but-absent is a hard boot error, auto-injected-but-absent stays best-effort), auth implies email, keep automation whenever plugins: lists a connector, and pair triggers with job
PLAT-F-03Boot Sequencethe onEnable export — the seam where an app binds runtime code — has 4 real sites and was documented only in objectstack-dataits own subsection with the AppPlugin invocation and a worked export
PLAT-F-04Part 3plugin authoring stopped at kernel.use(plugin) with no path to a distributable plugin; the ADR-0025 §3.4 pipeline was mentioned nowhere in skills/a 3-row `os plugin build
PLAT-F-07kernel decisionthe guide offered two answers and routed serverless/edge to LiteKernel, while the repo's own example for that shape uses neither kernela third branch naming @objectstack/objectql/core and examples/embed-objectql (ADR-0076)
PLAT-A-02frontmatterthe description never named capabilities / requires:, the key that decides which service plugins bootone clause added, paid by A-01

Facts re-read against source before writing, per the card's assumption 5: blank/objectstack.config.ts:22,30; serve.tsCAPABILITY_PROVIDERS and the auth ⇒ email implication at :2281-2321; onEnable at app-showcase :283, app-crm :127, app-todo :33; PLATFORM_CAPABILITY_TOKENS in packages/spec/src/kernel/platform-capabilities.ts.

CAPABILITY_PROVIDERS holds 20 entries — the audit's "~20" was right. An earlier revision of this PR claimed 14 and offered that as a correction to the audit; that claim was itself wrong and is retracted. See Review round 1.

premise_false

  • PLAT-E-05 — premise false; not implemented. The audit proposed adding an os:check marker to the Complete Plugin Example so plugin/kernel examples would finally be type-checked. Measured: the gate's "skills + docs" surface resolves from packages/spec only (SURFACES in packages/spec/scripts/check-skill-examples.ts, resolutionDir: SPEC_DIR, selfPackages: [SPEC_DIR]), and @objectstack/core is not a dependency of packages/spec — that package's node_modules has no @objectstack scope at all. Marking the block produced skills/objectstack-platform/SKILL.md:804:44 error TS2307: Cannot find module '@objectstack/core'. Every plugin/kernel example in this package imports Plugin / PluginContext / ObjectKernel / LiteKernel from there, so no such example can be gated without a new SURFACES entry — another package, which this flight may not edit. The marker was reverted; check:skill-examples is green with 258 marked blocks. Filed as follow-up below.
  • PLAT-C-01 — premise partly false. "DELETE the mode table → one pointer line" is not available: check:skill-identifier-liveness registers ## Seed Data as exhaustive over SeedMode, and deleting the table turned five live members (insert, update, upsert, replace, ignore) into capabilities no AI author reading the catalog can reach. The gate caught it. Fixed the author's way — the table stays, and gained the ⚠️ Data-loss flag on replace the audit noted was missing. The shrink-only gap ledger is maintainer-only and was not touched.
  • PLAT-C-03 — not applied, by ruling. The card's ANCHOR RULINGS keep SKILL.md:59-70 because the pm-dispatch flight points there. The overlap the audit identified is real but is the anchor's to settle.
  • PLAT-G-02 — not applied, by ruling. Moving references/plugin-hooks.md to rules/ is exactly what the card forbids (the path is pinned stable for objectstack-data's inbound link). The catalog-wide drift it names is real and is listed as follow-up.

Card assumptions verified rather than assumed: (1) skills/objectstack-platform/** is byte-identical at a59f78d, d63c8a25 and this branch's actual base 909a4417git diff --stat empty for both; note origin/main had moved past the d63c8a25 named in the card. (2) bootstrap-patterns has zero inbound links, with plugin-lifecycle as a positive control that hits abundantly. (3) check:skill-docsis the drift gate, it is in the derived family, and the frontmatter edit did force regeneration — of two files, not one (below). (4) the ratchet reds on a deleted file whose row remains — probed directly: re-adding the row gave exit 1 and "cannot read … — red, not a skip (#4690)", then the script was restored and the restore confirmed by hash match.

Files outside the card's literal list

  • skills/README.md — regenerated, as the card anticipated for a frontmatter edit.
  • content/docs/ai/skills-reference.mdxalso regenerated, because one generator writes both and check:skill-docs fails on both. Not anticipated by the card; flagged here. Both diffs are frontmatter-derived only, confined to this package's row. Not content/docs/releases/.

follow-up for packages/spec

  • Extend SURFACES in packages/spec/scripts/check-skill-examples.ts with a resolution root that can see @objectstack/core, so plugin / kernel / service examples across the catalog become type-checkable. Today 78 of this package's 80 TypeScript fences are unchecked and the two checked ones both teach data authoring — the least proprietary content in the package. This is PLAT-E-05's real blocker.

follow-up for the catalog

  • PLAT-G-02: hand-authored per-topic files live under the generated references/ directory, which skills/README.md:55-58 reserves for generated pointers. This package and objectstack-data (references/data-hooks.md) both do it — a catalog-wide placement decision, not a lone slip, and one this flight is explicitly forbidden to settle by moving the file.

Review round 1

Contract review failed one span — the requires: table added for PLAT-F-02. Three defects, all from reading a bounded slice of CAPABILITY_PROVIDERS instead of reading it to its closing brace. Fixed in 224d5d9a; the cross-flight link repair below landed in 25012189:

#defecttruth at sourcefix
1audit row named @objectstack/service-audit@objectstack/plugin-audit (AuditPlugin), serve.ts:1473-1475row corrected
2triggers row named @objectstack/service-triggers, which does not exist@objectstack/trigger-record-change (RecordChangeTriggerPlugin), extras @objectstack/trigger-schedule (ScheduleTriggerPlugin, TimeRelativeTriggerPlugin) and @objectstack/trigger-api (ApiTriggerPlugin), serve.ts:1506-1537row corrected; the entry's own comment ("so pair triggers with job") became a row note and the fifth rule
3"the remaining vocabulary … resolve the same way", and the claim that the map holds 14 entriesthe map holds 20; the other eight tokens resolve by two different mechanismstable lists all 20 against their real pkg; the eight are split into tier-gated (no map entry, opened by dedicated run() blocks per the CAPABILITY_TO_TIER docblock at serve.ts:1166-1171) and enterprise/cloud (no open-edition provider: hierarchy-security ships in @objectstack/security-enterprise via plugins[], ai-seat and governance are cloud-runtime only, platform-capabilities.ts:57-66)

20 + 5 + 3 = the 28 tokens in PLATFORM_CAPABILITY_TOKENS, counted from the frozen array rather than asserted. Defect 3 is the one worth naming plainly: the "14 entries" figure was published as a correction to the audit when the audit was right and the correction was the error — a truncated read reported as a finding.

Cross-flight link repair

references/plugin-hooks.md routed readers to objectstack-data's rules/hooks.md for per-record validation, defaults and audit trails. The data flight (PR #14427, head 061e5f4c, delivered) DELETES that file and consolidates hooks into objectstack-data/references/data-hooks.md, so the reference was repointed before it could dangle — now a real relative link, ../../objectstack-data/references/data-hooks.md, verified to resolve from references/. The old text named both the doomed rules/hooks.md and the surviving references/data-hooks.md; naming only the survivor makes the span 22 bytes shorter. git grep rules/hooks.md over this package returns nothing further, so that was the only site.

The PR title still carries the pre-patch figure (−3,778); the accurate net is −3,608. Left alone deliberately — the patch instruction was not to retitle.

Gates

Head sha 25012189. Command list derived from the real change set by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (9 paths; re-derived after regeneration added the two generated files, which pulled in 20 further docs-family gates). The full 46 were run on 15b4ac79: 45 exit 0, 1 NOT MEASURED. Review round 1 touched only SKILL.md and references/plugin-hooks.md, so the change set and therefore the derived family are unchanged; the card-named gates were re-run on 25012189 and are listed below.

The one non-green in that full run is NOT MEASURED by its own verdict text — node scripts/check-test-completeness.mjs exits 3, not 1: "PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named… the local reading for this gate is NOT MEASURED." CI tees the log and passes the path, so this branch is unreachable there. Not a finding, and not read as green.

Card-named gates on 25012189, every exit captured before any pipe, all exit 0:

gateverdict line
check-skills-token-ratchet"36 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted" — SKILL.md 12871 / 12984, plugin-hooks.md 2413 / 2628
check:skill-examples"258 marked example(s) across 100 file(s), 3 surface(s)"
check:skill-identifier-liveness"OK — Leg 1: 493 citation(s) over 46 published file(s) … Leg 2: 9 registered exhaustive section(s), 0 ledgered gap(s)" — 493, up from 491: the corrected package names are themselves live-checked citations
check:skill-docsexit 0 with no regeneration needed (round 1 touched no frontmatter)
check:skill-compatibility"11 SKILL.md file(s) reconciled against 78 workspace packages"
check:published-readme-linksexit 0 — run additionally to prove the repointed cross-package link resolves

Two gates initially reported exit 3 for missing local build prerequisites and were re-run properly rather than recorded as failures: check:doc-formula-expressions (needed @objectstack/formula built) and check:skill-examples (needed @objectstack/client-react built — it refuses rather than false-greening, #7122). Both green afterwards.

Control bytes: node scripts/check-nul-bytes.mjs green, plus a direct scan of all changed files for the wider control-byte range — no hits.

skip-changeset applies and is on the PR: this diff releases nothing from any package. skills/ is named in the changeset gate's own release-nothing enumeration (scripts/check-empty-changeset.mjs), which pins a "skills/**-only PR carrying NO changeset" as a green fixture, and scripts/check-skills-token-ratchet.mjs is a CI-internal gate script — the workflow calls that the textbook case.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

…-B-01)
`rules/bootstrap-patterns.md` had ZERO inbound links repo-wide — the only
reference to its path anywhere in the tree was its own ceiling row in
`scripts/check-skills-token-ratchet.mjs`. `SKILL.md:715-717` links only
lifecycle / service-registry / hooks-events, so nothing ever routed a reader
to it; verified with `git grep -n bootstrap-patterns` against a positive
control (`git grep -n plugin-lifecycle` hits abundantly).
Its content was already carried by SKILL.md: the driver table (:66-74 =
SKILL.md:351-357), the HTTP-layer table (:76-83 = :389-397), the "no `driver:`
key, refused at load" block plus the `defineStack validation failed` sample
(:7-31,87-105 = :209-234), and manifest required fields (:29-31,107-130 =
:327-339). Its own last line pointed back at SKILL.md.
1,093 tokens of the published bundle that no customer agent could reach.
The ceiling row goes with the file: the gate treats an unreadable ratcheted
path as RED, not as a skip (#4690) — verified by a controlled probe that
re-added the row (exit 1, "cannot read ... — red, not a skip"), then restored
the script and confirmed the restore by hash match.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
… the pointer file (PLAT-B-02, D-04, D-05, D-06)
`rules/plugin-hooks-events.md` opened by declaring itself "a compact pointer.
Complete documentation lives in the canonical reference" and then reproduced
that reference: the event table, the `data:*` warning, the custom-hook
convention, execution order, and a DO/DON'T list. SKILL.md linked only the
pointer, so the 2,628-token canonical file sat TWO hops from the entry file
behind 985 tokens that restated it.
SKILL.md now links `references/plugin-hooks.md` directly at both sites
(`:717` and `:865`) and the pointer file is deleted with its ceiling row.
Checked before deleting: the pointer carried no fact absent from the
canonical reference or from SKILL.md — its one non-hooks item ("no circular
dependencies between plugins, both kernels throw") is already the
`Dependency resolution` row of the ObjectKernel-vs-LiteKernel table. So the
merge is a relink plus a deletion, and the compact DO/DON'T shape it had is
what now closes the canonical file.
`references/plugin-hooks.md` PATH IS UNCHANGED on purpose:
`skills/objectstack-data/rules/hooks.md:202` links to it across packages, and
that link is verified still resolving.
Paid inside `references/plugin-hooks.md`, per the shrink-only ratchet:
- PLAT-D-04 — the 7-item "Best Practices" list, every item of which
restated a span of the same file, is replaced by the compact DO/DON'T
rules-of-thumb folded in from the deleted pointer.
- PLAT-D-05 — "Hook Naming Conventions" deleted; its only new rule
(lower-case) folded into the Custom Hooks convention line.
- PLAT-D-06 — the second of two near-identical vitest blocks deleted; it
differed only in asserting `receivedData` instead of `hookCalled`.
Token deltas: references/plugin-hooks.md 2628 -> 2418 (ceiling 2628);
SKILL.md 12984 -> 12982 (ceiling 12984 — the relinked paths are shorter than
the deleted ones); rules/plugin-hooks-events.md 985 -> deleted with its row.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…07, C-05)
`rules/service-registry.md` 2329 -> 1754 tokens (ceiling 2331):
- PLAT-B-07 — "Well-Known Service Keys" was the SAME table as
`SKILL.md:1008-1024` with the columns inverted and only 6 of its 13 rows,
and both then repeated "the REST plugin registers no service". One table
now, in SKILL.md; this file points at it.
- PLAT-D-03 — deleted "Service Naming Conventions" (generic advice: "use
descriptive names", "avoid abbreviations"), a "Testing Service
Registration" block whose only assertions were `toBeDefined()` and
`toThrow()`, and a 10-item "Best Practices" list restating this file's own
Registration Patterns section and its `null`-placeholder paragraph.
`rules/plugin-lifecycle.md` 2404 -> 1777 tokens (ceiling 2408):
- PLAT-D-08 — the ❌/✅ "getService() in init() without a declared
dependency" lesson was already in `service-registry.md:193-223`,
differing only in the names used (CachePlugin/db-pool vs
AnalyticsPlugin/objectql) and closing on the SAME paragraph about never
registering `null`. Replaced with the rule plus a link to the one worked
pair.
- PLAT-D-02 — deleted a 10-item "Best Practices" list (items 1-7 restate
this file's own Phase 1/2/3 headings; 8-10 are generic: "version your
plugin", "use reverse domain names") and a "Testing Lifecycle" section of
two vitest blocks whose only assertions were `toBeDefined()` and
`isConnected()`.
- PLAT-C-05 — dropped this file's copy of the `data:*`-boundary warning.
The boundary was stated five times in-package; the canonical statement
stays in `references/plugin-hooks.md` and SKILL.md keeps exactly one.
No content was moved to another package: each deletion either had a surviving
in-package statement or was generic advice that changed no decision.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…B/C/D/E/F/G)
Deletions and rewrites (SKILL.md 12984 -> 12696 tokens, ceiling 12984):
- PLAT-B-05 — `defineStack()` was 12% down the file behind 1,441 tokens of
preamble. It (with the Manifest Reference it needs) is now the first
section after the title.
- PLAT-B-03 — "When to Use This Skill" appeared TWICE, 650 lines apart,
both restating the frontmatter. A loaded package is already selected.
- PLAT-B-06 — the package narrated its own edit history ("the original
'quickstart' skill"). A customer agent never chose between two former
skills.
- PLAT-D-07 — the CRM Blueprint restated the directory tree 18 lines above
and pointed at data / i18n territory; only its `requires:` row was
platform-specific, and that is now taught properly (F-02).
- PLAT-D-01 — the ASCII Decision Guide restated the table two lines above.
- PLAT-F-05 — `composeStacks()` had a section plus a strategies table and
ZERO usages outside `packages/spec` and its own tests; real multi-app
composition is AppPlugin registration. Reduced to a pointer at the schema,
not deleted (live surface, zero measured usage).
- PLAT-F-06 — driver-as-a-`plugins:`-entry was taught as THE canonical
bootstrap; no example config does it and the CLI wires the driver itself
from the resolved DB URL. Reframed as embedding/tests only.
- PLAT-C-01 — seeds are objectstack-data's; the copy here taught a raw
literal writing `object:` by hand, which that skill forbids verbatim.
Now a pointer PLUS the `mode` table (see below).
- PLAT-C-02 — the example object file re-taught field types in a spelling
7 of 7 real object files do not use (`export default {}` vs
`ObjectSchema.create({...})`).
- PLAT-C-04, B-04 — a restatement of the rule it delegates, and a
cross-reference to a section that documents an in-process TS API and
contains no HTTP route.
- PLAT-C-05 — SKILL.md stated the `data:*` boundary twice; one statement
remains (the one that explains the silent registration).
- PLAT-E-01, E-02, E-03, E-04 — four blocks that could not compile:
`defineStack`/`SqlDriver` used un-imported with `CrmApp`/`TodoApp`
undefined; `this.pool` on a plain object literal plus `err.message` on a
`catch` binding; a type argument naming a non-exported class from another
fence; and `{ ... }` / `{ … }` ellipsis placeholders (TS1109).
- PLAT-G-01 — v5.0 vocabulary: the runtime workspace is `environment`, not
`project`, in all five spans (skills/README.md:88; the CLI surface is
`os environments`).
- PLAT-G-03 — the `os` / `objectstack` binary alias is now stated at first
use instead of 800 lines later.
- PLAT-A-01 — the frontmatter sold "adapters" and the body refutes it 385
lines in ("There are no `@objectstack/adapter-*` packages"). Both the
description and the section heading now name the Hono HTTP layer.
- The `blank` template's "in-memory driver, Hono server" was true of the
RUNNING APP and false of the file a reader opens: the template config has
neither; both arrive from CLI auto-registration.
Additions, each paid by a deletion in this same file:
- PLAT-F-01 — `manifest.engines.protocol`, stamped into every project
`create-objectstack` emits and carried by all three example apps, was
mentioned NOWHERE in this package. One manifest row + why it is checked
before anything loads.
- PLAT-F-02 — `requires: [...]` decides which service plugins boot and was
taught as one blueprint cell and one bare word. Now a token table plus the
four rules that change what you write: precedence, declaring-is-a-demand
(hard boot error vs best-effort), `auth` implies `email`, and keep
`automation` whenever `plugins:` lists a connector.
- PLAT-F-03 — the `onEnable` export, the seam where an app binds runtime
code, used by all three example apps and documented only in
objectstack-data.
- PLAT-F-04 — `os plugin build|sign|publish`: authoring stopped at
`kernel.use(plugin)` with no path to a distributable plugin.
- PLAT-F-07 — a third answer to the kernel question: `examples/embed-objectql`
uses NEITHER kernel (`@objectstack/objectql/core`, ADR-0076).
- PLAT-A-02 — the description now names the capability key.
Generated files regenerated because the frontmatter changed, as the drift gate
demands: `skills/README.md` AND `content/docs/ai/skills-reference.mdx` (one
generator writes both; `pnpm --filter @objectstack/spec gen:skill-docs`). Both
diffs are frontmatter-derived only.
`## Seed Data` keeps its `mode` table: `check:skill-identifier-liveness`
registers that section as exhaustive over `SeedMode`, and deleting the table
made five live members unreachable (caught by the gate, fixed the author's
way — the shrink-only gap ledger is maintainer-only and was not touched). The
table now also carries the Data-loss flag on `replace` that it was missing.
PLAT-E-05 is NOT implemented — its premise is false; see the PR body.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…al registry (review round 1)
Contract review round 1 failed the `requires:` table I added in the previous
commit. Three defects, all mine, all from reading a bounded slice of
`CAPABILITY_PROVIDERS` instead of reading it to its closing brace:
1. `audit` named `@objectstack/service-audit`. The real entry is
`@objectstack/plugin-audit` (`AuditPlugin`), serve.ts:1473-1475.
2. `triggers` named `@objectstack/service-triggers`, which does not exist. The
entry is `@objectstack/trigger-record-change` (`RecordChangeTriggerPlugin`)
with extras `@objectstack/trigger-schedule` (`ScheduleTriggerPlugin`,
`TimeRelativeTriggerPlugin`) and `@objectstack/trigger-api`
(`ApiTriggerPlugin`), serve.ts:1506-1537.
3. "the remaining vocabulary resolves the same way" was false, and so was the
claim that the map holds 14 entries. It holds TWENTY — I bounded an `awk`
range by guess and stopped at `sms`, then reported the truncation as a
correction to the audit. The audit's "~20" was right and my correction was
the error.
The table now lists all 20 provider-backed tokens against their real `pkg`
values, and the eight remaining tokens are separated into the two mechanisms
that actually resolve them: five tier-gated tokens with NO map entry, opened by
dedicated blocks in `serve.ts` `run()` (CAPABILITY_TO_TIER docblock,
serve.ts:1166-1171), and three enterprise/cloud tokens with no open-edition
provider at all — `hierarchy-security` ships in
`@objectstack/security-enterprise` via `plugins[]`, `ai-seat` and `governance`
are cloud-runtime only (platform-capabilities.ts:57-66). 20 + 5 + 3 = the 28
tokens in `PLATFORM_CAPABILITY_TOKENS`, counted from the frozen array rather
than asserted.
The `triggers` entry's own comment carries a rule an author needs — schedule
triggers run on the job service, "so pair `triggers` with `job`" — so that is
now both a row note and the fifth rule: `triggers` alone arms record-change
triggers, and autolaunched scheduled flows stay silent without `job`.
SKILL.md 12696 -> 12871 tokens, ceiling 12984 unchanged and not raised; the
growth is paid from the headroom this flight's own deletions created.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…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-litantos-litant changed the title skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,778 tokens)skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens)Sep 2, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 06:53
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to a conflict with the base branch Sep 2, 2026
Nine sibling skills flights landed on main after this branch's base. Both
conflicts fell inside the BEGIN/END GENERATED: skills region of the two mixed
generated files (skills/README.md, content/docs/ai/skills-reference.mdx);
resolved by clearing the markers in place — preserving main's text-merged prose
outside the region — and regenerating both wholesale with
`pnpm --filter @objectstack/spec gen:skill-docs` on the merged tree.
scripts/check-skills-token-ratchet.mjs auto-merged (each flight edited its own
package's ceiling rows). No behaviour or content change to the platform package.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01489YWhZEoHT9oXshiyywQy
@claude
claudeBot requested a review from os-zhuangSeptember 2, 2026 14:54
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/xlskip-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(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens) - #14351

Merged
os-zhuang merged 7 commits into
mainfrom
claude/issue-14299-skills-platform-optimization
Sep 2, 2026
Merged

skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens)#14351
os-zhuang merged 7 commits into
mainfrom
claude/issue-14299-skills-platform-optimization

Conversation

@os-litant

@os-litantos-litant commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Part of #14299

Skills catalog optimization flight for skills/objectstack-platform (program #14292, maintainer mandate 2026-09-02 「审核所有的 skills,进行全面的优化。」). The 50-finding audit record is posted verbatim on the card. Governed face — stays draft; needs:contract-review on both carriers.

Why Part of and not a closing keyword: only the implementable half of the card landed. PLAT-H-01 is deferred to decision card #14296 item 2 and PLAT-G-02 to the catalog follow-up below, so merging this must not close the card while its deferred half is still undecided. The card stays open; pm:dispatched is stripped by hand at merge.

Per-file token delta

Token unit is the ratchet's own: ceil(utf8 bytes / 4).

Filebeforeafterceilingnote
SKILL.md129841287112984−113; every addition paid in-file. Review round 1 spent 175 of the freed headroom on the corrected requires: table
references/plugin-hooks.md262824132628−215; absorbed the deleted pointer's DO/DON'T, plus the cross-flight link repair
rules/plugin-lifecycle.md240417772408−627
rules/service-registry.md232917542331−575
rules/bootstrap-patterns.md1093deletedrow droppedorphan, zero inbound links
rules/plugin-hooks-events.md985deletedrow droppedself-declared pointer that restated its target
evals/README.md514514514untouched — DEFERRED per #14296 item 2
references/_index.md13441344generateduntouched

Package 24,281 → 20,673 = −3,608 (−14.9%). Bundle total 187,854 → 184,246. No ceiling was raised; no file grew; scripts/check-skills-token-ratchet.mjs was touched only to drop the two deleted files' rows.

The audit's package total of 24,278 is 3 tokens off — the measured base is 24,281 (sum of the eight rows above).

Why −3,608 and not the projected −5,970

Four of the projected reductions were withdrawn by evidence or by ruling, not skipped:

The five funded additions also cost more than the projected +355, because they were written against the measured facts (the requires: table carries all 20 provider-backed tokens plus the five rules that change what an author writes) rather than against the projection.

Per-item: 落点 | before | after

Deleted files

id落点beforeafter
PLAT-B-01rules/bootstrap-patterns.md1,093 tokens with zero inbound links repo-wide — the only mention of its path was its own ceiling row. Content already carried by SKILL.md (driver table, HTTP-layer table, the "no driver: key, refused at load" block, manifest required fields); its own last line pointed back at SKILL.mddeleted, with its ceiling row
PLAT-B-02rules/plugin-hooks-events.md + SKILL.md:717,865The file opened "This document is a compact pointer. Complete documentation lives in the canonical reference" and then reproduced it. SKILL.md linked only the pointer, so the 2,628-token canonical file sat two hops from the entry filedeleted; SKILL.md links references/plugin-hooks.md directly at both sites. Path unchanged on purposeskills/objectstack-data/rules/hooks.md:202 links to it across packages; verified still resolving

Checked before deleting the pointer: it carried no fact absent from the canonical reference or SKILL.md. Its one non-hooks item ("no circular dependencies between plugins, both kernels throw") is already the Dependency resolution row of the ObjectKernel-vs-LiteKernel table.

references/plugin-hooks.md

id落点beforeafter
PLAT-D-04:312-3277-item "Best Practices", every item restating a span of the same filereplaced by the compact DO/DON'T folded in from the deleted pointer
PLAT-D-05:238-251"Hook Naming Conventions", 4 good / 2 bad names; the convention was already given at :80-82 and demonstrated at :225-232deleted; its only new rule (lower-case) folded into the Custom Hooks convention line
PLAT-D-06:252-311two near-identical 25-line vitest blocks; the second differed only by asserting receivedData instead of hookCalledsecond block deleted

rules/plugin-lifecycle.md and rules/service-registry.md

id落点beforeafter
PLAT-B-07service-registry.md:145-158the same table as SKILL.md:1008-1024 with inverted columns and only 6 of its 13 rows; both then repeated "the REST plugin registers no service"one table, in SKILL.md; the rules file points at it
PLAT-D-03service-registry.md:270-319"Service Naming Conventions" (generic: "use descriptive names", "avoid abbreviations") + a test block asserting only toBeDefined()/toThrow() + a 10-item Best Practices restating the file's own sectionsdeleted
PLAT-D-08plugin-lifecycle.md:201-230the same ❌/✅ lesson as service-registry.md:193-223, differing only in names, closing on the same null-placeholder paragraphreplaced by the rule plus a link to the one worked pair
PLAT-D-02plugin-lifecycle.md:293-34010-item Best Practices (1-7 restate the file's own Phase headings; 8-10 generic: "version your plugin", "use reverse domain names") + two vitest blocks asserting only toBeDefined()/isConnected()deleted
PLAT-C-05plugin-lifecycle.md:110-113, SKILL.md:944-948the data:* boundary was stated five times in-packagein-package statements down to three; SKILL.md keeps exactly one (the one explaining the silent registration), per the anchor ruling; canonical statement stays in references/plugin-hooks.md

SKILL.md — structure

id落点beforeafter
PLAT-B-05section order1,441 tokens preceded defineStack() — the core construct sat 12% down the filedefineStack() (with the Manifest Reference it needs) is the first section after the title
PLAT-B-03:39-49, :699-708"When to Use This Skill" appeared twice, 650 lines apart, both restating the frontmatterboth deleted — a loaded package is already selected
PLAT-B-06:25-35narrated the package's own edit history ("the original 'quickstart' skill", "which is why they live in one skill")one sentence naming the two concerns
PLAT-D-07:142-158"CRM Blueprint": rows 2-3 restated the directory tree 18 lines above; rows 5-6 pointed at data / i18n territorydeleted; its only platform-specific row (requires:) is now taught properly under the Boot Sequence
PLAT-D-01:735-758ASCII "Decision Guide" restating the table two lines above; its gloss changed no branchdeleted, table survives
PLAT-B-04:1277-1279"see Health Monitoring earlier in this skill" — that section documents an in-process TS API and contains no HTTP routecross-reference dropped

SKILL.md — truthfulness

id落点beforeafter
PLAT-F-06:347-381driver-as-a-plugins:-entry taught as the canonical bootstrap. Zero example configs do it: app-showcase and the blank template list connector plugins, app-crm and app-todo have no plugins: key, and the CLI wires the driver itself from the resolved DB URL (serve.ts:2687-2745)selection table kept; the code reframed as embedding/tests only, with "pick a driver by setting the DB URL, not by writing code"
PLAT-F-05:498-522composeStacks() had a section plus a 3-row strategies table and zero usages outside packages/spec and its own testsreduced to a pointer at stack.zod.ts. Live surface with zero measured usage ⇒ one row, never delete the last mention
PLAT-C-01:548-576taught a raw data: [{ object: 'task', … }] literal — writing object: by hand, which objectstack-data/SKILL.md:1036 forbids verbatim ("Auto-set from objectDef.name — never write manually"); 24 real defineSeed( sites, 0 raw literalsliteral deleted, defineSeed() pointer added, mode table kept (see premise_false) and given the ⚠️ Data-loss flag on replace it was missing
PLAT-C-02:626-663re-taught field types in a shape 0 of 7 real object files use (export default {} vs ObjectSchema.create({…}))one line pointing at objectstack-data and the scaffolder's own note.object.ts
PLAT-G-01:303,319,322-323,1035five spans used the retired v5.0 word for the runtime workspace ("project runtime", "Project revisions", "isolated project kernel") against skills/README.md:88 and the os environments CLI surfaceall five now environment. Uses of "project" for the local source tree left alone — those are correct
imprecision:79-80the blank template "ships One example object, in-memory driver, Hono server" — the template config has neither; its plugins: array holds three connector executors and both arrive from CLI auto-registrationstates what is in the file, and that the driver and server come from the CLI
PLAT-A-01:5,9-10,20 and the section headingfrontmatter sold "drivers, adapters" while :394-397 answers "There are no@objectstack/adapter-* packages" — promise and truth 385 lines apartdescription and heading now name the Hono HTTP layer
PLAT-G-03:307-310 vs :1109the os / objectstack alias was declared 800 lines after first usestated at first use
PLAT-C-04:1299a 60-token restatement of the very rule it delegates to objectstack-datasymptom plus the one-line cause

SKILL.md — examples that could not compile

id落点beforeafter
PLAT-E-01:527-542"Host Pattern" read as a complete config file but had ≥4 errors on paste: defineStack and SqlDriver used un-imported, CrmApp/TodoApp undefined, and new SqlDriver({ ... }) is TS1109folded into the Multi-App Composition prose; no un-compilable block
PLAT-E-02:1059-1073typed the literal as a Plugin intersection then read this.pool.query(...) (TS2339) and err.message on a catch binding (TS18046); PluginHealthStatus never importedthe opt-in contract in prose plus the three real kernel call sites
PLAT-E-03:954-969kernel.getService with a type argument naming a non-exported class from a different fence (TS2304)type argument dropped
PLAT-E-04:296-298defineStack({ ... }, { strict: false }) — TS1109 by constructiondefineStack(config, { strict: false })

The funded additions — each paid by a deletion in the same file

id落点beforeafter
PLAT-F-01Manifest Referencemanifest.engines: { protocol: '^17' } has 4 real usages including every project the scaffolder emits, and grep engines skills/objectstack-platform/ returned 0one manifest row plus why the runtime checks it before it loads anything
PLAT-F-02Boot Sequencerequires: [...] decides which service plugins boot; taught as one CRM-blueprint cell and one bare word, while the Boot Sequence narrated a fixed auto-register list and never said requires: drives itall 20 provider-backed tokens against their real pkg values, the two other resolution mechanisms kept separate from them, and five rules that change what you write: precedence, declaring-is-a-demand (declared-but-absent is a hard boot error, auto-injected-but-absent stays best-effort), auth implies email, keep automation whenever plugins: lists a connector, and pair triggers with job
PLAT-F-03Boot Sequencethe onEnable export — the seam where an app binds runtime code — has 4 real sites and was documented only in objectstack-dataits own subsection with the AppPlugin invocation and a worked export
PLAT-F-04Part 3plugin authoring stopped at kernel.use(plugin) with no path to a distributable plugin; the ADR-0025 §3.4 pipeline was mentioned nowhere in skills/a 3-row `os plugin build
PLAT-F-07kernel decisionthe guide offered two answers and routed serverless/edge to LiteKernel, while the repo's own example for that shape uses neither kernela third branch naming @objectstack/objectql/core and examples/embed-objectql (ADR-0076)
PLAT-A-02frontmatterthe description never named capabilities / requires:, the key that decides which service plugins bootone clause added, paid by A-01

Facts re-read against source before writing, per the card's assumption 5: blank/objectstack.config.ts:22,30; serve.tsCAPABILITY_PROVIDERS and the auth ⇒ email implication at :2281-2321; onEnable at app-showcase :283, app-crm :127, app-todo :33; PLATFORM_CAPABILITY_TOKENS in packages/spec/src/kernel/platform-capabilities.ts.

CAPABILITY_PROVIDERS holds 20 entries — the audit's "~20" was right. An earlier revision of this PR claimed 14 and offered that as a correction to the audit; that claim was itself wrong and is retracted. See Review round 1.

premise_false

  • PLAT-E-05 — premise false; not implemented. The audit proposed adding an os:check marker to the Complete Plugin Example so plugin/kernel examples would finally be type-checked. Measured: the gate's "skills + docs" surface resolves from packages/spec only (SURFACES in packages/spec/scripts/check-skill-examples.ts, resolutionDir: SPEC_DIR, selfPackages: [SPEC_DIR]), and @objectstack/core is not a dependency of packages/spec — that package's node_modules has no @objectstack scope at all. Marking the block produced skills/objectstack-platform/SKILL.md:804:44 error TS2307: Cannot find module '@objectstack/core'. Every plugin/kernel example in this package imports Plugin / PluginContext / ObjectKernel / LiteKernel from there, so no such example can be gated without a new SURFACES entry — another package, which this flight may not edit. The marker was reverted; check:skill-examples is green with 258 marked blocks. Filed as follow-up below.
  • PLAT-C-01 — premise partly false. "DELETE the mode table → one pointer line" is not available: check:skill-identifier-liveness registers ## Seed Data as exhaustive over SeedMode, and deleting the table turned five live members (insert, update, upsert, replace, ignore) into capabilities no AI author reading the catalog can reach. The gate caught it. Fixed the author's way — the table stays, and gained the ⚠️ Data-loss flag on replace the audit noted was missing. The shrink-only gap ledger is maintainer-only and was not touched.
  • PLAT-C-03 — not applied, by ruling. The card's ANCHOR RULINGS keep SKILL.md:59-70 because the pm-dispatch flight points there. The overlap the audit identified is real but is the anchor's to settle.
  • PLAT-G-02 — not applied, by ruling. Moving references/plugin-hooks.md to rules/ is exactly what the card forbids (the path is pinned stable for objectstack-data's inbound link). The catalog-wide drift it names is real and is listed as follow-up.

Card assumptions verified rather than assumed: (1) skills/objectstack-platform/** is byte-identical at a59f78d, d63c8a25 and this branch's actual base 909a4417git diff --stat empty for both; note origin/main had moved past the d63c8a25 named in the card. (2) bootstrap-patterns has zero inbound links, with plugin-lifecycle as a positive control that hits abundantly. (3) check:skill-docsis the drift gate, it is in the derived family, and the frontmatter edit did force regeneration — of two files, not one (below). (4) the ratchet reds on a deleted file whose row remains — probed directly: re-adding the row gave exit 1 and "cannot read … — red, not a skip (#4690)", then the script was restored and the restore confirmed by hash match.

Files outside the card's literal list

  • skills/README.md — regenerated, as the card anticipated for a frontmatter edit.
  • content/docs/ai/skills-reference.mdxalso regenerated, because one generator writes both and check:skill-docs fails on both. Not anticipated by the card; flagged here. Both diffs are frontmatter-derived only, confined to this package's row. Not content/docs/releases/.

follow-up for packages/spec

  • Extend SURFACES in packages/spec/scripts/check-skill-examples.ts with a resolution root that can see @objectstack/core, so plugin / kernel / service examples across the catalog become type-checkable. Today 78 of this package's 80 TypeScript fences are unchecked and the two checked ones both teach data authoring — the least proprietary content in the package. This is PLAT-E-05's real blocker.

follow-up for the catalog

  • PLAT-G-02: hand-authored per-topic files live under the generated references/ directory, which skills/README.md:55-58 reserves for generated pointers. This package and objectstack-data (references/data-hooks.md) both do it — a catalog-wide placement decision, not a lone slip, and one this flight is explicitly forbidden to settle by moving the file.

Review round 1

Contract review failed one span — the requires: table added for PLAT-F-02. Three defects, all from reading a bounded slice of CAPABILITY_PROVIDERS instead of reading it to its closing brace. Fixed in 224d5d9a; the cross-flight link repair below landed in 25012189:

#defecttruth at sourcefix
1audit row named @objectstack/service-audit@objectstack/plugin-audit (AuditPlugin), serve.ts:1473-1475row corrected
2triggers row named @objectstack/service-triggers, which does not exist@objectstack/trigger-record-change (RecordChangeTriggerPlugin), extras @objectstack/trigger-schedule (ScheduleTriggerPlugin, TimeRelativeTriggerPlugin) and @objectstack/trigger-api (ApiTriggerPlugin), serve.ts:1506-1537row corrected; the entry's own comment ("so pair triggers with job") became a row note and the fifth rule
3"the remaining vocabulary … resolve the same way", and the claim that the map holds 14 entriesthe map holds 20; the other eight tokens resolve by two different mechanismstable lists all 20 against their real pkg; the eight are split into tier-gated (no map entry, opened by dedicated run() blocks per the CAPABILITY_TO_TIER docblock at serve.ts:1166-1171) and enterprise/cloud (no open-edition provider: hierarchy-security ships in @objectstack/security-enterprise via plugins[], ai-seat and governance are cloud-runtime only, platform-capabilities.ts:57-66)

20 + 5 + 3 = the 28 tokens in PLATFORM_CAPABILITY_TOKENS, counted from the frozen array rather than asserted. Defect 3 is the one worth naming plainly: the "14 entries" figure was published as a correction to the audit when the audit was right and the correction was the error — a truncated read reported as a finding.

Cross-flight link repair

references/plugin-hooks.md routed readers to objectstack-data's rules/hooks.md for per-record validation, defaults and audit trails. The data flight (PR #14427, head 061e5f4c, delivered) DELETES that file and consolidates hooks into objectstack-data/references/data-hooks.md, so the reference was repointed before it could dangle — now a real relative link, ../../objectstack-data/references/data-hooks.md, verified to resolve from references/. The old text named both the doomed rules/hooks.md and the surviving references/data-hooks.md; naming only the survivor makes the span 22 bytes shorter. git grep rules/hooks.md over this package returns nothing further, so that was the only site.

The PR title still carries the pre-patch figure (−3,778); the accurate net is −3,608. Left alone deliberately — the patch instruction was not to retitle.

Gates

Head sha 25012189. Command list derived from the real change set by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (9 paths; re-derived after regeneration added the two generated files, which pulled in 20 further docs-family gates). The full 46 were run on 15b4ac79: 45 exit 0, 1 NOT MEASURED. Review round 1 touched only SKILL.md and references/plugin-hooks.md, so the change set and therefore the derived family are unchanged; the card-named gates were re-run on 25012189 and are listed below.

The one non-green in that full run is NOT MEASURED by its own verdict text — node scripts/check-test-completeness.mjs exits 3, not 1: "PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named… the local reading for this gate is NOT MEASURED." CI tees the log and passes the path, so this branch is unreachable there. Not a finding, and not read as green.

Card-named gates on 25012189, every exit captured before any pipe, all exit 0:

gateverdict line
check-skills-token-ratchet"36 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted" — SKILL.md 12871 / 12984, plugin-hooks.md 2413 / 2628
check:skill-examples"258 marked example(s) across 100 file(s), 3 surface(s)"
check:skill-identifier-liveness"OK — Leg 1: 493 citation(s) over 46 published file(s) … Leg 2: 9 registered exhaustive section(s), 0 ledgered gap(s)" — 493, up from 491: the corrected package names are themselves live-checked citations
check:skill-docsexit 0 with no regeneration needed (round 1 touched no frontmatter)
check:skill-compatibility"11 SKILL.md file(s) reconciled against 78 workspace packages"
check:published-readme-linksexit 0 — run additionally to prove the repointed cross-package link resolves

Two gates initially reported exit 3 for missing local build prerequisites and were re-run properly rather than recorded as failures: check:doc-formula-expressions (needed @objectstack/formula built) and check:skill-examples (needed @objectstack/client-react built — it refuses rather than false-greening, #7122). Both green afterwards.

Control bytes: node scripts/check-nul-bytes.mjs green, plus a direct scan of all changed files for the wider control-byte range — no hits.

skip-changeset applies and is on the PR: this diff releases nothing from any package. skills/ is named in the changeset gate's own release-nothing enumeration (scripts/check-empty-changeset.mjs), which pins a "skills/**-only PR carrying NO changeset" as a green fixture, and scripts/check-skills-token-ratchet.mjs is a CI-internal gate script — the workflow calls that the textbook case.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

…-B-01)
`rules/bootstrap-patterns.md` had ZERO inbound links repo-wide — the only
reference to its path anywhere in the tree was its own ceiling row in
`scripts/check-skills-token-ratchet.mjs`. `SKILL.md:715-717` links only
lifecycle / service-registry / hooks-events, so nothing ever routed a reader
to it; verified with `git grep -n bootstrap-patterns` against a positive
control (`git grep -n plugin-lifecycle` hits abundantly).
Its content was already carried by SKILL.md: the driver table (:66-74 =
SKILL.md:351-357), the HTTP-layer table (:76-83 = :389-397), the "no `driver:`
key, refused at load" block plus the `defineStack validation failed` sample
(:7-31,87-105 = :209-234), and manifest required fields (:29-31,107-130 =
:327-339). Its own last line pointed back at SKILL.md.
1,093 tokens of the published bundle that no customer agent could reach.
The ceiling row goes with the file: the gate treats an unreadable ratcheted
path as RED, not as a skip (#4690) — verified by a controlled probe that
re-added the row (exit 1, "cannot read ... — red, not a skip"), then restored
the script and confirmed the restore by hash match.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
… the pointer file (PLAT-B-02, D-04, D-05, D-06)
`rules/plugin-hooks-events.md` opened by declaring itself "a compact pointer.
Complete documentation lives in the canonical reference" and then reproduced
that reference: the event table, the `data:*` warning, the custom-hook
convention, execution order, and a DO/DON'T list. SKILL.md linked only the
pointer, so the 2,628-token canonical file sat TWO hops from the entry file
behind 985 tokens that restated it.
SKILL.md now links `references/plugin-hooks.md` directly at both sites
(`:717` and `:865`) and the pointer file is deleted with its ceiling row.
Checked before deleting: the pointer carried no fact absent from the
canonical reference or from SKILL.md — its one non-hooks item ("no circular
dependencies between plugins, both kernels throw") is already the
`Dependency resolution` row of the ObjectKernel-vs-LiteKernel table. So the
merge is a relink plus a deletion, and the compact DO/DON'T shape it had is
what now closes the canonical file.
`references/plugin-hooks.md` PATH IS UNCHANGED on purpose:
`skills/objectstack-data/rules/hooks.md:202` links to it across packages, and
that link is verified still resolving.
Paid inside `references/plugin-hooks.md`, per the shrink-only ratchet:
- PLAT-D-04 — the 7-item "Best Practices" list, every item of which
restated a span of the same file, is replaced by the compact DO/DON'T
rules-of-thumb folded in from the deleted pointer.
- PLAT-D-05 — "Hook Naming Conventions" deleted; its only new rule
(lower-case) folded into the Custom Hooks convention line.
- PLAT-D-06 — the second of two near-identical vitest blocks deleted; it
differed only in asserting `receivedData` instead of `hookCalled`.
Token deltas: references/plugin-hooks.md 2628 -> 2418 (ceiling 2628);
SKILL.md 12984 -> 12982 (ceiling 12984 — the relinked paths are shorter than
the deleted ones); rules/plugin-hooks-events.md 985 -> deleted with its row.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…07, C-05)
`rules/service-registry.md` 2329 -> 1754 tokens (ceiling 2331):
- PLAT-B-07 — "Well-Known Service Keys" was the SAME table as
`SKILL.md:1008-1024` with the columns inverted and only 6 of its 13 rows,
and both then repeated "the REST plugin registers no service". One table
now, in SKILL.md; this file points at it.
- PLAT-D-03 — deleted "Service Naming Conventions" (generic advice: "use
descriptive names", "avoid abbreviations"), a "Testing Service
Registration" block whose only assertions were `toBeDefined()` and
`toThrow()`, and a 10-item "Best Practices" list restating this file's own
Registration Patterns section and its `null`-placeholder paragraph.
`rules/plugin-lifecycle.md` 2404 -> 1777 tokens (ceiling 2408):
- PLAT-D-08 — the ❌/✅ "getService() in init() without a declared
dependency" lesson was already in `service-registry.md:193-223`,
differing only in the names used (CachePlugin/db-pool vs
AnalyticsPlugin/objectql) and closing on the SAME paragraph about never
registering `null`. Replaced with the rule plus a link to the one worked
pair.
- PLAT-D-02 — deleted a 10-item "Best Practices" list (items 1-7 restate
this file's own Phase 1/2/3 headings; 8-10 are generic: "version your
plugin", "use reverse domain names") and a "Testing Lifecycle" section of
two vitest blocks whose only assertions were `toBeDefined()` and
`isConnected()`.
- PLAT-C-05 — dropped this file's copy of the `data:*`-boundary warning.
The boundary was stated five times in-package; the canonical statement
stays in `references/plugin-hooks.md` and SKILL.md keeps exactly one.
No content was moved to another package: each deletion either had a surviving
in-package statement or was generic advice that changed no decision.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…B/C/D/E/F/G)
Deletions and rewrites (SKILL.md 12984 -> 12696 tokens, ceiling 12984):
- PLAT-B-05 — `defineStack()` was 12% down the file behind 1,441 tokens of
preamble. It (with the Manifest Reference it needs) is now the first
section after the title.
- PLAT-B-03 — "When to Use This Skill" appeared TWICE, 650 lines apart,
both restating the frontmatter. A loaded package is already selected.
- PLAT-B-06 — the package narrated its own edit history ("the original
'quickstart' skill"). A customer agent never chose between two former
skills.
- PLAT-D-07 — the CRM Blueprint restated the directory tree 18 lines above
and pointed at data / i18n territory; only its `requires:` row was
platform-specific, and that is now taught properly (F-02).
- PLAT-D-01 — the ASCII Decision Guide restated the table two lines above.
- PLAT-F-05 — `composeStacks()` had a section plus a strategies table and
ZERO usages outside `packages/spec` and its own tests; real multi-app
composition is AppPlugin registration. Reduced to a pointer at the schema,
not deleted (live surface, zero measured usage).
- PLAT-F-06 — driver-as-a-`plugins:`-entry was taught as THE canonical
bootstrap; no example config does it and the CLI wires the driver itself
from the resolved DB URL. Reframed as embedding/tests only.
- PLAT-C-01 — seeds are objectstack-data's; the copy here taught a raw
literal writing `object:` by hand, which that skill forbids verbatim.
Now a pointer PLUS the `mode` table (see below).
- PLAT-C-02 — the example object file re-taught field types in a spelling
7 of 7 real object files do not use (`export default {}` vs
`ObjectSchema.create({...})`).
- PLAT-C-04, B-04 — a restatement of the rule it delegates, and a
cross-reference to a section that documents an in-process TS API and
contains no HTTP route.
- PLAT-C-05 — SKILL.md stated the `data:*` boundary twice; one statement
remains (the one that explains the silent registration).
- PLAT-E-01, E-02, E-03, E-04 — four blocks that could not compile:
`defineStack`/`SqlDriver` used un-imported with `CrmApp`/`TodoApp`
undefined; `this.pool` on a plain object literal plus `err.message` on a
`catch` binding; a type argument naming a non-exported class from another
fence; and `{ ... }` / `{ … }` ellipsis placeholders (TS1109).
- PLAT-G-01 — v5.0 vocabulary: the runtime workspace is `environment`, not
`project`, in all five spans (skills/README.md:88; the CLI surface is
`os environments`).
- PLAT-G-03 — the `os` / `objectstack` binary alias is now stated at first
use instead of 800 lines later.
- PLAT-A-01 — the frontmatter sold "adapters" and the body refutes it 385
lines in ("There are no `@objectstack/adapter-*` packages"). Both the
description and the section heading now name the Hono HTTP layer.
- The `blank` template's "in-memory driver, Hono server" was true of the
RUNNING APP and false of the file a reader opens: the template config has
neither; both arrive from CLI auto-registration.
Additions, each paid by a deletion in this same file:
- PLAT-F-01 — `manifest.engines.protocol`, stamped into every project
`create-objectstack` emits and carried by all three example apps, was
mentioned NOWHERE in this package. One manifest row + why it is checked
before anything loads.
- PLAT-F-02 — `requires: [...]` decides which service plugins boot and was
taught as one blueprint cell and one bare word. Now a token table plus the
four rules that change what you write: precedence, declaring-is-a-demand
(hard boot error vs best-effort), `auth` implies `email`, and keep
`automation` whenever `plugins:` lists a connector.
- PLAT-F-03 — the `onEnable` export, the seam where an app binds runtime
code, used by all three example apps and documented only in
objectstack-data.
- PLAT-F-04 — `os plugin build|sign|publish`: authoring stopped at
`kernel.use(plugin)` with no path to a distributable plugin.
- PLAT-F-07 — a third answer to the kernel question: `examples/embed-objectql`
uses NEITHER kernel (`@objectstack/objectql/core`, ADR-0076).
- PLAT-A-02 — the description now names the capability key.
Generated files regenerated because the frontmatter changed, as the drift gate
demands: `skills/README.md` AND `content/docs/ai/skills-reference.mdx` (one
generator writes both; `pnpm --filter @objectstack/spec gen:skill-docs`). Both
diffs are frontmatter-derived only.
`## Seed Data` keeps its `mode` table: `check:skill-identifier-liveness`
registers that section as exhaustive over `SeedMode`, and deleting the table
made five live members unreachable (caught by the gate, fixed the author's
way — the shrink-only gap ledger is maintainer-only and was not touched). The
table now also carries the Data-loss flag on `replace` that it was missing.
PLAT-E-05 is NOT implemented — its premise is false; see the PR body.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…al registry (review round 1)
Contract review round 1 failed the `requires:` table I added in the previous
commit. Three defects, all mine, all from reading a bounded slice of
`CAPABILITY_PROVIDERS` instead of reading it to its closing brace:
1. `audit` named `@objectstack/service-audit`. The real entry is
`@objectstack/plugin-audit` (`AuditPlugin`), serve.ts:1473-1475.
2. `triggers` named `@objectstack/service-triggers`, which does not exist. The
entry is `@objectstack/trigger-record-change` (`RecordChangeTriggerPlugin`)
with extras `@objectstack/trigger-schedule` (`ScheduleTriggerPlugin`,
`TimeRelativeTriggerPlugin`) and `@objectstack/trigger-api`
(`ApiTriggerPlugin`), serve.ts:1506-1537.
3. "the remaining vocabulary resolves the same way" was false, and so was the
claim that the map holds 14 entries. It holds TWENTY — I bounded an `awk`
range by guess and stopped at `sms`, then reported the truncation as a
correction to the audit. The audit's "~20" was right and my correction was
the error.
The table now lists all 20 provider-backed tokens against their real `pkg`
values, and the eight remaining tokens are separated into the two mechanisms
that actually resolve them: five tier-gated tokens with NO map entry, opened by
dedicated blocks in `serve.ts` `run()` (CAPABILITY_TO_TIER docblock,
serve.ts:1166-1171), and three enterprise/cloud tokens with no open-edition
provider at all — `hierarchy-security` ships in
`@objectstack/security-enterprise` via `plugins[]`, `ai-seat` and `governance`
are cloud-runtime only (platform-capabilities.ts:57-66). 20 + 5 + 3 = the 28
tokens in `PLATFORM_CAPABILITY_TOKENS`, counted from the frozen array rather
than asserted.
The `triggers` entry's own comment carries a rule an author needs — schedule
triggers run on the job service, "so pair `triggers` with `job`" — so that is
now both a row note and the fifth rule: `triggers` alone arms record-change
triggers, and autolaunched scheduled flows stay silent without `job`.
SKILL.md 12696 -> 12871 tokens, ceiling 12984 unchanged and not raised; the
growth is paid from the headroom this flight's own deletions created.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…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-litantos-litant changed the title skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,778 tokens)skills(platform): optimization flight — orphan and pointer files removed, hooks reference linked directly, requires/engines/onEnable taught (net −3,608 tokens)Sep 2, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 06:53
@os-zhuang
os-zhuang added this pull request to the merge queueSep 2, 2026
@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to a conflict with the base branch Sep 2, 2026
Nine sibling skills flights landed on main after this branch's base. Both
conflicts fell inside the BEGIN/END GENERATED: skills region of the two mixed
generated files (skills/README.md, content/docs/ai/skills-reference.mdx);
resolved by clearing the markers in place — preserving main's text-merged prose
outside the region — and regenerating both wholesale with
`pnpm --filter @objectstack/spec gen:skill-docs` on the merged tree.
scripts/check-skills-token-ratchet.mjs auto-merged (each flight edited its own
package's ceiling rows). No behaviour or content change to the platform package.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01489YWhZEoHT9oXshiyywQy
@claude
claudeBot requested a review from os-zhuangSeptember 2, 2026 14:54
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/xlskip-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