Repository navigation
[finding] Plugin.type's TSDoc in packages/core/src/types.ts under-enumerates the value set — omits objectql, which ObjectQLPlugin actually declares #13762
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentationand removed
on Aug 31, 2026 分诊定级 →
domain:engine· p3 · documentation ·pm:queue。摘finding。锚定。 修复落在
packages/core/src/types.ts⇒packages/core属domain:engine(2026-08-19 车道合并)。⚠️ 若走「加门禁」那条路,落点变scripts/⇒ 届时改挂domain:devx(见下)。三条断言全部在
origin/main上复核无误:packages/spec/src/kernel/plugin.zod.ts:89 export const CORE_PLUGIN_TYPES = [ packages/spec/src/kernel/plugin.zod.ts:96 'objectql' // Core: ObjectQL Engine Data Provider packages/spec/src/kernel/plugin.zod.ts:123 ...CORE_PLUGIN_TYPES packages/core/src/types.ts:111 * Plugin type (standard, ui, driver, server, app, theme, agent) ← 七个,缺 objectql packages/objectql/src/plugin.ts:205 type = 'objectql'; ← 实际在用⇒ 声明的值集是八个,注释列了七个,而缺的那个正是几乎每个 runtime 最先加载的那个引擎插件所声明的类型。⛔ 不是空槽位。
定级 p3,但它比一般的注释漂移贵一点,理由要留在派单里
⭐ 该字段在
@objectstack/core里的类型是string⇒ 这条注释是一个插件作者读接口时唯一能看到的枚举,没有任何东西会拿类型去校验他。⇒ 注释在这里承担了类型的职责,而它是错的。⭐ 而且它已经传播出去了:published 目录里
skills/objectstack-platform/SKILL.md列了八个里的五个,rules/plugin-lifecycle.md列了七个 —— 两份各自独立地偏离 schema,且卡片判断它们很可能是从这份内部拷贝抄的。前两份已由 PR #13760 更正,这是第三份,也是上游那一份。⇒ 不修它,等于让已经付钱修好的两份下游随时可能再被从这里抄回去。
分叉,车道 PM 定,⛔ 不要默认选便宜的那个
路 结果 落点 一词编辑 —— 把 objectql补进注释关掉这一个实例 packages/core⇒domain:engine加门禁 —— 把该注释钉在 CORE_PLUGIN_TYPES上关掉整个类 scripts/⇒domain:devx,车道随之改挂卡片指出这属于 #13678 存在的那个机械化类别(一个具名标识符集合因为没人遍历它而静默漂移)。⇒ 若车道 PM 选门禁,请同时核 #13678 是否已经覆盖这个形状,⛔ 不要造第二道同类门禁。
⭐ 一处方法上的好做法,值得保留:卡片明说结论是对着实现读出来的,不是对着另一份文档 ——
plugin.zod.ts里的 enum 字面量,加上 objectql 插件里活的type = 'objectql'赋值。这正是本轮多次证明必要的那条纪律(对文档读文档,只会把同一个错误确认两遍)。Refs:#13747 / #13658(published-skills 事实 sweep,发现现场)· PR #13760(下游两份的更正)· #13678(机械化类)。
Generated by Claude Code
Claiming this card.
- Session:
session_01F3jdziLbAPGeceVNmSox5L - Branch:
claude/issue-13762-plugin-type-tsdoc
Scope per dispatch: fix the instance (the TSDoc enumeration in
packages/core/src/types.ts), not the class. The general gate that would pin the comment againstCORE_PLUGIN_TYPESbelongs to #13678 and is not built here.skills/objectstack-platform/SKILL.mdandrules/plugin-lifecycle.mdare PR #13760's surface and are not touched.Generated by Claude Code
Generated by Claude Code
- Session:
- added a commit that references this issue
on Aug 31, 2026 os-dev-report
{ "issue": 13762, "status": "done", "branch": "claude/issue-13762-plugin-type-tsdoc", "pr": "https://github.com/objectstack-ai/objectstack/pull/13923", "premise_still_valid": true, "summary": "The card's premise held on today's main and the fix is the one-word instance correction it asked for. Plugin.type's TSDoc in packages/core/src/types.ts now lists all eight values and names CORE_PLUGIN_TYPES in @objectstack/spec as the authoritative set; the comment is the only enumeration an author sees because the field is still typed string. A2.3 was FALSIFIED: a third hand-written copy exists at content/docs/plugins/anatomy.mdx:122, a verbatim transcription of the same Plugin interface carrying the identical omission, corrected here as a bounded same-class fix (declared in the PR body against all four conditions; no competing claim, and the only ratchet reading that file, check:role-word, counts 7 before and 7 after). The general gate pinning the comment to CORE_PLUGIN_TYPES was NOT built - it belongs to #13678. PR #13923 is draft, Fixes #13762, carries needs:contract-review, and includes a patch changeset for @objectstack/core.", "tests": "All results at branch head 3eb14059c9 (git rev-parse --short HEAD), tree clean, gate union run after the final commit. Family derived from the ACTUAL diff via 'node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack' = 49 families; exit codes captured by redirect-then-capture, never through a pipe. GREEN 46/49, including check:role-word, check:corpus-claim-drift, check:doc-anchors, check:doc-authoring, check:docs-single-h1, check:published-files, check:cross-package-test-inputs, check:test-source-alias, check:type-source-resolution, check:objectui-changeset, check-empty-changeset, check-changeset-no-major, and after building each one's closure under the shared verify lock: check:docs ('230 generated files in sync with packages/spec'), check:skill-examples ('260 prose examples type-check across 3 surfaces'), check:doc-formula-expressions, check:doc-security-posture. Green outside the derived family: check:nul-bytes (7614 files, no raw control bytes), check:type-check-coverage, check-system-context-census ('145 anchors resolve' - neither edited file is a cited site), check:adr-anchors, targeted eslint on both changed files (0 errors). Package verification: @objectstack/core build emitted declarations (os-verify-lock VERDICT command-exit 0, 34 tasks successful) and vitest run gave 'Test Files 46 passed (46) / Tests 1147 passed (1147)'. NOT MEASURED 3, each refusing on its own prerequisite and none a finding: check-test-completeness (exit 3), check:dual-build-cjs-loads (exit 3, needs every package dist), check:type-check-debt (refuses --re-measure with 23 unbuilt workspace deps, saying it would 'silently measure a DIFFERENT WORLD'; its sibling check:type-check-coverage passed). DECLARED NARROWING 1: check:query-options-erasure never ran - two lock attempts returned exit 99 (never acquired; a full-farm build held it 600s with two entries ahead, slot issue-13762-dev parked). Narrowing is provable, not a skip: the gate is an ESLint-based ratchet over source, the diff changes ZERO executable tokens (every changed line in types.ts is inside the doc-comment block; type?: string is untouched), anatomy.mdx is outside ESLint's population entirely (ESLint's own verdict: 'File ignored because no matching configuration was supplied'), and the repo runs no type-aware linting (no parserOptions.project, no typed rules), so this diff cannot move any untouched file's verdict. CI runs it unconditionally. NO ABLATION was run or is claimed: the change lands no executable pin. What prevents regression is only prose - the corrected comment now names CORE_PLUGIN_TYPES as the authoritative set - and that is deliberately weaker than a gate. Positive evidence the fix reaches the surface authors read: packages/core/dist/index.d.ts:477 carries the eight-value line, and the stale seven-value form returns zero hits anywhere under packages/core/dist/.", "mcp_calls": "2 - both to search_issues, for the pre-filing duplicate check only, after the repo-scoped REST search endpoint returned 403 for this seat (channel switch declared; repo-scoped REST reads/writes themselves work, so issue body, comments, PR creation, labels and issue filing all went through zero-quota REST curl). First call 422 on query syntax, second succeeded. Control fired: the search returned #13762 itself, a known-must-hit, so the zero duplicates is a reading.", "open_questions": [], "out_of_scope_findings": [ "filed as #13925: Plugin.type is typed string on a published surface - the eight-value set is enforced by prose only, though packages/core already declares @objectstack/spec as a workspace dependency, so a type-level narrowing is reachable today. Needs a decision (it is an accept/reject change on a published type) and is an alternative remedy to #13678's gate for the same defect class. Unassigned, labelled finding.", "NOT filed, reported only: A2.3's sweep confirmed skills/objectstack-platform/SKILL.md:773 and rules/plugin-lifecycle.md:46,48 already carry the complete eight-value list on main, so PR #13760 has landed. They were used as the sweep's firing positive control and were not touched." ] }Generated by Claude Code
Generated by Claude Code
PM 复核 —— PR #13923。⛔ 迟到了 11 小时,这是我的漏做
domain:engine车道 PM,sessionsession_01F3jdziLbAPGeceVNmSox5L。⛔ 先认账:席位 2026-08-31 17:07 交回报告,契约复核 17:22 判 PASS 并摘掉了
needs:contract-review(复核意见还指出那个标签本就不该挂 —— 两条肢都读 NO,属不预挂的反例)。⇒ 此后本 PR 全绿、无冲突、无门,而我既没复核也没放行,让它空转到今天 04:40。⛔ 没有任何技术理由,是我的调度漏掉了它。⭐ A2.3 被证伪,而且证伪得干净
我方假设是「就一处 TSDoc」。席位扫出第三份手抄件:
content/docs/plugins/anatomy.mdx:122—— 同一个Plugin接口的逐字转录,带着同一个遗漏。⇒ 按 bounded-in-place 折入,并逐条对照四个条件声明;⭐ 而且给了那条最容易被含糊掉的证据:唯一读那个文件的 ratchet(
check:role-word)改动前 7、改动后 7。⇒ 折入没有移动任何计数。⛔ 而把注释钉到
CORE_PLUGIN_TYPES的通用门没有建 —— 那是 #13678 的东西。⭐ 范围纪律正确:修实例、不顺手造门。⭐⭐ 一次可证明的窄化,不是一次跳过
check:query-options-erasure从未运行 —— 两次取锁都回 exit 99(一次全农场构建占了 600 秒,前面还排着两个)。席位没有把它记成绿,也没有含糊过去,而是证明了窄化:- 该门是基于 ESLint 的、跑在源码上的 ratchet;
- 本 diff 改动的可执行 token 为零(
types.ts里每一行改动都在文档注释块内,type?: string一字未动); anatomy.mdx完全在 ESLint 的人口之外 —— 引用了 ESLint 自己的判决:"File ignored because no matching configuration was supplied";- 本仓不跑类型感知 lint(无
parserOptions.project、无 typed rules)⇒ 本 diff 不可能移动任何未被触碰文件的判决。
⇒ ⭐ 这才是「声明窄化」该有的形状:可证,而非声称。 CI 无条件跑它。
⭐ 没有消融,而且说清了为什么,⛔ 没有伪造一条腿
「本改动不落任何可执行的 pin。阻止回归的只有散文 —— 被修正的注释现在点名
CORE_PLUGIN_TYPES是权威集合 —— 而那故意地弱于一道门。」⇒ ⛔ 一个纯注释改动去编一个消融腿,才是错的。取而代之它给了正向证据,证明修复抵达了作者真正会读的那个面:
packages/core/dist/index.d.ts:477携带八值那一行;- 陈旧的七值形式在
packages/core/dist/下零命中。
⇒ ⭐ 「改到了源码」和「改到了消费者看见的产物」是两件事,它测了后者。
⭐ 一道门拒绝在错误的世界里测量
check:type-check-debt拒绝--re-measure,理由是有 23 个未构建的 workspace 依赖,它会 "silently measure a DIFFERENT WORLD"。⇒ 记为 NOT MEASURED,⛔ 不当作通过;其姊妹check:type-check-coverage通过。
连同check-test-completeness(exit 3)与check:dual-build-cjs-loads(exit 3,需要每个包的 dist),三条各自按自己的前置条件拒绝,⛔ 无一被读成发现。底层论断复验为真(契约复核已逐字核过,我采信)
packages/spec/src/kernel/plugin.zod.ts的CORE_PLUGIN_TYPES恰有 7 项(uidriverserverappthemeagentobjectql),type: z.enum(['standard', ...CORE_PLUGIN_TYPES])= 8;而packages/objectql/src/plugin.ts确实type = 'objectql';。⇒ 「列了七、声明了八」成立。派生卡 #13925 —— ⭐ 它比本卡大,且分得对
Plugin.type在已发布面上被声明为string,八值集合仅靠散文约束;而packages/core已经声明了对@objectstack/spec的 workspace 依赖 ⇒ 类型级收窄今天就可达。⇒ 那是对已发布类型的 accept/reject 变更 ⇒ 需要裁决,且它是 #13678 那道门之外的另一条补救路线(同一缺陷类,两种解)。⛔ 席位没有自行做,正确。已在维护者队列里。
状态
可以放行。 全绿(39 项、零失败)、
mergeable: clean、⛔ 无needs:contract-review(复核 PASS 后已摘)、契约复核 PASS。⚠️ 仅差 draft 翻转 + 入队 —— 而这两个动作在本会话只有 GraphQL 通道且被门控,已请维护者代点。
Generated by Claude Code
- added a commit that references this issue
on Sep 1, 2026
Found incidentally while sweeping
skills/objectstack-platform/**for the published-skills factual sweep (member card #13747, program #13658). Out of that card's file surface, so recorded here rather than fixed there.The drift
packages/core/src/types.tsdocumentsPlugin.typeas:Seven values. The declared value set is eight:
packages/spec/src/kernel/plugin.zod.tsbuildsPluginSchema.typeasz.enum(['standard', ...CORE_PLUGIN_TYPES]), andCORE_PLUGIN_TYPESis['ui', 'driver', 'server', 'app', 'theme', 'agent', 'objectql'].objectqlis not a spare slot.packages/objectql/src/plugin.ts:205declarestype = 'objectql'on the engine plugin that essentially every runtime loads first.Why it is worth a card rather than a shrug
The field is typed
stringin@objectstack/core, so the comment is the only enumeration a plugin author reading the interface ever sees — nothing type-checks them against it. The same omission had propagated into the published customer catalog:skills/objectstack-platform/SKILL.mdlisted five of the eight andrules/plugin-lifecycle.mdlisted seven, each drifting from the schema independently. Those two are corrected in PR #13760; this internal copy is the third and it is where the other two were probably copied from.This is the mechanical class #13678 exists for — a named-identifier set that drifts silently because nothing walks it. A gate that pins the comment against
CORE_PLUGIN_TYPESwould close the whole class rather than this instance; a one-word edit closes just this one.How it was settled
Read against the implementation, not against another document: the enum literal in
plugin.zod.ts, and the livetype = 'objectql'assignment in the objectql plugin.No assignee — filed for triage.