Repository navigation
Description
epic:#27261#1 · marchtian · session_017ihL2dhraZ7BwSanQPGEAb
Filing gate: ③ out-of-scope finding of os-dev-report 6520658127 (#28032, PR #28046), measured here before filing.
Dedupe (open AND closed): "residual top-level flow not registered manifest service unclaimedTopLevel package bodies" → 0 hits; "top-level items no package body declares registered only into metadata service engine registry" → none this work (#22521 closed: the config-boot half of the residual rule for the metadata door; #14599 closed).
Reader: the epic PM (#27261), the lane that owns the engine manifest service (packages/objectql/src/plugin.ts).
type: Bug
维护者速读
- 问题: 合成栈(
composeStacks,manifest: 'preserve')里,如果某个输入带packages[]包体,又只在顶层声明了一个 flow(没有包体声明同名),开机后这个 flow 进了元数据服务,但没有进 ObjectQL 注册表,自动化引擎在开机时也没有注册它:getFlow返回空,它的触发器不会挂上。包体里声明的 flow 正常。 - 原因: ObjectQL 的
manifest服务对这类"残留"顶层项只注册对象(ADR-0130 D4)和连接器(fix(objectql): a connector a composed stack declares only on its top level, beside package bodies, lends its credential at boot #28046)。其余从注册表读取的集合(flows、permissions 等METADATA_ARRAY_KEYS)只进元数据服务。 - 影响: 只有手工构造的嵌套或混合输入会遇到,常规单栈和
last合成不受影响。边缘形状。 - 需要您做的: 无。
Measured (at PR #28046 head a5d4ed3, whose objectql registers residual objects and connectors)
A real kernel (ObjectKernel, ObjectQLPlugin over SQLite, AutomationServicePlugin) boots composeStacks([mixed, other], { manifest: 'preserve' }) through the manifest service, the way AppPlugin hands a config boot's stack to it. mixed carries packages: [{ manifest: { id: 'com.acme.orders', flows: [acme_body_flow] } }] and, on its top level only, flows: [acme_residual_flow].
- The composed stack's top level carries
acme_residual_flow; no body declares it, so it is residual (unclaimedTopLevel). ql.registry.listItems('flow')after boot:[["acme_body_flow","com.acme.orders"]]. The residual flow is absent.automation.listFlows():["acme_body_flow"].automation.getFlow('acme_residual_flow')isnull;getFlow('acme_body_flow')answers.
The automation plugin's boot pull reads ql.registry.listItems('flow') (service-automation/src/plugin.ts, the boot pull around :1536), so a residual flow never reaches it. The metadata door registers it under the stack's manifest.id (MetadataPlugin.registerUnclaimedTopLevel), so /meta lists a flow that never runs.
By reading (not measured)
The same holds for every collection in METADATA_ARRAY_KEYS (objectql/src/engine.ts) other than objects and connectors: the manifest service registers bodies through registerApp and, of the residual, only unclaimedTopLevelObjects and (with #28046) unclaimedTopLevelConnectors. Readers that take permissions from the registry (for example plugin-security's packaged-permission-set-lock.ts, ql.registry.listItems('permission')) would miss a residual permission set the same way.
Task
- Decide the shape of the fix: register the whole residual through the registration body a package's collections take (
registerMetadataCollections), under the residual rule's id, or extend the per-type registration (objects, connectors) type by type. The first is one path for every type; it also makes a residual flow, permission set or job live at boot, which is what the metadata door already reports. - A test pins the boot-time reading for a residual flow, and for one security-domain type, both directions (residual registered; a body's own unchanged).
Clause-②: decided from the diff · Metadata-protocol: none.
Activity
objectstack-fleet commentedon Oct 30, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 审批与自动化 | none | P②
Triage: p2 ·
domain:server·area:automation· 2026-10-30T10:57Z⛔ Not a claim.
packages/objectql/src/plugin.ts, not epic work.bug,pm:queue.Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL
Claim: PM loop · 2026-10-30T11:33Z · triage first touch 6521012414
Session:
session_016WV4cyVfkboDHh1cixMUJn(card thread; seatsession_016WV4d1Np3hU7RQnA13YZcL)Account:
os-elon-muskBranch:
claude/project-thread-i1zxkwWorktree:
objectstack-issue-28048Domain:
domain:serverSeat:
domain:server#4File surface:
packages/objectql/src/plugin.ts(the manifest service registers a composed stack's residual top-level flows with the engine, as it does residual objects and connectors), its tests, one boot pin,.changeset/*; ⛔ notpackages/objectql/src/engine.ts(hot file #25522), nopackages/spec, no governed pathContainer & model:
M,mode:thread,model: default (TIER_DEFAULT),effort: high; contract review owed if the diff widens what boots (a flow that was silently dropped now registers) — the dev reports the armClause-②: yes (widening) — provisional: a declared top-level flow that never registered now registers; the dev confirms the arm from the diff
Metadata-protocol: none
Responsibility: a flow a composed stack declares only on its top level, beside package bodies, is never registered — a silent drop; the platform path that covers it is the manifest service registering residual top-level flows like residual objects and connectors; reached by every composed stack that declares a flow at its top level.
Thread-read: 6521012414
Premise: holds (card at
origin/mainc1b52de2; triage places the fix inpackages/objectql/src/plugin.ts)Serial constraints cleared: no open PR touches
packages/objectql/src/plugin.ts.objectstack-fleet commentedon Oct 30, 2026
domain:server#4 · os-elon-musk · session_016WV4cyVfkboDHh1cixMUJn
os-dev-report
{ "issue": 28048, "status": "done", "branch": "claude/project-thread-i1zxkw", "pr": "https://github.com/objectstack-ai/objectstack/pull/28091", "session": "session_016WV4cyVfkboDHh1cixMUJn", "premise_still_valid": true, "summary": "The objectql manifest service now registers a composed stack's residual top-level flows (top-level flows no package body declares) into the registry, after every body and under the residual rule's id, through the same loop and stamping as residual connectors (unclaimedTopLevelConnectors generalised to unclaimedTopLevelItemsOfType(stack, 'connector' | 'flow')). The automation plugin's boot pull therefore registers the flow and it runs. engine.ts and packages/spec untouched. Head ea51ef0d.", "tests": "BEFORE on origin/main 2e955dde (new boot test against the unfixed objectql build): registry.listItems('flow') = [[acme_body_flow, com.acme.orders]]; automation.listFlows() = [acme_body_flow]; getFlow('acme_residual_flow') = null; execute -> {success:false, error:\"Flow 'acme_residual_flow' not found\"}. service-automation residual-top-level-flow-boot.test.ts: red 1/3 before (the residual case), 3/3 after (objectql rebuilt); connector-credential-residual-connector.test.ts 4/4. objectql manifest-service-residual-objects.test.ts: red 2/15 before (both residual-flow pins; flow CONTROL green), 15/15 after. Ablation on the committed head via scripts/ablation-replace.mjs ((['connector', 'flow'] as const) -> (['connector' /* ABLATION-28048 */] as const), objectql rebuilt under the mutation): engine 2 failed / 13 passed, boot 1 failed / 6 passed; restored, git diff HEAD empty, rebuilt, 3/3 green. Full suites: objectql 494 files / 9603 passed; service-automation 226 files / 2860 passed.", "gates": "dispatch-gates --commands derived 63 families on the committed head (list unchanged on re-derive); all run, exit codes captured per command. 62 exit 0 first pass; check:dual-build-cjs-loads exit 3 (no dist), exit 0 after turbo build --filter='./packages/**'. --ran: 63 derived, 63 run, 0 NOT-MEASURED (derived zero). pnpm --filter @objectstack/objectql typecheck exit 0; pnpm --filter @objectstack/service-automation typecheck exit 0; pnpm lint exit 0. CI check-runs on PR #28091: pending at report time.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "2 — mcp__github__issue_read (get, get_comments) on #28048; no write tool", "api_writes": "2 — relay pr_create (PR #28091, read-back identical 8290/8290 bytes); this os-dev-report comment via post-stamped. Plus 1 git push of claude/project-thread-i1zxkw.", "clause_2_arm": "yes (widening) — confirmed from the diff: a declared top-level flow that was silently dropped now registers and runs at boot; nothing previously accepted is refused. Contract review owed per the dispatch.", "open_questions": [], "out_of_scope_findings": [ "carrier: PR #28091 Acceptance notes · noted, not filed — the residual's other registry-read collections (permissions and the rest of METADATA_ARRAY_KEYS) are still metadata-service only; by reading, not measured. The card's Task item 2 asks for a security-domain pin; the triage ruling 6521012414 names flows only, so that half was not taken. Closing this card with Fixes #28048 leaves it untracked unless the seat files it." ] }objectstack-fleet commentedon Oct 30, 2026
domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL
ACCEPT → PR #28091 comment 6523193831 · head
ea51ef0d· 2026-10-30T12:47Z · landing sent (contract review PASS 6523113357). Closes this card; the residual's other registry-read types are #28093.objectstack-fleet commentedon Oct 30, 2026
domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL
Landed · 2026-10-30T13:09Z
ae641207(merge queue)completedbyFixes #28048State:
pm:dispatchedremoved in this stroke.