Repository navigation
cli/console: the deployment's SDUI component manifest reaches the metadata save door (page.requires enforcement, stage ①) #20542
Description
Ruled: 5902378057 · letter A + E — the channel is a kernel service under one constant key exported by @objectstack/metadata-protocol, read per publish; built together with #20312 stage ② in one domain:cli PR; this card closes not_planned, merged into #20312 stage ② (cloud#2482 follows) · 2026-09-30T01:47Z
Filed by the director seat (objectstack#12708, session_01AsCNgFBs8HCjwhyHQsFbx3) as the predecessor of #20312, per ruling 5881821895 on that card (batch #241 item 1, letter A, maintainer 「同意」): page.requires is enforced per ADR-0080 §5 in three stages, and this card is stage ①. ⛔ Not a claim.
What
No host hands the metadata save door a component manifest today, so the door cannot judge an html page's source against the deployment's components:
evaluateRuntimeAuthoringGateaccepts an optionalsduiManifest(packages/metadata-protocol/src/runtime-authoring-gate.ts:625, passed through at:697); its one call site,packages/metadata-protocol/src/protocol.ts:5148, does not pass it.- The CLI resolves a manifest for
os validate/os build/os lint(packages/cli/src/utils/sdui-manifest.ts,resolveSduiManifest): the project'ssdui.manifest.json, else@objectstack/console/dist/sdui.manifest.json.@objectstack/console'spackage.jsonexportsmap exposes only./package.json, so that fallback specifier is expected to fail Node's exports check and resolveabsent— NOT MEASURED; measure it first. os servedoes not resolve a manifest at all.
Do
- Measure the console fallback: does
createRequire(...).resolve('@objectstack/console/dist/sdui.manifest.json')succeed under the package'sexports? If not, add the subpath to@objectstack/console'sexports(one line) so the CLI's existing fallback and this card's reader both work. os serve(and the standalone host path it shares) resolves the manifest throughresolveSduiManifestand passes it intoevaluateRuntimeAuthoringGateassduiManifest.- A host that resolves no manifest prints one boot line — 「page source and
requiresare not validated at save: no SDUI manifest」 — instead of degrading silently (the [finding] os validate / compile / lint validate JSX pages at parse level only when no SDUI manifest resolves, and say nothing: the author-time JSX gate silently degrades #20113 posture on the CLI side). - Pins: the save door receives the manifest when the host has one; the boot line appears when it has none; the console fallback resolves.
Out of scope here, stages ② and ③ on #20312: compiling the page source at save, stamping requires, the load-time report.
Clause-②: no (nothing narrows until stage ②). Lane: domain:cli (the host and the console package); the save-door pass-through is a one-line change in metadata-protocol.
Activity
objectstack-fleet commentedon Sep 29, 2026
Serial: this card is dispatched after #19922 lands (same resolver, hard serial)
domain:cliexecution PM seat #6024 · sessionlocal_1d2a197c-c20e-4e90-9be8-413d4d432289· written 2026-09-29T04:33Z · ⛔ not a claim;pm:queuestaysresolveSduiManifest(packages/cli/src/utils/sdui-manifest.ts), and step 2 hasos servecall that same resolver. [finding] the CLI's@objectstack/consolemanifest fallback can never resolve:resolveSduiManifest()asks for@objectstack/console/dist/sdui.manifest.json, but the console'sexportsmap publishes only./package.json#19922 (p2bug, claimed by this seat in the same act) is the fix of exactly that fallback: resolve@objectstack/console/package.jsonfrom the CLI's location and joindist/sdui.manifest.json. Two parallel edits of one resolver would give two answers to 「where the console manifest lives」.@objectstack/consolemanifest fallback can never resolve:resolveSduiManifest()asks for@objectstack/console/dist/sdui.manifest.json, but the console'sexportsmap publishes only./package.json#19922 lands, step 1's measurement reads its fix. Anexportssubpath on@objectstack/consolemay then be unnecessary, and the dispatch re-derives that. Step 2 reuses the fixed resolver.evaluateRuntimeAuthoringGateatpackages/metadata-protocol/src/protocol.ts:5148. That is thedomain:enginepackage, so its one line is declared on the claim as a cross-domain surface.@objectstack/consolemanifest fallback can never resolve:resolveSduiManifest()asks for@objectstack/console/dist/sdui.manifest.json, but the console'sexportsmap publishes only./package.json#19922 lands,divon an html page is refused wherever a manifest resolves (ruling A on [Decision] may a kind:'html' page author intrinsic HTML tags (div, a)? The console manifest says no, 3 of 3 shipped html pages say yes, and #19922's fallback cannot go live until one side changes #20112). A host that now hands the save door a manifest inherits that refusal: stage ① must say so, or state that it passes the manifest without judging (stages ② and ③ are metadata: refuse to save or load a page whoserequiresnames a plugin that is not loaded (1 key) #20312's).objectstack-fleet commentedon Sep 29, 2026
Serial update: #19922 has landed. Step 1 of this card is done there, and dispatch waits on one file hold
domain:cliexecution PM seat #6024 · sessionlocal_1d2a197c-c20e-4e90-9be8-413d4d432289· written 2026-09-29T14:07Z · ⛔ not a claim;pm:queuestays5883700298is met. [finding] the CLI's@objectstack/consolemanifest fallback can never resolve:resolveSduiManifest()asks for@objectstack/console/dist/sdui.manifest.json, but the console'sexportsmap publishes only./package.json#19922 closedcompleted(PR fix(cli)!: the JSX page gate's console manifest fallback resolves through @objectstack/console/package.json, so a project without its own manifest gets full component checking #20589 →9b402dbaed).@objectstack/console/package.json(the one subpath itsexportspublishes), joined withdist/sdui.manifest.json(consoleSduiManifestPath,packages/cli/src/utils/sdui-manifest.ts:178onmain).@objectstack/console'sexportsis not widened. The dispatch re-measures it as H0 instead.os validate path/to/objectstack.config.tsfrom elsewhere never reads that project's manifest #20166: answered on [finding] the JSX page gate looks for the project's sdui.manifest.json in the invoker's cwd, not beside the config the command was given:os validate path/to/objectstack.config.tsfrom elsewhere never reads that project's manifest #20166 in this act. The two are not folded, and they run in parallel on disjoint files withresolveSduiManifest's signature frozen. This card'sos servecall passes the config's directory, the project-root rule [finding] the JSX page gate looks for the project's sdui.manifest.json in the invoker's cwd, not beside the config the command was given:os validate path/to/objectstack.config.tsfrom elsewhere never reads that project's manifest #20166 establishes.domain:clipackages (689 sites, 166 numbers, 95 files): the ruling C+D stage for this lane (from #20556) #20594's stage 3, in flight) rewrites comments acrosspackages/cli/src/**, including theservetests. This card is dispatched once PR docs(cli): re-anchor the dead tracker citations in packages/cli/src to the commits that decided them, and the source-hashes header at its producer #20656 lands.Clause-②: nobecause nothing narrows until stage ②. Handing the save door a manifest could change a save verdict ifevaluateRuntimeAuthoringGatealready judges page source with one. The dev measures that first, and a changed verdict is reported, not shipped.objectstack-fleet commentedon Sep 29, 2026
Claim: PM loop round 6 of the
domain:cliseat's sessionlocal_1d2a197c(batch3):priority:p2, stage ① ofpage.requiresenforcement (ruling5881821895on #20312), after #19922 landed; run in parallel with #20166 on disjoint filesSession:
local_1d2a197c-c20e-4e90-9be8-413d4d432289Account:
hotlongBranch:
claude/issue-20542-serve-sdui-manifestWorktree:
objectstack-issue-20542Domain:
domain:cliSeat:
domain:cli#1File surface:
packages/cli/src/commands/serve.ts: resolve the manifest throughresolveSduiManifest(configDir), hand it to the save door, and print one boot line when none resolves. It includes the standalone host path it shares, if that path is inpackages/cliorpackages/runtime, named in the report;packages/metadata-protocol/src/protocol.ts: the one-line pass-through ofsduiManifestintoevaluateRuntimeAuthoringGateat:5148, plus the smallest wiring that carries the host's manifest to it. This is a cross-lane touch (packages/metadata*isdomain:engine), declared here per the card's lane assignment;.changeset/20542-*.md.Read-only:
packages/cli/src/utils/sdui-manifest.ts(#20166's; its signature is frozen),packages/console/**(⛔exportsstays closed, since PR #20589 already made the fallback resolve),packages/spec/**. Stop on breach and explain in the reportContainer & model:
M,mode:subagent,model: default tier(dispatch-gates --tier: no path-derived mandate).Clause-②: no
Thread-read: 5891952823
Serial constraints cleared:
PR #20589 (#19922) landed at 9b402dbaed, and PR #20656 (#20594 stage 3, comments across packages/cli/src) landed at 6bff748bbd. The file lists of all 6 open PRs were read in this act, and none touches serve.ts or metadata-protocol/src/protocol.ts. #20166, dispatched in the same act, touches the validate / compile / lint callers onlyTaken 2026-09-29T15:27Z,
main6bff748bbd. Executes the card's steps 2 to 4. Step 1 is done by PR #20589 and is re-measured as H0.Clause-②: noholds only if handing the save door a manifest changes no save verdict (the card: nothing narrows until stage ②). The dev measures that first, and a changed verdict is reported, not shipped.objectstack-fleet commentedon Sep 29, 2026
os-dev-report
{ "issue": 20542, "status": "needs_decision", "branch": "claude/issue-20542-serve-sdui-manifest", "pr": null, "session": "local_1d2a197c-c20e-4e90-9be8-413d4d432289", "premise_still_valid": true, "summary": "Stopped before building, per the dispatch's fork clause: no existing seam carries a host fact from `os serve` to the save door, so every wiring needs a new public option on the protocol or a new service contract (options in open_questions). H0 holds: the console fallback resolves to the workspace copy's path, `os serve` resolves no manifest, and the save door is handed none. H1 holds, measured at the real save door with a trap-restored mutation: handing the gate the tracked manifest changes no verdict for a `div`, an `avatar` or a `box` html page (all 200, no issues, no advisories), because the one rule that reads the manifest, `validateJsxPages`, is CLI_ONLY, so `Clause-②: no` stands. The ruling's cloud confidence gap is now read: cloud's per-env kernels mount `createMetadataProtocolPlugin({ environmentId })` and never pass through `os serve`, so a CLI-only wiring would not reach cloud.", "tests": "All readings on BASE 6bff748bbd (origin/main at worktree creation), Node v26.7.0, macOS. Build: `pnpm turbo run build --filter=@objectstack/cli... --concurrency=2` under os-verify-lock (declared UNLOCKED mode, no flock on this host): 'Tasks: 59 successful, 59 total / Cached: 58 cached', VERDICT command-exit 0. H0: from packages/cli/dist, `consoleSduiManifestPath()` = packages/console/dist/sdui.manifest.json (the workspace copy's path; exists=false in this worktree because no console build ran); `resolveSduiManifest(examples/app-showcase)` = absent, lookedAt [the project path, that console path]; `git grep -c 'resolveSduiManifest|sdui' packages/cli/src/commands/serve.ts` exits 1 with zero hits, and the control `resolveConsolePath` in the same file hits 2; packages/runtime/src and packages/objectql/src hold zero `sduiManifest` hits; protocol.ts:5148 is the only non-test call of `evaluateRuntimeAuthoringGate`, and its argument object has 0 `sduiManifest` keys. H1 static: the gate forwards `sduiManifest` (:697) into `runRuntimeAuthoringRules` and on into the rule context, whose one reader is `validateJsxPages` (lint authoring-rules.ts:1060, `surfaces: CLI_ONLY`); `runtimeAuthoringRulesFor('page')` = [validatePresetComparands]. H1 at rule level (lint dist): three html pages whose source roots in a div, in an avatar (inside flex), or in a box, each run through runRuntimeAuthoringRules type page, with and without the tracked repo-root sdui.manifest.json (107 components; div absent, avatar absent, box present), give errors=[] advisories=[] rulesRun=1 in all 6 runs. The control leg: `validateJsxPages` with the same manifest refuses the div and the avatar pages (jsx-forbidden-tag and jsx-unknown-component on each), and without it refuses nothing. So the manifest is live, and only the runtime surface ignores it. H1 at the real save door: `os dev --fresh --seed-admin` on examples/app-crm on a random port, sign in as the seeded dev admin, then PUT /api/v1/meta/page/NAME (active) for h1_div, h1_avatar, h1_box. Without a manifest (main): 200, 200, 200 (state=active, seq=1), no issues, no advisories, GET readback 200 with the source stored. With the manifest: the mutation went through `node scripts/ablation-replace.mjs` in WRAP mode, anchor 'orgWallEnforced: this.orgWallEnforced(),' (protocol.ts:5162) 1 → 0, blob 10802c1003d9 → 4f73b2159ade. It hands the gate the manifest from an env var and logs a probe. `pnpm --filter @objectstack/metadata-protocol build` exit 0; `ablation-dist-preflight.mjs metadata-protocol H1-PROBE` marker present in 2 built files; the server log printed '[H1-PROBE] sduiManifest handed to the gate for page/h1_div: 107 components' once per save (3 of 3). Verdicts: 200, 200, 200, no issues, no advisories, identical to the leg without it. Restore: blob after restore == HEAD blob 10802c1003d9, `git diff HEAD` empty; rebuilt; preflight --absent: 'marker absent from all 24 built files', 'working tree clean against HEAD'; `git status --porcelain` 0 lines. Both servers were torn down by the script's own trap, and 0 listeners were left on either port. H2 / H3: NOT MEASURED, reason: nothing was built (fork clause).", "mcp_calls": "0", "api_writes": "1 -- POST /repos/objectstack-ai/objectstack/issues/20542/comments (this os-dev-report, via scripts/pm/post-stamped.mjs). Not REST: one `git push` of the empty branch (the write-route probe, through with-fleet.sh). No PR create and no label-write, because there is no PR.", "open_questions": [ { "question": "How does the host's SDUI manifest reach `assertRuntimeAuthoringRules` (protocol.ts:5148)? Measured: the protocol is assembled inside ObjectQLPlugin's built-in mode (standalone stack, and the artifact fallback through it) or inside createMetadataProtocolPlugin (cloud per-env kernels, cloud main 3efda046, artifact-kernel-factory.ts:662/667). Its only host inputs today are the constructor arguments, the kernel service map read lazily (the resolveFlowCanonicalizer pattern, protocol.ts:4827), and process env (orgWallEnforced). Cloud's host HTTP layer serves the same @objectstack/console (objectos-runtime node-server.ts:42/74) and holds zero sdui.manifest / resolveSduiManifest references. So no route exists without a new public surface.", "options": [ "A: a kernel service. `os serve` resolves `resolveSduiManifest(path.dirname(configPath))` once and registers the result under ONE service key exported as a constant from @objectstack/metadata-protocol (not a CoreServiceName slot, so no spec edit). The protocol reads that key per publish, the way it reads `automation`, and passes `sduiManifest` at :5148. Absent or unusable: the one boot line, and the boot continues. Reach: every `os serve` composition (library/standalone, artifact fallback, host config, OS_MODE=off), since all share one kernel, plus cloud with one registerService line per per-env kernel. Cost: 2 source files (serve.ts, protocol.ts) plus tests, and one stringly-keyed service contract.", "B: a declared assembly option. `sduiManifest` goes on AssembleMetadataProtocolOptions (plugin.ts:120), MetadataProtocolPluginOptions, ObjectQLPluginOptions, the protocol constructor (protocol.ts:4842) and StandaloneStackConfigSchema (runtime), is forwarded by createDefaultHostConfig, and is passed by serve.ts. Reach: library-mode boots, plus cloud via createMetadataProtocolPlugin({ environmentId, sduiManifest }). It misses host-config boots whose config instantiates its own ObjectQLPlugin. Cost: about 6 source files in 4 packages (two in domain:engine), 4 to 5 new typed public options.", "C: a public setter on ObjectStackProtocolImplementation, called by a small CLI plugin once `protocol` is registered. The reach is A's. Cost: 2 files, a new public method and mutable state after construction, plus an ordering dependency on when `protocol` registers.", "D: an OS_ env var holding a manifest path, read by the protocol per publish. Reach: any host that sets it. Cost: a new deployment config key and file I/O inside the protocol. It also bypasses the ruled resolver (the ruling names resolveSduiManifest)." ], "recommendation": "A. Real business need: the pull is the REST/MCP save door on every `os serve` composition and on cloud's per-env kernels. A reaches all of them with one line per host. B misses host-config boots, and cloud needs a new option either way. Long-term soundness: A follows the protocol's own pattern for facts another layer owns: read lazily per call, where resolveFlowCanonicalizer's header says 'Inside a server there is nothing to thread'. Reading per publish records no startup verdict. B copies the declared-at-assembly precedent (authoringChannel, runPlatformMigrations), but those record what the kernel IS, while the manifest belongs to the UI host layer. Preventing AI authoring errors: stage 1 is neutral, since H1 measured that no verdict moves. B's typed options beat A's string key here, so A must export the key as one constant used by both producer and consumer. Startup scope: A is 2 files and adds no public option. B is about 6 files across 4 packages. Whichever route is chosen: until stage 2 lands, a host that DOES hand over a manifest boots silently while page source is still unvalidated at save. Only the no-manifest boot line is a true statement at stage 1." } ], "out_of_scope_findings": [], "gates": "dispatch-gates --repo objectstack-ai/objectstack --commands exit 2: 'this branch changes nothing against origin/main (merge base 6bff748bb) -- nothing to derive'. pnpm lint, check-issue-citations and package test/typecheck were not run, reason: empty diff, no PR. The one heavy command (the build above) ran in os-verify-lock's declared UNLOCKED mode.", "line_budget": "n/a -- no skills/** and no governed surface touched; zero lines changed", "deviations": [ "No code, no PR, no label-write: the dispatch's clause 'if the wiring needs more than that (a new public option on the protocol, a new service contract), stop and report it as a fork before building it' fired", "First ablation-replace attempt was a no-op: the replacement contained the anchor text (count 1 → 1). The tool refused it and auto-restored (blob == HEAD, git diff HEAD empty), and no reading was taken. Re-run with the anchor spelled distinctly, in the replacement shown in tests", "The real-door leg first tried examples/app-showcase: compile failed on the unbuilt @objectstack/connector-slack dist, outside the cli build closure. Switched to examples/app-crm, whose deps sit inside the closure. The page bodies were PUT, not taken from the app", "Cloud was read at its origin/main (3efda046) through a fetch into an own ref (refs/os-dev/issue-20542-cloud-main), deleted after the read. Nothing in cloud was checked out or edited", "Verification ran in os-verify-lock's declared UNLOCKED mode (no flock on this macOS host)" ], "files_changed": [] }Generated by Claude Code
objectstack-fleet commentedon Sep 29, 2026
回决策箱:阶段 ① 的前提「A 不新增契约」被实测证伪,需要裁定 manifest 走哪条通道到达保存入口
domain:cli执行席 #6024 · sessionlocal_1d2a197c-c20e-4e90-9be8-413d4d432289· 写于 2026-09-29T15:48Z · 依据 os-dev-report5893633630(dev 在派发令的分叉条款处停下,未写代码、未开 PR)Release: the claim
5893325271is released in this stroke (premise falsified). The assignee comes off;pm:dispatched→needs-user-decision. The empty branchclaude/issue-20542-serve-sdui-manifeststays as a marker, and #20312 stayspm:blockedon this card.一句话问题: 裁决让「部署自带的组件清单」送达元数据保存入口,但实测发现,任何一条送达路径都要新增一个公开接口。而阶段 ① 单独落地时,不会改变任何一次保存的结果。
背景与 Governing text:
5881821895(metadata: refuse to save or load a page whoserequiresnames a plugin that is not loaded (1 key) #20312,维护者「同意」,letter A 分三阶段):①「os serveresolves the manifest through the CLI's existingresolveSduiManifestand passes it intoevaluateRuntimeAuthoringGate」;其理由写的是「A adds no contract」。protocol.ts:4827resolveFlowCanonicalizer,读automation服务)。前提(dev 实测,附复查命令):
git grep -n "evaluateRuntimeAuthoringGate(" origin/main -- packages/metadata-protocol/src/protocol.ts只有:5148一处,参数里没有sduiManifest;os serve不解析 manifest(git grep -c "resolveSduiManifest" origin/main -- packages/cli/src/commands/serve.ts为 0)。createMetadataProtocolPlugin({ environmentId })装配,完全不经过os serve(cloud main3efda046,artifact-kernel-factory.ts:662/667)。validateJsxPages是CLI_ONLY,运行时页面规则只有validatePresetComparands。dev 在真实保存入口(os dev+ PUT/api/v1/meta/page/…)用临时改动把 manifest 交进去,div/avatar/box三个 html 页面有无 manifest 都是 200,无问题、无提示。改动已还原,并经 blob 核对。选项 × 真实代价:
os serve解析一次 manifest,注册到一个由@objectstack/metadata-protocol导出的常量服务键下;协议每次发布时按需读取(同automation的读法)os serve形态都覆盖:库模式、独立栈、artifact 回退、宿主配置。云端每个 per-env 内核多一行注册即可。约 2 个源文件,新增一个「字符串键」服务契约sduiManifest加进 4 个包的装配选项与构造参数(其中两个属于domain:engine),由serve.ts传入OS_变量存 manifest 路径,协议每次发布时读文件resolveSduiManifest业务含义直译:
四轴(业务立场):
os serve、云端 per-env 内核)的保存入口都用本部署的组件清单判页面,正如 Salesforce 部署校验和 Power Apps 解决方案依赖检查都在服务端、按部署判定。A 用协议自己「按需读别层事实」的惯例,一条通道覆盖全部宿主;B 把 UI 宿主层的事实写进内核装配面,还漏掉宿主配置启动。os-decision-facets
5881821895(metadata: refuse to save or load a page whoserequiresnames a plugin that is not loaded (1 key) #20312, A staged) → 1 hit; ADR-0080 §5 (ruled); thread: cli/console: the deployment's SDUI component manifest reaches the metadata save door (page.requires enforcement, stage ①) #205425883700298,5891952823,5893633630推荐:A(内核服务通道),时序按 E:通道与 ② 同期落地。
裁后执行:
not_planned,理由写「并入 metadata: refuse to save or load a page whoserequiresnames a plugin that is not loaded (1 key) #20312 阶段 ②」。metadata: refuse to save or load a page whoserequiresnames a plugin that is not loaded (1 key) #20312 摘掉Blocked-by回队,由派发 ② 的席位在同一个 PR 里建 A 通道,加上保存时编译和启动提示。云端那一行注册另立 cloud 卡。fix(cli)!: the JSX page gate reads the project's sdui.manifest.json b…
objectstack-fleet commentedon Sep 30, 2026
Ruling: batch #247 item 2 · letter A + E · maintainer 「20542 同意」 2026-09-30T01:39Z
Director seat (objectstack#12708, summon #30 续 2,
session_01AsCNgFBs8HCjwhyHQsFbx3). Provenance: maintainer, live PM chat with the director seat, 2026-09-30, replying 「11111 同意;20665 业务上需要支持,ENFORCE;20542 同意;5930 v18 启动;20513 A」 to batches #246–#249 as presented; 「同意」 is to the director's recommendation in chat (A + E), which followed thedomain:cliseat's escalation5893682204and the dev's measurements5893633630.Ruled: A + E. The deployment's SDUI component manifest reaches the metadata save door through a kernel service:
os serveresolves it once through the CLI's existingresolveSduiManifest(path.dirname(configPath))and registers the result under one constant service key exported by@objectstack/metadata-protocol(not aCoreServiceNameslot, no spec edit); the protocol reads that key per publish, the way it readsautomation(theresolveFlowCanonicalizerpattern), and passessduiManifestintoevaluateRuntimeAuthoringGateatprotocol.ts:5148. Absent or unusable: the one boot line, and the boot continues. Timing E: the channel is built together with stage ② (save-time compile and refusal) in one PR — stage ① alone changes no save verdict (measured: the only rule reading the manifest,validateJsxPages, isCLI_ONLY), and the "no manifest" boot line is a half-truth until stage ② exists. ⛔ Not B (4–5 typed public options across four packages, and host-config boots that instantiate their ownObjectQLPluginare missed), ⛔ not C (mutable state after construction plus an ordering dependency), ⛔ not D (bypasses the ruled resolver).Readings that decided it:
os servecomposition and, with one registration line, the cloud's per-env kernels; the protocol's own convention for facts another layer owns is to read them lazily from the kernel service table, not to thread them through assembly.Execution parameters:
not_planned— merged into metadata: refuse to save or load a page whoserequiresnames a plugin that is not loaded (1 key) #20312 stage ②; the empty marker branchclaude/issue-20542-serve-sdui-manifestmay be deleted by its seat.requiresnames a plugin that is not loaded (1 key) #20312 returns topm:queue(itsBlocked-byremoved) with the dispatch rewritten: one PR in thedomain:clilane builds the A channel (the constant key in@objectstack/metadata-protocol,os serve's registration, the per-publish read and the:5148pass-through — the metadata-protocol lines declared as a cross-lane touch), the save-time compile and refusal of stage ②, and the boot line; stage ③ stays metadata: refuse to save or load a page whoserequiresnames a plugin that is not loaded (1 key) #20312's own follow-on.pm:blockedon metadata: refuse to save or load a page whoserequiresnames a plugin that is not loaded (1 key) #20312): each per-env kernel registers the console manifest under the same key.State:
needs-user-decisionremoved; closednot_plannedwith this record; the Ruled line goes on the body in the same stroke; #20312 re-labelled and its dispatch pointer posted in the same act.feat(cli,metadata-protocol): the save door compiles an html page's so…