Skip to content

chore(core, plugin-security): isFederatedObject is spelled four times; every copy should read the spec predicate platformProvisionsStorage #31849

Closed

Description

@objectstack-fleet

domain:server#2 · os-steve · session_01ADHkmQKZzp4DLtqiCkZZRM

Found while reviewing #31812 (PR #31846). That PR moves isFederatedObject from @objectstack/objectql down to @objectstack/core. After it lands, the question "is this object federated (ADR-0015 external)?" is answered in four places:

copy spelling
packages/core/src/security/tenant-field.ts (after #31846) schema?.external != null
packages/objectql/src/federated-object.ts re-exports the core binding (after #31846)
packages/plugins/plugin-security/src/federated-phantom-anchors.ts:117 schema?.external != null, its own copy
packages/plugins/plugin-sharing/src/federated-phantom-anchors.ts:96 !platformProvisionsStorage(schema)

@objectstack/spec/data's platformProvisionsStorage (injected-system-column-provenance.ts:269) is the predicate #7865's convergence map names as the one spelling. plugin-sharing already reads it. The external test is the same everywhere today, but three of the copies restate it, and a change to what "federated" means (for example a schemaMode reading) would have to find all of them.

Ask

  • @objectstack/core's isFederatedObject returns !platformProvisionsStorage(schema). @objectstack/objectql keeps re-exporting it, and every existing import keeps working.
  • plugin-security drops its own copy and imports the core binding (it already depends on @objectstack/core).
  • plugin-sharing imports the core binding too, or keeps reading the spec predicate directly; either is fine as long as no copy restates external != null.
  • Pin: one test in core proves isFederatedObject and !platformProvisionsStorage agree on {}, { external: {} }, { external: null }, null and an array.

Accept: git grep -n "external != null\|external == null" packages/core packages/objectql packages/plugins finds no predicate copy outside the spec. Behaviour is unchanged, so this is a patch with Clause-②: no and Metadata-protocol: none.

Blocked-by: #31812 (PR #31846).

Activity

  1. objectstack-fleet commented on Nov 9, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: confirmed p3 · pm:queue → pm:blocked on #31812 · 2026-11-09T07:56Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. added
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 9, 2026
  3. objectstack-fleet commented on Nov 9, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: unblocked · pm:blocked → pm:queue · 2026-11-09T08:53Z

    ⛔ Not a claim.


    Generated by Claude Code

  4. added
    pm:queueReady for the PM dispatch loop
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    pm:queueReady for the PM dispatch loop
    on Nov 9, 2026
  5. objectstack-fleet commented on Nov 9, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-steve · session_01ADHkmQKZzp4DLtqiCkZZRM

    Claim: PM loop round 20 · 2026-11-09T09:11Z
    Session: session_01ADHkmSLoDy6zFb6HpabaTT (card thread, dev) · seat session_01ADHkmQKZzp4DLtqiCkZZRM
    Account: os-steve
    Branch: claude/project-thread-pbq1qf
    Worktree: objectstack-issue-31849
    Domain: domain:server
    Seat: domain:server#2
    File surface: packages/core/src/security/tenant-field.ts, packages/plugins/plugin-security/src/federated-phantom-anchors.ts, packages/plugins/plugin-sharing/src/federated-phantom-anchors.ts, their tests, root .changeset/; any other copy converged is named in the PR. ⛔ No packages/spec/** change, no ui/**
    Container & model: S, mode:thread, model: default tier, effort: medium
    Clause-②: no
    Metadata-protocol: none
    Responsibility: #31812 review follow-up, filed by this seat
    Thread-read: none
    Premise: holds as filed, read at claim on origin/main 3f0e3ace: core's isFederatedObject and plugin-security's copy restate external != null; plugin-sharing reads platformProvisionsStorage
    Serial constraints cleared: Blocked-by #31812 is closed (PR #31846 merged 8fca8f7); #31852 (this seat, PR #31876) touches different files in core and plugin-sharing

    Scope: Fixes #31849. Every isFederatedObject answers through @objectstack/spec/data's platformProvisionsStorage; no copy restates external != null. Behaviour unchanged. Order: /mnt/project-files/server-seat2/standard-order.md + /mnt/project-files/server-seat2/31849-delta.md. Summons: the maintainer's 「server 任务很多,你应该跟进并发5」 (project chat, 2026-11-09T02:28Z).

  6. objectstack-fleet commented on Nov 9, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-steve · session_01ADHkmSLoDy6zFb6HpabaTT
    os-dev-report

    {
      "issue": 31849,
      "status": "done",
      "branch": "claude/project-thread-pbq1qf",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/31896",
      "session": "session_01ADHkmSLoDy6zFb6HpabaTT",
      "premise_still_valid": true,
      "head": "10eb82ed",
      "summary": "core isFederatedObject now returns !platformProvisionsStorage(schema). plugin-security and plugin-sharing re-export core's binding from federated-phantom-anchors.ts (export names unchanged); objectql keeps its re-export. Seven more source copies of the external presence test (objectql search-companion, cli x3, service-analytics isExternalObject, trigger-schedule bind line, metadata-protocol save-door datasource binding) now call the same binding. Accept grep (external != null / == null under core, objectql, plugins, non-test) answers 0.",
      "tests": "New: core src/security/tenant-field.test.ts (7 inputs: agreement with !platformProvisionsStorage + expected verdict; barrel identity), plugin-security and plugin-sharing src/federated-object-binding.test.ts (toBe core binding). Forced edit: objectql federated-injected-column-readers.test.ts READERS row for search-companion isDdlManaged (not-a-read). At 10eb82ed: core 141/141 files 3237 tests; plugin-sharing 73/73, 1497; plugin-security 252/252, 6051 passed 45 skipped; objectql targeted 6 files 212/212; typecheck green for core, objectql, plugin-security, plugin-sharing, cli, metadata-protocol, service-analytics, trigger-schedule. At 73db2448: objectql 580/580 (11935), service-analytics 214/214, trigger-schedule 12/12, metadata-protocol 330 passed 5 skipped, cli unit 404/406 then the 2 dist-needing published-subpath pins 2/2 after full build. Ablations via ablation-replace (restored blob == HEAD): plugin-security restore local external != null copy -> identity pin RED (Object.is), layer0 suite green; plugin-sharing restore old wrapper -> identity pin RED; core revert to external != null -> agreement pin GREEN 8/8 (why identity pins carry the guard). No dist leg: tests import module under test from src.",
      "gates": "dispatch-gates --commands at 10eb82ed: 80 derived, all exit 0; --ran reconcile exit 0, '80 run, 0 NOT-MEASURED'. First round at 73db2448: 76 exit 0, 4 exit 3 (dual-build-cjs-loads, i18n, i18n-coverage, i18n-walk-parity) cleared to 0 after the full packages+examples build. check-platform-checklist --changed-from origin/main: OK, 0 lost. eslint --no-inline-config on changed .ts: exit 0. CI check-runs: in_progress at report time.",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "files_changed": [
        "packages/core/src/security/tenant-field.ts",
        "packages/core/src/security/tenant-field.test.ts",
        "packages/plugins/plugin-security/src/federated-phantom-anchors.ts",
        "packages/plugins/plugin-security/src/federated-object-binding.test.ts",
        "packages/plugins/plugin-security/src/security-plugin.ts (comment)",
        "packages/plugins/plugin-sharing/src/federated-phantom-anchors.ts",
        "packages/plugins/plugin-sharing/src/federated-object-binding.test.ts",
        "packages/plugins/plugin-sharing/src/sharing-service.ts (comment)",
        "packages/objectql/src/search-companion.ts",
        "packages/objectql/src/federated-injected-column-readers.test.ts",
        "packages/objectql/src/engine-driver-options.ts (comment)",
        "packages/objectql/src/integrity/dangling-reference-audit.ts (comment)",
        "packages/cli/src/commands/migrate/unmapped-columns.ts",
        "packages/cli/src/utils/schema-migrate.ts",
        "packages/cli/src/utils/schema-migration-plugins.ts",
        "packages/services/service-analytics/src/plugin.ts",
        "packages/triggers/trigger-schedule/src/time-relative-trigger.ts",
        "packages/metadata-protocol/src/protocol-save-door-refusals.ts",
        ".changeset/31849-federated-object-one-binding.md"
      ],
      "line_budget": "156 additions, 36 deletions over 19 files (PR stat)",
      "deviations": [
        "File surface widened beyond the delta's list per ruling 1: seven more converged copies (cli x3, service-analytics, trigger-schedule, metadata-protocol, objectql search-companion) plus comment-only rewording in four files so the accept grep reads 0; all named in the PR body.",
        "plugin-sharing takes core's binding (ruling 3 option one) rather than keeping its own spec wrapper.",
        "First plugin-security ablation attempt left the core import in place beside the restored function; re-run faithfully (import deleted + copy restored), same RED. Both restored, diff empty.",
        "Full suites for objectql, service-analytics, trigger-schedule, metadata-protocol, cli were run at 73db2448, before the main merge; at 10eb82ed they got typecheck (and objectql targeted files). cli integration tier left to CI."
      ],
      "mcp_calls": "3 — mcp__github__issue_read x2 (card get, comments), mcp__github__pull_request_read x1 (PR get read-back); no write tools",
      "api_writes": "2 — fleet-write relay pr_create (#31896); this os-dev-report comment via post-stamped.mjs",
      "open_questions": [
        {
          "question": "New test file names: core src/security/tenant-field.test.ts and federated-object-binding.test.ts in plugin-security and plugin-sharing. No new public name (export names unchanged).",
          "options": [
            "A keep",
            "B fold the plugin identity pins into existing suites"
          ],
          "recommendation": "A, each file pins one fact and the ablation evidence points at it"
        },
        {
          "question": "platformProvisionsStorage and the old presence test differ only on a function or an array carrying an own external property; no producer hands one to these seams. Pin it?",
          "options": [
            "A leave unpinned (behaviour on records unchanged)",
            "B add a case pinning the spec answer"
          ],
          "recommendation": "A, pinning a shape no producer emits would freeze an accident"
        }
      ],
      "security_findings": "none",
      "out_of_scope_findings": [
        "class: none · spec prose packages/spec/src/data/injected-system-column-provenance.ts:263 still says plugin-security holds a hand-rolled copy (stale after this PR); card forbids packages/spec edits · carrier: none, noted in PR Acceptance notes"
      ]
    }

    Stamped 2026-11-09T10:40Z.


    Generated by Claude Code

  7. objectstack-fleet commented on Nov 9, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-steve · session_01ADHkmQKZzp4DLtqiCkZZRM

    ACCEPT → PR #31896 comment 6738645258 · head 10eb82ed · 2026-11-09T11:14Z · landing: pr_ready + automerge_enable

  8. objectstack-fleet commented on Nov 9, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-steve · session_01ADHkmQKZzp4DLtqiCkZZRM

    落地 · 2026-11-09T12:26Z

    reading value
    PR #31896 MERGED 2026-11-09T12:26Z, merge commit d9f626b91 (ACCEPT 6738645258)
    #31849 closed by the PR's Fixes #31849

    Landed:

    • Every runtime "is this object federated" check reads @objectstack/spec/data's platformProvisionsStorage: core's isFederatedObject is its negation, and plugin-security and plugin-sharing re-export that one binding under their existing names.
    • Seven more source copies of external != null (objectql, cli, service-analytics, trigger-schedule, metadata-protocol) now call it too. Answers unchanged.

    Carried: none.

  9. added a commit that references this issue on Nov 10, 2026
    d9f626b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions