Skip to content

feat(spec,services): deployment-level state has no organization column — settings global rung, plumbing objects, the audit ledger, #12699 made total (ADR-0131 D7) #15207

Description

@hotlong

⛔ BLOCKED — the v18 development line is not open.

Blocked-by: #15193

History: this line read Blocked-by: #15193 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. Tables that belong to no organization — the job queue, delivery records, migration journals, the audit ledger, the notification inbox — lose their organization column; deployment-level runtime settings leave sys_setting; and cloud's "this deployment declares this object platform-global" switch becomes simply "on this deployment the object has no organization column".

Scope. (1) systemFields.tenant: false on the objects no writer attributes to an organization: sys_job, sys_job_run, sys_job_queue, sys_flow_dispatch, sys_migration, sys_migration_journal, sys_secret (scoped through its owning setting), sys_presence — each confirmed by a writer census with a firing control, not by the name looking infrastructural. ⛔ NOT sys_http_delivery (#13565 stamps it from the webhook's organization; redeliver() walls by tenant) and ⛔ NOT sys_email (#11741 / #11303 decision 2 stamp it at the producers) — both are tenant data. The sys_inbox_message / sys_notification* / sys_user_preference family is decided by its writer facts (recipient-anchored in cloud's reading) and recorded in the C7 inventory. ADR-0087 entry per removed column. (2) sys_audit_log: no injected organization column; the organization a row is about becomes a plain attribution field under a name the tenant-field resolver does not claim (not organization_id); RLS readers of the audit page filter on it explicitly. (3) sys_setting scope: 'global' rows leave the tenant-scoped object per §6 Q3 — configuration, or a tenant-less sys_platform_setting; settings-service.ts's user → tenant → deployment cascade reads the new source. (4) #12699: platformGlobalObjects becomes an input to resolveInjectedSystemColumns on the declaring deployment — no column injected, so Layer 0 and the driver have nothing to scope; the stand-down semantics retire.

Absorbs: #13433 (sys_activity.environment_id declared live with no writer) belongs to this census — read it and give that column a verdict in the same pass.

Acceptance. DDL for each listed object carries no organization_id; the settings cascade resolves deployment values from the new source (pinned); an audit row about a deployment-level action is written without refusal and is visible to platform admins; on a deployment declaring an object platform-global the table has no column (cloud pins this in C10).

Refs: ADR-0131 D7 · ADR-0007 · ADR-0057 · #12699 · #13565 · #11741 · #13636 (sys_audit_log specimen) · #13433 · #13564 read-side ledger U-A.

Activity

  1. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    Contributor

    v18 pre-opening re-verification (C6): mostly HOLDS. One listed object is wrong; four small refinements

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-06T14:38Z. ⛔ 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.

    Holds:

    Corrections:

    Day one: dispatchable once #15193 closes, with the corrections above.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    Contributor

    Triage: unlocked, pm:blocked → pm:queue. The v18 line is open: #15193 was closed on the maintainer's word. C6, dispatchable first

    Blocked-by: none

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-07T12:36Z. ⛔ Not a claim, ⛔ not a dispatch.

    The blocker is released:

    At claim (as #15193 requires, because these premises were measured in 2026-09): the file surface is re-verified against the then-current main. At this write, every repository path the body names in backticks exists on main (879bd38c5b).

    • Order: C10 (cloud#1979) waits on this card, per its Blocked-by: line.

    The release state:

    • main is not yet in Changesets pre mode; the opening card follows this unlock.
    • A breaking change landing before the opening is graded minor with its BREAKING banner and ADR-0087 disposition, under the launch-window convention. Once pre mode is in, major is open.
    • ⛔ chore: version packages #21988 is not merged.
  3. 34 remaining items

  4. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 1 (stage: scope item (4), #12699 made total, the last open item of this card; items (1), (2) and (3) landed as PRs #22107, #22266 and #22166, released 6061099316) · 2026-10-08T14:19Z
    Session: session_01LAi5BVvQNiYzepSAcsoFLK
    Account: os-litant (the seat's linked user as GET /user answers it; the card's assignee from this act)
    Branch: claude/issue-15207-platform-global-no-column
    Worktree: objectstack-issue-15207-global
    Domain: domain:spec (the card also carries domain:services; this seat holds it whole, as for items (2) and (3))
    Seat: domain:spec#1 (seat post #6017)
    File surface (at origin/main 79c35d45e2; stop on breach and explain in the report). Scope item (4) alone, under ADR-0131 D7: "an object a deployment declares platform-global gets no organization column on that deployment (the injected-columns plan reads the declaration), so Layer 0 and the driver agree by having nothing to scope". ADR-0131 retires #12699's stand-down semantics.

  5. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    Contributor

    os-dev-report
    {
    "issue": 15207,
    "status": "done",
    "branch": "claude/issue-15207-platform-global-no-column",
    "pr": "#22331",
    "session": "session_01LAi5BVvQNiYzepSAcsoFLK (subagent = the PM's id)",
    "premise_still_valid": true,
    "summary": "Draft PR #22331 (line 1 Fixes #15207, line 2 the claim's Clause-② line verbatim) makes the #12699 declaration total under ADR-0131 D7. The spec plan resolveInjectedSystemColumns(def, deployment?) takes the validated platformGlobalObjects as an optional input; ObjectQLPlugin.start() reads org-scoping FIRST (before loadMetadataFromService and the first schema sync) and installs it with SchemaRegistry.setDeploymentPlatformGlobalObjects(), which re-plans objects registered earlier in other plugins' init(); a declared object is registered and provisioned with no organization_id, no tenant index and systemFields.tenant false recorded (a materializeBaseLayer stamp with its write-side strip), so Layer 0 and the driver have nothing to scope. plugin-security's getObjectSecurityMeta fold and its platform-global boot line retire, with no fallback; the one reader moved to @objectstack/core (rules unchanged); OrganizationsPlugin declares providesServices org-scoping; a provider that registers outside init() with a different declaration fails the boot at kernel:ready by name. ADR-0087 D3 entry platform-global-object-organization-column-retired + one step-18 fragment + regenerated registry.ts; changeset major (objectql, plugin-security; pre mode is in) / minor (spec, core) / patch (organizations) with BREAKING banner and FROM/TO.",
    "readings": {
    "p1": "HOLDS, measured at 799eb00 before any edit through a booted ObjectKernel (ObjectQLPlugin over better-sqlite3, the real SecurityPlugin, a fixture org-scoping provider composed AFTER the objects plugin, declaring platformGlobalObjects: [qa_widget_registry]): the declared object was registered WITH organization_id and its table created with the column (columnInfo); security.getReadFilter(declared, member) answered undefined (the fold at security-plugin.ts getObjectSecurityMeta, third tenancyDisabled clause) while the sibling answered { organization_id: org_acme }; a system read of the declared table carrying tenantId org_acme returned only the org_acme row of two (the SQL driver's tenant arm). Control, no declaration: both walled.",
    "p2": "HOLDS through ADR-0116's Phase 1/2 split plus the provider's providesServices declaration; NOT through a per-plugin edge (measured). Plan computed: SchemaRegistry.registerObject -> applySystemFields -> resolveInjectedSystemColumns, inside each registrant's init() via manifest.register, and again at start() (loadMetadataFromService, restoreMetadataFromDb) and later; columns fixed at ObjectQLPlugin.start() installRegisteredSchemas. org-scoping registered: OrganizationsPlugin.init(), which hard-depends on the engine; serve composes it after Auth and the app plugins, and the fixture confirmed the declared object was already registered when the provider initialized. Order: every init() completes before any start(), so the engine's start() sees a provider that registers in init() (now declared providesServices: ['org-scoping'], ADR-0116 D2) and no table exists yet; the registry re-plans what registered earlier. Measured: an engine-side optionalDependencies edge on the provider is a cycle (resolvePluginOrder over the two declarations throws 'Circular dependency detected: com.objectstack.engine.objectql'; CONTROL without the edge orders engine then organizations); an edge from every object registrant is an open-ended set. No plugin moved and no boot data step was added; the only new boot behaviour is the kernel:ready refusal for a provider that registered outside init() with a different declaration.",
    "p3": "HOLDS. Absent key: registered shapes JSON-identical (registry with no install vs empty install), spec plan byte-identical over eight shapes, kernel pin with every column kept. Junk (bare string): the engine warns 'platformGlobalObjects' REFUSED exactly once and no object loses its column or wall; the reader's whole-key refusal and per-key independence are pinned in core.",
    "p4": "HOLDS. git grep platformGlobalObjects at 799eb00: spec schema/docs/authorable-surface, the reader, plugin-security's consumer and boot log, and tests; no declarer. Every pin uses a fixture provider.",
    "p5": "Measured. Author-time surfaces that compute the plan with no deployment name organization_id for a declared object: lint system-fields.ts (addressable names), spec import-mapping-target.ts, scripts/platform-object-tenancy-census.mjs, cli authoring-filter-judge. Runtime surfaces on the declaring deployment agree with it: the registry, the DDL, the /meta read exits (pinned through ObjectStackProtocolImplementation: governServedItem re-plans served bodies without the deployment, which the systemFields.tenant false record answers), the metadata bridge describe reads, lifecycle provenance (absent), and the field doors (INVALID_FIELD 400 / INVALID_FILTER). Stated in the plan's module doc, tenancy-posture.ts and the changeset. One composition-dependent one-shot surface: os migrate plan / apply compose the host config's plugins, not serve's posture-driven OrganizationsPlugin, so on a declaring deployment whose provider arrives only through serve a migrate plan reads no declaration and would add the column back (additive). PR Acceptance notes; carrier C10."
    },
    "tests": "Head 5322c2b unless noted (it merged origin/main dc4a5c6 via os-regen-merge.sh; regeneration wrote nothing). Through os-verify-lock, VERDICT command-exit 0 each: spec --project local 626 files / 18728 passed / 1 todo; spec --project repo step18-rationale-merge + conversions-major18-merge 21 passed; objectql --project local 385 files / 7562 passed; core 83 files / 2258 passed; organizations 11 files / 151 passed; plugin-security 183 files / 3835 passed / 45 skipped at 86db7e8 (later only a test-file type annotation and an unused objectql accessor changed; the touched plugin-security files re-ran green after). Typecheck exit 0 for core, objectql, plugin-security, organizations, spec, each with check:test-typecheck (ledgers held: core 4/4/4, objectql 40/234/65, spec 52/246/135, plugin-security 0, organizations 0). New pins: spec plan 5 cases, core reader 11, objectql registry 7, plugin-security kernel 8; rewritten: deployment-platform-global-exemption 8, tenant-layer0-verdict-end-to-end (declared sweep now matches 2 rows, was 1), tenant-layer0-verdict-on-operation (fixture re-registered as the registry registers it). Reverse verification via scripts/ablation-replace.mjs (hold mode, trap restore on EXIT INT TERM, absolute path): anchor "!(name !== '' && deploymentDeclaresPlatformGlobal" replaced so it never matches (anchor 1->0, blob 6e571966dd -> 88efcbbb14); spec rebuilt; ablation-dist-preflight found the marker in 6 built files; results: spec plan 2 red / 20 green (exactly the two declared-object pins), registry 5 red / 2 green (absent and opted-out controls green), kernel 4 red / 4 green (absent-key, junk-key, no-stand-down and late-provider controls green), end-to-end 1 red / 2 green. Restore: blob == HEAD 6e571966dd, git diff HEAD empty, whole tree clean; spec rebuilt (after ~45 min of lock contention behind a cli and a dogfood full run), preflight --absent: marker in none of 234 built files; same files green 22 / 7 / 11.",
    "gates": {
    "head": "5322c2b755",
    "derivation": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths) at 5322c2b: 109 families (the claim-time list had 91; added: spec check:migration-registry, check:spec-changes, check:upgrade-guide, check:engine-double-contract, check:future-spec-major, check:objectql-double-limit, check:query-options-erasure, check:type-check-coverage, check:type-check-debt, check:where-matcher, check-scripts-symbol-anchors + self-test, check:agent-test-spelling, check:bash32-floor, check:cli-command-ids, check:entry-guard, check:parse-guard, check:pnpm-filter-targets)",
    "final_battery": "all 109 ran at 5322c2b, each exit captured before any pipe, all exit 0",
    "reconciliation": "dispatch-gates --ran: '109 derived famil(ies) accounted for — 109 run, 0 NOT-MEASURED (a DERIVED zero — all 109 recorded an exit code and none of them is 3)', exit 0",
    "first_pass_findings": "check:engine-double-contract exit 1 (the registry pin's three doubles absent from the pinned ledger; --write, committed); check:slot-lookup exit 1 (one untyped any service lookup in the kernel pin; typed); check:dts-closure exit 1, check:dual-build-cjs-loads exit 3, check:i18n exit 3 (unbuilt packages; green after a full turbo build, 72 tasks, 71 cached)",
    "named_minimum": "check-adr-0087-registration: '[major+BREAKING+bang+clause-②-narrowing] registered platform-global-object-organization-column-retired (new here)'; check-changeset-no-major: pre mode (tag next), major exempt; check-empty-changeset exit 0; check-platform-object-tenancy-census exit 0 (84 objects, 49 in reach, 35 outside, unmoved); spec check:generated 15/15 up to date; check:migration-registry 400 semantic; check:api-surface unchanged; check:nul-bytes exit 0",
    "extra_by_hand": "check:init-service-contract exit 0 (36 declared / 1 self-provided / 3 without a workspace provider); check:startup-registry-verdict exit 0 (45 seams, none recording a verdict the boot can contradict); node scripts/pm/check-governed-merges.mjs --pr 22331: NOT governed, 1742 changed lines",
    "lint": "proven narrowing: eslint --no-inline-config --format json over the 21 changed .ts files = 21 results, 0 errors, 0 warnings; population from eslint.config.mjs packages/** and */ TS globs; invariance: the config states it enables no type-aware linting (no parserOptions.project, no typed rules), so no untouched file's verdict can move; full pnpm lint is CI's",
    "not_measured": "none of the derived families. CI-only: full pnpm lint, cli layers (no cli file touched), dogfood, and the lanes dispatch-gates prints outside its derived total"
    },
    "line_budget": "vs merge base dc4a5c6: 23 files, +1479 / -263 = 1742 changed lines (PR object agrees per check-governed-merges); generated registry.ts +61, engine-double ledger +15",
    "clause_2": "Claim line kept verbatim on PR line 2. Measured on the built closure: value yes holds (@objectstack/core gains readDeploymentOrgScopingEntitlement and two types; resolveInjectedSystemColumns gains an optional parameter with no new spec export, check:api-surface unchanged); arm stays narrowing (a declared object loses its column on the declaring deployment). Changeset: 'Clause-②: yes (narrowing)'.",
    "c7_fate": "On a declaring deployment, each declared object's existing organization_id is ADR-0131 D10 fate 1 (column dropped): schema sync is additive, the boot drift report names it orphaned, the declarer (C10) owns the data step and backfill, then os migrate apply --allow-destructive; no boot step reads or writes it (D14). Stated in the PR body.",
    "mcp_calls": "0",
    "api_writes": "3 relay writes, each POST /repos/objectstack-ai/objectstack/dispatches executed by fleet-write.yml as objectstack-fleet[bot]: (1) pr_create = POST /repos/objectstack-ai/objectstack/pulls (draft) giving #22331, body read back identical (18463 bytes); (2) label-write --assign os-litant = the issues/22331 assignees write, read back as matching; (3) this os-dev-report comment = POST /repos//issues/15207/comments via post-stamped. Plus git pushes (not REST writes). No labels written (the PR has a changeset; size/xl is automation's).",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: C10 (cloud#1979, the control plane's composition) · noted, not filed, in the PR's Acceptance notes — os migrate plan / apply compose the host config's plugins, not serve's posture-driven OrganizationsPlugin; on a declaring deployment whose org-scoping provider arrives only through serve, a migrate plan reads no declaration and would add organization_id back to a declared object's table (additive sync). No in-repo declarer (P4), so no public door reaches it here · dedupe words: os migrate platformGlobalObjects, schema-migration composition org-scoping, declared platform-global column re-added",
    "carrier: 承接者:无 · Acceptance notes only — author-time tools (lint addressable names, import mapper, tenancy census) name organization_id on a declared object; the declaring deployment refuses it as an unknown field. Inherent to a deployment input; stated in the plan's docs and the changeset"
    ],
    "deviations": [
    "Mechanism: the plan reads the declaration at ObjectQLPlugin.start() (ADR-0116 Phase 1/2 split + the provider's providesServices) and the registry re-plans objects registered earlier, rather than a soft dependency or an init-time requirement; measured that neither per-plugin edge can order the provider ahead of the registration-time plan (engine-side edge is a cycle). This is the seat lean recorded for item (4) ('registry reads the declaration at schema sync, after the provider is guaranteed'). The Zone 3 'requirer with no provider' pin has no subject in this design (the start-time read is optional, single posture has no provider); pinned instead: a provider registering outside init() refuses the boot at kernel:ready by name.",
    "The registry records the plan's answer on a declared object's base layer as systemFields.tenant false (a materializeBaseLayer stamp with a write-side strip), so every existing reader (plugin-security's two clauses, the tenant index predicate, lifecycle provenance, the /meta read exits' injection pass) answers without a second reading of the declaration; the registry itself reads the declaration only through the spec plan (deploymentWithholdsTenant).",
    "Files outside the claim's surface (each named in the PR body): packages/plugins/organizations/src/organizations-plugin.ts (providesServices — the provider declaration the claim's ordering bullet names; lane to re-declare); packages/core/src/security/deployment-org-scoping-entitlement.ts (+ .test.ts, index.ts) — the reader moved, both consumers import it; packages/objectql/src/federated-injected-column-readers.test.ts (two census rows the census requires); scripts/engine-double-contract.pinned.json (--write for the new pin's doubles).",
    "New boot refusal at kernel:ready in ObjectQLPlugin (declaration changed after start()) — not in the dispatch's list; it is the validation half of the declared order.",
    "Changeset grade major for @objectstack/objectql and @objectstack/plugin-security, per the claim ('major under pre mode if breaking'); .changeset/pre.json is mode pre, tag next.",
    "origin/main moved 8 commits after the merged base dc4a5c6 (including #22186, #22197 and #22317 on registry.ts, engine.ts and security-plugin.ts). A no-commit merge probe auto-merges with no conflict; not merged in this round (the PR is at the tested head).",
    "Commit trailers use the model-free pair AGENTS.md requires (Claude-Session + Co-authored-by: Claude), not the harness reminder's model-named line; the PR footer is the AGENTS.md session-URL form, not the harness two-line form.",
    "Killed only my own processes by recorded PID: a pre-merge plugin-security suite (superseded by the merge) and a queued lock wrapper whose rebuild had not run (its tests would have read the mutated dist).",
    "Scratch probes (P1 kernel probe inside plugin-security src, the cycle probe in the scratchpad) were not committed; the P1 file was deleted before the first commit."
    ],
    "files_changed": [
    ".changeset/15207-platform-global-no-organization-column.md",
    "packages/spec/src/data/injected-system-columns.ts, injected-system-columns.test.ts",
    "packages/spec/src/security/tenancy-posture.ts, tenant-layer0-verdict.ts (docs)",
    "packages/spec/src/migrations/entries/semantic/18.platform-global-object-organization-column-retired.ts, packages/spec/src/migrations/registry.ts (regenerated + one step-18 fragment)",
    "packages/objectql/src/registry.ts, plugin.ts, engine.ts (docblocks), registry-deployment-platform-global.test.ts (new), federated-injected-column-readers.test.ts",
    "packages/core/src/security/deployment-org-scoping-entitlement.ts (moved from plugin-security), deployment-org-scoping-entitlement.test.ts (new), index.ts",
    "packages/plugins/plugin-security/src/security-plugin.ts, auto-org-admin-grant.ts (docblock), platform-global-no-organization-column.test.ts (new), deployment-platform-global-exemption.test.ts (rewritten), tenant-layer0-verdict-end-to-end.test.ts, tenant-layer0-verdict-on-operation.test.ts",
    "packages/plugins/organizations/src/organizations-plugin.ts",
    "scripts/engine-double-contract.pinned.json"
    ],
    "cleanup": "After this report is posted: node_modules removed and the worktree objectstack-issue-15207-global removed with git worktree remove (no --force); the branch stays on origin."
    }

  6. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    Contributor

    ✅ ACCEPT on the diff: PR #22331 at 5322c2b755 (item (4), #12699 made total). Landing held for the at-tier contract review and CI

    domain:spec seat 1 (#6017) · os-litant · session session_01LAi5BVvQNiYzepSAcsoFLK · 2026-10-08T17:45Z · holder of claim 6061910188; the review of record for the report 6065642320.

    Checklist (read on GitHub and in the PR's own diff, merge base dc4a5c6308):

    • Form: draft, base main, assignee os-litant. Line 1 is Fixes #15207, because this is the card's last item. Line 2 is the claim's Clause-② line, verbatim.
    • Size: 23 files, +1,479 / −263. check-governed-merges: not governed.
    • ADR-0131 D7, read in the diff:
      • resolveInjectedSystemColumns(def, deployment?) takes the validated platformGlobalObjects. A declared object gets no organization_id, no tenant index, and systemFields.tenant: false recorded on its base layer.
      • ObjectQLPlugin.start() reads org-scoping before the first schema sync. The registry re-plans objects that other plugins' init() registered earlier, so the columns are fixed only once.
    • The stand-down retires with no fallback: security-plugin.ts drops the platformGlobalObjects.has(object) clause of the getObjectSecurityMeta fold and its boot line. The one remaining clause is systemFields.tenant === false, which the plan now records. Nothing reads the declaration a second time.
    • The ordering is declared (ADR-0116): OrganizationsPlugin declares providesServices: ['org-scoping'] (D2), and every init() completes before any start(). The dev measured that an engine-side soft dependency on the provider is a cycle ("Circular dependency detected"), with a control that orders cleanly without it. A provider that registers outside init() with a different declaration refuses the boot at kernel:ready, by name. That is the validation half of a declared order (ADR-0078). No plugin moved, and no boot data step was added.
    • Premises P1–P5 hold as measured. P1 is through a booted kernel:
      • Before the change, the declared object had the column, the wall stood down, and the SQL driver's tenant arm still scoped it.
      • P3: an absent key is byte-identical to today, over eight shapes. A junk key exempts nothing and is refused once.
    • An authored organization_id on a declared object stays the author's column, and the wall keeps scoping it, with a named warning. Accepted: the declaration removes only the platform's injected column.
    • Reverse verification: with the plan's read of the declaration ablated, exactly the declared-object pins go red (spec 2, registry 5, kernel 4, end-to-end 1), and every control stays green. Restore was proven by blob equality and a dist preflight.
    • Grade: major for objectql and plugin-security under pre mode, minor for spec and core, patch for organizations, with the BREAKING banner and FROM/TO. ADR-0087 D3 entry platform-global-object-organization-column-retired at step 18, with the regenerated registry.ts.
    • C7's fate is stated in the PR body. On a declaring deployment, the existing organization_id is fate 1: the boot drift report names it, the declarer (C10) owns the data step, and no boot step reads it (D14).
    • Gates: 109 derived and 109 run at the head, 0 NOT-MEASURED. check:init-service-contract and check:startup-registry-verdict were run by hand, and both exit 0.

    Cross-lane: the files beyond the claim's regions are re-declared on #6367, #20966, #21118 and #6021 (6065682328 and the three beside it). No open PR touches them.

    Serial coupling with #22130 (PR #22215, protocol 18): this PR adds a step-18 semantic entry. Whichever of the two lands second regenerates spec-changes.json and the protocol upgrade guide through os-regen-merge.sh before it enqueues.

    Out of scope, carried:

    • os migrate plan / apply compose the host config's plugins, not serve's posture-driven OrganizationsPlugin. On a declaring deployment whose provider arrives only through serve, a migrate plan reads no declaration and would add the column back (additive). There is no in-repo declarer, so no public door here reaches it. It is carried by C10 (cloud#1979) and named in the PR's Acceptance notes.
    • Author-time tools (lint addressable names, the import mapper, the tenancy census) name organization_id on a declared object. That is inherent to a deployment input, and the plan's docs and the changeset say so.
  7. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    Contributor

    os-dev-report
    {
    "issue": 15207,
    "status": "done",
    "round": "fix round on PR #22331 (claim 6061910188, seat ACCEPT 6065729426; the contract review PASS 6065958488 on 5322c2b is void by this push)",
    "branch": "claude/issue-15207-platform-global-no-column",
    "pr": "#22331",
    "session": "session_01LAi5BVvQNiYzepSAcsoFLK (subagent = the PM's id)",
    "premise_still_valid": true,
    "summary": "One commit, 6b05507, fast-forward from 5322c2b; the PR stays draft. The step-18 D3 entry platform-global-object-organization-column-retired named the declaration by its tracker number in reason, which os migrate meta prints as why:. It now says 'Before this, the declaration stood the security layer's organization wall down...'. Every string field of the built entry (id, surface, replacement, reason, acceptanceCriteria) was checked against the test's own TRACKER_ID regex: all clean. The step-18 rationale fragment, which os migrate meta also prints as the hop rationale but the test does not hold, said it the same way and now reads 'the deployment's platform-global declaration'. The entry file's leading code comment keeps its tracker ids: the test header names surface, replacement, reason (why:) and acceptanceCriteria (verify:) as the printed block, and a source comment is printed nowhere. registry.ts regenerated by gen:migration-registry (2 lines). main not merged: GitHub reported the PR mergeable at 5322c2b, and the delta stays two files.",
    "diff_this_round": "packages/spec/src/migrations/entries/semantic/18.platform-global-object-organization-column-retired.ts (1 line), packages/spec/src/migrations/registry.ts (2 lines: the generated copy of reason, and the rationale fragment); +3 / -3",
    "tests": "At 6b05507, each through os-verify-lock and each exit captured before any pipe. (1) pnpm --filter @objectstack/cli exec vitest run --project integration test/migrate-meta-engine-guidance.test.ts: exit 0, 1 file / 3 passed, including 'prints every covered block verbatim, and no printed block names a tracker id'. It ran against a spec dist built from this head: the field check read dist/migrations MIGRATIONS_BY_MAJOR and found the new reason text. (2) pnpm --filter @objectstack/cli test (both projects): exit 1, 358 files passed and 3 failed, 4805 tests passed and 35 skipped. All 3 failures are the same prerequisite, packages/cli itself unbuilt: 'packages/cli is not built (./dist/index.js is absent)' in published-subpath-console.pin and published-subpath-hook-body.pin, and 'dist/commands/serve.js does not exist' in dev-standalone-self-heal.integration. After turbo run build --filter=@objectstack/cli (59 tasks), those 3 files: exit 0, 3 files / 33 passed. So every cli test file passed at this head; the 358 in the full run and the 3 in their re-run (a declared narrowing of the re-run to the files that failed on the prerequisite). (3) spec --project local src/migrations: exit 0, 4 files / 203 passed; spec --project repo step18-rationale-merge + conversions-major18-merge: exit 0, 21 passed. (4) check:migration-registry exit 0 ('registry.ts is current (400 semantic, 247 retired-key, 222 retired-def)'); node scripts/check-adr-0087-registration.mjs --base origin/main exit 0 ('[major+BREAKING+bang+clause-②-narrowing] registered platform-global-object-organization-column-retired (new here)'); spec check:generated exit 0 ('All 15 generated artifacts are up to date', against a spec dist built at this head).",
    "gates": {
    "head": "6b055079e8",
    "derivation": "dispatch-gates --commands --repo objectstack-ai/objectstack (no paths) at 6b05507 derives the same 109 families as at 5322c2b; the change adds none",
    "run_this_round": "the 40 families that read the touched files (every spec check:, check-adr-0087-registration and self-test, check-changeset-no-major, check-empty-changeset, check:doc-authoring, check:issue-citations, check-issue-citations, check:nul-bytes, check-spec-docblock-symbol-anchors, check:future-spec-major, check-keyed-text-bounds, check-comment-mask-, check:spec-parsed-alias, check:pm-changeset-deadline-census): all exit 0 at 6b05507",
    "carried": "the other 69 families: all exit 0 at 5322c2b with --ran 109/109/0 NOT-MEASURED; this round's diff touches none of their inputs beyond the files the 40 above read"
    },
    "line_budget": "vs merge base dc4a5c6: 23 files, +1479 / -263 = 1742 changed lines (unchanged in size; this round +3 / -3)",
    "root_cause_of_the_miss": "The round-1 report listed the cli layers as CI-only and not measured, on the rule that no cli file was touched. But migrate-meta-engine-guidance.test.ts reads the whole migration registry through @objectstack/spec, so a spec registry entry is a cli test input. Measured now. The derived gate battery could not name it: it is a test in the cli integration layer, not a gate family. Noted, not filed: nothing is broken now, and the rule is held by this very test in the merge queue's required set.",
    "mcp_calls": "0",
    "api_writes": "1 relay write this round: this os-dev-report comment, POST /repos/objectstack-ai/objectstack/dispatches (fleet-write.yml as objectstack-fleet[bot]) executing POST /repos//issues/15207/comments via post-stamped. Plus 1 git push (fast-forward 5322c2b..6b05507), not a REST write. The PR body, labels and assignee are untouched.",
    "pr_body_replacement": null,
    "open_questions": [],
    "out_of_scope_findings": [],
    "deviations": [
    "The step-18 rationale fragment was reworded too, beyond the entry the test hit. os migrate meta prints it, so it is author-shown, though the test does not hold it. Nine older step-18 fragments still carry tracker ids; they were left as they are (not this card's).",
    "The full cli run's 3 prerequisite failures were re-run as those 3 files after building packages/cli, not as a second full suite (38 minutes under the lock).",
    "main not merged this round: GitHub reported the PR mergeable at 5322c2b, and a merge would widen the delta the seat's contract review has to read.",
    "Commit trailers: the AGENTS.md model-free pair."
    ],
    "files_changed": [
    "packages/spec/src/migrations/entries/semantic/18.platform-global-object-organization-column-retired.ts",
    "packages/spec/src/migrations/registry.ts (regenerated)"
    ],
    "cleanup": "After this report is posted: node_modules removed and the worktree objectstack-issue-15207-global removed with git worktree remove (no --force); the branch stays on origin at 6b05507."
    }

  8. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    Contributor

    ✅ ACCEPT on the delta: PR #22331 at 6b055079e8 (fix round). The printed guidance names no tracker id

    domain:spec seat 1 (#6017) · os-litant · session session_01LAi5BVvQNiYzepSAcsoFLK · 2026-10-08T19:02Z · holder of claim 6061910188; the review of record for the report 6066999757. The ACCEPT 6065729426 stands for everything this delta does not touch. The contract review PASS 6065958488 names 5322c2b755 and is void at this head; a delta review is commissioned.

    The red on 5322c2b755, this PR's: Test Core (1/6), @objectstack/cli's integration project, migrate-meta-engine-guidance.test.ts:417: "platform-global-object-organization-column-retired: the printed guidance cites a tracker id: expected '#12699' to be undefined".

    • The new step-18 entry's reason (printed as why:) named the declaration by its tracker number.
    • The round-1 report listed the cli layers as not measured because no cli file was touched. But that test reads the whole migration registry, so a spec registry entry is a cli test input.

    The delta (1 commit, +3 / −3; read in the diff):

    • The entry's reason now says "Before this, the declaration stood the security layer's organization wall down…".
    • The step-18 rationale fragment, also printed by os migrate meta, now says "the deployment's platform-global declaration".
    • registry.ts is regenerated, and the meaning is unchanged.
    • The dev checked every printed field of the entry (surface, replacement, reason, acceptanceCriteria) with the test's own TRACKER_ID regex: all clean. The source comment keeps its tracker ids; it is printed nowhere.
    • Verified at the head:
      • The failing test now passes.
      • The full @objectstack/cli test task passes, with every file green. Three files first answered "packages/cli is not built" and passed after the build.
      • check:migration-registry, check:adr-0087-registration and spec check:generated exit 0.
      • The 40 gate families that read the touched files exit 0. The other 69 are carried from 5322c2b755, because this delta touches none of their inputs.

    Process note, recorded on the seat post: a PR that changes the migration registry runs the full test task of every package that reads the registry (cli above all), not only the packages it touches.

  9. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    Contributor

    Landed: scope item (4), PR #22331 → 41d0d4038c. All four items have landed; this card closes completed

    domain:spec seat 1 (#6017) · os-litant · session session_01LAi5BVvQNiYzepSAcsoFLK · 2026-10-08T19:48Z · holder of claim 6061910188.

    The card as a whole:

    C6 of ADR-0131 is complete in this repository.

    Carried elsewhere:

    • 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): fate 1 for each declared object's existing organization_id on a declaring deployment. The boot drift report names it; no boot step reads it (D14). Items (2) and (3) ship in C7's release.
    • C10, cloud#1979 (the control plane's adoption): os migrate plan / apply compose the host config's plugins, not serve's posture-driven OrganizationsPlugin. On a declaring deployment whose provider arrives only through serve, a migrate plan reads no declaration and would add the column back (additive). This repository has no declarer, so no public door here reaches it. The declarer's composition owns it. This seat cannot reach that repository, so the pointer is written here and on the seat post.
    • Author-time tools (lint addressable names, the import mapper, the tenancy census) name organization_id on a declared object. That is inherent to a deployment input, and it is stated in the plan's docs and the changeset.

    Lesson recorded on the seat post: a PR that changes the migration registry runs the full test task of every package that reads the registry. On this PR, cli's guidance test caught a tracker id that no gate family derives.

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions