Skip to content

spec: export the artifact envelope's declared top-level key set — downstream seams can derive the collection half and must hand-copy the rest #14877

Description

@baozhoutao

Found while implementing objectstack-ai/cloud#1888 (artifact assembly silently dropped metadata.packages[]). Filed, not fixed — out of that card's scope, and the change belongs in this repo.

Measured on framework 655b106 (the pin cloud main carries) and cloud main @ b16b3d3, both read-only worktrees.

The asymmetry

@objectstack/spec exports PLURAL_TO_SINGULAR and METADATA_ALIASES, so a downstream consumer can ask the contract "which keys are metadata collections?" and get an answer that stays correct as the spec evolves. cloud uses exactly that:

cloud/packages/service-cloud/src/cloud-artifact-helpers.ts
  export const KNOWN_METADATA_CATEGORIES = new Set([
      ...Object.keys(PLURAL_TO_SINGULAR),
      ...Object.keys(METADATA_ALIASES),
      ...CLOUD_ONLY_METADATA_CATEGORIES,
  ]);

That derivation was bought by an incident (cloud#897: a hand-copied category list drifted after ADR-0090 D3 renamed roles to positions, and every hosted publish silently dropped positions[]).

There is no equivalent export for the artifact envelope's NON-collection top-level keys — manifest, requires, packages, and whatever comes next. COMPOSE_KEY_DISPOSITIONS (packages/spec/src/stack.zod.ts:839) is the one place that enumerates every top-level key of ObjectStackDefinitionSchema with its composition rule, and it is module-private:

git -C objectstack grep -n "COMPOSE_KEY_DISPOSITIONS" -- packages/spec/src/index.ts   # no hits

ObjectStackDefinitionSchema itself is exported, but it is a lazySchema(() => strictObject({...}).superRefine(...)), so its key set is not reachable without digging into zod internals — not a contract a consumer should be reading.

What that costs, concretely

cloud#1888: packages (ADR-0130 D4, stack.zod.ts:1237) is declared on the artifact envelope, produced by composeStacks([...], { manifest: 'preserve' }), written by os compile, and read at load by resolveArtifactPackageOrder at the metadata door. The cloud seam's merge dropped it, because the only list that could have carried it is hand-maintained. The consequence on the hosted path was the duplicate-ownership state objectstack#14599 had already repaired at the door — every item of a multi-package artifact registering under one arbitrary member's package id — re-created downstream and visible nowhere.

The class already has five members on the cloud side (positions, requires, data, datasets, packages). The collection half of it was closed structurally in 2026; the non-collection half is still a list someone has to remember to edit.

And there is a sixth on the way: #14865 will add a top-level grantedPermissions key to the artifact envelope. With an exported key set it arrives at every downstream seam for free. Without one it is another hand edit in another repo, discovered the same way.

What would close it

Some export whose content is derived from the schema rather than transcribed. Options, cheapest first — the choice is the spec owner's, not this issue's:

  1. Export COMPOSE_KEY_DISPOSITIONS (or a Readonly view of it). It already exists, already enumerates every top-level key, and CONCAT_ARRAY_FIELDS is already derived from it inside the module, so there is a precedent for it being the source of truth. Cheapest, and carries composition semantics a consumer may also want ('concat' tells cloud that concatenating packages across bundles is correct, which today is knowledge the cloud comment has to assert from reading this file).
  2. Export a narrower derived set — e.g. STACK_DEFINITION_TOP_LEVEL_KEYS, or an array-valued subset — if exposing the disposition table is more surface than wanted. Must be derived from the same table, never a second literal, or the export becomes the drift it exists to prevent.
  3. Do nothing and accept the hand-copy, in which case the honest form is a note in stack.zod.ts saying that adding a top-level key obliges an edit at each downstream seam, and naming them. Stating the coupling is worth something even unautomated.

Whichever way it goes, the reason to decide it here rather than in cloud is that the answer is one export in one place, versus one hand-maintained list per consuming repo.

Not blocked on

cloud#1888 is repaired independently in objectstack-ai/cloud#1892 — packages is now a declared passthrough there, and that seam also gained a diagnostic that names any array-valued artifact key it drops without recognising, so the next occurrence is loud rather than silent. This issue is the upstream half that would stop the occurrence instead of reporting it.

Duplicate check

One targeted search_issues over objectstack-ai/objectstack for the exported-key-set question returned 2 issues, neither this one: #14865 (declare grantedPermissions on the artifact schema — the next instance of the problem, not the mechanism) and #5005 (closed — composeStacks dropping non-array top-level keys, the incident that produced COMPOSE_KEY_DISPOSITIONS in the first place). Non-empty result set, so the instrument reached the population. Repo-scoped REST reads work from this container but /search/issues is refused (HTTP 403, sessions bound to configured repositories), and listing every open issue in this repo would be the wide scan the dispatch rules forbid — hence the one semantic search.

Filed unassigned for triage.

Activity

  1. added theissue type on Sep 4, 2026
  2. os-zhuang commented on Sep 4, 2026

    @os-zhuang
    Contributor

    Triage: needs-user-decision · domain:spec · priority:p2. Lands in packages/spec/src/stack.zod.ts.

    Triage seat, session session_01SwJQDFKe8tVit3BXQ9EfR5, R+145, 2026-09-04T16:05Z.

    Why escalated: options 1 and 2 both add a public export to @objectstack/spec. By the mechanical boundary test that widens the public surface ⇒ Feature ⇒ manual floor, whichever way the facets point. ⛔ Triage does not adjudicate it.

    • ① 项目长远合理性(权重 ≥50%,领起推荐) —— 同一个类的集合半边已经结构性关掉了:PLURAL_TO_SINGULAR / METADATA_ALIASES 是导出的、可派生的,下游因此能向契约提问而不是抄写。非集合半边至今仍是「每个消费仓一份手抄清单」。长远终态只有一种:一处派生,而不是 N 处手抄。①指向 1 或 2。⛔ 3 出局:它把耦合写成散文,而散文不阻止漂移 —— 这个类已经付过两次事故了。
    • ② 实际业务拉动 —— 实测、具名、且有日期。 云侧这个类已有五个成员(positions、requires、data、datasets、packages),其中两个是事故买来的:cloud#897(ADR-0090 D3 把 roles 改名 positions,每次托管发布静默丢 positions[])与 cloud#1888(packages 被合并丢掉,把 objectstack#14599 已在门口修好的重复归属状态在下游重建)。第六个已在路上 —— spec: declare grantedPermissions on EnvironmentArtifactSchema (record of manifest id → PluginPermissions) — the artifact-contract half of #14034 / #11333 Phase 1, which must land BEFORE cloud can write it (plain z.object strips undeclared keys at the artifact door) #14865 会给 artifact 信封加顶层 grantedPermissions。⇒ 有实测拉动,按分歧推荐序:荐长远形态一次付清。
    • ③ 防 AI 犯错 —— 一个 AI 写下游 seam 时,无法向契约提问「顶层键有哪些」。ObjectStackDefinitionSchema 虽已导出,但它是 lazySchema(() => strictObject({...}).superRefine(...)),键集要挖 zod 内部才拿得到 —— ⛔ 那不是消费方该读的契约。于是它只能手抄,而手抄的漂移静默:cloud#1888 的后果「visible nowhere」是原话。导出使之可派生,是把一类静默错误变成结构上不可能。
    • ④ 创业阶段不扩散 —— 唯一的反向力,且真实:这是给已发布包加公开面。但要看加的是什么 —— 选项 1 导出的 COMPOSE_KEY_DISPOSITIONS 已经存在、且已经是模块内的真相源(CONCAT_ARRAY_FIELDS 就是从它派生的)。⇒ 不是新增能力,是把一条既有不变量暴露到它已被需要的地方。④在 1 与 2 之间偏 2(面更窄)。

    推荐:1(导出 COMPOSE_KEY_DISPOSITIONS,或其 Readonly 视图)。 ①以≥50% 权重领起并指向一处派生;②有具名拉动、取长远终态;③指向结构性不可能;④真实反对但有界。⭐ 在 1 与 2 之间选 1 的理由是多出的那点面正好是消费方已经在用的:'concat' 这条 disposition 告诉 cloud「跨 bundle 拼接 packages 是对的」,而这条知识今天由 cloud 的注释靠读这个文件断言。把它导出,是把一句断言换成一次查询。
    回退:2(更窄的派生集合,如 STACK_DEFINITION_TOP_LEVEL_KEYS) —— 若维护者判断整张 disposition 表面太大。⛔ 硬约束:必须从同一张表派生,永远不可以是第二份字面量,否则这个导出本身就变成它要防的那种漂移。
    ⛔ 不建议 3。 它是唯一不改变结果的选项 —— 下一个顶层键照旧在每个消费仓手抄一遍,照旧静默地漏。
    置信缺口: ⛔ 未测量 cloud 之外是否还有消费者需要这个键集。若只有 cloud 一家,选项 2 的性价比上升(面更窄、拉动同样被满足);⛔ 这不翻转「要导出」本身,只影响导出多宽。

    priority:p2:今天没有开着的缺陷(cloud#1888 已由 cloud#1892 独立修复,并加了诊断使下次响亮而非静默),但 #14865 是一个有日期的复发,而这张卡正是能让它免费到达每个下游 seam 的那一处改动。

    ⚠️ 读数出处:framework 655b106(cloud main 所 pin)与 cloud main b16b3d3,均为只读工作树,2026-09-03。⛔ 实施前在今天的 origin/main 上重核 COMPOSE_KEY_DISPOSITIONS 仍是模块私有、且仍枚举全部顶层键。


    Generated by Claude Code

  3. os-warren commented on Sep 4, 2026

    @os-warren
    Collaborator

    Maintainer ruling recorded — 1: export the compose-key disposition table (a Readonly view of COMPOSE_KEY_DISPOSITIONS) from @objectstack/spec, so every downstream seam derives the artifact envelope's top-level key set — and each key's disposition — from one source

    Director seat, summon #14, session session_01LsEjuNMPitCHwEfYftZ1um (GitHub os-warren), 2026-09-04. Provenance: maintainer, live PM chat, decision batch #38 (item 3, presented with the recommendation 1, fallback 2), verbatim reply 「同意」. Premise: triage facets 5542294490 (COMPOSE_KEY_DISPOSITIONS is already the module-private source of truth in packages/spec/src/stack.zod.ts, CONCAT_ARRAY_FIELDS derives from it; cloud's seam carries a hand-copied five-member list bought by cloud#897 and cloud#1888, with #14865's grantedPermissions next).

    Ruled: 1. @objectstack/spec exports a read-only view of the disposition table (Readonly<Record<TopLevelKey, Disposition>>, frozen), plus the derived key set if convenient — ⛔ derived from the same table, never a second literal. Not taken: 2 (a narrower key-set-only export — the fallback if the maintainer had judged the full table too wide; the 'concat' disposition is exactly the knowledge cloud asserts today by reading this file), 3 (prose only — does not change the outcome).

    Why (① ≥50%): the collection half of this class is already structurally closed (PLURAL_TO_SINGULAR / METADATA_ALIASES exported and derivable); the non-collection half is still one hand-copied list per consuming repo. One derivation, not N copies. ② has named, dated pull (two incidents, a third key arriving). ③: an AI writing a downstream seam can ask the contract instead of digging zod internals. ④ is real but bounded — the table already exists and is already the truth source.

    Execution: domain:spec lane, S. Re-verify on today's origin/main that the table is still module-private and still enumerates every top-level key before exporting (triage's own caveat). Add a pin that the exported view and ObjectStackDefinitionSchema's key set agree (so the table cannot drift from the schema silently), and a README/docs line under the spec package's compose section. Clause-②: yes (new exported symbol) ⇒ needs:contract-review on the PR, review at CONTRACT_REVIEW_TIER. Changeset: @objectstack/spec minor. Cross-link cloud#897, cloud#1888, #14865, #14599.

    State transition, same stroke: needs-user-decision → pm:queue. priority:p2 · domain:spec unchanged. Ledger: director seat post #12708, batch #38.


    Generated by Claude Code

  4. claude commented on Sep 5, 2026

    @claude
    Contributor

    Claim: PM loop round R2 — domain:spec seat, session_01M59rPZZFzqhfMUPFqqZTkf, 2026-09-05T18:40Z. One dev, branch claude/issue-14877-export-compose-key-dispositions, mode:subagent, tier claude-fable-5-1. Size S.

    Clause-②: yes

    Ruled card, executed as ruled: director ruling 5542628978 (2026-09-04T15:20Z; maintainer verbatim 「同意」 to decision batch #38 item 3) — 1: @objectstack/spec exports a read-only view of the compose-key disposition table (a frozen Readonly record from top-level key to disposition), plus the derived top-level key set if convenient — ⛔ derived from the same table, never a second literal; a pin that the exported view's key set and ObjectStackDefinitionSchema's top-level key set agree (so the table cannot drift from the schema silently); one README / docs line under the spec package's compose section. Not taken: 2 (key-set-only export), 3 (prose only). Clause-② yes: a new exported symbol on the published surface — the seat runs the in-seat contract review, then hangs and clears needs:contract-review on both carriers (PR + this card).

    File face (readings on origin/main f7db8f4fd at 2026-09-05T18:38Z): packages/spec/src/stack.zod.ts — COMPOSE_KEY_DISPOSITIONS at :875 (module-private, the @internal StackDefinitionKey type just above it, CONCAT_ARRAY_FIELDS derived at :962, the AssembledPackageBodyKey derivation at :999, the runtime unknown-key warning at :2827 naming the table, readers at :3210 / :3261 / :3270); packages/spec/src/index.ts:109 already re-exports * from './stack.zod', so the export is the frozen read-only view (and the type) becoming exported under a public name with a describe-grade docblock; a pin file beside compose-stacks-key-loss.test.ts (key set of the view === top-level key set of ObjectStackDefinitionSchema, the view is frozen, every value is a declared disposition); the api-surface / export-origins / declaration-map shards regenerated by tooling; one docs line (the spec package's compose section — the dev locates it: packages/spec/README.md or the content/docs page that documents composeStacks); one @objectstack/spec changeset (minor, additive — no BREAKING banner; the adr-0087 disposition the gate accepts for an additive export). Cross-links: cloud#897, cloud#1888, #14865, #14599. Hot-file check at 18:38Z: no open PR touches stack.zod.ts or spec/src/index.ts; #14512 (the artifact-duplication program, ruled B, pm:queue awaiting the seat's reader-program cards) reads the same table and lands later — no overlap in this lap.


    Generated by Claude Code

  5. claude commented on Sep 5, 2026

    @claude
    Contributor

    Review — ACCEPT · Clause-② contract review PASS (domain:spec seat at CONTRACT_REVIEW_TIER, session_01M59rPZZFzqhfMUPFqqZTkf, 2026-09-05T22:18Z; PR #16051 at head f8d52d540; ruling 5542628978 option 1, executed as ruled; the dev's report comment is still being posted — this verdict is the diff read, the report's gate evidence is checked on arrival).

    Contract limb — the diff is the ruled shape, read 22:16–22:18Z on origin/main…f8d52d540:

    • One source, exported and frozen. COMPOSE_KEY_DISPOSITIONS in stack.zod.ts becomes export const … = Object.freeze({ … } as const satisfies Record of StackDefinitionKey to ComposeDisposition) — the same object composeStacks reads, literal-typed so a consumer's the indexed type of the table at K is K's disposition; StackDefinitionKey and ComposeDisposition lose @internal and are exported; STACK_DEFINITION_KEYS is Object.freeze(Object.keys(COMPOSE_KEY_DISPOSITIONS)) — derived, never a second literal — and CONCAT_ARRAY_FIELDS now derives from it, so the in-file derivations share the one table. The docblocks say what each disposition means and why the table is public (cloud#897 / cloud#1888 named).
    • Pins bear weight (compose-key-dispositions-export.pin.test.ts, 279 lines): the table's key set equals ObjectStackDefinitionSchema's declared top-level key set in BOTH directions with the drift named per direction (>40 keys, no duplicates); STACK_DEFINITION_KEYS equals that set and contains the incident keys; both exports frozen (assignment, new key, delete, push all throw); every value is in the disposition vocabulary and every vocabulary word is used; the ruled shape is assignable; and the behaviour pins — every 'concat' key concatenates in stack order (>30 keys incl. packages, requires) and every 'single' key passes through when identical and refuses naming the key when different — so the export cannot drift from what composeStacks does.
    • Surface: four new entries in api-surface/root.json / export-origins/root.json (two consts, two types), regenerated by tooling; nothing renamed, narrowed or removed. Docs: one paragraph in content/docs/getting-started/examples.mdx under the composition section. Changeset: @objectstack/spec minor, additive (no BREAKING banner — correct), naming both exports and both types, cross-links carried. Governed predicate: 0 of 6 paths (22:16Z).

    Landing path: CI on f8d52d540 running (main green). The seat hangs and clears needs:contract-review on both carriers (PR #16051, #14877) at this head, runs the pair check, and flips to ready + auto-merge (squash) once every check is green; a main merge lap by tooling first if the head is behind main's shard moves. On merge: #14877 closes by the PR; cloud's seam (KNOWN_METADATA_CATEGORIES + the hand-copied envelope list) can switch to the export — the cloud lane's follow-up, filed by the seat on landing.


    Generated by Claude Code

  6. claude commented on Sep 5, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 14877,
      "status": "done",
      "branch": "claude/issue-14877-export-compose-key-dispositions",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/16051",
      "premise_still_valid": true,
      "summary": "Executed ruling 1 as recorded (comment 5542628978). packages/spec/src/stack.zod.ts: COMPOSE_KEY_DISPOSITIONS is now exported under its existing name as Object.freeze over the unchanged as-const-satisfies literal (one declaration, one name — the composeStacks runtime warning, every in-module link and cloud's seam comment already say it; a second view name would leave the private one in the user-facing message), with a describe-grade docblock; STACK_DEFINITION_KEYS is the derived key set (Object.freeze of Object.keys of the table, never a second literal; CONCAT_ARRAY_FIELDS now derives from it); StackDefinitionKey and ComposeDisposition are exported with their internal tags removed. Literal typing kept (M4): dist/index.d.ts declares the per-key literals, so AssembledPackageBodyKey still derives. New pin file compose-key-dispositions-export.pin.test.ts (15 tests): key-set equality with ObjectStackDefinitionSchema.shape in BOTH directions (44 keys each side, drift named per direction), frozen (assign/new-key/delete throw), every value in the ComposeDisposition vocabulary via a total record tsc holds, assignability to the ruled read-only record shape, every concat key concatenates and every single key passes-through/refuses in composeStacks (the export's concat subset is the composer's), derivation order, and ./index re-exports the same objects. Docs: one paragraph under content/docs/getting-started/examples.mdx → Composition Pattern (packages/spec/README.md has no compose section). Changeset: @objectstack/spec minor, additive, cross-links cloud#897, cloud#1888, #14865, #14599; no ADR-0087 marker because the gate judges only declared-breaking changesets. Shards: api-surface/root.json and export-origins/root.json regenerated by tooling (+4 each), declaration-map unchanged, gen:schema no diff. Premise re-verified on f7db8f4fd: the table was module-private and total (44 = 44); M1 held so the stop condition never triggered; M2 held (export-star reached the root surface without touching index.ts); M3 held (all compose-stacks-*.test.ts green). Main moved to 2e3576503 while I was paused; no merge taken because git diff f7db8f4fd..origin/main over my whole file face is empty. Assignee arrived set to the PM identity; I wrote nothing to it and posted no second claim. In-repo literal sweep found no copy of the table (per-purpose collection subsets only, each with its own gate; runtime's artifact-collections.ts already derives from the schemas). PR body: footer sent without a leading rule line per platform-readings and it survived; the platform appended its own rule + footer block, left as the platform's. needs:contract-review untouched. Worktree removed after the PR opened.",
      "tests": "Tree f8d52d540, every build/test under scripts/pm/os-verify-lock.sh slot issue-14877. (1) pnpm --filter @objectstack/spec build: 'VERDICT command-exit 0 · held the lock 165s'; 'check-dts-emitted: 34/34'. (2) pnpm --filter @objectstack/spec typecheck: tsc clean; 'check:test-typecheck: OK — @objectstack/spec's test layer compiles under tsconfig.test.json; 54 file(s) / 261 error(s) / 145 pinned signature(s) held in test-typecheck-debt.json' (ledger unchanged; the pin file compiles with 0 errors — the first run had 2 TS7006 in it, fixed by typing the spy-call parameter, not by ledgering). (3) pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2: 'Test Files 479 passed (479) · Tests 12853 passed (12853)', VERDICT command-exit 0, held 388s. (4) The pin file alone: 15 passed. (5) pnpm --filter @objectstack/spec check:generated after gen:api-surface and gen:export-origins: '✓ All 15 generated artifacts are up to date'. (6) Gates: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (from merge-base, no paths) = 95 commands, each run with exit captured by redirect before any pipe; --ran reconciliation: '95 derived, 95 run, 0 NOT-MEASURED, 0 UNRUN'. 89 exit 0 on the first pass; 6 were PREREQUISITE NOT MET (exit 3, and check:skill-examples exit 1 whose own text says 'the package is not built'). After building the '@objectstack/lint...' and '@objectstack/client-react...' closures under the lock (34 tasks, VERDICT command-exit 0), re-run green: check:doc-formula-expressions ('22 record-scoped formula example(s) across 428 files judged clean'), check:doc-security-posture ('27 ObjectSchema.create example(s) … carry an os validate-clean security posture'), check:docs-transcript-drift ('4 declared transcript value(s) across 405 page(s) … equal what the registry derives'), check:skill-examples ('✅ 257 prose examples type-check across 3 surface(s)'). Declared to CI as NOT MEASURED here: check:dual-build-cjs-loads and check:type-check-debt — both need every workspace package built (78 more dist directories). (7) eslint, a measured narrowing: population from eslint.config.mjs (files glob covers ts/tsx/mts/cts/js/jsx/mjs/cjs only, so the .mdx and .changeset files are outside it); pnpm exec eslint --no-inline-config --format json over the 2 touched TS files: 2 files, 0 errors, 0 warnings; invariance: the config declares no parserOptions.project and no typed rules for any file, so this diff cannot move an untouched file's verdict. pnpm check:nul-bytes OK (7711 files); control-byte grep over the 4 touched files: none. (8) Ablation for pin weight, from the committed state with a trap and absolute paths (HEAD blob 65657ebf2e207f5b114f120797d500dca02a1dc9): injected futureBogusKey: 'concat' into the table (on-disk count 1) and removed Object.freeze from it (count 0) → pin file 7 failed / 8 passed — pin 1's three parity tests (naming futureBogusKey in onlyInTable), pin 2's two table-frozen tests, and two later tests that read the table after pin 2's writes now succeed; restore via git checkout HEAD -- absolute-path, proven by git hash-object equal to the HEAD blob and 'git diff HEAD --stat' empty; restored run 15/15 green. No dist leg applies: the pin imports ./stack.zod from src (no alias). (9) Consumer sweep direction: none — additive export, nothing removed or narrowed; turbo ls --affected against BASE lists 75 packages (everything depends on spec), the farm CI owns. CI on the PR: in_progress at report time.",
      "mcp_calls": "0 — every GitHub read and write went over repo-scoped REST (issue and comments read 200; PR POST 201; this comment); no MCP call was made",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  7. claude commented on Sep 5, 2026

    @claude
    Contributor

    Landing provenance (domain:spec seat, session_01M59rPZZFzqhfMUPFqqZTkf, 2026-09-05T22:43Z): PR #16051 flipped to ready and auto-merge (squash) enabled at 22:43Z on head f8d52d540 — every check on that head green (34 success / 7 skipped, none red), mergeable_state: clean; ACCEPT + Clause-② PASS 5555157398, the dev's report 5555167530 confirms the gate evidence (44 = 44 both ways, 15 pins, full spec suite, 95/95 gate families); needs:contract-review hung and cleared on both carriers at f8d52d540 (22:17Z), pair check ✓; governed predicate 0 of 6 paths. The enqueue reading and the landing note follow on MERGED (landing watch armed 23:08Z).


    Generated by Claude Code

  8. claude commented on Sep 5, 2026

    @claude
    Contributor

    Landed (domain:spec seat, session_01M59rPZZFzqhfMUPFqqZTkf, 2026-09-05T23:57Z): PR #16051 merged 2026-09-05T23:50:36Z as 69602e578 through the merge queue (squash; added_to_merge_queue 22:43:49Z, about 67 minutes in queue across two group rebuilds). Probe on origin/main at 2026-09-05T23:51Z (tip 69602e578): git grep -c "export const COMPOSE_KEY_DISPOSITIONS" origin/main -- packages/spec/src/stack.zod.ts = 1; control 0 at f7db8f4fd. ACCEPT + Clause-② PASS 5555157398 at f8d52d540, carriers cycled on both, pair ✓.

    Follow-up the verdict owes, filed in this stroke: the cloud-lane seam card #16084 (repo:cloud, reader the repo:cloud seat — cloud's KNOWN_METADATA_CATEGORIES and the hand-copied envelope list switch to COMPOSE_KEY_DISPOSITIONS / STACK_DEFINITION_KEYS; the cloud repository is not reachable from this session, so the card lives here with a named reader and the pin-lag criterion).

    Release: session_01M59rPZZFzqhfMUPFqqZTkf — reason: landed, card closed by Fixes #14877 — destination: none (closed); the owed work is on #16084. Same stroke: pm:dispatched stripped, assignee cleared.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions