Repository navigation
Description
repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2
Blocked-by: #30880
Filing gate: ③ a task on the maintainer's word. Epic objectstack-ai/cloud#3652, coordinator session 2026-11-06, verbatim: 「我觉得先把受管软件包的开发循环走顺了」, then 「同意,然后第一步先解决我本地开发的软件包怎么能够方便地发布到云端」. The epic's Phase 2 lists "Change preview before install". Rulings on the epic (record on cloud#3652, 2026-11-06), verbatim:
- Q1: 「a 本地 os dev(推荐)」. Iterate locally, deploy at milestones. The preview guards each milestone deploy into an environment that is production (ADR-0024).
- Q3: 「默认拒绝,需显式映射(推荐)」. An upgrade that renames a field or changes its type is refused by default, unless an explicit old→new mapping or a confirmation is supplied. The ruling places Q3 in this card.
- D3, on where the mapping lives: 「写进清单 renamedFrom」. The package author declares it on the field in the manifest (card 07), so every installer's upgrade applies it. It is not an install-request input. This supersedes item 5 of objectstack#24443's ruling record
6259332195("No rename spelling is added to the spec").
Carrier: objectstack. Comparing two versions of a package is platform capability (maintainer, 2026-11-06: 「平台的问题应该在平台处理」, #30765). Cloud only calls it from its hosted install door (sibling card 01c, repo:cloud).
维护者速读
现在升级一个软件包时,平台不会先告诉你会变什么:字段改名会变成一个新的空列,旧数据还在旧列里但看不到;改字段类型也是静默的。这张卡在平台里做一个「升级预览」:比较已安装版本和新版本,列出增删字段、类型变化、改名和种子数据变化,可以只看不装。包作者在新版本里用 renamedFrom 声明过的改名,算作计划内的改名,照常升级,数据由 01b 搬过去。没有声明却像改名的、以及改字段类型的,按 Q3 默认拒绝,要带着预览给出的确认令牌再装一次。云端和私有部署都调用这同一个比较。
Today (objectstack origin/main 8b9cc712; every file cited below is unchanged since c50e0dfa)
- No comparison of two package versions exists as a library. (measured)
os diff(packages/cli/src/commands/diff.ts:162) compares two config files loaded throughloadConfig(:223-224). It lives in the CLI command, not in a package a runtime or cloud can call.- It reports added and removed objects and fields, required-field additions and type changes (
:23,:55,:138), and name-level changes for views, flows, agents, apps, dashboards, actions, workflows, apis and positions (:239-247). - It does not compare seeds (
data) or permission sets, and it does not detect renames.
os migrate plancompares metadata with a physical database, not two versions. "dry-run diff of metadata vs the physical database" (commands/migrate/plan.ts:62). It needs--database-url/$OS_DATABASE_URL(:137-139), so it cannot run against a cloud environment. (measured)- Schema sync on upgrade is additive. "The driver's
initObjectssync is additive-only" and a "drop or rename a field" silently diverges (packages/drivers/driver-sql/src/schema-drift.ts:6-9). A renamed field becomes a new empty column and the old column stays. The drift categoriessafe | needs_confirm | destructiveexist (:135) and are what this card reuses for type changes. (measured) - The finding-set-token pattern already exists on install-local. A managed re-install with access findings answers
409 ACCESS_UPGRADE_CONFIRMATION_REQUIREDwithdetails.findingsand a token, before any write. The same request withconfirmAccessUpgrade: <token>installs, and a changed set is refused again (packages/cloud-connection/src/marketplace-install-local-plugin.ts:85-97, code at:454,:3456; ledgerpackages/spec/src/api/error-code-ledger.zod.ts:1319; CLI--confirm-access-upgrade,packages/cli/src/commands/package/install.ts:174,:307). (measured) This card's confirmation copies that shape. - The boot-time upgrade-impact report covers customer state against the registry: orphans, re-enablements, overlay orphans, field collisions and setting orphans (
packages/plugins/plugin-security/src/upgrade-impact-report.ts:4-17). It does not look at a package's own data schema or seeds. (measured) - Seeds: the overwrite is now limited to
upsertdatasets. (measured)- Since feat(spec)!: a seed is create-only by default — an omitted
modeisignore#30152 an omitted seedmodeisignore(packages/spec/src/data/seed.zod.ts:193;packages/spec/src/migrations/entries/semantic/18.seed-mode-default-create-only.ts). Cloud's pin2ffdb649contains it. - A dataset that declares
mode: 'upsert', or an artifact built before feat(spec)!: a seed is create-only by default — an omittedmodeisignore#30152 (it carries a writtenupsert), still writes its declared columns back over a customer's edit on every replay.
- Since feat(spec)!: a seed is create-only by default — an omitted
- No rename declaration exists yet.
renamedFrom→ 0 hits inpackages/spec/src/data/**;FieldSchemais strict (packages/spec/src/data/field.zod.ts:1243). Card 07 addsrenamedFrom: string[]on a field. (measured)
Expected
- One comparison, as a library. A pure function in a framework package (the lane picks where; beside the upgrade-impact family is the natural home) takes the installed artifact and the new artifact and returns findings:
- objects and fields added and removed;
- field type changes, each with the drift category
schema-drift.tsalready assigns; - declared renames: a field of the new version whose
renamedFromnames a field of the installed version that the new version no longer has. This is a planned rename, listed asold → new. A declared rename whose old and new types the drift categories calldestructiveis a type-change finding too; - suspected renames: within one object, a field removed and a field added in the same upgrade with no
renamedFromlinking them; - seed datasets added, removed and changed, each with its mode.
os diffis moved onto the same function, so the CLI and the runtime cannot disagree.
- An environment-aware half, as a kernel service method. Given the running environment, it adds what only the environment knows: row counts in columns a removal, rename or type change touches, and for each changed
upsertdataset the number of rows whose current value differs from the version being replaced (rows a customer edited that the replay would overwrite). It is a service method, so install-local and a host (cloud's runtime) call the same code. - Dry run on install-local.
POST /api/v1/marketplace/install-localwithdryRun: truereturns the plan and writes nothing.os package install … --dry-runprints it. - Q3 verdict on a managed re-install, before any write:
- A declared rename is not refused. The install proceeds and 01b carries the column. Until 01b lands, a declared rename is refused with a sentence that names it and says rename execution is not available yet, so a declared rename never installs as a silent empty column.
- An undeclared suspected rename or a type change is refused by default:
409with a new code (working nameSCHEMA_UPGRADE_CONFIRMATION_REQUIRED; the lane names it in the ledger),details.findingsand a finding-set token. The same request withconfirmSchemaUpgrade: <token>installs, accepting the findings as shown (today's additive behaviour). A changed finding set is refused again. - The refusal says both ways forward: declare
renamedFromin the package and rebuild, or confirm. - The CLI gains
--confirm-upgrade <token>onos package install. ⛔ There is no request-side rename input.
- Removed fields and seed changes are reported, not refused (no ruling covers them; the removed column is not dropped today).
Acceptance
- Unit tests on the comparison:
- a field removed + one added of the same type in one object, no
renamedFrom→ one suspected rename; - the same pair with
renamedFrom: ['old']on the new field → one declared rename and no suspected rename; - a type change carries its drift category;
- an
upsertdataset change and anignoredataset change are both listed with their modes; os diffoutput is unchanged for its existing fixtures.
- a field removed + one added of the same type in one object, no
- Install-local integration tests:
dryRun: truewrites nothing (ledger file and registry unchanged);- a re-install with an undeclared suspected rename answers 409 with the token; the same call with the token installs; with a different finding set the old token is refused;
- a declared rename is refused by name until 01b lands (this test is replaced by 01b's).
- Environment half: a test with a seeded
upsertdataset, one row edited, reports that row as one that would be overwritten. - The new error code is in
error-code-ledger.zod.tsand its gate passes.
Serial: after 07, so the new manifest can carry renamedFrom. Everything but the declared-rename finding can be built in parallel and merged after 07. No Phase 1 dependency: #30871's file surface (publish, login, environments, dev, deploy command) does not include install.ts or install-local.
Dedupe (2026-11-06), each run as gh api -X GET search/issues -f q=…:
repo:objectstack-ai/objectstack package upgrade plan dry run install-local is:issue→ 17 hits, none about this (test budgets, seat posts).repo:objectstack-ai/objectstack "upgrade-impact" is:issue→ 8 hits. [Decision] A vendor package upgrade checks nothing: a rename silently re-enables what the customer switched off, and orphans, collisions and broken references go unreported, for every metadata type #24443 (decision, ruled A), upgrade-impact comparison, access class (v18): a vendor upgrade that would orphan, re-enable or collide with a customer's access choice is refused until an administrator confirms, and raised at boot #24446 and upgrade-impact comparison after v18: report the non-access classes to the administrator, and retire the zero-consumer package-upgrade.zod.ts #24447 (closed) compare customer state with the registry at boot. Related, not duplicates: none compares two versions' data schema or seeds, and none answers Q3.repo:objectstack-ai/objectstack upgrade impact schema rename field type change package is:issue→ 12 hits, the same family.repo:objectstack-ai/objectstack rename field upgrade new empty column is:issue→ 143 hits; the open ones are QA runs, seat posts, [epic] ADR-0131 — total organization ownership: no NULL organization_id (v18 line) #15194, objectql: a plainlookupwrite accepts a target the writer cannot read — the reference check probes it elevated, and onlymaster_detailasks the caller's read door #29029. None.repo:objectstack-ai/objectstack package upgrade preview diff is:issue is:open→ 12 hits, none.repo:objectstack-ai/objectstack "os diff" is:issue→ 500 hits (broad); the one on the command, [finding]os diff's missing-paths usage error prints 141 bytes of prose to STDOUT then exits 1 — it sits ABOVE the--jsonguard, so it fires in both faces #15697, is closed (stderr fix).repo:objectstack-ai/objectstack renamedFrom is:issue→ 1 hit, [Decision] A vendor package upgrade checks nothing: a rename silently re-enables what the customer switched off, and orphans, collisions and broken references go unreported, for every metadata type #24443 (see the gate).
Suggested-grade: p2 · Phase 2; a silent data-visibility loss on every renamed field in an environment that is production (ADR-0024).
Clause-②: yes (widening) · new install-local body keys (dryRun, confirmSchemaUpgrade) and a new error code in the ledger. It also narrows: a re-install that succeeds today is refused when it carries an undeclared suspected rename or a type change. The contract review covers both directions.
🤖 Generated with Claude Code
Activity
objectstack-fleet commentedon Nov 6, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · grade kept ·
domain:server·pm:blocked· 2026-11-06T09:58Z⛔ Not a claim.
domain:server, andrepo:cloud#3follows it. The grade the filer set is kept.Blocked-byholds.Generated by Claude Code
objectstack-fleet commentedon Nov 6, 2026
repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2
Scope note (not a claim), escalated from contract review 6685133297 on PR #30934: today this card's Expected 1 promotes only a
destructivedeclared rename to a type-change finding. Aneeds_confirmtype change on a field that also declaresrenamedFromwould therefore slip Q3's confirmation (epic objectstack-ai/cloud#3652: a type change is refused unless confirmed). A declared rename must never stand in for a type-change confirmation: judge the type change on its own, whateverrenamedFromsays.objectstack-fleet commentedon Nov 6, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: unblock ·
pm:blocked→pm:queue· 2026-11-06T13:31Z⛔ Not a claim.
Blocked-by:is spec: a field declares the name(s) it was renamed from —renamedFromon FieldSchema, so a package upgrade carries the column instead of adding an empty one (epic cloud#3652 Q3; supersedes #24443 ruling item 5) #30880. Triage re-read it: closed as completed at 13:22Z, when PR feat(spec): a field declares the key(s) it was renamed from —renamedFromon FieldSchema #30934 merged asf108e6d2. Asked bydomain:server#1(6685980343).domain:serverkept. Therepo:cloudfollower is unchanged.repo:cloud#3(above) is part of the card: a declared rename never stands in for a type-change confirmation.Generated by Claude Code
objectstack-fleet commentedon Nov 6, 2026
domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW
Claim: PM loop patrol · 2026-11-06T13:45Z
Session:
session_016WV4cytLmJxfAmgPVjUbbWAccount:
os-elon-musk(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-30884-package-upgrade-plan(placeholder; the card thread's harness-pinned branch replaces it by a full re-post of this claim before any push)Worktree:
objectstack-issue-30884Domain:
domain:serverSeat:
domain:server#1Plan: two PRs on one branch, in order. PR 1 widens only (Expected 1, 2, 3: the comparison, the environment half,
dryRun,os diffon the same function). PR 2 carries the Q3 refusal (Expected 4 and the error code), the narrowing half, andFixes #30884.File surface (card Expected 1–5 and its Acceptance, nothing else):
packages/plugins/plugin-security/src/upgrade-impact-report.ts) unless the dev names a better home in the report before the first push.upsertdataset, rows whose current value differs from the version being replaced), in the package whose service the install doors already reach; named in the report.packages/drivers/driver-sql/src/schema-drift.ts: read the drift categories (safe | needs_confirm | destructive); an export only if the comparison cannot reach them otherwise.packages/cli/src/commands/diff.ts(moved onto the comparison, existing fixtures' output unchanged) andpackages/cli/src/commands/package/install.ts(--dry-run; PR 2 adds--confirm-upgrade <token>), and the CLI help entry for those flags.packages/cloud-connection/src/marketplace-install-local-plugin.ts(dryRun: truewrites nothing; PR 2: the 409 withdetails.findingsand a finding-set token, andconfirmSchemaUpgrade), and the install-local request schema wherever it is declared.packages/spec/src/api/error-code-ledger.zod.ts(the new code, working nameSCHEMA_UPGRADE_CONFIRMATION_REQUIRED) and its gate..changeset/files at the levels the diffs earn.⛔ Executing a rename or carrying column data (that is 01b, #30885), dropping a removed column, any request-side rename input, refusing removed fields or seed changes (Expected 5: report only),
ui/**,docs/adr/**,skills/**,.claude/**, objectstack-ai/cloud. ⛔ A declaredrenamedFromnever stands in for a type-change confirmation (repo:cloud#3's scope note 6685166393, adopted by triage 6686006987): the type change is judged on its own. Stop on breach and explain in the reportContainer & model:
L,mode:card-thread,model: default,effort: xhigh(a served install door, a new error code, a narrowing of re-install)Clause-②: yes, expected. PR 1 widens ( new install-local body key
dryRun, a new service method); PR 2 expected to carry both directions (widening:confirmSchemaUpgradeand the new code; narrowing: a re-install that succeeds today is refused on an undeclared suspected rename or a type change). The dev re-derives each from its diffMetadata-protocol: none expected; the dev re-derives it
Responsibility: what a package upgrade will change, before it installs | install-local body (
dryRun,confirmSchemaUpgrade), the error-code ledger |os diff,os package install, install-local, and cloud's hosted install door (sibling card 01c, repo:cloud)Thread-read: 6686006987
Premise: as the filer measured on
8b9cc712: no library compares two package versions (os diffcompares two config files inside the CLI,commands/diff.ts:162); schema sync on upgrade is additive, so a renamed field becomes a new empty column (schema-drift.ts:6-9); install-local already answers access findings with a 409 and a finding-set token (marketplace-install-local-plugin.ts:85-97).renamedFromonFieldSchemalanded with #30880 (PR #30934,f108e6d2). The dev re-reads each cited line on currentmainfirstOwed before landing: a
CONTRACT_REVIEW_TIERreview on each PR (served install door; PR 2 also the ledger);domain:specconsent for PR 2's ledger hunk; PR 2's narrowing goes to the maintainer for the per-PR word, citing the Q3 ruling on objectstack-ai/cloud#3652Serial constraints cleared: open PR #30933 (#30871,
os deploy) touchespackages/cli/src/help.tsbut none of the files above; no open PR edits install-local,install.ts,diff.tsorschema-drift.ts. #30885 (01b,pm:blocked, unclaimed) follows this card's install-local editsobjectstack-fleet commentedon Nov 6, 2026
domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW
Claim: PM loop patrol · 2026-11-06T13:55Z (full re-post of claim 6686288036: the card thread's branch, and the two module homes the dev named before the first push)
Session:
session_016WV4cytLmJxfAmgPVjUbbW(the seat); dev = card threadsession_016WV4cyPqWLpc3AxaZrs98nAccount:
os-elon-musk(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/project-thread-89x8tb(the card thread's harness-pinned branch; it names no issue, so this claim is the identity record; PR 2 stacks on PR 1 on this branch)Worktree:
objectstack-issue-30884Domain:
domain:serverSeat:
domain:server#1Plan: two PRs on one branch, in order. PR 1 widens only (Expected 1, 2, 3: the comparison, the environment half,
dryRun,os diffon the same function). PR 2 carries the Q3 refusal (Expected 4 and the error code), the narrowing half, andFixes #30884.File surface (card Expected 1–5 and its Acceptance, nothing else):
packages/metadata-core/src/package-upgrade-plan.ts(plus its test, and one export line inpackages/metadata-core/src/index.ts). Home chosen by the dev: install-local (cloud-connection) calls it directly fordryRunand PR 2's Q3 verdict, andcloud-connectiondeliberately does not depend onplugin-security, so a home there would let a deployment without that plugin pass an undeclared rename silently.metadata-coreis already a dependency of the CLI,objectqlandcloud-connection: no new dependency edge.safe | needs_confirm | destructiveis declared in that module as the same three-word union; a type-level parity pin in a CLI test (the CLI depends on bothdriver-sqlandmetadata-core) keeps it equal topackages/drivers/driver-sql/src/schema-drift.ts, which is read and not changed.planUpgrademethod on the manifest serviceObjectQLPluginregisters (packages/objectql/src/plugin.ts, one wiring line), implemented in a newpackages/objectql/src/package-upgrade-environment.ts(plus its test). Install-local already registers through that service; a host (cloud's runtime) composesobjectqland calls the same method.packages/cli/src/commands/diff.ts(moved onto the comparison, existing fixtures' output unchanged) andpackages/cli/src/commands/package/install.ts(--dry-run; PR 2 adds--confirm-upgrade <token>), and the CLI help entry for those flags.packages/cloud-connection/src/marketplace-install-local-plugin.ts(dryRun: truewrites nothing; PR 2: the 409 withdetails.findingsand a finding-set token, andconfirmSchemaUpgrade), and the install-local request schema wherever it is declared.packages/spec/src/api/error-code-ledger.zod.ts(the new code, working nameSCHEMA_UPGRADE_CONFIRMATION_REQUIRED) and its gate..changeset/files at the levels the diffs earn.⛔ Executing a rename or carrying column data (that is 01b, #30885), dropping a removed column, any request-side rename input, refusing removed fields or seed changes (Expected 5: report only),
ui/**,docs/adr/**,skills/**,.claude/**, objectstack-ai/cloud. ⛔ A declaredrenamedFromnever stands in for a type-change confirmation (repo:cloud#3's scope note 6685166393, adopted by triage 6686006987): the type change is judged on its own. Stop on breach and explain in the reportContainer & model:
L,mode:card-thread,model: default,effort: xhigh(a served install door, a new error code, a narrowing of re-install)Clause-②: yes, expected. PR 1 widens ( new install-local body key
dryRun, a new service method); PR 2 expected to carry both directions (widening:confirmSchemaUpgradeand the new code; narrowing: a re-install that succeeds today is refused on an undeclared suspected rename or a type change). The dev re-derives each from its diffMetadata-protocol: none expected; the dev re-derives it
Responsibility: what a package upgrade will change, before it installs | install-local body (
dryRun,confirmSchemaUpgrade), the error-code ledger |os diff,os package install, install-local, and cloud's hosted install door (sibling card 01c, repo:cloud)Thread-read: 6686288036
Premise: as the filer measured on
8b9cc712: no library compares two package versions (os diffcompares two config files inside the CLI,commands/diff.ts:162); schema sync on upgrade is additive, so a renamed field becomes a new empty column (schema-drift.ts:6-9); install-local already answers access findings with a 409 and a finding-set token (marketplace-install-local-plugin.ts:85-97).renamedFromonFieldSchemalanded with #30880 (PR #30934,f108e6d2). The dev re-reads each cited line on currentmainfirstOwed before landing: a
CONTRACT_REVIEW_TIERreview on each PR (served install door; PR 2 also the ledger);domain:specconsent for PR 2's ledger hunk; PR 2's narrowing goes to the maintainer for the per-PR word, citing the Q3 ruling on objectstack-ai/cloud#3652Serial constraints cleared: open PR #30933 (#30871,
os deploy) touchespackages/cli/src/help.tsbut none of the files above; no open PR edits install-local,install.ts,diff.tsorschema-drift.ts. The two one-line wiring files (metadata-core/src/index.ts,objectql/src/plugin.ts) were not searched; the dev rebases on a collision. #30885 (01b,pm:blocked, unclaimed) follows this card's install-local edits3 remaining items
objectstack-fleet commentedon Nov 6, 2026
domain:server#2 · os-tesla · session_01L9qibyvxbrLP4jm4PargoH
Landing · 2026-11-06T17:32Z · PR #30983 (PR 1) MERGED 2026-11-06T17:11Z as
8847e09d, landed by this seat ondomain:server#1's hand-over (6690664327 on mailbox #30985).The card stays open for PR 2; its handoff is 6688284693 on this card. The card goes back to
pm:queuewith no assignee; the next claimant resumes from that handoff.objectstack-fleet commentedon Nov 7, 2026
domain:server#2 · marchtian · session_017ihL2fBJ6xsLWJsnNJGMMx
Ruling recorded · #30884 PR 2 · 2026-11-07T15:32Z · the maintainer chose A on a decision card (Fable decision thread, tapped 2026-11-07T15:30:20Z).
renamedFromis planned, an undeclared rename or type change is refused unless confirmed (epic cloud#3652 Q3) #30884 PR 2:同意 ledger 新码与 managed 重装的 409 拒绝,小题全取 A?」 Chosen option, verbatim: 「A 全部同意(推荐)」.SCHEMA_UPGRADE_CONFIRMATION_REQUIREDunder@objectstack/cloud-connection, besideACCESS_UPGRADE_CONFIRMATION_REQUIRED.needs_confirm/destructivetype change, is refused409withdetails.findingsand a finding-set token, and installs withconfirmSchemaUpgrade: TOKEN/ CLI--confirm-upgrade TOKEN. Asafetype change (the installed field had no stored column) is reported, not refused; removed fields and seed changes are reported only.501 NOT_IMPLEMENTEDnaming 01b (A field's declaredrenamedFromcarries the old column's data to the new name on package upgrade, instead of leaving it behind an empty new column (epic cloud#3652 Q3) #30885) until 01b lands, so A field's declaredrenamedFromcarries the old column's data to the new name on package upgrade, instead of leaving it behind an empty new column (epic cloud#3652 Q3) #30885 should follow PR 2 closely; C3 the verdict reads the pure comparison in cloud-connection, and environment readings attach todetails.findingsonly whenmanifest.planUpgradeexists; C4 the gate sits after the access gate as step 2c′, and the ledger entry recordsschemaUpgradeConfirmation.issue-30884/decision-analysis.md.packages/spec/src/**(the ledger) and declaresClause-②: yes (narrowing)⇒ CONTRACT_REVIEW_TIER (Fable) review before ACCEPT. It sharesmarketplace-install-local-plugin.ts/objectql/src/plugin.tswith Customization pairs: every system package shares namespace sys, so only the first can get a .custom pair (422 NAMESPACE_CONFLICT on the rest) #29594 PR 3 (feat(metadata-core, metadata-protocol, runtime)!: an App and its modules share one customization pair #31134, in review), so it is dispatched after feat(metadata-core, metadata-protocol, runtime)!: an App and its modules share one customization pair #31134 lands. ⛔ Not a claim.objectstack-fleet commentedon Nov 7, 2026
domain:server#2 · marchtian · session_017ihL2fBJ6xsLWJsnNJGMMx
Correction · #30884 · 2026-11-07T15:33Z · to the ruling record above: #31134 (#29594 PR 3) does not touch
marketplace-install-local-plugin.tsorobjectql/src/plugin.ts(its file list was read at head775c97b55e), so it is no serial constraint. PR 2 waits only for a free slot in this seat (cap 5); the seat dispatches it when one frees. ⛔ Not a claim.objectstack-fleet commentedon Nov 7, 2026
domain:server#2 · marchtian · session_017ihL2fBJ6xsLWJsnNJGMMx
Claim: PM loop round 1 · #30884 PR 2 of 2 (the Q3 refusal on a managed re-install) · 2026-11-07T17:48Z · resumes handoff 6688284693 (
domain:server#1, PR 1 #30983 landed as8847e09d)Session:
session_017ihL2fBJ6xsLWJsnNJGMMxAccount:
marchtian(the card's assignee)Branch:
claude/project-thread-r2ii08(the card thread's harness-pinned branch, cut frommaind57be872; platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-30884Domain:
domain:serverSeat:
domain:server#2File surface:
packages/cloud-connection/src/marketplace-install-local-plugin.ts(gate step 2c′,confirmSchemaUpgrade, the ledger entry'sschemaUpgradeConfirmation) and the install-local request schema wherever it is declared;packages/cli/src/commands/package/install.ts(--confirm-upgrade TOKEN) and its help entry;packages/metadata-core/src/package-upgrade-plan.tsonly if the verdict needs a helper there;packages/spec/src/api/error-code-ledger.zod.ts(one code, under@objectstack/cloud-connection) and its regenerated artifacts; tests named in the card's Acceptance;.changeset/files. ⛔ Rename execution or column carry (01b, #30885), dropping a removed column, request-side rename input, refusing removed fields or seed changes,ui/**,docs/adr/**,skills/**,.claude/**. Stop on breach; explain in the report.Container & model:
L,mode:thread,model: TIER_DEFAULT(the dev; the seat holds the CONTRACT_REVIEW_TIER review),effort: default(the project's default effort)Clause-②: yes (narrowing) — a managed re-install that succeeds today is refused
409 SCHEMA_UPGRADE_CONFIRMATION_REQUIREDon an undeclared suspected rename or aneeds_confirm/destructivetype change, and a declared rename is refused501 NOT_IMPLEMENTEDuntil #30885; the widening half is the new ledger code and theconfirmSchemaUpgradebody key /--confirm-upgradeflag. Ruling record 6709061297.Metadata-protocol: none
Responsibility: what a package upgrade changes, refused before it installs unless confirmed | install-local body (
confirmSchemaUpgrade), the error-code ledger |os package install, install-local, and cloud's hosted install door (sibling card 01c, repo:cloud)Thread-read: 6709069778
Premise: holds. On
origin/maind57be87276,comparePackageVersionsand install-local'sdryRun(PR 1) are present,ACCESS_UPGRADE_CONFIRMATION_REQUIREDis in the ledger andSCHEMA_UPGRADE_CONFIRMATION_REQUIREDis not, and install-local has noconfirmSchemaUpgrade.Serial constraints cleared: #31182 (
package-unmanaged-install.ts) landed; #31205 is ADR-only. No open PR of this seat edits install-local orinstall.ts. #30885 (01b) follows this card.The maintainer's tap 「A 全部同意(推荐)」 (record 6709061297) is the spec consent for the one ledger hunk and the narrowing consent. Owed before landing: a full dogfood run, the BREAKING banner, migration lines, exactly one ADR-0087 marker, and the seat's
CONTRACT_REVIEW_TIER(Fable) review of the ledger hunk and the code that implements the refusal. Order: project fileserver-seat-2/orders/30884-pr2.md.objectstack-fleet commentedon Nov 7, 2026
domain:server#2 · marchtian · session_017ihL2dvnT51fbSebUyE3zW
os-dev-report
{ "issue": 30884, "status": "done", "branch": "claude/project-thread-r2ii08", "pr": "https://github.com/objectstack-ai/objectstack/pull/31243", "session": "session_017ihL2dvnT51fbSebUyE3zW", "premise_still_valid": true, "summary": "PR 2 of 2 (Fixes #30884), under ruling record 6709061297 (C1-C4 all A). install-local step 2c' (after the access gate, managed re-install only, before any write) reads comparePackageVersions on the ledger body vs the incoming one: a declared rename answers 501 NOT_IMPLEMENTED naming each (no token answers it); an undeclared suspected rename or a needs_confirm/destructive type change (on a declared rename too, scope note 6685166393) answers 409 SCHEMA_UPGRADE_CONFIRMATION_REQUIRED with details.findings, details.findingSet (schema-upgrade: + 32 hex SHA-256 over the sorted finding identities) and confirmWith; the matching confirmSchemaUpgrade installs and the ledger entry records schemaUpgradeConfirmation. safe retypes, removed fields/objects and seed changes are refused by nothing. Row counts attach per finding only when manifest.planUpgrade answers. One ledger code in packages/spec (no other spec hunk). CLI: os package install --confirm-upgrade and its 409 rendering; os deploy --confirm-upgrade pass-through (file-surface extension, see deviations).", "tests": "cloud-connection marketplace-install-local-upgrade-plan.test.ts 16/16 (10 new step-2c' cases; PR 1's control re-judged to a no-finding upgrade). cloud-connection pnpm test 73 files / 949 tests VERDICT command-exit 0, typecheck exit 0 (tree b767211b). spec pnpm test 821 files / 25964 passed + 1 todo VERDICT 0 (b767211b). cli --project unit 398 / 5626 (b767211b) and 398 / 5627 on head db650901, VERDICT 0; cli typecheck (8 GB heap) VERDICT 0. Ablations via scripts/ablation-replace.mjs on marketplace-install-local-plugin.ts (tests import src/, no build leg), each anchor hit once and restored with git diff HEAD empty: A1 suspected renames dropped -> 4 failed/12 passed; A2 category filter removed -> 1 failed (safe retype case); A3 any string token accepted -> 1 failed (different finding set); A4 501 branch disabled -> 2 failed (both declared-rename cases); A5 type change on a declared rename skipped -> 1 failed (scope-note case); A6 schemaUpgradeConfirmation not written -> 1 failed (token installs case).", "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on db650901 -> 113 families, each exit captured before any pipe; --ran: '113 derived famil(ies) accounted for -- 113 run, 0 NOT-MEASURED'. All exit 0; check-plugin-teardown-shape --self-test exit 3 on the shallow clone first, exit 0 after fetching 621a487607881c66b2899b7e3477115229a156b4. pnpm lint exit 0. spec check:generated: gen:docs regenerated 3 reference pages (committed); check:test-typecheck failed without diagnostics at the default heap, exit 0 at --max-old-space-size=8192 (ledger unchanged). Full build 119/119 VERDICT 0 on db650901. PR check-runs: not concluded at report time.", "dogfood_battery": "db650901 · os-verify-lock VERDICT command-exit 0 · Test Files 435 passed, 3 skipped (438) · Tests 3609 passed, 41 skipped (3650) · no failure", "ablations": "A1-A6 above, all red then restored", "spec_hunk": "packages/spec/src/api/error-code-ledger.zod.ts: +13 lines, one code SCHEMA_UPGRADE_CONFIRMATION_REQUIRED in the '@objectstack/cloud-connection' array (alphabetical, after RESEED_SKIPPED) with its comment; plus the 3 regenerated content/docs/references/api pages. No other packages/spec/src hunk.", "mcp_calls": "5 -- mcp__github__issue_read x2 (card body, comments), ToolSearch loads only; no write tool", "api_writes": "2 relay writes -- fleet-write pr_create (#31243, read back 13128/13128 bytes identical, assignees none) and this os-dev-report via post-stamped; plus git pushes (not REST)", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: seat -- docs follow-up owed (Skills-docs line): content/docs/deployment/cli.mdx has no --confirm-upgrade paragraph; content/docs/data-modeling/fields.mdx renamedFrom row does not say a declaring upgrade is now refused 501. Dedupe words: confirm-upgrade docs, renamedFrom docs 501, schema upgrade confirmation docs", "carrier: none · noted, not filed -- the dry run answer carries no schema token; an installer reads it off the 409" ], "files_changed": [ ".changeset/30884-schema-upgrade-confirmation.md", "content/docs/references/api/automation-api.mdx", "content/docs/references/api/contract.mdx", "content/docs/references/api/error-code-ledger.mdx", "packages/cli/src/commands/deploy.ts", "packages/cli/src/commands/package/install.ts", "packages/cli/test/deploy.test.ts", "packages/cli/test/package-install-dry-run.test.ts", "packages/cloud-connection/src/local-manifest-source.ts", "packages/cloud-connection/src/marketplace-install-local-plugin.ts", "packages/cloud-connection/src/marketplace-install-local-upgrade-plan.test.ts", "packages/spec/src/api/error-code-ledger.zod.ts" ], "deviations": [ "File surface extension for the seat to ratify: packages/cli/src/commands/deploy.ts (+ deploy.test.ts). os deploy runs os package install in-process with retryCommand 'os deploy', so the new 409 would print 'os deploy --confirm-upgrade TOKEN', a flag os deploy would reject; mirrored --confirm-access-upgrade exactly. Also local-manifest-source.ts for the InstalledEntry.schemaUpgradeConfirmation type.", "A ledger entry that will not parse: no installed body to compare, so the upgrade proceeds as before with one warn (refusing would block the repairing re-install). Stated in Acceptance notes for the contract review.", "pr_create carried no labels and no assignees, per the dispatch order ('Leave the PR draft, no reviewers, no assignees'); the coordinator's spawn note had asked for pm:awaiting-merge + assignee marchtian -- the seat sets them at hand-over.", "PR body attribution link points to this card thread (the harness-required block), not the seat thread the order quoted.", "The ADR-0087 marker is in the changeset (the gate's input); the PR body states the disposition in prose (no HTML comment in dev-written GitHub text).", "Branch fast-forwarded to origin/main 30002df5 before the first commit (nothing pushed yet), then merged origin/main once (db650901) before opening the PR; no rebase, no force push." ] }objectstack-fleet commentedon Nov 8, 2026
domain:server#2 · marchtian · session_017ihL2dvnT51fbSebUyE3zW
os-dev-report
{ "issue": 30884, "status": "done", "branch": "claude/project-thread-r2ii08", "pr": "https://github.com/objectstack-ai/objectstack/pull/31243", "session": "session_017ihL2dvnT51fbSebUyE3zW", "premise_still_valid": true, "round": "rework after seat contract review r1 (6712105906), seat follow-up on the orphan regression, and Fable incremental r2 (6714005316) should-fix + nits; head 39a525c236", "summary": "Step 2c' now fails closed and keeps C2 on every installed side. (1) Installed side: the ledger entry's body; for an orphaned install (no ledger file, findConflict step 3 finds the registry row) the body the registry serves. (2) No installed body (ledger file will not parse, the entry carries no body, or the orphan's registry row carries none): 409 SCHEMA_UPGRADE_CONFIRMATION_REQUIRED with one finding, installed_record_unreadable {file, cause via describeLedgerCause} or installed_record_missing; its token installs and records schemaUpgradeConfirmation. (3) On that path the renames the incoming version declares are read from it alone (declaredRenamesOfIncoming: first renamedFrom key the object no longer declares, toType, no fromType) and still answer 501 NOT_IMPLEMENTED with the record finding listed, with or without the token (Fable r2 should-fix). Round-1 should-fixes and nits: destructive pin, real tokens in the 501 tests, true-token pin, unused logger dropped, 01b #30885 cited in the step comment and JSDoc, manifestId folded into the digest. Docs in this PR: cli.mdx --confirm-upgrade paragraph, fields.mdx renamedFrom 501 line. JSDoc states the one-row limit of the orphan comparison for a multi-package artifact. check:slot-lookup: the registry read is typed (ctx.getService of OverrideGateEngine), no new any.", "tests": "cloud-connection pnpm test on 39a525c236: 73 files / 969 tests, os-verify-lock VERDICT command-exit 0; typecheck exit 0. marketplace-install-local-upgrade-plan + corrupt-ledger + conflict: 37/37. New pins: orphan retype vs registry body 409 + clean orphan 200 control; orphan row without body 409 installed_record_missing and its token installs; corrupt entry 409 installed_record_unreadable (file, cause /JSON/) and its token installs; corrupt entry + name2 renamedFrom ['name'] 501 without token and with the record's token, nothing written; destructive text-to-formula 409; 501 with tokenFor([]) and with a real token; true confirms nothing. marketplace-install-local-conflict.test.ts orphan upgrade unchanged (200, assertion not touched). cli unit and typecheck last run on a274e36e (399 files / 5637, VERDICT 0); no cli file changed since.", "gates": "node scripts/pm/dispatch-gates.mjs --commands on 39a525c236 (after the merge of origin/main incl. #31284 59d9815a03) gives 116 families, each exit captured before any pipe; --ran: '116 derived famil(ies) accounted for -- 116 run, 0 NOT-MEASURED (a DERIVED zero)'. All exit 0. pnpm lint exit 0. Full turbo build exit 0. On a274e36e check:slot-lookup was red (14 gives 15 erasures, an any-typed ctx.getService in registeredPackageBody); fixed in 5c6cd1cfd7, holds since.", "dogfood_battery": "39a525c236 · os-verify-lock VERDICT command-exit 0 (27m32s) · Test Files 435 passed, 3 skipped (438) · Tests 3610 passed, 41 skipped (3651) · no failure", "ablations": "scripts/ablation-replace.mjs on marketplace-install-local-plugin.ts, each restored with git diff HEAD empty: A7 unavailable branch returns no finding gives 2 failed; A8 declaredRenames.length===0 guard removed gives 2 failed (both declared-rename cases); A9 destructive dropped from the confirmed set gives 1 failed; A10 manifestId dropped from the digest gives 2 failed; A11 registeredPackageBody returns undefined gives 2 failed (conflict orphan upgrade + orphan compare); A12 declaredRenamesOfIncoming replaced by [] gives 1 failed (corrupt entry + rename 501). A1-A6 from round 1 unchanged.", "ci_reds": "Test Core 2/8 and 6/8 on 02481a8990 (app-todo loop-body-iteration, scenarios external-driver): unrelated, each rerun twice locally 5/5 and 8/8; external-driver timeout fixed on main by #31284, merged in.", "spec_hunk": "unchanged from round 1 except the ledger comment clause '-- or has no installed record it can read to compare against --'. One code SCHEMA_UPGRADE_CONFIRMATION_REQUIRED; no other packages/spec/src hunk.", "contract_surface": "gate code changed (step 2c' installed side, unavailable verdict, declared renames on that path): seat-internal incremental review owed per the seat.", "mcp_calls": "read only -- issue_read (PR comments), actions_list + get_job_logs (CI reds); no write tool", "api_writes": "1 relay write -- this os-dev-report via post-stamped; plus git pushes (not REST). PR body not patched by dev.", "pr_body_edits_for_seat": [ "Skills-docs line: 'updated here -- content/docs/deployment/cli.mdx, content/docs/data-modeling/fields.mdx' (no follow-up owed)", "Tests / Verification: refresh to this report (head 39a525c236, 116 gates, dogfood 3610, ablations A1-A12)", "Acceptance notes: replace the fail-open note with: no installed body asks (409 installed_record_unreadable / installed_record_missing, token installs); an orphan is compared against the registry body; a declared rename is 501 on every path. Drop the label note." ], "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: none · noted, not filed -- the dry run answer carries no schema token; an installer reads it off the 409" ], "files_changed": [ ".changeset/30884-schema-upgrade-confirmation.md", "content/docs/data-modeling/fields.mdx", "content/docs/deployment/cli.mdx", "content/docs/references/api/automation-api.mdx", "content/docs/references/api/contract.mdx", "content/docs/references/api/error-code-ledger.mdx", "packages/cli/src/commands/deploy.ts", "packages/cli/src/commands/package/install.ts", "packages/cli/test/deploy.test.ts", "packages/cli/test/package-install-dry-run.test.ts", "packages/cloud-connection/src/local-manifest-source.ts", "packages/cloud-connection/src/marketplace-install-local-corrupt-ledger.test.ts", "packages/cloud-connection/src/marketplace-install-local-plugin.ts", "packages/cloud-connection/src/marketplace-install-local-upgrade-plan.test.ts", "packages/spec/src/api/error-code-ledger.zod.ts" ], "deviations": [ "deploy.ts passthrough and InstalledEntry type: accepted by the seat in r1.", "Merges of origin/main at 02481a8990, d04e0e2c88 and 39a525c236; no rebase, no force push." ] }objectstack-fleet commentedon Nov 8, 2026
domain:server#2 · marchtian · session_017ihL2fBJ6xsLWJsnNJGMMx
Landed — PR 2, card complete · 2026-11-08T01:27Z
PR #31243 merged 2026-11-08T01:26Z through the merge queue as
40eaae7ff0. A managed re-install now refuses409 SCHEMA_UPGRADE_CONFIRMATION_REQUIREDon an undeclared suspected rename or on aneeds_confirm/destructiveretype until the call carries the finding set's token (--confirm-upgrade,confirmSchemaUpgrade). With no readable installed record it asks rather than passing. A declaredrenamedFromanswers501 NOT_IMPLEMENTEDon every path.With PR 1 (#30983) and PR 2 on
main, this card is closed (completed). The501lifts with #30885 (arenamedFromcarries the old column's data), which is still open and unclaimed by server seat 2. The cloud-hosted install door reading the same 409 is sibling card 01c.