Skip to content

Seed loader: an org-scoped reference probe filters on organization_id even when the target declares another tenantField #33393

Closed

Description

@objectstack-fleet

domain:server#5 · os-elon-musk · session_016WV4cw787kMeaX7oyz7DDC

Loose end of #33207 / #33206 (PR #33222, merged 2026-11-14T15:49Z), filed at seat 5's direction from area A4's parked review fixes. Read at origin/main 2026-11-14T18:2xZ.

Line

A seed reference whose target object walls its rows by a declared tenancy.tenantField other than organization_id (e.g. workspace_id, injected column switched off) · the seed loader's org-scoped reference probe · rare (custom tenant field) · read, not measured.

packages/metadata-protocol/src/seed-loader.ts on main:

  • probeScopeOf returns organization for such a target (it is not global, because resolveTenantFieldName(definition) is non-null), and
  • the probe then filters where.organization_id = organizationId (around line 2832), a column the target does not have.

So the probe either errors or matches nothing, and the reference is reported unresolved although a row of that organization exists. The rest of the parked fix is already on main (exhaustive id-ordered member paging; a refused membership probe reported on sys_member; global only when no tenant column).

Do

  • In the organization scope, filter on the target's resolved tenant column (resolveTenantFieldName(definition), falling back to organization_id), not on organization_id always.
  • Pin it: a target declaring tenancy: { enabled: true, tenantField: 'workspace_id' } with the injected column off; a seed row referencing it by name resolves to the row of the seeding organization and not to another organization's row of the same name. Ablate.

Reader who acts: packages/metadata-protocol/src/seed-loader.ts (probeScopeOf and the reference probe), packages/runtime/src/seed-org-scoped-references.integration.test.ts.
Suggested grade: p3. Lane: domain:server.

Activity

  1. objectstack-fleet commented on Nov 14, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-elon-musk · session_016WV4cw787kMeaX7oyz7DDC

    Claim: area-lease pilot #33059, area thread A4 (data layer) · p3 (A4's p1/p2 are on hold, blocked on a decision, or done) · dispatched to an os-dev subagent of this area thread
    Session: session_016WV4cw787kMeaX7oyz7DDC (area thread; subagent of it)
    Account: os-elon-musk
    Branch: claude/area-A4-33393
    Worktree: objectstack-a4-33393
    Domain: domain:server
    Seat: domain:server#5
    File surface: packages/metadata-protocol/src/seed-loader.ts (the org-scoped reference probe and probeScopeOf), packages/runtime/src/seed-org-scoped-references.integration.test.ts, one changeset. Stop on breach.
    Container & model: M, mode:subagent, model: default, effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: a seed reference to an object walled by a declared non-default tenancy.tenantField resolves within the seeding organization
    Thread-read: none
    Premise: re-measured at origin/main before any edit; premise_still_valid: false is a valid result
    Serial constraints cleared: the area's other in-flight card (#33005) touches protocol-registry-hydration.ts / protocol-history-and-publish.ts, not seed-loader.ts

  2. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 14, 2026
  3. objectstack-fleet commented on Nov 14, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-elon-musk · session_016WV4cw787kMeaX7oyz7DDC
    os-dev-report

    {
      "issue": 33393,
      "status": "done",
      "branch": "claude/area-A4-33393",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/33409",
      "session": "session_016WV4cw787kMeaX7oyz7DDC",
      "premise_still_valid": true,
      "summary": "Premise measured true on main 7e2eadd29: with a target declaring tenancy {enabled: true, tenantField: 'workspace_id'} and systemFields {tenant: false}, probeScopeOf classifies it 'organization' and the probe filters organization_id, which the SQL driver refuses (INVALID_FILTER, 'no such column: organization_id' on crm_workspace_tag), so the reference was reported unresolved although the load organization's row existed. Fix in packages/metadata-protocol/src/seed-loader.ts: probeScopeOf now returns a scope object whose 'organization' arm carries the resolved tenant column (resolveTenantFieldName(definition) ?? DEFAULT_TENANT_FIELD), and the probe filters where[tenantColumn] = organizationId; the sys_member membership probe (sys_member.organization_id), own-organization and global scopes are unchanged. Pinned in packages/runtime/src/seed-org-scoped-references.integration.test.ts (real AppPlugin replayer + SeedLoaderService + ObjectQL + SqlDriver/better-sqlite3): North and South replays each resolve 'Gold' to their own organization's row, with South's inserted first; changeset @objectstack/metadata-protocol patch, Clause-②: no, Metadata-protocol: none. Card assignee not touched.",
      "tests": "Premise (main 7e2eadd29 dist, pin added): 1 failed | 17 passed, 'crm_deal.tag = Gold -> crm_workspace_tag.name not found; the probe was refused (INVALID_FILTER)'. After fix (99f60e1df, metadata-protocol rebuilt): seed-org-scoped-references 18/18. Ablation at 99f60e1df: ablation-replace.mjs anchor x1->x0, marker x0->x1, blob 8c5d2429->6fa7d5a4; ablation-dist-preflight marker present in 2 built files; pin red (1 failed | 17 passed); restore blob == HEAD 8c5d2429, git diff HEAD empty, preflight --absent: marker absent from all 24 built files, tree clean; pin green 18/18; git status --porcelain empty. A first ablation attempt used a comment marker that tsup strips: the preflight refused it (exit 1) before any verdict was read, so it was not counted. At merged head ae21eae6f: pnpm --filter @objectstack/metadata-protocol test -> Test Files 339 passed | 9 skipped (348), Tests 22848 passed | 43 skipped, VERDICT command-exit 0; metadata-protocol typecheck + runtime typecheck (incl. check:test-typecheck) VERDICT command-exit 0; runtime src/*seed*.test.ts (21 files) 201/202 passed, the one failure a 5000 ms timeout in seed-tenancy-autonumber-split ('[wiring] the app-plugin handoff fires on the organization insert itself') on the shared box, which passed 15/15 re-run alone; eslint --no-inline-config on the two changed source files exit 0. Narrowing declared: the full runtime package suite and other metadata-protocol dependents were not run locally (public surface unchanged: a private method's return type); CI Test Core runs them.",
      "gates": "At ae21eae6f: node scripts/pm/dispatch-gates.mjs --commands derived 64 families; each run with exit captured before any pipe: 63 exit 0; pnpm check:dual-build-cjs-loads exit 3 (PREREQUISITE NOT MET, needs full pnpm build: NOT MEASURED locally, left to CI). --ran reconciliation: '64 derived famil(ies) accounted for — 63 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3)', exit 0. PR check-runs: in_progress at report time (not waited on, per contract).",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "0",
      "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, fleet-write run 43631269965, body read back 4952/4952 bytes identical, assignee os-elon-musk); os-dev-report comment via post-stamped.mjs (POST /repos/objectstack-ai/objectstack/issues/33393/comments). git push (empty branch probe, fix commit, merge commit) not counted.",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": [
        "class: a · reach: named producer — AppPlugin's per-organization seed-replayer on a walled boot (real AppPlugin + SqlDriver, measured on branch 99f60e1df with a temporary case, then removed) · evidence: a seed dataset OF an object walled by a declared tenancy.tenantField with systemFields.tenant false ({ object: 'crm_workspace_tag', mode: 'upsert', externalId: 'name', records: [{ name: 'Silver' }] }) makes replayer(ORG_NORTH) throw the driver's INVALID_FILTER ('A filter on object crm_workspace_tag names a column the database could not resolve'): SeedLoaderService.loadExistingRecords (packages/metadata-protocol/src/seed-loader.ts, per-tenant replay branch) filters the SOURCE object's existing rows by where.organization_id, the same hard-coded column this card fixed on the reference-target side; a fix also has to settle what the loader stamps on such rows (seedRowNeedsOrganization answers only for organization_id), so it is not a mechanical in-place fix · dedupe words: loadExistingRecords tenantField, seed replay workspace_id INVALID_FILTER, per-organization replay tenant column, seed source object organization_id filter",
        "carrier: none · noted, not filed — seed-tenancy-autonumber-split.integration.test.ts '[wiring] the app-plugin handoff fires on the organization insert itself' hit the 5000 ms default timeout once in a 21-file run on the shared box; passed alone"
      ]
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:serverDomain lane — seat card indexed by label:pm:seatlease:A4pm:dispatchedDispatched to a dev agent by /pm-dispatchpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions