Repository navigation
fix(objectql): a flow a composed stack declares only on its top level, beside package bodies, registers with the automation engine at boot - #28091
Conversation
…, beside package bodies, registers with the automation engine at boot The manifest service registered a multi-package stack's residual objects and connectors only. The automation plugin's boot pull reads flows from the ObjectQL registry, so a residual flow was listed by the metadata service and never registered with the engine. Residual flows now take the connectors' path: after every body, under the residual rule's id, stamped on a shallow copy. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cyVfkboDHh1cixMUJn
📓 Docs Drift CheckThis PR changes 1 package(s): 6 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 20 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin e02989dd532df0026150f02e1e203a39c0d8a814 && git checkout e02989dd532df0026150f02e1e203a39c0d8a814
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 6b125a7ab7ba57b7c4f783ac1ef76b881659a96e ea51ef0d69650160126edf7da3102aad0756eab3 && git checkout -B drift-repro 6b125a7ab7ba57b7c4f783ac1ef76b881659a96e && git merge --no-ff ea51ef0d69650160126edf7da3102aad0756eab3
node scripts/docs-audit/affected-docs.mjs --json 6b125a7ab7ba57b7c4f783ac1ef76b881659a96e
|
|
domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL Contract-review-claim: session_016WV4d1Np3hU7RQnA13YZcL · head ea51ef0 · 2026-10-30T12:26Z |
|
domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL Contract reviewServed-tier: Inputs read: card #28048 (body, triage 6521012414, claim 6521637331, os-dev-report 6522793952), PR #28091 (body, file list, ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Must-fix: none. Implemented-by: VERDICT: PASS |
|
domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL 维护者速读
席位意见:ACCEPT。 席位核对Head-sha:
|
Requested by Elon · project thread
domain:server#4 · os-elon-musk · session_016WV4cyVfkboDHh1cixMUJn
Fixes #28048
Clause-②: yes (widening)
Metadata-protocol: none
维护者速读
composeStacks,manifest: 'preserve')里,某个输入带packages[]包体、又只在顶层声明了一个 flow(没有包体声明同名)时,ObjectQL 的manifest服务现在把这个“残留”flow 注册进 ObjectQL 注册表,归属栈自己的manifest.id,和残留对象、残留连接器已有的做法一样;自动化引擎开机即注册并可运行它。/meta能列出),但自动化引擎开机只从注册表拉 flow,所以getFlow返回空、执行报 “not found”,触发器不会挂上:声明了却静默不生效。packages/objectql/src/plugin.ts(unclaimedTopLevelItemsOfType与manifest服务里的残留注册循环)。pnpm --filter @objectstack/service-automation exec vitest run src/residual-top-level-flow-boot.test.ts(需先构建@objectstack/objectql),预期 3 passed:残留 flow 开机注册、归栈 id、可运行;包体 flow 只注册一次;无顶层 flow 的栈不变。What changes
packages/objectql/src/plugin.ts.unclaimedTopLevelConnectors(stack)becomesunclaimedTopLevelItemsOfType(stack, type)fortype'connector' | 'flow': the residual rule's own answer (unclaimedTopLevel,@objectstack/metadata), filtered to one type, asunclaimedTopLevelObjectsreads it for objects. Themanifestservice registers the residual's connectors and flows in one loop, in the place the connectors already registered: after every body and after the residual objects, under the residual rule's id, throughregistry.registerItem(type, …), the verb a body's connectors and flows take. Each item is stamped with the stack's version on a shallow copy, so the artifact's own entry is left as it arrived. The "emptypackages: []" warning no longer fires for a stack whose only residual is a flow. The connector path is unchanged in behaviour; its docblock moved into the shared reader.packages/services/service-automation/src/residual-top-level-flow-boot.test.ts(new). A real kernel (ObjectKernel, ObjectQLPlugin over SQLite, AutomationServicePlugin) bootscomposeStacks([mixed, other], { manifest: 'preserve' })through themanifestservice, the wayAppPluginhands a config boot's stack to it. Pins: the residual flow registers with the engine at boot, owned by the stack's id, and a run succeeds; a flow a package body declares and the top level repeats is registered once, owned by the body; CONTROL: a stack with no top-level flow registers exactly the bodies' flows.packages/objectql/src/manifest-service-residual-objects.test.ts. Three engine-half pins, mirroring the connector ones: a residual flow registers under the stack's id and version beside a body's own; it registers when the stack has no other residual item; CONTROL: a top-level flow a body repeats is the body's, registered once..changeset/28048-residual-top-level-flow-registers.md.@objectstack/objectqlpatch.Why
The measurement (before the fix, at
origin/main2e955dde)The new boot test's stack, booted against the unfixed
@objectstack/objectqlbuild:mixedcarriespackages: [{ manifest: { id: 'com.acme.orders', flows: [acme_body_flow] } }]and, on its top level only,flows: [acme_residual_flow].ql.registry.listItems('flow'):[["acme_body_flow","com.acme.orders"]]. The residual flow is absent.automation.listFlows():["acme_body_flow"].automation.getFlow('acme_residual_flow'):null;getFlow('acme_body_flow')answers.automation.execute('acme_residual_flow'):{ success: false, error: "Flow 'acme_residual_flow' not found" }.The card's premise held. The composed stack's
manifest.idhere is the last input's (com.acme.other), which is the id the residual rule names; the pin reads it off the stack rather than hard-coding it.Why flows, and why this path
The triage ruling (6521012414) places the fix in the
manifestservice and names flows. Flows are a type a boot-time reader takes from the registry alone (the automation plugin's boot pull), exactly like connectors, so they take the connectors' path. The card's wider option (register the whole residual throughregisterMetadataCollections) lives inpackages/objectql/src/engine.ts, which is a hot file held by #25522 and outside this claim's surface; it was not taken.Clause-②
yes (widening): a declared top-level flow that was silently dropped now registers and runs at boot. Nothing an author can write is refused that was accepted before, and no key is added (Metadata-protocol: none).Verification
residual-top-level-flow-boot.test.ts: red before the fix (1 of 3: the residual case), green after (3 of 3), against a rebuilt@objectstack/objectql.connector-credential-residual-connector.test.tsstays 4 of 4.manifest-service-residual-objects.test.ts: red before (2 of 15: both residual-flow pins; the flow CONTROL green), 15 passed after.scripts/ablation-replace.mjs((['connector', 'flow'] as const)→(['connector' /* ABLATION-28048 */] as const), objectql rebuilt under the mutation): engine pins 2 failed / 13 passed, boot pins 1 failed / 6 passed (the connector pins stay green); restored,git diff HEADempty, rebuilt, green.@objectstack/objectql494 files, 9603 passed;@objectstack/service-automation226 files, 2860 passed.pnpm --filter @objectstack/objectql typecheckandpnpm --filter @objectstack/service-automation typecheck: exit 0.pnpm lint: exit 0.dispatch-gates --commandsderived 63 families on the committed head; all run with exit codes recorded. One exit 3 on the first pass (check:dual-build-cjs-loads, no dist for 41 packages), measured green afterturbo run build --filter='./packages/**'.--ran: 63 derived, 63 run, 0 NOT-MEASURED (a derived zero). The head is 10 commits behindorigin/main; none of them touches the files this diff changes.Acceptance notes
manifestservice now registers the residual's objects, connectors and flows. The other registry-read collections a residual can carry (permissions and the rest ofMETADATA_ARRAY_KEYS) are still metadata-service only, as the card notes by reading. Not measured and not widened here (the triage ruling names flows); named in the os-dev-report.manifestservice. The artifact door hands the engine the same stack through the same service; it was not booted separately.Human Minimum
packages/specholds no runtime logic. (Not touched.)pnpm lintpasses.main, one pull request.packages/spectouched: not touched.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.🤖 Generated with Claude Code
https://claude.ai/code/session_016WV4cyVfkboDHh1cixMUJn