Repository navigation
feat(metadata-core,metadata-protocol,objectql,plugin-security): the sys_metadata family goes tenant-less; the per-organization overlay axis retires; managed content is sealed (ADR-0131 D6/D7/D13) #15206
Description
Activity
- addedpriority:p1High: required for production / M2High: required for production / M2
on Sep 4, 2026 - added a commit that references this issue
on Sep 5, 2026 - added a commit that references this issue
on Sep 9, 2026 objectstack-fleet commented
on Oct 6, 2026 ContributorMore actionsv18 pre-opening re-verification (C5): DRIFTED badly. It is now XL and needs three maintainer rulings before it can be cut again
Triage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-06T14:39Z. ⛔ Not a claim, ⛔ not a dispatch. Read-only re-verification on objectstackmain6befe19c6e. The cut base was 2026-09-04, 3,298 commits earlier. The maintainer asked for this pre-opening preparation in the triage seat's chat: 「现在就可以处理吧」. Classes, positions and functions only. The claiming seat applies these corrections before building. The body is not rewritten.Corrections:
- The four
sys_metadatatables do not "declaresystemFields.tenant: false".- Each declares its own
organization_id:metadata-core/src/objects/sys-metadata.object.ts:132,sys-metadata-audit.object.ts:113,sys-metadata-commit.object.ts:129,sys-metadata-history.object.ts:148. - Indexes key on it:
sys-metadata:226-231;history:183-188, withevent_seqper-organization;commit:146-148; and the runtimeOVERLAY_INDEX_COLUMNS(overlay-index.ts:137). - So the fields, the indexes and the runtime index all need re-keying.
- The physical column drop is C7's (D10: drops are the manual ceremony, last). It is not this card's.
- Each declares its own
- The
sys_view_definitionpositive control ("only the named files reference it") was already false at the cut, and still is: 35 files then, 37 now.- The non-test mentions are comments only, so "no reader or writer of its rows" holds.
- The "CLI migration allowlist entry" does not exist as a list entry. No ADR-0087 entry exists yet.
- Already done: the ADR-0005 and ADR-0017 amendment notes landed with the ADR merge.
- The managed-flow acceptance contradicts D6 as amended (Regime C). Flow disable has shipped (
flow-activation-store.ts,domains/activation-gate.ts). The permission-set clone has no linkage to refuse; its organization-owned copy is C3's.
New surface since the cut, which this card's retirement now has to remove (about 31 commits;
protocol.tsgrew from 21,613 to 27,853 lines, andorganizationIdForMetaReadcalls from 14 to 30):- the org-first served-row path (
servedOverlayRowCandidates:1994,mergePackageAwareOverlay:2122,findServedOverlayRow:9912); - the anonymous form intake's org-layer refusals (
:16163,:16232;metadata-core/src/anonymous-form-intake.ts). This is the 17.7 security layering; item-lock.ts:350resolveOverlayLockLayer;- the org gate on layered reads;
- the org fold in cached ETags;
- org overlays outranking packaged translations;
rest/src/meta-item-read-gate.ts([finding] class closure: six more places the runtime dispatcher's/metareads answer differently fromRestServer's, measured by #20320's census (unknown type,?preview=DRAFT, item translation and doc locale, the book tree, object?preview=draft) #20408).
Needs the maintainer before it is cut again:
- Split
allowOrgOverride. The same flag also decides whether an environment overlay of a packaged item is allowed (isOverlayAllowed:15886→refusePackagedBaseOverride:17067/refusePackagedBaseRemoval:17176). Turning off the five flags would also close the environment overlays D6 keeps. - What becomes of the shipped 17.x org-layer public-form withdrawal semantics (a security behaviour).
- The
singleDefault-Organization rows. fix(plugin-email): a metadata-door email template edit survives the next boot #21818 measured that undersingleevery Studio save of a view, dashboard, report, translation or email template is stored org-scoped, and new code relies on it (the email bootstrap, the anonymous form doors). "singleobserves no change" is false. Their migration to environment scope can collide by name: multi-organizationsingledeployments are reported at boot, not refused.
Generated by Claude Code
- The four
objectstack-fleet commented
on Oct 6, 2026 ContributorMore actionsRuling pointers: batch #282 items 3 and 4 (decision cards #22008 and #22011) · both A · maintainer 「同意」 2026-10-06T16:01Z
Director seat, summon #35,
session_01VYToj6PQehTEKNrjGM9akg(via the relay). Records: 6020151485 on #22008 and 6020163868 on #22011, both closed. This card stayspm:blockedon #15193 and #15195. Thread-read: none newer than the body's blocked notice.- decision: ADR-0131 C5 — under
single, Studio saves are stored organization-scoped today. At the v18 upgrade, are they promoted to the environment, kept behind a compatibility read, or dropped? #22011 → A. Undersingle, the Default Organization's organization-scopedsys_metadatarows of the five presentational types (fix(plugin-email): a metadata-door email template edit survives the next boot #21818's measurement) are promoted to environment scope by the migration ceremony (C7, feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211): D10 fate 3 with the environment as the owner. No compatibility read of the Default Organization's rows is kept (D13 retires the organization-scoped write path), and nothing is dropped (D10 sanctions deletion of mirrors only). Conflict rule: another organization's row of the same name is reported, never guessed (D10 fate 4); the operator chooses per row. - decision: ADR-0131 C5 — 17.x honours a public form's withdrawal saved at the organization layer. When that layer retires, are those withdrawals carried to the environment layer, dropped, or kept as a special read? #22008 → A. Organization-layer withdrawals of public forms are carried to the environment layer by the same ceremony, fail-closed: on a multi-organization deployment a form any organization withdrew is withdrawn at the environment layer. No
anonymousFormIntakeOrgScopeRefusal-class read survives the retirement. Pin owed with C7: a form withdrawn before the upgrade is refused at the anonymous intake doors after it, on both kernels. - Together with decision: ADR-0131 §6 Q1 — at the v18 upgrade, do customer-edited email templates become environment-level Studio templates, stay as the Default Organization's overrides, or get dropped? #22005's ruling (email templates, letter C): one ceremony, one conflict rule.
Generated by Claude Code
- decision: ADR-0131 C5 — under
objectstack-fleet commented
on Oct 7, 2026 ContributorMore actionsRuling pointer: batch #283 item 5 (decision card #22007) · C · maintainer 「其他同意」 2026-10-07T01:25Z
Director seat, summon #35,
session_01VYToj6PQehTEKNrjGM9akg(via the relay). The record is 6028809298 on #22007, which is closed. This card stayspm:blockedontarget:v18. Thread-read: 6020252365.allowOrgOverrideis renamed, not split and not re-meant. When the per-organization axis retires (ADR-0131 D6), the key atpackages/spec/src/kernel/metadata-plugin.zod.ts:267takes a name that says "may an environment overlay this packaged item", with an ADR-0087 D2 load-time conversion (an existing manifest naming the old key loads unchanged), and the per-organization path behindisOverlayAllowed(protocol.ts:15886) is deleted. The new name is fixed by the contract review of this card's change.- Not taken: A (a second key with the organization one frozen at
false, a permanently dead key) and B (the old name governing environments). - Scope of this card gains: rename, D2 conversion, deletion of the per-organization path; generated baselines and docs follow. The five types that enable the key today keep their environment overlays through the rename. Together with the batch 🔗 Broken links detected in documentation #282 pointers above (withdrawal promotion A, Default Organization promotion A), C5's three rulings are now all on record.
Generated by Claude Code
- added 4 commits that reference this issue
on Oct 7, 2026 objectstack-fleet commented
on Oct 7, 2026 ContributorMore actionsScope amended by #22007 (ruled C,
6028809298): renameallowOrgOverrideto an environment-overlay key, with a load-time conversion, and delete the per-organization pathTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-07T12:31Z. ⛔ Not a claim, ⛔ not a dispatch. The v18 line opened in this act (#15193 closed on the maintainer's word,6037915987).What C5 now carries:
- The rename.
allowOrgOverride(packages/spec/src/kernel/metadata-plugin.zod.ts:267, today "Allow per-org overlay writes via runtime metadata API") is renamed to a key that says what it will then mean: may an environment overlay this packaged item. ⛔ The new name is fixed by the contract review of the C5 change, not here. - The conversion. An ADR-0087 D2 load-time conversion, so that an existing manifest naming the old key still loads unchanged.
- The deletion. The per-organization path behind
isOverlayAllowed(packages/metadata-protocol/src/protocol.ts:15933onmain) is deleted. Generated baselines and docs follow. - No overlay is lost. The five types that enable the key today (view, dashboard, report, translation, email template) keep their environment overlays through the rename.
⛔ Not taken: a second key with the organization one frozen at
false(A), or the old name with a new meaning (B).This card stays
pm:blockedbehind C1 (#15195), per itsBlocked-by:line. Its file surface is re-verified at claim.- The rename.
54 remaining items
objectstack-fleet commented
on Oct 9, 2026 ContributorMore actionsACCEPT (seat review): PR #22447 at head
fa9f7b6483. Stage S3: the/metadoors carry no organization, organization-admin metadata authoring closes, andmanage_org_presentationretiresdomain:engine#2·session_01Bw3y2DWhT9RPnrmDsNqEVG(os-tesla), claim 6076144407 · 2026-10-09T12:50Z. Read against GitHub, not the reports (os-dev-reports 6077667992, 6078632031, 6078815440, 6079504896, 6080128648 and 6080865956).Contract reviews at
CONTRACT_REVIEW_TIER- 6078132696: PASS on
9a2d880352. - 6078714194: PASS on
4a222dc938. - 6080287167: FAIL on
82bd7e85a2, on the withdrawal clause (①14f; see below). - 6081190446: PASS on this head. The code is byte-identical to the heads the earlier records judged.
Shape. Draft, base
main.Refs #15206 (S3), with no closing keyword.Clause-②: no (narrowing). 45 files, +1313/−2698. NOT governed (check-governed-merges --pr 22447: 4,011 changed lines, under 5,000).The change, as read in the diff
metaWriteCapabilityVerdictadmitsisSystemormanage_metadataonly. Itsmanage_org_presentationarm and itscanonicalType/activeOrganizationIdinputs are removed. The four REST item doors and the dispatcher PUT refuse an organization admin with403.manage_org_presentationleavesPLATFORM_CAPABILITIES. A permission set that names it still parses, and the grant admits nothing. This is registered as an ADR-0087 semantic entry.- Every
/metawrite lands withorganization_idNULL, and every/metaread is environment → code, on both transports. The read flip and the write flip land together. - Legacy organization rows are pinned as served by no
/metadoor. The anonymous form doors keep triage's Q3 → A read: they read a form view in the Default Organization, fail-closed.
The dev's Q1 is answered A.
/referencesreads environment → code with every other/metadoor. It follows the stage plan's rule that the read flips with the write. Every contract review on this PR judges it the same way (① item 6).Published text, checked sentence by sentence against the diff
- The changeset ("What changes", "What moves for consumers", "What a deployment observes", "What does not change").
content/docs/concepts/metadata-lifecycle.mdx:109(the D6 callout) and its table row.content/docs/kernel/contracts/metadata-service.mdx("Environment Customization").concept.mdxandcreate-vs-edit-form.mdx, one line each.- The
acceptanceCriteriaof18.meta-doors-organization-scope-retired. - The seat withheld ACCEPT once (6079074423). Three of these sentences, and later the entry's, said a legacy organization overlay is "not served" and that a Studio re-save makes the edit live. That is false for a public form's view, because
resolveFormBySlugprefers the Default Organization's overlay. Two prose rounds scoped the sentences to the/metadoors and named the public-form exception. - The seat's own error, recorded. The seat's prescription in 6079074423 said the form doors prefer the organization's overlay "body and withdrawal alike". That dropped its own qualifier: a withdrawal in either layer closes the form (
findPublicFormView, the kill-switch rule). The dev wrote it faithfully into five copies, and the review FAILed it (6080287167 ①14f). A third prose round corrected all five copies. As they now stand, each sentence holds againstresolveFormBySlugandfindPublicFormViewat this head (6081190446 ①14).
Generated drift. It was re-measured on a throwaway merge with
origin/main: zero (6078815440). The later merges ofmaintouched no generated or os-regen path of this PR.registry.tswas regenerated bygen:migration-registryfor each entry patch. Since this head's merge base (166a94f75d),mainhas moved 3 commits. They touch no generated path and share onlyrest-server.ts, outside this PR's hunks, andgit merge-treeis clean.CI on
fa9f7b6483. All seven required contexts are success, with 0 failures. The skips (Console Pin Gate, by theconsolepath filter; Packed-tarball smoke, opt-in; Auto Label and Check PR Size on the body-edit event) are on the expected-skip roster.mergeable_state: clean.The review's flags, answered
packages/runtime/src/domains/packages.ts(an S4-territory edit; byte-identical behaviour) is declared todomain:clion [PM seat] domain:cli — 🟢 os-elon-musk · session_01BmsuLyUeuG5CNpZFMH1jzS #6024 (6077944243).- The objectui pin moved under the merge; the review re-measured it, and nothing removed here is imported there.
Out of scope, one line each
- objectui's
CapabilityMultiSelectField.tsx, its i18n packs andCapabilityMultiSelectField.specParity-6285.test.tsxstill carrymanage_org_presentation. Its parity test reds on the spec bump that carries this release. Relayed on landing to objectui#12030, the v18 dependency move, as an item for its break list (rule 3). - The anonymous form doors still serve a legacy organization overlay's body until C7. Pointer posted on feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211 in this act.
protocol.tscomments and two tests still name the deletedorganizationIdForMetaWrite: S4's rewrite.metadata-lifecycle.mdx:239,241"Per-org overlay" rationale wording: stale, not false. S5 carries it. The generated reference pages'allowOrgOverridetext is spec: renameallowOrgOverrideto an environment-overlay key with an ADR-0087 load-time conversion (ADR-0131 C5's spec half, split from #15206 per #22007 ruling C) #22340's.- The package-manifest read (
assemblePackageManifest, the/packagesdoor) still names the caller's organization: S4's, with the domain's raw threading. - The PR body's stale verification lines were corrected in this act.
Next: ready, then auto-merge, in this act. After the merge: the landing record, the objectui relay, and S4's claim (it carries #22350).
- 6078132696: PASS on
objectstack-fleet commented
on Oct 9, 2026 ContributorMore actionsLanded (stage): PR #22447 →
7895671162through the merge queue.domain:engine#2·session_01Bw3y2DWhT9RPnrmDsNqEVG· 2026-10-09T13:38Z.- C5 stage S3. The PR is
Refs #15206 (S3); it carries no closing keyword, and this card is still open. - Content on
origin/main:metaWriteCapabilityVerdictadmitsisSystemormanage_metadataonly.manage_org_presentationis gone fromPLATFORM_CAPABILITIES; it remains only in the retirement comments.organizationIdForMetaWriteis no longer exported.meta-doors-organization-scope-retiredis inregistry.ts..changeset/15206-meta-doors-environment-only.mdis present.- The queue branch is gone.
- Merged at 2026-10-09T13:37Z.
- Records: ACCEPT 6081239588. Contract reviews: 6078132696 PASS, 6078714194 PASS, 6080287167 FAIL, then 6081190446 PASS on the landed head. Seat patch notes: 6079074423.
- Relays in this act:
- objectui#12030 (the v18 dependency move) gets the
manage_org_presentationbreak-list item (rule 3). - feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211 has the public-form pointer (6081248392).
- The S3 cloud session is archived.
- objectui#12030 (the v18 dependency move) gets the
- Stage status: S1, S2 and S3 are on
main. S4 carries [decision] once ADR-0131 C5 makes package metadata environment-wide, does deletePackage's organization-scope guard (organizationId / allTenants, TENANT_SCOPE_REQUIRED, #7780) retire? #22350 (ruling A 6070750378) and is claimed by this seat next. S5 follows S4. S6 is feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211's. S7 is optional and carries the ADR-0029 D9.6 / ADR-0086 D1 notes.
- C5 stage S3. The PR is
objectstack-fleet commented
on Oct 9, 2026 ContributorMore actionsClaim: PM loop round 2 · 2026-10-09T13:41Z
Session:session_01Bw3y2DWhT9RPnrmDsNqEVG
Account:os-tesla(the seat's linked user, asget_meanswers it; the card's assignee)
Branch:claude/issue-15206-s4-protocol-env-only
Worktree: the cloud session's own checkout (mode:cloud)
Domain:domain:engine
Seat:domain:engine#2(seat post #20966)
Provenance:- S3 landed as
7895671162(landing record 6082066129). This claim covers stage S4 only, per the stage plan 6067844889 and stage 0's S4 row (6067752061). S5 is claimed with its own dispatch. - S4 carries [decision] once ADR-0131 C5 makes package metadata environment-wide, does deletePackage's organization-scope guard (organizationId / allTenants, TENANT_SCOPE_REQUIRED, #7780) retire? #22350 (ruling A, 6070750378), claimed in the same act on that card. The PR names it as a second
Refsline, and this seat closes it with S4's landing record. - Binding: the card body (ADR-0131 D6/D7); triage's Q1 A, Q2 B and Q3 A (6068032120); ruling A on [decision] once ADR-0131 C5 makes package metadata environment-wide, does deletePackage's organization-scope guard (organizationId / allTenants, TENANT_SCOPE_REQUIRED, #7780) retire? #22350. Q1 → C (6073941543) binds S5, not S4.
File surface (stage 0's S4 row, measured at3599fef123; re-read by symbol onorigin/main7895671162): domain:engine, inpackages/metadata-protocol:protocol.ts:orgScopedWriteRefusalloses its exemption and names the posture.anonymousFormIntakeOrgScopeRefusal/…ReopenRefusalare deleted as unreachable.resolveMetaItemOrgScope,resolveDraftOrgScopeForPublishandgetOverlayRepogo to one environment repository. The write scopes of save, publish / promote, rollback,revertCommit,publishPackageDrafts,discardPackageDrafts,duplicatePackage,reassignOrphanedMetadataanddeletePackagego with them.migrateStoredMetadataskips organization rows and reports them. The audit and commit records write NULL. So doesapplyRemoteMetadataMutation. BothTENANT_SCOPE_REQUIREDrefusals are removed ([decision] once ADR-0131 C5 makes package metadata environment-wide, does deletePackage's organization-scope guard (organizationId / allTenants, TENANT_SCOPE_REQUIRED, #7780) retire? #22350 A).sys-metadata-repository.ts: noorganizationIdoption. Alsostored-migration.ts,runtime-authoring-gate.ts, and the identity pin (protocol.org-scoped-write-refused.test.ts) with its dependent tests.
- Cross-lane, declared before editing:
domain:cli:packages/runtime/src/domains/packages.ts, covering the raw organization threading,requireUninstallOrganizationScope([decision] once ADR-0131 C5 makes package metadata environment-wide, does deletePackage's organization-scope guard (organizationId / allTenants, TENANT_SCOPE_REQUIRED, #7780) retire? #22350 A) andassemblePackageManifest's organization read (S3's carried finding).domain:services:packages/services/service-automation/src/flow-credential-migration.ts.domain:spec:packages/spec/src/api/protocol.zod.ts, coveringorganizationIdon the save / publish / delete metadata requests andorganizationId/allTenantson the package delete request. Also theerror-code-ledger.zod.tsTENANT_SCOPE_REQUIREDrows, ADR-0087 entries, the regeneratedregistry.tsand the generated artifacts.
- The comments and two tests that still name the deleted
organizationIdForMetaWrite(S3's carried finding). - ⛔ Not the read narrowing (S5), not the anonymous form doors' organization read (C7, feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211), and no deletion of stored rows (C7).
- Stop on a breach and explain in the report.
Container & model:L,mode:cloud,model: default(dispatch-gates --tier: no path-derived mandate). It may split into S4a (protocol) and S4b (packages domain and callers) at the human-merge line.
Clause-②: yes (narrowing) - Narrowing on most of the surface: organization-scoped writes are refused, and request keys retire. But one refusal lifts: a package delete naming neither
organizationIdnorallTenants, refused today withTENANT_SCOPE_REQUIRED, is accepted. Ruling A decides that directly. The decision card filed it asClause-②: yes("deleting a ruled guard"), so it is declared yes. It owes a contract review at tier before the queue.
Responsibility: n/a — not a defect card
Thread-read: 6082066129
Serial constraints cleared: at 2026-10-09T13:41Z, 9 open PRs read byfilename. - None touches
metadata-protocol'sprotocol.ts,sys-metadata-repository.ts,stored-migration.tsorruntime-authoring-gate.ts, norruntime'spackages.tsorflow-credential-migration.ts. - PR fix(objectql): an update-mode validate() preview judges the stored row merged with the patch (#22445) #22471 (objectql: an update-mode
validate()preview (an import dry run of a matched row) reads no stored row, so a rule that reads an omitted column refuses a row the real update admits #22445, this seat, in the merge queue) editsprotocol.zod.tsatValidateData, a different region. - PR feat(storage)!: retire the storage scope public from StorageScopeSchema and refuse it at the upload doors (#22443) #22469 and PR feat(spec)!: an element binds data through dataSource only — retire the element-layer flat binding keys and object-grid.defaultFilters (#11509) #22421 regenerate
registry.ts; the later lander regenerates after mergingmain. - The plan's predecessors are on
main: S3, PR fix(metadata-protocol): a packaged item's save answers the package door before the checks that judge its body, on every kernel topology #22338 (35afb15878) and PR feat(spec, metadata-protocol): each _drafts row carries the draft body's own label, or null #22323 (c512c255c5). spec: renameallowOrgOverrideto an environment-overlay key with an ADR-0087 load-time conversion (ADR-0131 C5's spec half, split from #15206 per #22007 ruling C) #22340 (the key rename) waits for S5.
- S3 landed as
objectstack-fleet commented
on Oct 9, 2026 ContributorMore actionsos-dev-report
{ "issue": 15206, "stage": "S4", "status": "done", "branch": "claude/issue-15206-s4-protocol-env-only", "pr": "https://github.com/objectstack-ai/objectstack/pull/22515", "head": "537fa89c8", "session": "session_01NcYr731pAx356wDedHe9Ca (dispatched by domain:engine#2, session_01Bw3y2DWhT9RPnrmDsNqEVG, claim 6082123637 — newest Claim on #15206, names this branch: verified)", "premise_still_valid": true, "summary": "The metadata protocol refuses every organization-scoped write, FIRST and for every type, with 403 NOT_OVERRIDABLE whose first sentence names the tenancy posture. The verbs covered are saveMetaItem (draft and publish), publishMetaItem, deleteMetaItem, rollbackMetaItem, revertCommit, rollbackToPackageCommit, publishPackageDrafts, discardPackageDrafts, revertStoredPackage, duplicatePackage and reassignOrphanedMetadata. The five-type exemption and the hatch's org arm are gone; orgScopedWriteRefusal, the two anonymous-form-intake org refusals, envWideRawViewRows, resolveMetaItemOrgScope and resolveDraftOrgScopeForPublish are deleted; the audit and commit ledgers write NULL; migrateStoredMetadata and the flow credential move report legacy org rows instead of re-saving them. #22350 A: deletePackage retires organizationId/allTenants (400 INVALID_REQUEST), both TENANT_SCOPE_REQUIRED refusals and the runtime door's requireUninstallOrganizationScope; the uninstall is environment-wide, and legacy org rows of the package are removed with it through the repository. The /packages door threads no organization into any verb, the manifest read or the commit list. The identity pin is flipped to none accepted (302 tests) and reverse-verified. ⚠ The PR is 6,304 changed lines, over the human-merge line, which is 3,000 on main at PR time (PR #22490 landed): see deviations[0].", "files_changed": "89 files vs merge-base: +1502 / -4802. Source: packages/metadata-protocol/src/protocol.ts, runtime-authoring-gate.ts; packages/runtime/src/domains/packages.ts; packages/services/service-automation/src/flow-credential-migration.ts; packages/cloud-connection/src/marketplace-install-local-plugin.ts (1 type line); packages/spec/src/api/protocol.zod.ts, error-code-ledger.zod.ts, stack.zod.ts (comment), migrations/entries/semantic/18.metadata-write-organization-scope-refused.ts + 18.package-uninstall-environment-wide.ts (new), migrations/registry.ts (gen), authorable-surface/api.json (3 lines, gate-proved), content/docs/references/api/* (gen); .changeset/15206-protocol-environment-only.md; content/docs/deployment/environment-variables.mdx, content/docs/kernel/contracts/metadata-service.mdx. Tests: 33 metadata-protocol, 17 objectql, 6 rest, 12 runtime (2 integration files deleted: package-revert-commit-org-scope, package-revert-commit-attribution-org-scope), 1 service-automation, 2 dogfood, spec protocol.test.ts.", "tests": "At 537fa89c8 (main e148ca98 merged), under the verify lock: (1) metadata-protocol full suite: VERDICT command-exit 0, 223 files / 28,304 passed / 19 skipped. (2) runtime packages-*.test.ts plus 5 integration files and domain-protocol-handle-typing: exit 0, 30 files / 498 passed. (3) objectql: the 18 touched files plus typecheck and check:test-typecheck, exit 0; rest: 6 touched files plus 11 related, exit 0; service-automation flow-credential-migration including a new org-row case, exit 0; metadata-core meta-write-org-scope, exit 0. (4) dogfood: 11 files on rebuilt dist, 167 passed. (5) typecheck --no-bail: spec, metadata-protocol, objectql, rest, service-automation, runtime, cloud-connection, cli and dogfood all Done. (6) spec check:generated: all 15 up to date. Reverse verification (fix committed first; scripts/ablation-replace.mjs with a trap): the five-type exemption re-inserted at the saveMetaItem refusal turned 17 red / 285 green. The red cases are the 10 tier-A save cases plus 7 view-based cases (3 posture sentences, the hatch, topology, 2 legacy re-saves); every other type and every control stayed green. The restore was verified blob equal to HEAD with an empty git diff HEAD. One earlier ablation run measured nothing (spec dist was mid-rebuild by a sibling job, suite import error) and is discarded, not counted.", "gates": "dispatch-gates --commands at 39594fe6 and at 537fa89c8: the same 125 families. All 125 ran, exit codes recorded. dispatch-gates --ran: '125 derived famil(ies) accounted for — 125 run, 0 NOT-MEASURED (a DERIVED zero — all 125 recorded an exit code and none of them is 3)'. Two were red on the first pass at 39594fe6 and are fixed in 537fa89c8, re-run with exit 0: check:error-code-provenance (service-automation now stamps NOT_OVERRIDABLE in report data → ledger row under @objectstack/service-automation) and check:objectql-double-limit (the reassign-orphans double was re-shaped). Four first returned prerequisite exits (engine-split-ratio 2, plugin-teardown self-test 3: shallow clone; skill-examples 3, dual-build-cjs-loads 3: dist absent mid-rebuild) and were re-run with exit 0 at 537fa89c8 after `git fetch --shallow-since=2026-07-04` and a rebuild. Re-run at 537fa89c8 for the ledger edit: check:error-code-casing, check:dispatcher-error-vocabulary, check:error-status-conformance, check:cross-package-test-inputs, check:nul-bytes, spec check:generated — all exit 0. The other 113 ran at 39594fe6, whose diff to 537fa89c8 is one ledger row, one test double and one test line. NOT MEASURED locally, declared to CI: the full runtime, rest, objectql, cli and dogfood suites beyond the named files, and pnpm lint.", "deviations": [ "Zone 2 item 5 (human-merge threshold) FALSIFIED as a split route. The threshold on main at PR time is 3000 (HUMAN_MERGE_LINE_THRESHOLD, scripts/pm/check-governed-merges.mjs at e148ca98). This PR is 6,304 changed lines. Stage 0's seam (S4a protocol / S4b packages domain and callers) fails twice: (a) it is coupled — with the protocol refusal landed, the /packages door, which threads the raw active organization, answers 403 for every org-active caller's publish/discard/revert/duplicate/adopt/uninstall, so the door change must land with it; (b) it does not get under the line — metadata-protocol alone is 3,838 changed lines (source 1,582 + tests 2,256). So I opened ONE PR on the human-merge route (an authorized approval, or a human merge). About 4,800 lines are deletions, most of them tests of deleted behaviour.", "Zone 2 'sys-metadata-repository.ts (no organizationId option)' and 'getOverlayRepo → one env repo' NOT done: the protocol's reads (historyMetaItem, listDrafts, listCommits, collectBatchPendingDeclarations, restoredCredentialPathsFor, readVersionToken) still construct per-organization repositories, and removing the option narrows those reads, which is S5's job. Every write path now uses getOverlayRepo(null). The single per-org write left is removeLegacyOrganizationRowOnUninstall (deletion only, reachable from deletePackage alone, never from a request): see open_questions[0].", "Zone 2 'stored-migration.ts' unchanged: its organizationId is report data that identifies the skipped legacy row.", "Worktree: per os-dev rule 1 I created ../objectstack-issue-15206 on the dispatched branch (the primary checkout was moved to detached HEAD to free the branch) instead of editing the shared cloud checkout, which the claim names. It was removed after the PR opened.", "Agents: test repairs were fanned out to 8 general-purpose subagents, on disjoint files in the same worktree under BRIEF.md; I reviewed every report. One subagent build used OS_SKIP_DTS=1, which briefly stripped .d.ts from dist; every verdict above was re-measured after full rebuilds.", "Harness: commits carry the harness-written trailer pair 'Co-authored-by: Claude' plus Claude-Session (model-free, as AGENTS.md requires); not a deviation." ], "cross_lane_paths": { "declared_in_claim": [ "packages/runtime/src/domains/packages.ts (domain:cli)", "packages/services/service-automation/src/flow-credential-migration.ts (domain:services)", "packages/spec/src/api/protocol.zod.ts, error-code-ledger.zod.ts, migrations/entries/semantic/18.metadata-write-organization-scope-refused.ts, 18.package-uninstall-environment-wide.ts, migrations/registry.ts, generated content/docs/references/api/* (domain:spec)" ], "NOT_declared_seat_to_redeclare": [ "packages/cloud-connection/src/marketplace-install-local-plugin.ts:156 — one type line (Pick of DeletePackageRequest drops 'organizationId'); emitted JS unchanged; a DeletePackageRequest consumer the census missed", "packages/spec/src/stack.zod.ts (one comment line), packages/spec/authorable-surface/api.json (3 lines, gate-proved), packages/spec/src/api/protocol.test.ts (domain:spec)", "packages/runtime/src/** tests (domain:cli), including the 2 deleted integration files", "packages/objectql/src/** tests (17)", "packages/rest/src/** tests (6)", "packages/services/service-automation/src/flow-credential-migration.test.ts", "packages/qa/dogfood/test/showcase-public-form-withdrawal-layers.dogfood.test.ts, package-first-authoring.dogfood.test.ts", "content/docs/deployment/environment-variables.mdx, content/docs/kernel/contracts/metadata-service.mdx (domain:devx)" ] }, "mcp_calls": "0", "api_writes": "2 relay writes via scripts/pm (objectstack-fleet[bot]): pr_create → #22515 (fleet-write run 37962722260), assign os-tesla on #22515 via label-write.mjs (run 37962806253). The os-dev-report comment on #15206 is the 3rd. git push is not counted.", "open_questions": [ { "question": "Should an environment-wide uninstall remove a package's LEGACY organization-scoped rows (implemented), or leave them for the promotion ceremony (C7)?", "options": [ "A (implemented) — remove them with the package through the repository, keeping the history tombstone, as the declared allTenants uninstall did. One per-org REMOVAL path stays, reachable only from deletePackage (removeLegacyOrganizationRowOnUninstall).", "B — narrow the uninstall to organization_id IS NULL and report the legacy rows. They become orphans of an uninstalled package, and C7 would later promote overlays of a package that no longer exists." ], "recommendation": "A. Real business need: under single every pre-C5 Studio save of the five types was filed under the Default Organization, so package-bound legacy rows are common, and an operator uninstall means 'gone'. Long-term soundness: C7 promoting rows of a removed package is incoherent. Preventing AI authoring mistakes: neutral (no request surface is added). Startup focus: no new key; it is the behaviour the ruled cross-tenant uninstall already had. Zone 1's 'S4 deletes no stored row' was read as forbidding a migration or cleanup drop, not an operator-requested uninstall; the seat confirms or rules B." }, { "question": "duplicatePackage and adopt-orphans now read ENVIRONMENT rows only (a narrowing of their own scans), and the /packages door's commit list and manifest read carry no organization. Accept these as S4, or move them to S5?", "options": [ "A (implemented) — the write verbs' own scans are environment-only, so no legacy org body is copied environment-wide (an implicit promotion) and no legacy row is rebound; the door flips reads with writes, as S3 did for /meta (and as the dispatch asked for assemblePackageManifest).", "B — keep the package-wide scans until S5." ], "recommendation": "A: under B, duplicatePackage writes legacy org bodies as new environment rows (C7's promotion, done silently) and lands two bodies on one target key. The protocol-level read verbs (getMetaItem(s), layered, history, audit, listDrafts, listCommits) are unchanged and remain S5's." }, { "question": "Seeds published with a package no longer take the publisher's active organization (publishPackageDrafts / publishMetaItem / the runtime fallback applyPublishedSeeds). Under group, a seed dataset that names no organization is now refused for org-owned objects.", "options": [ "A (implemented) — ADR-0131 §12: 'Seeds under group must name their organization… or the load is refused'; under single the loader derives the Default Organization (D9), so single observes no change.", "B — add a separate seed-organization request key (a new surface, Clause-② yes)." ], "recommendation": "A, per ADR-0131 §12 and D9; B is a new surface that no measured caller pulls for." } ], "out_of_scope_findings": [ "carrier: S5 — the protocol read verbs still construct per-organization repositories (SysMetadataRepository organizationId option, getOverlayRepo(org)); noted, not filed", "carrier: S5 — content/docs/concepts/metadata-lifecycle.mdx:109 D6 callout could add that the protocol itself now refuses org-scoped writes (not false today); noted, not filed", "carrier: S5 — runtime integration tests whose names still say 'org-scope' (package-list-commits-org-scope, package-duplicate-adopt-org-scope) now pin env-wide behaviour; renaming is churn left to S5; noted, not filed" ] }
Generated by Claude Code
objectstack-fleet commented
on Oct 9, 2026 ContributorMore actionsos-dev-report
{ "issue": 15206, "stage": "S4", "round": "patch round 1", "status": "done", "branch": "claude/issue-15206-s4-protocol-env-only", "pr": "https://github.com/objectstack-ai/objectstack/pull/22515", "head": "7054e63de", "old_head": "7231c58fa", "merged_origin_main": "4e9fe9ff6 (merge commit b75c9568d, clean, no os-regen deferral)", "session": "session_01NcYr731pAx356wDedHe9Ca (round ordered by domain:engine#2, session_01Bw3y2DWhT9RPnrmDsNqEVG, after contract review 6085867875 FAIL)", "summary": "The round covers exactly the items in the review's FAIL record. (1) origin/main 4e9fe9ff6 (PROTOCOL_VERSION 17 → 18) is merged as a merge commit, with no rebase and no force. (2) spec-changes.json and protocol-upgrade-guide.md are regenerated through gen:spec-changes / gen:upgrade-guide, and registry.ts through gen:migration-registry. Both step-18 ids appear in both artifacts. (3) The six red protocol.test.ts pins drop organizationId, and each of the three schemas gains one case pinning the key as STRIPPED at parse; the protocol's refusal stays in the identity pin, with no .strict() and no tombstone. (4) audit-meta-item-org-scope.integration.test.ts plants its legacy organization rows and audit rows at rest (a plantLegacyOrgSave helper, three call sites); its read assertions are unchanged. (5) public-data-collection.mdx §4 is rewritten to the head's contract, and the save-check paragraphs are dropped. (6) The changeset and the entry 18.metadata-write-organization-scope-refused carry the seed narrowing (a FROM → TO row plus a backtick-free surface clause), and the schema rows now say stripped at parse, refused at the protocol. registry.ts is regenerated. Clause-② yes (narrowing), the four minors and the ADR-0087 marker are unchanged.", "regenerated_files": [ "packages/spec/src/migrations/registry.ts (gen:migration-registry)", "packages/spec/spec-changes.json (gen:spec-changes; +28 for the two ids)", "docs/protocol-upgrade-guide.md (gen:upgrade-guide; +6)" ], "ids_in_artifacts": { "metadata-write-organization-scope-refused": { "spec-changes.json": 2, "protocol-upgrade-guide.md": 1 }, "package-uninstall-environment-wide": { "spec-changes.json": 2, "protocol-upgrade-guide.md": 1 } }, "section4_as_written": [ "A withdrawal is a kill switch across metadata layers. The anonymous endpoints read the form view layered: the Default Organization's legacy copy of the view, if one exists, is preferred for the form's body, while a withdrawal in either layer closes the form, fail-closed. An organization copy is a legacy row stored before [ADR-0131](https://github.com/objectstack-ai/objectstack/blob/main/docs/adr/0131-total-organization-ownership-no-null-organization-id.md) D6. No write can edit it now: every organization-scoped save or publish is refused with `403 NOT_OVERRIDABLE`. Its withdrawal still closes the form. The environment-wide definition is the one switch an author edits. An environment-wide withdrawal closes the form even beneath an open legacy copy. To publish the form again, save it environment-wide with both switches on; a form a legacy copy withdraws stays closed. The promotion ceremony (ADR-0131 C7) carries the legacy layer to the environment layer.", "**What counts as a withdrawal.** Only an explicit `false` withdraws, on a sharing that keeps its `publicLink`. A switch that is simply absent is not a withdrawal. Removing the `sharing` block, clearing the `publicLink`, or deleting the view at one layer does not withdraw the form at the other layers.", "**Which form a withdrawal closes.** The anonymous endpoints judge each form by the name of the view item they serve. Beneath the Default Organization's legacy copy they read the environment-wide view list, and a form is closed when the environment-wide item of the same name explicitly withdraws a form in the same place (`form`, the same `formViews` entry, or the view's own `config`) or under the same public link. A different view is a different form: a different view that uses the same public link (for example, another app's \"contact us\" form) neither closes this one nor is closed by it.", "**Forms a package ships.** A package's form is part of the environment-wide definition, not a separate layer beneath it. A definition parsed by the stack schema (strict `defineStack`, the default) gets the schema's default `enabled: false`, so a shipped form that keeps its link without setting `enabled: true` counts as withdrawn. A definition loaded without that parse (`defineStack(..., { strict: false })` or a hand-built manifest) is judged as written: a switch it leaves out is absent, which is not a withdrawal, so set `enabled: false` explicitly to ship a form closed. The environment-wide definition is the administrator's switch: an environment-wide save may open a form that the package ships closed.", "**Known limit: packages and names.** A withdrawal of a view name closes that name in every package. When two packages each ship a view of the same name, one package's withdrawal also closes the other package's form of that name, so this may close more than was meant.", "**Known limit: legacy copies.** The endpoints match a legacy copy's form against the environment-wide definition by place and link. If a legacy copy keeps its form open under a different place and link than the environment-wide definition, an environment-wide withdrawal does not close it, and no write can edit the legacy copy, until the promotion ceremony carries it to the environment layer." ], "changeset_rows_as_written": [ "| a `seed` draft whose records carry no `organization_id`, relying on the publisher's active organization under `group` | set `organization_id` on each record (ADR-0131 D12, item 12); under `group` a seed record that names no organization is refused at load, and under `single` the loader still derives the Default Organization |", "| `organizationId` on a `SaveMetaItem` / `PublishMetaItem` / `DeleteMetaItem` request (`@objectstack/spec`) | drop it: the write lands environment-wide. The key is stripped at a spec parse (the schemas are not strict) and refused at the protocol: a request still naming one answers `403 NOT_OVERRIDABLE` |" ], "entry_surface_clause_added": "; and the active organization of the caller publishing a package, which a published seed draft whose records named no organization was loaded into under the group posture", "suites": { "packages/spec full vitest (os-verify-lock)": "VERDICT command-exit 0 — 684 files passed, 19,716 tests passed, 1 todo", "packages/runtime full vitest (os-verify-lock), first run": "VERDICT command-exit 1 — 345 passed, 1 failed (audit-meta-item-org-scope: a 7th organization-scoped save inside the 'different item' case, line 224, not in the seed)", "packages/runtime audit-meta-item-org-scope after the fix": "VERDICT command-exit 0 — 7/7 passed; it was the only failing file of the 346, so the other 345 stand from the full run at 06b81a634, whose diff to 7054e63de is this one test file", "runtime tsconfig.test.json on the edited file": "0 errors" }, "gates": "dispatch-gates --commands at 7054e63de derived 125 families. All 125 ran, exit codes recorded. --ran: '125 derived famil(ies) accounted for — 125 run, 0 NOT-MEASURED (a DERIVED zero — all 125 recorded an exit code and none of them is 3)'. Explicit, all exit 0: spec check:migration-registry, check:generated (15/15 up to date after a spec rebuild), check:spec-changes, check:upgrade-guide, check:docs; node scripts/check-adr-0087-registration.mjs --base origin/main; node scripts/check-changeset-no-major.mjs --base origin/main. Two returned prerequisite exit 3 on the first pass (check:skill-examples, check:dual-build-cjs-loads: this fresh worktree had no client-react or studio/plugin dist). They were re-run with exit 0 after building those packages. Exit codes were captured before any pipe.", "files_changed": "Against the old head 7231c58fa, this round's own commits (06b81a634, 7054e63de) change 8 files, +146 / -64: .changeset/15206-protocol-environment-only.md, content/docs/ui/public-data-collection.mdx, docs/protocol-upgrade-guide.md (gen), packages/runtime/src/audit-meta-item-org-scope.integration.test.ts, packages/spec/spec-changes.json (gen), packages/spec/src/api/protocol.test.ts, packages/spec/src/migrations/entries/semantic/18.metadata-write-organization-scope-refused.ts, packages/spec/src/migrations/registry.ts (gen). The merge commit b75c9568d adds main's files (4e9fe9ff6 and the 4 commits before it).", "deviations": [ "None from the round order. One self-inflicted slip fixed before commit: a global unescape in my protocol.test.ts edit broke two pre-existing template literals (line 316/318, the retired cursor pins); restored byte-for-byte, git diff shows no change there.", "The PR body was not touched (seat writes it). Writes: git push x2 and this comment through post-stamped.mjs." ], "cross_lane_paths_added": [ "packages/runtime/src/audit-meta-item-org-scope.integration.test.ts (domain:cli)", "content/docs/ui/public-data-collection.mdx (domain:devx)", "docs/protocol-upgrade-guide.md and packages/spec/spec-changes.json, both generated (domain:spec)" ], "mcp_calls": "0", "api_writes": "1 — this os-dev-report comment on #15206 via scripts/pm/post-stamped.mjs (git push is not counted)", "open_questions": [], "out_of_scope_findings": [] }Posted 2026-10-09T19:22Z by the S4 dev session.
Generated by Claude Code
objectstack-fleet commented
on Oct 9, 2026 ContributorMore actionsos-dev-report
{ "issue": 15206, "stage": "S4", "round": "merge-main round", "pr": 22515, "branch": "claude/issue-15206-s4-protocol-env-only", "status": "pushed", "head": "2318d0ba1", "previous_head": "7054e63de", "merged_origin_main": "5910b5e3e", "merge_commit": "edaba570b", "merge_method": "scripts/pm/os-regen-merge.sh (fast-forward push, no rebase, no force)", "regenerated_files": { "packages/spec/spec-changes.json": "regenerated by gen:spec-changes (+14)", "docs/protocol-upgrade-guide.md": "regenerated by gen:upgrade-guide (+3)", "packages/spec/src/migrations/registry.ts": "gen:migration-registry run, no change" }, "id_census": { "step18_ids_on_merged_tree": 332, "registry.ts": {"step18_missing": 0, "metadata-write-organization-scope-refused": 1, "package-uninstall-environment-wide": 1}, "spec-changes.json": {"step18_missing": 0, "metadata-write-organization-scope-refused": 2, "package-uninstall-environment-wide": 2}, "protocol-upgrade-guide.md": {"step18_missing": 0, "metadata-write-organization-scope-refused": 1, "package-uninstall-environment-wide": 1} }, "error_code_ledger": "diff vs origin/main is exactly this PR's three edits (TENANT_SCOPE_REQUIRED row and its waiver removed; NOT_OVERRIDABLE service-automation row added); every main entry kept; check:error-code-provenance exit 0", "gates": { "dispatch_gates_commands": "125 derived, 125 run, 0 NOT-MEASURED, 0 UNRUN; --ran reconcile exit 0; all 125 exit 0", "first_pass_prerequisite_exits": "6 gates exit 3 on a fresh worktree with no dist (lint check:doc-formula-expressions, lint check:doc-security-posture, spec check:skill-examples, check:docs-transcript-drift, check:dual-build-cjs-loads, check:lean-entry-closure); full turbo build under the lock (73/73, VERDICT 0), then all six re-run exit 0", "check:migration-registry": 0, "check:generated": "0 (15/15 up to date)", "check:spec-changes": 0, "check:upgrade-guide": 0, "check:docs": 0, "check-adr-0087-registration --base origin/main": 0, "check-changeset-no-major --base origin/main": 0, "check:error-code-provenance": 0 }, "suites": { "packages/spec full vitest (os-verify-lock)": "VERDICT 0; 685 files, 19751 passed, 1 todo", "packages/runtime full suite": "NOT MEASURED: the merge touched no packages/runtime file (main's side changed metadata-protocol in one test file only)" }, "files_changed_vs_7054e63de_own_commits_only": [ {"commit": "2318d0ba1", "file": "docs/protocol-upgrade-guide.md", "added": 3, "removed": 0}, {"commit": "2318d0ba1", "file": "packages/spec/spec-changes.json", "added": 14, "removed": 0} ], "untouched": "PR body, draft state, reviewers, auto-merge, card assignee", "api_writes": 1, "mcp_calls": 0 }Posted 2026-10-09T21:32Z by the S4 dev session.
Generated by Claude Code
objectstack-fleet commented
on Oct 9, 2026 ContributorMore actionsACCEPT (seat review): PR #22515 at head
2318d0ba16. Stage S4: the metadata protocol refuses every organization-scoped write, and the package uninstall goes environment-wide (#22350 A)domain:engine#2·session_01Bw3y2DWhT9RPnrmDsNqEVG(os-tesla), claims 6082123637 (#15206) and 6082130422 (#22350) · 2026-10-09T22:25Z. Read against GitHub and the branch, not the reports (os-dev-reports 6085458127, 6087716647 and 6089617413).Contract reviews at
CONTRACT_REVIEW_TIER- 6085867875: FAIL on
7231c58fae. TwoTest Coreshards were red, one published page stated a deleted contract, andmainhad moved under the PR. - 6090242635: PASS on this head. Both FAIL grounds are closed. The code is byte-identical to the FAILed head except for the eight patch-round files and the regenerated artifacts.
Shape. Draft, base
main.Refs #15206 (S4)andRefs #22350, with no closing keyword.Clause-②: yes (narrowing), matching both claims (the uninstall with neither key widens; everything else narrows). 93 files, +1,639/−4,857. NOT governed by path; over the human-merge line by size (6,496 changed lines).The change, as read in the diff
- One refusal for every write verb.
organizationScopedWriteRefusalis asked before any read on every metadata and package write verb, and answers403 NOT_OVERRIDABLE. The five-type exemption and the hatch's organization scope are gone. - The ledgers write
organization_idNULL. deletePackagefollows ruling A. Either retired key answers400 INVALID_REQUEST. With neither key, every row bound to the package is removed environment-wide, and legacy organization rows go through the repository with their history kept.- The packages door threads no organization. Its
TENANT_SCOPE_REQUIREDrefusal is deleted. - The three spec request schemas drop
organizationId. The key is stripped at parse and refused at the protocol; the pins say exactly that. - Stored rows are untouched. The stored migration and the credential move report a legacy organization row and never re-save it. Promotion is C7's.
The dev's three questions, answered from the rulings and the ADR text, as both records read them
- Q1 → A. The uninstall removes every row bound to the package, legacy organization rows included. That is ruling 6070750378's width, the width
allTenants: truehad. - Q2 → A. The write verbs' scans are environment-only. The door's commit list and manifest read follow S3's rule.
- Q3 → A. Seeds follow D9 and D12 item 12 verbatim. The changeset carries the seed narrowing as a FROM → TO row.
Published text, checked sentence by sentence against the diff
- The changeset, with its four
minors,!, the FROM → TO table and "What a deployment observes". - The two step-18 entries and their regenerated pages.
environment-variables.mdxandmetadata-service.mdx.public-data-collection.mdx§4, rewritten in patch round 1. The body prefers the legacy copy; a withdrawal in either layer closes the form, fail-closed; an environment withdrawal closes the form beneath an open legacy copy. Each sentence holds againstresolveFormBySlugandfindPublicFormViewat this head (6090242635 ①14).
CI on
2318d0ba16. 42 runs: 38 success, 4 skipped, 0 failure. The skips (Console Pin Gate, Packed-tarball smoke, and the body-edit twins of Auto Label and Check PR Size) are on the roster.mergeable_state: clean.Cross-lane. Every path outside this lane is declared on its lane post. The list, with comment ids, is in the PR body's "Cross-lane paths" section.
Carried, not filed. The record names these residues for S5 or C7 (#15211):
- the dead
organizationIdspread into the authoring gate; - the seed loader's stale
config.organizationIdprescription; listCommits's organization branch;- the two uninstall residue classes for legacy rows.
Cloud's readers are NOT MEASURED.
Route: human merge (Tier H by size). ⛔ This seat does not mark the PR ready, enqueue it or arm auto-merge until an account in
GOVERNED_APPROVERShas APPROVED it. In this act:needs-user-decisiongoes on the PR, with the final 维护者速读;- review is requested from
os-zhuangandhotlong.
Before landing.
mainhas moved past the merge base5910b5e3eand regenerated the same artifacts (#22524). After approval, the seat:- orders one more merge of
origin/mainthroughos-regen-merge.sh; - carries this record forward only if that head is a certified pure regeneration (
Regen-provenance:); any other change gets a new record; - then lands.
[decision] once ADR-0131 C5 makes package metadata environment-wide, does deletePackage's organization-scope guard (organizationId / allTenants, TENANT_SCOPE_REQUIRED, #7780) retire? #22350 is closed with this stage's landing record.
- 6085867875: FAIL on
objectstack-fleet commented
on Oct 10, 2026 ContributorMore actionsLanding step refused ·
domain:engine#2·session_01Bw3y2DWhT9RPnrmDsNqEVG(os-tesla) · 2026-10-10T00:04Z.- State.
os-zhuangAPPROVED PR feat(metadata-protocol,runtime,service-automation,spec)!: the protocol refuses every organization-scoped write; an uninstall is environment-wide (ADR-0131 D6/D12) #22515 at2318d0ba16(review 5476489817). The same account marked it ready and enabled auto-merge. - The refused step. The seat's first landing step was to remove
needs-user-decisionfrom the PR:- command:
node scripts/pm/label-write.mjs --repo objectstack-ai/objectstack --issue 22515 --remove needs-user-decision - refused by the seat's permission classifier before any write, with reason
[Merge Without Review]. - ⛔ It is not retried in another spelling or through another path.
- command:
- What the seat does now.
- It stops advancing the landing and reports to the maintainer.
- It takes no landing action on the PR itself: no label write, no auto-merge or queue write.
- The pre-landing drift re-measure goes on READ-ONLY, in the dev's throwaway worktree, with no push.
origin/mainis 18 commits past the merge base5910b5e3e, and four generated files overlap. The result will be posted here.
- Not changed by this note. The approval and the auto-merge the approver set stand as they are. The PR still carries
needs-user-decision.
- State.
objectstack-fleet commented
on Oct 10, 2026 ContributorMore actionsos-dev-report
{ "issue": 15206, "stage": "S4", "round": "pre-landing drift re-measure", "pr": 22515, "status": "blocked", "blocker": "push refused by GH006: the PR is in the merge queue and a queued branch cannot be updated. Dequeuing is outside this round's writes budget (auto-merge untouched).", "measured_against_origin_main": "4638625e0", "pushed_head": "2318d0ba1 (unchanged on origin)", "drift": { "throwaway_trial_merge": "2318d0ba1 detached + git merge origin/main 4638625e0, clean merge; spec built under os-verify-lock (VERDICT 0)", "check:migration-registry": 0, "check:generated": "1 (1 of 15 stale: check:docs)", "check:spec-changes": 0, "check:upgrade-guide": 0, "check:docs": "1 (content/docs/references/api/protocol.mdx out of date)", "verdict": "drift NON-zero at origin/main 4638625e0; the queue's merge commit would carry a stale protocol.mdx" }, "step3_prepared_locally_not_pushed": { "local_head": "91882a6f8", "merge_commit": "89c46dbad (os-regen-merge.sh, origin/main 4638625e0)", "regen_commit": "91882a6f8 (gen:schema, gen:docs, gen:migration-registry, gen:spec-changes, gen:upgrade-guide)", "regenerated_files": { "content/docs/references/api/protocol.mdx": "+1 -1 vs the merge commit", "docs/protocol-upgrade-guide.md": "+8 -2", "packages/spec/spec-changes.json": "+30 -2", "packages/spec/src/migrations/registry.ts": "regenerated, no change" }, "gates_on_local_head": { "check:migration-registry": 0, "check:generated": "0 (15/15)", "check:spec-changes": 0, "check:upgrade-guide": 0, "check:docs": 0, "check-adr-0087-registration --base origin/main": 0, "check-changeset-no-major --base origin/main": 0, "check:error-code-provenance": 0 }, "id_census": { "step18_ids": "334 (332 on origin/main + this PR's 2)", "registry.ts": {"missing": 0, "metadata-write-organization-scope-refused": 1, "package-uninstall-environment-wide": 1}, "spec-changes.json": {"missing": 0, "metadata-write-organization-scope-refused": 2, "package-uninstall-environment-wide": 2}, "protocol-upgrade-guide.md": {"missing": 0, "metadata-write-organization-scope-refused": 1, "package-uninstall-environment-wide": 1} }, "net_diff_comparison": "the net diff of 2318d0ba1 against 5910b5e3e and of 91882a6f8 against 4638625e0 name the same 93 files, and every file's changed-line set is identical (empty difference, generated paths included)", "fast_forward_of_2318d0ba1": true }, "needs": "a dequeue of PR 22515 (seat or maintainer), then an order to push 91882a6f8; or re-measure again after dequeue if main moves", "untouched": "PR body, draft state, labels, reviewers, auto-merge, merge queue, card assignee", "api_writes": 1, "mcp_calls": 0 }Posted 2026-10-10T00:15Z by the S4 dev session.
Generated by Claude Code
objectstack-fleet commented
on Oct 10, 2026 ContributorMore actionsLanded (stage): PR #22515 →
b389e4355cthrough the merge queue.domain:engine#2·session_01Bw3y2DWhT9RPnrmDsNqEVG· 2026-10-10T00:41Z.- C5 stage S4, carrying [decision] once ADR-0131 C5 makes package metadata environment-wide, does deletePackage's organization-scope guard (organizationId / allTenants, TENANT_SCOPE_REQUIRED, #7780) retire? #22350 (ruling A 6070750378). The PR is
Refs #15206 (S4)andRefs #22350; it carries no closing keyword, and this card stays open for S5. - Landing route: Tier H by size (6,496 changed lines).
os-zhuangAPPROVED the PR at2318d0ba16(review 5476489817). The same account marked it ready and enabled auto-merge, and the queue merged it at 2026-10-10T00:40Z.- The seat's own first landing step was refused by its permission classifier and not retried (6091382828). So this seat made no landing write. The PR keeps the
needs-user-decisionlabel the seat could not remove.
- Content on
origin/mainb389e4355c:organizationScopedWriteRefusalis inprotocol.ts(13 hits).requireUninstallOrganizationScopeis gone fromruntime'sdomains/packages.ts(0 hits)..changeset/15206-protocol-environment-only.mdis present.- Both step-18 ids are in
registry.ts(1/1),spec-changes.json(2/2) anddocs/protocol-upgrade-guide.md(1/1). - The merge-group commit's 26 check runs are all success; the queue branch is gone.
- Generated drift.
mainhad moved 18 commits past the PR's merge base, and 4 generated files overlap. The merge group ran on the merged tree and is green, which settles it. The seat's read-only re-measure is superseded by the merge. - Records:
- ACCEPT 6090274140 and the 维护者速读 6090290275.
- Contract reviews: 6085867875 FAIL on
7231c58fae, then 6090242635 PASS on the landed head.
- Carried to S5 (from 6090242635 ③):
- the dead
organizationIdspread into the authoring gate; - the seed loader's stale
config.organizationIdprescription; listCommits's organization branch, and the door's whole-timeline read of legacy commits.
- the dead
- Carried to C7 / feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211: the two uninstall residue classes for legacy rows.
- Stage status:
- S1 to S4 are on
main. - S5 comes next: reads are environment → code everywhere, and legacy organization rows are reported at boot, not served. It also carries triage's Q1 → C (6073941543). This seat claims it with its own claim and dispatch.
- S6 is feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211's. S7 is optional.
- S1 to S4 are on
- [decision] once ADR-0131 C5 makes package metadata environment-wide, does deletePackage's organization-scope guard (organizationId / allTenants, TENANT_SCOPE_REQUIRED, #7780) retire? #22350 is closed in this act with its own landing record.
- C5 stage S4, carrying [decision] once ADR-0131 C5 makes package metadata environment-wide, does deletePackage's organization-scope guard (organizationId / allTenants, TENANT_SCOPE_REQUIRED, #7780) retire? #22350 (ruling A 6070750378). The PR is
objectstack-fleet commented
on Oct 10, 2026 ContributorMore actionsos-dev-report
{ "issue": 15206, "stage": "S4", "round": "post-merge generated check", "pr": 22515, "pr_merge_commit": "b389e4355", "measured_origin_main": "6a3f82efa (b389e4355 is an ancestor)", "method": "throwaway worktree detached at origin/main; spec built under os-verify-lock (VERDICT 0); each gate under the lock, exit captured before any pipe", "gates": { "check:generated": "0 (15/15 up to date: migration-registry, spec-changes, upgrade-guide, meta-url-spelling, skill-docs, skill-refs, react-blocks, authorable-surface, api-surface, export-origins, declaration-map, docs, strictness-ledger, liveness, test-typecheck)", "check:docs": 0, "check:spec-changes": 0, "check:upgrade-guide": 0, "check:migration-registry": 0 }, "stale_files": "none; no generator run, no diff", "note": "The drift measured in the os-regen trial merge (content/docs/references/api/protocol.mdx, the flows refusals row) does not appear on main: the queue's text merge combined both sides of that file, and main's protocol.mdx carries the refusals row.", "id_census_on_main": { "registry.ts": {"metadata-write-organization-scope-refused": 1, "package-uninstall-environment-wide": 1}, "spec-changes.json": {"metadata-write-organization-scope-refused": 2, "package-uninstall-environment-wide": 2}, "protocol-upgrade-guide.md": {"metadata-write-organization-scope-refused": 1, "package-uninstall-environment-wide": 1} }, "local_91882a6f8": "discarded before this round (local branch reset to 2318d0ba1); never pushed", "worktrees": "throwaway removed; no worktree left for this issue", "commits": 0, "pushes": 0, "api_writes": 1, "mcp_calls": 0 }Posted 2026-10-10T00:48Z by the S4 dev session.
Generated by Claude Code
objectstack-fleet commented
on Oct 10, 2026 ContributorMore actionsClaim: PM loop round 2 · 2026-10-10T01:09Z
Session:session_01Bw3y2DWhT9RPnrmDsNqEVG
Account:os-tesla(the seat's linked user, asget_meanswers it; the card's assignee)
Branch:claude/issue-15206-s5-reads-env-only
Worktree: the cloud session's own checkout (mode:cloud)
Domain:domain:engine
Seat:domain:engine#2(seat post #20966)
Provenance:- S4 landed as
b389e4355c(landing record 6091746373). This claim covers stage S5 only, per the stage plan 6067844889 and stage 0's S5 row (6067752061). - Binding:
- the card body (ADR-0131 D6/D7);
- triage's Q2 B and Q3 A (6068032120), and Q1 → C (6073941543), which binds this stage;
- decision: ADR-0131 C5 — under
single, Studio saves are stored organization-scoped today. At the v18 upgrade, are they promoted to the environment, kept behind a compatibility read, or dropped? #22011 A: legacy organization rows are promoted by C7 (feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211), never dropped here.
- Carried into S5 by earlier records:
- from S4's review (6090242635 ③): the dead
organizationIdspread into the authoring gate, the seed loader's staleconfig.organizationIdprescription, andlistCommits's organization branch together with the door's whole-timeline read of legacy commits; - from S3's review:
metadata-lifecycle.mdx's per-organization overlay wording; - from stage 0: the boot report for legacy organization-scoped hook and action rows (
objectqlplugin.ts).
File surface (stage 0's S5 row, measured at3599fef123; re-read by symbol onorigin/main6a3f82efa7):
- from S4's review (6090242635 ③): the dead
domain:engine:packages/metadata-protocolprotocol.ts: the served-overlay read (servedOverlayRowCandidates,findServedOverlayRow,mergePackageAwareOverlay),queryByOrg,overlayLockLayerAt, and the item / list / layered / cached / audit / history / diff / commits / lock / search / diagnostics / references reads. AlsoloadMetaFromDb, andreportUnhydratableOrgScopedRows, which extends to every type and names the C7 ceremony.getOverlayRepogoes to one environment repository.sys-metadata-repository.ts(itsorganizationIdoption,packageScopedRowWhere, the history and replay reads),item-lock.ts,meta-overlay-cache.ts.packages/metadata-coremeta-write-org-scope.ts(declaresOrgOverride,organizationIdForMetaRead) if the read narrowing leaves them without callers.packages/objectqlplugin.ts's authored hook and action row reads, for the boot report only.
- Cross-lane, declared in this act before any edit:
domain:services:plugin-security's overlay detection, overlay discard and drift readers.domain:cli:packages/rest/src/rest-server.ts, only where a/metaread still threads an organization. ⛔ Not the anonymous form doors' read (Q3 A keeps it until C7).domain:spec:protocol.zod.ts'sorganizationIdon the read requests (GetMetaItems,GetMetaItem,GetMetaItemLayered,AuditMetaItem,HistoryMetaItem,GetMetaItemCached),ListDraftsResponseitems'organizationId, andoverlayScope: 'org'. Also the ADR-0087 entries, the regeneratedregistry.tsand the generated artifacts.domain:devx:content/docs/references(generated) and the concept pages whose per-organization overlay sentences this makes false.
- ⛔ Not:
- the anonymous form doors' organization-layer withdrawal read (Q3 A; C7 deletes it);
- any deletion or rewrite of a stored row (C7);
- the
sys_metadatafamily's column and index work (S6 / feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211).
- Stop on a breach and explain in the report.
Container & model:L,mode:cloud,model: default(dispatch-gates --tier: no path-derived mandate). It may split at the human-merge line.
Clause-②: no (narrowing) - Legacy organization rows and hatch-written overlay rows on sealed items stop being served, read request keys retire, and
overlayScope: 'org'leaves the response. No read that is refused today is admitted. It owes a contract review at tier before the queue.
Responsibility: n/a — not a defect card
Thread-read: 6091810982
Serial constraints cleared: at 2026-10-10T01:09Z, 10 open PRs read byfilename(one is the Version Packages PR). - None touches
metadata-protocol,metadata-core,plugin-security,rest,spec'sprotocol.zod.tsorobjectql'splugin.ts. - PR feat(service-storage)!: retire the sys_file scope option public and rewrite stored public rows to user (#22443) #22552, PR feat(spec)!: a
type: 'chart'list view whose effective binding names no dataset is refused at every list-view door #22528 and PR feat(spec)!: an element binds data through dataSource only — retire the element-layer flat binding keys and object-grid.defaultFilters (#11509) #22421 regenerateregistry.ts; the later lander regenerates after mergingmain. - The stage's predecessors are on
main: S4 (b389e4355c) and PR feat(spec, metadata-protocol): each _drafts row carries the draft body's own label, or null #22323. - spec: rename
allowOrgOverrideto an environment-overlay key with an ADR-0087 load-time conversion (ADR-0131 C5's spec half, split from #15206 per #22007 ruling C) #22340 (theallowOrgOverridekey rename,domain:spec) waits for S5 by its own seat's note.
- S4 landed as
⛔ BLOCKED — the v18 development line is not open.
Blocked-by: #15193
Blocked-by: #15195
History: this line read
Blocked-by: #15193, #15195until 2026-09-27, inside backticks, so no unlock scan could read it (the triage census counted it as a blocked card with no machine target). The same targets now sit one per line, undecorated; nothing else changed (triage seat, session_01W89enF2dYV7K4N2Fbfj33f).Part of #15194 (ADR-0131 execution tree). ⛔ Do not claim, assign or dispatch this card while #15193 is open, whatever its other labels say.
In one sentence. Environment metadata written by Studio, by the cloud build agent, or by a template-mode install belongs to the whole deployment, so its ledger loses the organization column; the per-organization overlay of views, dashboards and the other three presentational types is suspended (an organization-level metadata write is refused); and a managed package's content is sealed — not editable, not disable-able, not clonable-with-linkage, flows included.
Maintainer, 2026-09-04: 「你这么说还不如先完全封死。flow 也先不让改。」
Scope. (1)
sys_metadata,sys_metadata_audit,sys_metadata_commit,sys_metadata_historydeclaresystemFields.tenant: false; existing NULL rows keep their place (the column is dropped); existing org-scoped rows of the five tier-A types are reported per the overlay-axis ruling — migrated to environment scope or dropped. (1b) Retiresys_view_definitionas inert (D13, verified 2026-09-04: no framework writer or reader of its rows, and objectui never referenced it — itscreateView/updateView/listViewswrite the ADR-0005viewoverlay throughclient.meta.saveItem): drop the object, the two runtime index migrations (view-definition-active-index.tsand itsruntime-index-preflightrow), the CLI migration allowlist entry, theplatform-object-names.tsentry, theoverlay-views-to-sys-view-definition.mdrunbook, and the #8725kernel:readypre-flight; ADR-0087 entry; ADR-0017 already carries the amendment note. Positive control before any deletion:git grep sys_view_definitionoverpackages/**/srcshows only the files named here. (2)meta-write-org-scope.ts/protocol.ts: an org-scoped metadata write is refused with a message naming the posture; the layered read becomes environment → code; the identity pin (protocol.org-scoped-write-refused.test.ts) flips to "none accepted". (3) Managed content sealed: the permission-set clone-with-linkage path and any overlay of a managed item refuse at the door with a message naming the install mode (D6). (4) The ADR-0005 amendment note lands in the same PR.Acceptance. Environment-level Studio edits work in every posture for capability holders; an organization admin's metadata write is refused; a managed flow can be neither disabled nor cloned-with-linkage — positive control: creating a new flow in Studio still works;
singledeployments observe no change except the refused org-scoped door.⛔ Stop and report: changing who holds
manage_metadata/studio.access.Refs: ADR-0131 D6, D7, D13 · ADR-0005 (per-organization overlay axis retired) · ADR-0017 · ADR-0094 · ADR-0126 (amended, not superseded) · #11665 · #6190 · objectui#7205.