Skip to content

feat(core): narrow Plugin.type to the closed PluginType set the spec declares (#13925) - #14608

Merged
os-musk merged 5 commits into
mainfrom
claude/issue-13925-plugin-type-closed-set
Sep 2, 2026
Merged

feat(core): narrow Plugin.type to the closed PluginType set the spec declares (#13925)#14608
os-musk merged 5 commits into
mainfrom
claude/issue-13925-plugin-type-closed-set

Conversation

@os-musk

@os-musk os-musk commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Fixes #13925

Plugin.type on the published @objectstack/core surface was string while the authority — PluginSchema.type in @objectstack/spec, declared z.enum(['standard', ...CORE_PLUGIN_TYPES]) — was a closed set enforced only at parse; the TSDoc beside it carried the enumeration as prose, and prose drifted (#13762). Maintainer ruling 2026-09-01 (director batch #25, comment 5494598699, correction 5494610258): core aligns to the declared contract, the in-repo census is corrected in the same PR, no warning window, Clause-② YES.

What changed

  • packages/core/src/types.ts — new exported PluginType = 'standard' | (typeof CORE_PLUGIN_TYPES)[number], derived from the spec's constant over the published @objectstack/spec/kernel subpath (already a workspace:* dependency of core; zero new dependency edges). Plugin.type?: PluginType; the docblock points at the type instead of re-listing members.
  • packages/core/src/plugin-type-closed-set.test.ts (new) — RUNTIME parity pin: the Zod enum's options, read by walking PluginSchema.shape.type's wrapper chain (optional, default, enum), equal the union's members in declared order; every member parses; five non-members (bogus, ui-plugin, plugin, module, Standard) are refused with invalid_value at path type.
  • packages/rest/src/plugin-type-closed-set.pin.test.ts (new) — COMPILE-TIME pin on the PUBLISHED .d.ts: a non-member literal, a string-typed value and a PluginMetadata literal each carry a @ts-expect-error; positive controls: all eight members compile with no directive, and the published union is type-level equal to the spec-derived shape in both directions. Placement rationale under Deviations.
  • .changeset/core-plugin-type-closed-set.md@objectstack/core: minor with the **BREAKING** banner (launch-window convention: a breaking change ships as minor; the banner and the ADR-0087 disposition are the carriers) and adr-0087: not-required (no-migration-prescription) — a TypeScript narrowing of a runtime interface; no metadata key, spec symbol or stored representation moves, so objectstack migrate meta has nothing to rewrite; the compiler at the assignment is the channel (PR feat(spec): refuse a null comparand in the ordering positions — $gt / $gte / $lt / $lte (#14080) #14425 / feat(spec): declare the not-found arm on IDataDriver.update() and un-mask driver-memory's published update/upsert types #14434 precedent).
  • Census corrections — 41 files (40 as const initializers, one test literal), listed below.
  • content/docs/plugins/anatomy.mdx — the copied Plugin interface's type?: string; line and docblock follow the type (bounded in-place fix; see Deviations).

Measurements (PM assumptions, Zone 2)

  1. Subpath reachability — CONFIRMED. packages/spec/package.json exports["./kernel"] maps import/require (and browser) to dist/kernel/index.{mjs,js} with .d.mts/.d.ts types. Built at BASE 9c7d9d4b3, all four carry CORE_PLUGIN_TYPES (.d.mts 1, .d.ts 1, .mjs 4, .js 4 occurrences); from packages/core, import { CORE_PLUGIN_TYPES } from '@objectstack/spec/kernel' resolves in ESM and CJS to the seven-member array. The root @objectstack/spec does NOT export it (ESM import fails: "does not provide an export named 'CORE_PLUGIN_TYPES'"), so the subpath is the only value path; core already spells @objectstack/spec/kernel at 15 import sites. Both an import type (types.ts, for the derived union) and a value import (the parity test) are used.
  2. Zod gate strictness — CONFIRMED (ruling item 3 does NOT fire). On the built dist: PluginSchema.safeParse({ type: 'bogus' }) and { type: 'ui-plugin' } are REFUSED with invalid_value at path ["type"] ("expected one of standard|ui|driver|server|app|theme|agent|objectql"); standard and objectql are accepted; an absent type is accepted (the .default('standard').optional() wrapper). ManifestSchema.type (manifest.zod.ts:245, spreads the same constant) refuses bogus AND standard — its set is plugin + CORE + module/gateway/adapter, a different (package-manifest) vocabulary that does not overlap the plugin one at the edges. No .catch, .or(z.string()), .passthrough() or refinement exists on the key (wrapper chain measured: optional, default, enum). Re-measured identically on the rebuilt dist after the origin/main merge.
  3. Census instrument and result — see the table. Two instruments, both real: tsup's dts emit at build time (turbo run build --continue=always over ./packages/*, ./packages/*/*, ./examples/*^...: 71/71 green at the final tree) and the workspace typecheck CI runs (turbo run typecheck over ./packages/*, ./packages/*/*, ./apps/*, plus pnpm --filter './examples/*' run typecheck). Every hit is ONE shape: an implements Plugin class whose type = 'MEMBER' property initializer widens to string (TS2416 "Property 'type' in type 'X' is not assignable to the same property in base type 'Plugin'"), with TS2345 at that class's kernel.use() call sites as a consequence — plus three object-literal mocks in one objectql test (row 41). Zero hits on computed strings, as string casts or third-party manifests; zero production hits whose value is a non-member. The correction in every class case is as const on the initializer — the spelling three sibling services (service-datasource, service-messaging, service-automation) already used — so no annotation is added and no other line in any of those files changes.
  4. Changeset level — measured against the gates at 962914029: check-adr-0087-registration — "1 declared-breaking changeset(s), each carrying an ADR-0087 disposition" (exit 0); check-changeset-no-major — "This diff introduces no major bump" (exit 0); check-empty-changeset — "No empty-frontmatter changeset introduced by this diff (1 declaring changeset(s) added)" (exit 0). The ADR-0087 body carries no arrow rewrite, FROM/TO label or rewrite table, so the no-migration-prescription category is claimed on a body the detector reads as prescription-free.
  5. check:api-surface — not moved. It is packages/spec's script (tsx scripts/build-api-surface.ts --check) and ledgers spec's exports; packages/spec is untouched and core's exports are not ledgered by it. The published-surface pin for core lives in the rest test program instead.
  6. Clause-② — see the section below.

Census (file · compile error that named it · correction)

Instrument column: dts = tsup's dts emit during the workspace build (turbo run build --continue=always); tsc = tsc --noEmit --pretty false on the package's tsconfig.json; test-tsc = the package's tsconfig.test.json program (check:test-typecheck, EXACT per-file ratchet). Correction column: as const = the type = 'MEMBER' initializer becomes type = 'MEMBER' as const; nothing else in the file changes. The trailing TS2345s ("Argument of type 'X' is not assignable to parameter of type 'Plugin'") at the same class's kernel.use() sites clear with the same edit and are listed for completeness, not edited.

# File Compile error that named it Correction
1 packages/services/service-i18n/src/i18n-service-plugin.ts dts + tsc: (75,3) TS2416: Property 'type' in type 'I18nServicePlugin' is not assignable to the same property in base type 'Plugin' as const
2 packages/metadata/src/plugin.ts tsc: (265,5) TS2416 … 'MetadataPlugin'; consequence src/plugin-shutdown-releases-repository.test.ts(61,16) TS2345 as const
3 packages/objectql/src/plugin.ts tsc: (206,3) TS2416 … 'ObjectQLPlugin'; consequence src/kernel-factory.ts(38,20) TS2345 as const
4 packages/runtime/src/app-plugin.ts tsc: (64,5) TS2416 … 'AppPlugin' as const
5 packages/runtime/src/driver-plugin.ts tsc: (21,5) TS2416 … 'DriverPlugin' as const
6 packages/runtime/src/external-validation-plugin.ts tsc: (207,3) TS2416 … 'ExternalValidationPlugin' as const
7 packages/runtime/src/observability/observability-service-plugin.ts tsc: (74,5) TS2416 … 'ObservabilityServicePlugin' as const
8 packages/runtime/src/app-plugin-shutdown-emits-unregistered.test.ts none — outside every tsc program (runtime is TEST_DEBT; its typecheck excludes tests); pre-scan, identical shape at line 56 as const (declared under Deviations 3)
9 packages/runtime/src/external-validation-shutdown-clears-timers.test.ts none — as above, line 58 as const (Deviations 3)
10 packages/services/service-cluster/src/authz-cluster-bridge-plugin.ts tsc: (53,5) TS2416 … 'AuthzClusterBridgePlugin' as const
11 packages/services/service-cluster/src/cluster-service-plugin.ts tsc: (50,5) TS2416 … 'ClusterServicePlugin' as const
12 packages/services/service-cluster/src/metadata-cluster-bridge-plugin.ts tsc: (63,5) TS2416 … 'MetadataClusterBridgePlugin' as const
13 packages/services/service-job/src/job-service-plugin.ts tsc: (72,3) TS2416 … 'JobServicePlugin' as const
14 packages/services/service-cache/src/cache-service-plugin.ts tsc: (70,3) TS2416 … 'CacheServicePlugin' as const
15 packages/services/service-knowledge/src/knowledge-service-plugin.ts tsc: (62,3) TS2416 … 'KnowledgeServicePlugin'; consequence src/__tests__/plugin-shutdown-unsubscribes.test.ts(65,14) TS2345 as const
16 packages/services/service-knowledge/src/__tests__/plugin-shutdown-unsubscribes.test.ts tsc: (45,3) TS2416 … 'FakeRealtimePlugin'; consequence (63,14) TS2345 as const
17 packages/services/service-queue/src/queue-service-plugin.ts tsc: (52,3) TS2416 … 'QueueServicePlugin' as const
18 packages/triggers/trigger-api/src/plugin.ts dts: (50,5) TS2416 … 'ApiTriggerPlugin' as const
19 packages/plugins/plugin-hono-server/src/hono-plugin.ts dts: (229,5) TS2416 … 'HonoServerPlugin' as const
20 packages/services/service-realtime/src/realtime-service-plugin.ts dts: (54,3) TS2416 … 'RealtimeServicePlugin' as const
21 packages/plugins/plugin-pinyin-search/src/pinyin-search-plugin.ts dts: (44,3) TS2416 … 'PinyinSearchPlugin' as const
22 packages/services/service-storage/src/storage-service-plugin.ts dts: (168,3) TS2416 … 'StorageServicePlugin' as const
23 packages/plugins/plugin-audit/src/audit-plugin.ts dts: (66,3) TS2416 … 'AuditPlugin' as const
24 packages/plugins/plugin-reports/src/reports-plugin.ts dts: (48,3) TS2416 … 'ReportsServicePlugin' as const
25 packages/plugins/plugin-sharing/src/sharing-plugin.ts dts: (318,3) TS2416 … 'SharingServicePlugin' as const
26 packages/plugins/plugin-security/src/security-plugin.ts dts: (756,3) TS2416 … 'SecurityPlugin' as const
27 packages/plugins/plugin-email/src/email-plugin.ts dts: (267,3) TS2416 … 'EmailServicePlugin' as const
28 packages/triggers/trigger-record-change/src/plugin.ts dts: (34,5) TS2416 … 'RecordChangeTriggerPlugin' as const
29 packages/triggers/trigger-schedule/src/time-relative-plugin.ts dts: (37,5) TS2416 … 'TimeRelativeTriggerPlugin' as const
30 packages/plugins/plugin-auth/src/auth-plugin.ts dts: (255,3) TS2416 … 'AuthPlugin' as const
31 packages/plugins/plugin-approvals/src/approvals-plugin.ts dts: (95,3) TS2416 … 'ApprovalsServicePlugin' as const
32 packages/plugins/knowledge-memory/src/index.ts tsc + test-tsc: (210,3) TS2416 … 'KnowledgeMemoryPlugin' as const
33 packages/plugins/knowledge-ragflow/src/index.ts tsc + test-tsc: (280,3) TS2416 … 'KnowledgeRagflowPlugin' as const
34 packages/plugins/plugin-dev/src/dev-plugin.ts tsc + test-tsc: (396,3) TS2416 … 'DevPlugin' as const
35 packages/qa/http-conformance/src/node-plugin.ts tsc: (27,5) TS2416 … 'NodeServerPlugin' as const
36 packages/triggers/trigger-schedule/src/plugin.ts tsc: (38,5) TS2416 … 'ScheduleTriggerPlugin' as const
37 packages/plugins/plugin-approvals/src/plugin-shutdown-cancels-escalation-job.test.ts test-tsc: (64,3) TS2416 … 'FakeJobServicePlugin'; consequence (81,20) TS2345 as const
38 packages/plugins/plugin-email/src/plugin-shutdown-detaches-template-bridge.test.ts tsc + test-tsc: (134,5) TS2416 … 'FixturePlugin'; consequence (154,16) TS2345 as const
39 packages/plugins/plugin-reports/src/plugin-shutdown-releases-dispatcher.test.ts tsc + test-tsc: (101,3) TS2416 … 'FakeJobServicePlugin'; consequence (215,48), (230,48), (244,48) TS2345 as const
40 packages/plugins/plugin-webhooks/src/plugin-shutdown-stops-auto-enqueuer.test.ts tsc + test-tsc: (88,5) TS2416 … 'FixturePlugin'; consequence (108,16) TS2345 as const
41 packages/objectql/src/plugin.integration.test.ts test-tsc ratchet (@objectstack/objectql#typecheck): TS2322: Type '"metadata"' is not assignable to type 'PluginType | undefined' x2 (lines 323, 371) and Type '"test"' … x1 (line 137) the three kernel.use() mocks register a metadata service and nothing reads their type; neither spelling was ever a plugin type (the Zod gate refuses both), so the literal becomes the member they are: 'standard'. NOT a rejection fixture, so no cast.

Non-hits worth stating: packages/runtime/src/migration-recovery-plugin.ts:60 (readonly type = 'standard' — readonly keeps the literal type) and the three services already spelling as const compile unchanged. The three implements Plugin files origin/main touched between BASE and the merge (plugin-email, runtime/app-plugin, service-analytics/plugin.ts) carry no widened initializer on the merged tree (re-scan at 962914029: zero matches).

Clause-② self-reading

Yes. The diff narrows the accept set of a published type: Plugin.type (and PluginMetadata.type through extends) goes from string to the eight-member PluginType. Any consumer assigning a computed or string-typed value, or a literal outside the set, stops compiling. Runtime accept/reject behaviour is unchanged (the Zod gate refused such values already). needs:contract-review is hung on this PR at creation; the PR stays draft for the in-seat contract review.

Verification

Head for every reading below: 962914029 (the origin/main merge at f60ab90ae, taken after the last content commit 6a98b2118); every heavy run went through scripts/pm/os-verify-lock.sh and its VERDICT line is quoted, never a bare exit code; exit codes were captured after redirects. Wall-clock figures are shared-box seconds.

  • Dependency closure rebuilt on the merged tree before any reading: pnpm install --frozen-lockfile; pnpm --filter @objectstack/spec build then check:generated ("All 15 generated artifacts are up to date", exit 0); turbo run build --filter=./packages/* --filter=./packages/*/* --filter=./examples/*^... --continue=always --concurrency=2 — "Tasks: 71 successful, 71 total", VERDICT command-exit 0, zero error TS lines.
  • Census instrument, merged tree, downstream direction (turbo run typecheck over the filters CI uses — a superset of the prefix filter ...@objectstack/core, i.e. every downstream consumer of core): ./packages/* — "Tasks: 73 successful, 73 total", VERDICT command-exit 0; ./packages/*/* — "Tasks: 108 successful, 108 total", VERDICT command-exit 0; ./apps/* — "Tasks: 2 successful, 2 total" (TURBO_APPS_EXIT=0); pnpm --filter ./examples/* run typecheck — EXAMPLES_EXIT=0. Zero error TS lines in any slice. The same three slices were green on the pre-merge tree at 6a98b2118 after the corrections (the objectql ratchet red at d1422d081 is what named row 41).
  • pnpm --filter @objectstack/core exec vitest run --maxWorkers=2 — "Test Files 48 passed (48) · Tests 1159 passed (1159)", VERDICT command-exit 0 (the new parity file: 3/3).
  • pnpm --filter @objectstack/rest typecheck (inside the ./packages/* slice) — green; its check:test-typecheck ratchet reports the pin file at zero errors (rest's ledger is at zero, so an error arriving in any test file there is red).
  • pnpm lint (whole repo, eslint . --no-inline-config) — VERDICT command-exit 0, held 125s; no narrowing needed.
  • Gate union derived at this head with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (no path list; the tool's stderr names objectstack-ai/objectstack at 962914029 and flags the tree as 7 commits behind a moving origin/main — the shared-ref effect, not a stale checkout): 68 commands, all run — 66 exit 0 with each verdict line kept in a per-gate log, pnpm check:type-check-debt VERDICT command-exit 0 through the lock ("68/78 workspace packages type-checked, 10 in the DEBT ledger, 305 frozen raw errors" — no entry moved), and two bare node scripts/... invocations returned exit 3 (NOT MEASURED in the gates' own words): node scripts/check-test-completeness.mjs ("PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named"; only CI produces that log, so it is CI's reading), and node scripts/pm/check-half-states.mjs ("repo-scoped reads are refused — this container cannot make one repo-scoped request"; GET /repos/objectstack-ai/objectstack answers 403 from this container, the known channel shape — its self-test form pnpm check:pm-half-states is Add unified query DSL with MongoDB-style operators #52 in the union and passed). Neither is read as green or red.
  • Beyond the union, the always-runs: pnpm check:nul-bytes ("OK, scanned 7964 text files, no raw ASCII control bytes"), pnpm check:error-status-conformance ("every derivable runtime status is documented, and every documented status is reachable"), pnpm check:type-check-coverage exit 0 (the rest pin sits inside a program a typecheck script runs; no phantom directive). Every family in the PM's seed is inside the 68; the derivation added the docs and spec-docs families the anatomy.mdx edit pulls in.

Ablation (reverse verification)

Script: ablation.sh (trap-restored, absolute paths, run through the verify lock; VERDICT command-exit 0, held 82s). Precondition proven: committed tree at 962914029, git diff HEAD empty, HEAD blob of packages/core/src/types.ts = 7687b550a….

Predicted direction, stated before the run: reverting only the narrowing line turns the three @ts-expect-error directives in packages/rest/src/plugin-type-closed-set.pin.test.ts into TS2578 "Unused '@ts-expect-error' directive" — exactly 3, all TS2578, all in that file; the positive controls stay green; the core RUNTIME parity test stays green under the mutation (it reads the Zod enum, not the TS field) and is not this leg's subject.

  • Mutation leg. type?: PluginType; to type?: string; — on disk by anchored counts (PluginType-line 1 to 0, string-line 0 to 1) and by blob (f9454880b…, differs from HEAD). Core rebuilt (exit 0); node scripts/ablation-dist-preflight.mjs @objectstack/core 'type?: PluginType;' --absent — "marker absent from all 12 built files". rest tsc --noEmit -p tsconfig.test.json: exit 2, 3 errors, all in the pin file, all TS2578 at lines 42, 58 and 70 — the observed direction equals the predicted one.
  • Restore leg. git checkout HEAD -- REPO_ROOT/packages/core/src/types.ts (absolute path, HEAD named); proven by blob equality with HEAD (7687b550a… both), by git diff HEAD empty and by whole-tree git status --porcelain empty; core rebuilt (exit 0); preflight present — "marker present in 2 built files (index.d.ts, index.d.cts) … working tree clean against HEAD"; rest tsc: exit 0, 0 errors.

Deviations from the claim, declared

  1. Compile-time pin placed in packages/rest, not packages/core. The claim asked for @ts-expect-error cases "in the package's test typecheck program"; measured, @objectstack/core has no typecheck script at all (scripts: build, test, test:watch) — it is a type-check DEBT ledger entry (98 errors) and check:type-check-coverage refuses a @ts-expect-error in a package no typecheck script compiles (line 2036). The precedent packages/rest/src/plugin-metadata-retired-fields.pin.test.ts is the sanctioned placement: rest's tsconfig.test.json program is run by its typecheck script (EXACT per-file ratchet at zero) and resolves @objectstack/core to the BUILT dist/index.d.ts, so the pin guards the published contract. Amendment posted on the card (comment 5507815954).
  2. content/docs/plugins/anatomy.mdx — one code-block line plus its docblock, the copied Plugin interface. Bounded in-place fix under the four conditions (same defect class as the card — the exact block [finding] Plugin.type's TSDoc in packages/core/src/types.ts under-enumerates the value set — omits objectql, which ObjectQLPlugin actually declares #13762's PR docs(core): list objectql in Plugin.type TSDoc enumeration #13923 last edited; mechanical with the form pinned by the ruling; no other claim on the file on this lane; docs-audit gates already in the dispatched family). Declared in the same card comment.
  3. Two runtime test files corrected without a naming diagnosticpackages/runtime/src/app-plugin-shutdown-emits-unregistered.test.ts:56 and packages/runtime/src/external-validation-shutdown-clears-timers.test.ts:58. @objectstack/runtime's typecheck is tsc --noEmit on a config that excludes tests and the package is a TEST_DEBT ledger entry (206), so no program the census runs reads them; the pre-scan (implements Plugin classes with a widened type initializer) found them in the identical shape, and as const is a no-op at runtime. Declared here rather than silently left to red the moment runtime's test layer is onboarded.

Out of scope, filed

Generated by Claude Code

🤖 Generated with Claude Code

https://claude.ai/code/session_0112hMx9hjJ9BgB28X97DS68


Generated by Claude Code

…declares

`Plugin.type` was `string` on a published surface while the authority —
`PluginSchema.type` in @objectstack/spec, `z.enum(['standard',
...CORE_PLUGIN_TYPES])` — was a closed set enforced only at parse; the
TSDoc beside it carried the enumeration as prose, and prose drifted.
Maintainer ruling 2026-09-01: core aligns to the declared contract.

- `PluginType = 'standard' | (typeof CORE_PLUGIN_TYPES)[number]`, derived
  from the spec's constant over the published `@objectstack/spec/kernel`
  subpath (already a dependency; zero new edges), exported from core.
- `Plugin.type?: PluginType`; the docblock points at the type instead of
  re-listing members.
- Runtime parity pin in core: the Zod enum's options equal the union's
  members in declared order; members parse, non-members are refused with
  `invalid_value` at `type`.
- Compile-time pin in packages/rest (its test-typecheck program reads
  core's built .d.ts; core is a type-check DEBT package, so a
  `@ts-expect-error` there would be a phantom): non-member literal,
  `string`-typed value and PluginMetadata each refused; every member and
  type-level equality with the spec-derived shape as positive controls.
- Changeset: @objectstack/core minor with the BREAKING banner and the
  ADR-0087 no-migration-prescription disposition.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0112hMx9hjJ9BgB28X97DS68
…l so they satisfy PluginType

The workspace census under the narrowing (tsc per package, TS2416
"Property 'type' in type 'X' is not assignable to the same property in
base type 'Plugin'") names seventeen `implements Plugin` classes whose
`type = '<member>'` initializer widened to `string`. Each becomes
`type = '<member>' as const` — the spelling three sibling services
already use — and the downstream TS2345s at their `kernel.use()` sites
clear with it. The docs copy of the interface in
content/docs/plugins/anatomy.mdx follows the type.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0112hMx9hjJ9BgB28X97DS68
… by the build and test-typecheck programs

Second census pass (turbo build --continue=always over ./packages/*, then
tsc per package on the src and tsconfig.test.json programs): twenty-three
more `implements Plugin` classes — plugins, triggers, services, the
http-conformance node adapter, and four test fixtures compiled by their
package's `check:test-typecheck` ratchet — each TS2416 at its
`type = '<member>'` initializer. Same correction: `as const`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0112hMx9hjJ9BgB28X97DS68
… member they are

objectql's test-typecheck ratchet (EXACT, per-file) named
src/plugin.integration.test.ts: TS2322 "Type '"metadata"' is not
assignable to type 'PluginType | undefined'" (x2) and the same for
'"test"'. The three kernel.use() mocks register a `metadata` service and
nothing reads their `type`; neither spelling was ever a plugin type (the
Zod gate refuses both), so the member they are is `standard`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0112hMx9hjJ9BgB28X97DS68
@github-actions github-actions Bot added the size/m label Sep 2, 2026
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 28 package(s): @objectstack/core, @objectstack/metadata, @objectstack/objectql, @objectstack/knowledge-memory, @objectstack/knowledge-ragflow, @objectstack/plugin-approvals, @objectstack/plugin-audit, @objectstack/plugin-auth, @objectstack/plugin-dev, @objectstack/plugin-email, @objectstack/plugin-hono-server, @objectstack/plugin-pinyin-search, @objectstack/plugin-reports, @objectstack/plugin-security, @objectstack/plugin-sharing, @objectstack/http-conformance, @objectstack/runtime, @objectstack/service-cache, @objectstack/service-cluster, @objectstack/service-i18n, @objectstack/service-job, @objectstack/service-knowledge, @objectstack/service-queue, @objectstack/service-realtime, @objectstack/service-storage, @objectstack/trigger-api, @objectstack/trigger-record-change, @objectstack/trigger-schedule, touching 34 documentable anchor(s).

27 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json d15ecd85505c1d1d4af8eb53f5210a520d7d29d6.

5 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 71 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json d15ecd85505c1d1d4af8eb53f5210a520d7d29d6packageMentionDocs.

Which tree this was computed on

This run read content/docs from fb3d05ee3c91ada8f9d80e1194c078005f02c333 — the merge of head 96291402924c629f675e720b078b2af2c005f445 into base d15ecd85505c1d1d4af8eb53f5210a520d7d29d6, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin fb3d05ee3c91ada8f9d80e1194c078005f02c333 && git checkout fb3d05ee3c91ada8f9d80e1194c078005f02c333
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin d15ecd85505c1d1d4af8eb53f5210a520d7d29d6 96291402924c629f675e720b078b2af2c005f445 && git checkout -B drift-repro d15ecd85505c1d1d4af8eb53f5210a520d7d29d6 && git merge --no-ff 96291402924c629f675e720b078b2af2c005f445

node scripts/docs-audit/affected-docs.mjs --json d15ecd85505c1d1d4af8eb53f5210a520d7d29d6

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs d15ecd85505c1d1d4af8eb53f5210a520d7d29d6 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

os-musk commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

Landing provenance (engine execution seat, session session_0112hMx9hjJ9BgB28X97DS68): flipped ready at 15:03Z and armed auto-merge (squash) at 15:03:56Z on head 962914029.


Generated by Claude Code

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

Labels

Projects

None yet

2 participants