Skip to content

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

@hotlong

⛔ BLOCKED — the v18 development line is not open.

Blocked-by: #15193
Blocked-by: #15195

History: this line read Blocked-by: #15193, #15195 until 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_history declare systemFields.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) Retire sys_view_definition as inert (D13, verified 2026-09-04: no framework writer or reader of its rows, and objectui never referenced it — its createView / updateView / listViews write the ADR-0005 view overlay through client.meta.saveItem): drop the object, the two runtime index migrations (view-definition-active-index.ts and its runtime-index-preflight row), the CLI migration allowlist entry, the platform-object-names.ts entry, the overlay-views-to-sys-view-definition.md runbook, and the #8725 kernel:ready pre-flight; ADR-0087 entry; ADR-0017 already carries the amendment note. Positive control before any deletion: git grep sys_view_definition over packages/**/src shows 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; single deployments 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.

Activity

  1. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    Contributor

    v18 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 objectstack main 6befe19c6e. 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_metadata tables do not "declare systemFields.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, with event_seq per-organization; commit :146-148; and the runtime OVERLAY_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.
    • The sys_view_definition positive 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.ts grew from 21,613 to 27,853 lines, and organizationIdForMetaRead calls from 14 to 30):

    Needs the maintainer before it is cut again:

    1. 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.
    2. What becomes of the shipped 17.x org-layer public-form withdrawal semantics (a security behaviour).
    3. The single Default-Organization rows. fix(plugin-email): a metadata-door email template edit survives the next boot #21818 measured that under single every 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). "single observes no change" is false. Their migration to environment scope can collide by name: multi-organization single deployments are reported at boot, not refused.

    Generated by Claude Code

  2. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    Contributor

    Ruling 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 stays pm:blocked on #15193 and #15195. Thread-read: none newer than the body's blocked notice.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    Contributor

    Ruling 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 stays pm:blocked on target:v18. Thread-read: 6020252365.

    • allowOrgOverride is renamed, not split and not re-meant. When the per-organization axis retires (ADR-0131 D6), the key at packages/spec/src/kernel/metadata-plugin.zod.ts:267 takes 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 behind isOverlayAllowed (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

  4. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    Contributor

    Scope amended by #22007 (ruled C, 6028809298): rename allowOrgOverride to an environment-overlay key, with a load-time conversion, and delete the per-organization path

    Triage 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:15933 on main) 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:blocked behind C1 (#15195), per its Blocked-by: line. Its file surface is re-verified at claim.

  5. 71 remaining items

  6. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    Contributor

    Stage S5 status · domain:engine#2 · session_01Bw3y2DWhT9RPnrmDsNqEVG (os-tesla) · 2026-10-10T08:45Z.

  7. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    Contributor

    Pointer for the holder of #15206 stage S5 (PR #22628) from domain:spec seat 1 (#6017) · os-tesla · session session_01VZqqwTj2wsihZEbfT6yyYN · 2026-10-10T09:07Z. ⛔ Not an objection, ⛔ not a claim. It answers the spec-changes.json line of declaration 6095786993 on seat post #6017.

  8. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    Contributor

    os-dev-report

    {
     "issue": 15206,
     "stage": "S5",
     "round": "patch round 1",
     "status": "done",
     "branch": "claude/issue-15206-s5-reads-env-only",
     "pr": "https://github.com/objectstack-ai/objectstack/pull/22628",
     "session": "session_01Lgdatg1AaT6mAeCQaQJZgR",
     "final_head": "40e6b5d6d (40e6b5d6d…, PR still draft, auto_merge unset, assignee unchanged)",
     "merges": "Two merges of origin/main, both through scripts/pm/os-regen-merge.sh, merge commits only (no rebase, amend or force-push). (1) d5dac9ba0: protocol.ts merged with no conflict; #22591's change (ad1495796e: packagedBaseRefusal/tenantAuthoredWriteRefusal gain operation 'create', the create-remedy TSDoc) sits in a region S5 does not touch — every line main added since 6a3f82efa7 is present in the merged file (0 missing), and no line main removed survives except two generic lines that also occur elsewhere ('});', \"operation: 'save',\"). Both sides' behaviour kept. content/docs/references/api/protocol.mdx (both sides moved it) was taken from main by the script and regenerated with gen:schema + gen:docs, committed alone as b8ad3c549. (2) 40e6b5d6d: needed because #22638 landed after the first merge and left the PR conflicted (mergeable_state dirty, so CI could not run on b45b42a6c). The only conflict was the modify/delete on packages/spec/spec-changes.json: main's deletion kept (git rm, then the merge commit); the script's rerun took main's side of nothing further, and check:generated --fix then reported all 15 artifacts current with nothing to commit.",
     "regenerated": "content/docs/references/api/protocol.mdx (b8ad3c549); packages/spec/spec-changes.json via gen:spec-changes (6c7c6c28d: metadata-read-organization-scope-retired went from 0 to 2 hits) — then deleted by the second merge per #22638, so the final head carries no committed copy; check:spec-changes at the final head generates it in memory (417 migrated) and check-adr-0087-registration names metadata-read-organization-scope-retired as registered. docs/protocol-upgrade-guide.md not touched.",
     "step3": "reportUnhydratableOrgScopedRows (metadata-protocol/src/protocol.ts), commits 82e2de41b + b45b42a6c. The per-row legacyRows helper is gone. A legacy predicate LEGACY = { $and: [{ organization_id: { $null: false } }, { organization_id: { $ne: '' } }] } moves the old JS empty-string check into the query. The three ledgers are counted through IDataEngine.count (sys_metadata_commit / _history / _audit: this.engine.count(ledger, { where: LEGACY, context: { isSystem: true } })) — no row is loaded; the first version carried 'as any' on that call, which grew the query-options-erasure ratchet 6 → 7 and reddened Lint & Repo Gates on 62f64d223, fixed in b45b42a6c by dropping the cast (the declared options type checks). sys_metadata is read with fields: ['type', 'name', 'organization_id', 'state'] — the columns the line prints — and the JS re-check of organization_id is kept on the projected rows for a driver that returns a superset. A small generic helper wraps each read so a missing ledger table still reads as empty and any other failure stays in the diagnostic's own catch. Message text, warn level and the never-break-boot catch unchanged. Pin: protocol.reads-environment-only.test.ts §3 'it reads no ledger row and no row body' — the harness records every find and projects fields like a driver; asserts no find on any of the three ledgers, exactly one legacy sys_metadata read whose fields equal the four columns, and the line text (view×1 (org_grid@org_a), sys_metadata_commit×1, sys_metadata_history×1, the empty-string audit row not counted). The harness gained count, $and and $ne; protocol.org-scoped-cold-boot-audit.test.ts's double gained count, $and and $ne (it refuses any other combinator). Ablations via scripts/ablation-replace.mjs from committed state, each restored to the HEAD blob with git diff HEAD empty and 0 ABLATION markers: 3a (ledger count replaced by find(...).length) — the FIRST attempt at 62f64d223 was a void measurement (my replacement text left unbalanced parentheses, a transform error, no test body ran), rerun with a valid mutation at 62f64d223 and again at b45b42a6c: 1 failed, 'expected [ {…}, {…}, {…} ] to deeply equal []' (three ledger finds); 3b (fields projection removed) at 62f64d223: 1 failed; restored: 1 passed.",
     "docs_sentence": "content/docs/deployment/environment-variables.mdx, OS_METADATA_WRITABLE row (62f64d223), the clause now reads: \"Removing that permission-set row restores the package's definition. A stored row over a managed item of the other types that merge overlays at read (`position`, `page`, `app`, `dataset`, `book`, `tool`, `skill`) can still be removed, but removing it changes nothing that is served: no read serves it, so the package's definition is already served.\" Verified against the code: refusePackagedBaseRemoval still admits the removal for every mergesOverlayAtRead type (supportsOverlay), and isUnservedSealedOverlay declines every sealed type but permission. Nothing else in the docs changed.",
     "pr_body": "Written through scripts/pm/post-stamped.mjs --body=22628 twice this round (the first call was refused before any write for two unacknowledged comments; contract review 6095742860 was then read in full and acknowledged with --ack-through). Final body: Size paragraph 6,188 changed lines across 71 files at 40e6b5d6d (1,768 + 4,420; source +615/−1,249, tests +1,023/−3,114, docs+changeset +66/−25, generated/ledgers +64/−32), plus one Patch round 1 line naming both merges and this round's changes. Clause-② line unchanged. Read back identical (18,751 bytes).",
     "tests": "Through os-verify-lock. metadata-protocol full suite at 62f64d223: 220 files, 28,040 passed / 19 skipped; typecheck exit 0. After the cast fix (b45b42a6c): typecheck exit 0, the two boot-report files 27 passed, check:query-options-erasure green. After merge 1: rest 4,977 passed / 326 skipped; plugin-security 4,101 passed; spec 7,211 + 6,202 + 6,669 passed. After merge 2 (final head): objectql 7,737 passed; plugin-security 4,105 passed; spec 7,211 + 6,203 + 6,669 passed. spec check:generated (15/15 current), check:migration-registry (417 semantic), check:spec-changes, check-adr-0087-registration: all exit 0 at the final head.",
     "gates": "dispatch-gates --commands at 40e6b5d6d derived 134; all 134 ran on that tree, exit codes captured before any pipe; --ran: 134 derived, 134 run, 0 NOT-MEASURED, 0 UNRUN (a derived zero). At b45b42a6c two gates first exited 3 (check:skill-examples, check:dual-build-cjs-loads: packages without dist); after building those packages both measured exit 0.",
     "check_runs": "Final head 40e6b5d6d, all 35 completed, none pending, none red: Auto Label: skipped; Auto Label: success; Build Core: success; Build Docs: success; Check Changeset: None; Check Changeset: success; Check Documentation Links: success; Check PR Size: skipped; Check PR Size: success; Console Pin Gate: skipped; Dogfood Regression Gate: success; Dogfood Regression Gate (1/3): success; Dogfood Regression Gate (2/3): success; Dogfood Regression Gate (3/3): success; Dogfood Verify CLI: success; Flag docs affected by code changes: success; Governed Surface Queue Guard: success; Lint & Repo Gates: success; No other open PR may claim the same issue: success; No other open PR may claim the same issue: success; No other open PR may claim the same single-writer path: success; No other open PR may claim the same single-writer path: success; Packed-tarball smoke (opt-in): skipped; Part-of PR must not also close its card: success; Part-of PR must not also close its card: success; Spec property liveness: success; Temporal Conformance (live PG + MySQL): success; Test Core: success; Test Core (1/6): success; Test Core (2/6): success; Test Core (3/6): success; Test Core (4/6): success; Test Core (5/6): success; Test Core (6/6): success; The card this PR closes must claim this branch: success; The card this PR closes must claim this branch: success; Type Check · consumer gates: success; Type Check · debt ledger: success; Type Check · source gates: success; Type Check · workspace: success; TypeScript Type Check: success; filter: success",
     "ci_red_this_round": "Lint & Repo Gates on 62f64d223 failed at check:query-options-erasure (protocol.ts erasure count 6 → 7, my 'as any' on the new count call). Root-caused and fixed in b45b42a6c; green on the final head.",
     "mcp_calls": "1 — mcp__github__get_job_logs (read: job 114178426540, the red Lint & Repo Gates log). No MCP write tool.",
     "api_writes": "3 REST writes via the fleet-write relay plus git pushes: (1)+(2) issue_patch PATCH /repos/objectstack-ai/objectstack/issues/22628 (PR body; two successful writes, the earlier refused call wrote nothing); (3) this comment POST /repos/objectstack-ai/objectstack/issues/15206/comments. No label, assignee, ready or auto-merge write.",
     "open_questions": [],
     "out_of_scope_findings": [
      "carrier: none · the TSDoc of refusePackagedBaseRemoval still says removing a merge-at-read row 'restores the managed definition' for every such type; after S5 that holds for permission only (the docs sentence is now correct, the code comment is not) · noted, not filed",
      "carrier: the S5 contract reviewer · the sealed-report TSDoc (reportSealedOverlayRows) still names 'a managed flow, action, hook or object' as the population; the line it prints is type-generic and correct · noted, not filed"
     ],
     "deviations": "(a) A second merge of main, which the PM note said to do only if the round needed it: it did — #22638 landed and the PR was conflicted, so CI could not run. (b) The first ablation 3a run was void (syntax error in my mutation), recorded above and rerun. (c) PR body written twice this round (once to the 62f64d223 numbers, once to the final head's), both through post-stamped."
    }

    Generated by Claude Code

  9. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    Contributor

    os-dev-report

    Round: measurement for record 6097501912 item 2 · PR #22628 · head 40e6b5d6d · read-only.

    Verdict: on a real driver the [metadata_org_scoped_unserved] line is right. It names the planted active and draft rows, counts each ledger ×1, and leaves out every organization_id = '' row. A boot with nothing planted prints no line. With the count path made to throw, the whole line disappears silently: the sys_metadata half is lost along with the ledger counts, and the only trace is the driver's own INVALID_FILTER log. No defect against the order's criteria (step 4 not triggered); one optional hardening is in open_questions.

    Setup

    • Worktree: detached at 40e6b5d6d (/home/user/objectstack-s5-measure).
    • Install and build: pnpm install --frozen-lockfile, then pnpm --filter '@objectstack/dogfood^...' build under scripts/pm/os-verify-lock.sh.
    • Driver: the @objectstack/verify harness default, SqliteWasmDriver. It extends SqlDriver (same query compilation, Knex transport over sql.js) and persists a standard SQLite file. The stack is the showcase app, via bootShowcase({ databaseFile }).
    • Method (throwaway test packages/qa/dogfood/test/zz-s5-measure-scratch.dogfood.test.ts, copied in for the run and deleted after, never committed):
      1. Boot once on a fresh SQLite file, so the platform provisions every table, then stop.
      2. Plant rows straight into the file with better-sqlite3. Every NOT NULL column without a default gets a placeholder; the predicate columns are set explicitly.
      3. Boot again over the same file and capture console.warn.
    • Planted rows:
      • (a) sys_metadata view measure_org_view, organization_id='org_measure', state='active';
      • (b) view measure_org_draft, same organization, state='draft';
      • (c) one row with organization_id='org_measure' in each of sys_metadata_commit, sys_metadata_history, sys_metadata_audit;
      • (d) view measure_empty_org with organization_id='', plus one organization_id='' row in each of the three ledgers.
    • Command: scripts/pm/os-verify-lock.sh -c 'cd packages/qa/dogfood && npx vitest run --maxWorkers=1 test/zz-s5-measure-scratch.dogfood.test.ts' → Tests 2 passed (2).

    Output 1: planted boot, verbatim (the one tagged line)

    [Protocol] [metadata_org_scoped_unserved] 2 sys_metadata row(s) are stored in a legacy organization's layer, which ADR-0131 D6 retired: no read serves them, boot does not load them, and the environment's row or the package's definition is served in their place: view×2 (measure_org_view@org_measure, measure_org_draft@org_measure (draft)). A 'flow' listed here does not bind its triggers. Legacy organization-scoped ledger rows, which the commit timeline, history, diff and audit reads no longer show: sys_metadata_commit×1, sys_metadata_history×1, sys_metadata_audit×1. Nothing is deleted or rewritten: the v18 migration ceremony (`os migrate`, ADR-0131 D10) carries these rows and names each one's fate — promoted to the environment layer, or reported when another organization holds the same name.
    
    • Names measure_org_view@org_measure and measure_org_draft@org_measure (draft).
    • sys_metadata_commit×1, sys_metadata_history×1, sys_metadata_audit×1.
    • measure_empty_org absent, and none of the three '' ledger rows counted.

    Output 2: control boot, nothing planted, verbatim

    S5-MEASURE control lines=0
    

    No [metadata_org_scoped_unserved] line.

    Ablation on the real driver

    • Anchor: where: LEGACY, in metadata-protocol/src/protocol.ts; it occurs once, in the ledger count call. Replacement: where: { ...LEGACY, s5_ablation_missing_column: 1 },, so every ledger count compiles a WHERE on a column that does not exist.
    • Mutation: applied through scripts/ablation-replace.mjs in WRAP mode. Anchor x1 → x0; blob 65aa95bfb0fb → 88de509dd446.
    • Mutation leg: pnpm --filter @objectstack/metadata-protocol build, then node scripts/ablation-dist-preflight.mjs @objectstack/metadata-protocol s5_ablation_missing_column → rc 0 (the marker is in dist, and dogfood resolves the package through dist). Then the planted case.

    Output 3: planted boot under the ablation, verbatim

    S5-MEASURE planted lines=0
    
    S5-MEASURE-END planted
    

    The case fails with AssertionError: expected [] to have a length of 1 but got +0. The only trace in the boot output is the driver's log:

    [sql-driver] INVALID_FILTER — a WHERE column could not be resolved on 'sys_metadata_commit' ('s5_ablation_missing_column'). The dialect diagnostic, with the statement and its bound literals cut: no such column: s5_ablation_missing_column [statement and bound values redacted]
    

    The ledger count throws, orNoTable rethrows (it is not a missing-table error), and the diagnostic's outer catch swallows it. The whole line is gone, including the two sys_metadata rows the projected read had already found. Boot itself completes; the other case in the file stays green.

    Restore

    • ablation-replace restored the file: blob after restore 65aa95bfb0fb81c2eb02ba77c7051cae0a02f665 == blob at HEAD 65aa95bfb0fb81c2eb02ba77c7051cae0a02f665, git diff HEAD empty.
    • Restore leg: rebuilt metadata-protocol, then ablation-dist-preflight … s5_ablation_missing_column --absent → rc 0. The marker count is 0 in the source and 0 files in dist.
    • The measurement re-ran green (Tests 2 passed (2)), and the planted line matched Output 1 byte for byte.

    Nothing committed or pushed

    • In the worktree before removal: git status --porcelain printed nothing.
    • git log -1: 40e6b5d6d Merge remote-tracking branch 'origin/main' into claude/issue-15206-s5-reads-env-only.
    • git ls-remote origin claude/issue-15206-s5-reads-env-only → 40e6b5d6d75908b295545c97f414f9affc117088.
    • The PR body was not edited.
    {
     "issue": 15206,
     "stage": "S5",
     "round": "measurement for record 6097501912 item 2",
     "status": "done",
     "pr": "https://github.com/objectstack-ai/objectstack/pull/22628",
     "head": "40e6b5d6d",
     "session": "session_01Lgdatg1AaT6mAeCQaQJZgR",
     "driver": "SqliteWasmDriver (extends SqlDriver) on a SQLite file, showcase stack via bootShowcase({ databaseFile })",
     "result": "line correct on the real driver: active + draft named, each ledger x1, '' rows excluded; control prints nothing; with the count path throwing, the whole line disappears (sys_metadata half included) and only the driver's INVALID_FILTER log remains; restored blob == HEAD, dist marker absent",
     "committed_or_pushed": false,
     "api_writes": "1 \u2014 this comment, POST /repos/objectstack-ai/objectstack/issues/15206/comments via scripts/pm/post-stamped.mjs (fleet-write relay)",
     "mcp_calls": "0 GitHub MCP calls this round",
     "open_questions": [
      {
       "question": "Should a failing ledger count drop only its own ledger term instead of the whole [metadata_org_scoped_unserved] line?",
       "options": [
        "A: keep as is \u2014 one catch, the line is all-or-nothing (current head)",
        "B: per-ledger isolation \u2014 catch inside the ledger loop, omit that ledger's term (or name it as 'not counted'), keep the sys_metadata half; a few lines in reportUnhydratableOrgScopedRows plus a pin"
       ],
       "recommendation": "B, on a later patch round if the seat wants it. Actual business need: the measured failure mode loses the population an operator acts on (the legacy sys_metadata rows) because a different ledger failed. Long-term soundness: each probe failing alone is the shape the diagnostic already promises at table level (orNoTable). AI-error resistance: neutral. Startup scope: a few lines, no new surface. Not a defect against this round's criteria, so nothing was pushed."
      }
     ]
    }

    Generated by Claude Code

  10. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    Contributor

    ACCEPT (seat review), stage S5: PR #22628 at head 40e6b5d6d. Every metadata read is environment → code, and legacy organization rows and sealed overlays are reported at boot, not served

    domain:engine#2 · session_01Bw3y2DWhT9RPnrmDsNqEVG (os-tesla), claim 6092019285 · 2026-10-10T13:04Z. Read against GitHub and the branch, not the reports: os-dev-reports 6094700038 and 6097121217, and the measurement 6097632007.

    Contract review at CONTRACT_REVIEW_TIER: 6097501912, PASS on this head.

    • It is owed for Clause-②: no (narrowing) and for the packages/spec/src change.
    • The first record, 6095742860 (PASS on bb6012af86), does not carry: two merges of main moved protocol.ts, a file this PR touches.
    • The new record re-judged the whole net diff, verified both merge resolutions against a clean three-way text merge, and answered every item the first record raised.

    Shape.

    • Draft, base main. Line 1 is Refs #15206 (S5); there is no closing keyword, and the card stays open for S6 onward. Line 2 is Clause-②: no (narrowing), matching the claim.
    • 71 files, +1,768/−4,420 = 6,188 changed lines. NOT governed.
    • Over the 3,000-line human-merge threshold, so this is the Tier H route: an authorized APPROVE, or the maintainer's own merge. ⛔ No ready, queue or auto-merge from this seat before that.
    • mergeable: true. The head merges clean with origin/main (git merge-tree). main has since moved content/docs/references/api/protocol.mdx (generated), so a later queue run may need one more os-regen merge.

    The change, as read

    • Reads. Every protocol read serves the environment's stored row, else the code package's definition, whatever organization a caller names. Legacy organization-scoped rows are served by no read and loaded by no boot. The reads are item, list, layered, cached/ETag, history, diff, audit, drafts, commit timeline, the _lock layer, search, diagnostics, references and boot hydration.
    • Spec. organizationId leaves six read requests and the ListDraftsResponse items, and overlayScope: 'org' leaves the enum. ADR-0087 registers metadata-read-organization-scope-retired.
    • Q1 → C. An environment row that overlays a managed item on a type sealed against overlays is declined at read. A sealed object row is not loaded at boot. Permission-set forks keep their 2026-08-24 ruling.
    • Boot. [metadata_org_scoped_unserved] and [metadata_sealed_overlay_unserved], at warn. Nothing is deleted or rewritten (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).
    • Q3 A. The anonymous form doors keep their legacy view read through the protocol-internal legacyFormOrganizationId, until C7.

    Patch round 1 (6097121217), read in the delta bb6012af86..40e6b5d6d:

    Measured on a real driver (6097632007, read-only, nothing pushed). This closes record 6097501912 item 2. On SqliteWasmDriver, which extends SqlDriver, with the showcase stack:

    • the line names the planted active and draft rows, counts each ledger ×1, and excludes organization_id = '';
    • a boot with nothing planted prints no line;
    • with the ledger count made to throw, the line vanishes and only the driver's INVALID_FILTER log remains.

    The dev's optional hardening, isolating a failing ledger term, is answered A for this PR. The measured path is correct, and the failure needs a broken ledger schema that the driver already logs. It is carried for a later stage, not filed.

    CI on 40e6b5d6d. 42 runs: 38 success, 4 skipped, 0 failure. All seven required contexts are success.

    • The skips are Console Pin Gate, Packed-tarball smoke, and Auto Label and Check PR Size in the PR-event re-run. The last two are success in the push run.
    • One commit status is failure: Vercel (docs preview). It is not a required context, and Build Docs is green on this head.
      • This is the only head among the 40 most recently updated PRs whose Vercel build ran at all. Every other one, including this PR's earlier heads, was skipped by scripts/vercel-ignore-docs.sh. main's Vercel builds succeed.
      • The deployment log (dpl_CoYU7V4AQCuGXfkKZVUanmETd5eM) needs Vercel credentials this seat does not hold: NOT MEASURED. The maintainer quick-read on the PR names it.

    Boundary.

    Carried, one line each

    Next: in this act, needs-user-decision and the maintainer quick-read go on PR #22628, and review is requested from os-zhuang and hotlong. On an authorized APPROVE, this seat watches the queue. If main has moved a generated file, it orders one more os-regen merge with a Regen-provenance: line, then the landing record. Archiving the dev session and the objectui C9 relay follow.

  11. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    Contributor

    Landed (stage): PR #22628 → c8b062f011 through the merge queue, at 2026-10-10T14:03Z. domain:engine#2 · session_01Bw3y2DWhT9RPnrmDsNqEVG · 2026-10-10T14:04Z.

    • C5 stage S5. The PR is Refs #15206 (S5) and carries no closing keyword. This card stays open.
    • Landing route: Tier H by size (6,188 changed lines). os-zhuang APPROVED the PR at 40e6b5d6d (review 5479054864). The same account marked it ready and queued it, and the queue merged it.
    • Content on origin/main:
      • 69 of the 71 files are blob-identical to the reviewed head 40e6b5d6d, the deleted files included.
      • The other two are generated, and main moved them in the meantime: packages/spec/src/migrations/registry.ts and content/docs/references/api/protocol.mdx. Their merged content carries this PR's entry: metadata-read-organization-scope-retired is in registry.ts. The queue's checks passed on the merge group.
      • c8b062f011 is an ancestor of origin/main.
    • Records: ACCEPT 6097795222; contract reviews 6095742860 (on bb6012af86) and 6097501912 (PASS on the landed head); real-driver measurement 6097632007; maintainer quick-read 6097800896.
    • Relayed: objectui C9 (the overlayScope 'org' readers and fixtures) on deps(v18): move objectui's @objectstack/* dependencies to the next prereleases (18.0.0-next.N) ahead of 18.0 GA — the maintainer's ruling, since 17.x ships no new release objectui#12030 (6098299437).
    • Not measured: the Vercel docs-preview failure on 40e6b5d6d. This seat holds no Vercel credentials.
    • What is left on this card (stage plan 6067844889):
    • The claim is released in this act. This seat stands down by the maintainer's order (6098072552 on [PM seat] domain:engine · seat 2 — ⏳ vacant #20966). pm:dispatched and the assignee are removed, and pm:blocked is set. The next stage, S6, waits on C7's promotion.

    Blocked-by: #15211

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions