Skip to content

fix(dogfood): the criteria-less legacy sharing-rule row carries the organization the admin acts in - #24913

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-24879-sharing-rule-legacy-row-org
Oct 20, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-24879-sharing-rule-legacy-row-org

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #24879
Clause-②: no

The hourly full run's Dogfood Regression Gate (1/3) red (run 39419131283): one dogfood fixture went stale against the ruled retirement of the organization-less sharing-rule readers. This PR repairs the fixture. No product code changes, and no assertion changes.

What changed

One file, one case: packages/qa/dogfood/test/sharing-rule-criteria-required.dogfood.test.ts, "a criteria-less rule already IN the table shares nothing and loses its grants".

  • The case writes its legacy sys_sharing_rule row at the driver seam, and that row had no organization_id.
  • Since 7cacad5348 (PR feat(plugin-sharing,plugin-approvals,metadata-protocol)!: 18.x step 7 part 7a-3 — the organization-less readers of sharing rules, approval units and the seed loader retire #24828, 18.x step 7 part 7a-3), no admin read resolves a rule with no organization. findRuleRow and findRuleRowByName read the caller's own organization only (ADR-0131 D1/D8). So POST /sharing/rules/srule_3896_legacy/evaluate answered 404 RULE_NOT_FOUND before the criteria guard this case pins was reached.
  • The row now carries organization_id: the organization the admin acts in. It is read off the admin's own session (GET /auth/get-session, session.activeOrganizationId), which is the field the evaluate request's context is resolved from. No id is hard-coded.
    • The case asserts that get-session answers 200 and that the organization id is a non-empty string, so a missing id fails loudly instead of writing an organization-less row again.
  • That is the shape a pre-gate row has once the organization-ownership ceremony attributes it (ADR-0131 D10), which is the triage's done-when.
  • Every assertion is unchanged: evaluate answers below 300, matches 0 records, and materialises no sys_record_share grant.

The file's other writes do not share the cause. The direct-insert case (ql.insert('sys_sharing_rule', …, { context: SYS })) is refused for its missing criteria. It was green on main before this change (4 of 5 passed), and it is unchanged. Every other system-context call in the file is a read.

There is no skip and no retry, and a 404 is not accepted anywhere. The retirement in PR #24828 stays as it is, and nothing under packages/plugins/plugin-sharing/** or packages/spec/** is touched.

Evidence

Each row ran pnpm --filter @objectstack/dogfood exec vitest run --maxWorkers=2 test/sharing-rule-criteria-required.dogfood.test.ts, after building the dogfood closure (turbo run build --filter=@objectstack/dogfood) at the same commit. The test file, test/showcase-boot.ts and vitest.config.ts are byte-identical on the first three trees.

tree result
abd5acdaf7 (7cacad5348^, the commit of the last green hourly run, 39412016980) Tests 5 passed (5). The boot logs rule has no usable criteria — matching NO records instead of every record for legacy_match_all_3896.
7cacad5348 (PR #24828) Tests 1 failed | 4 passed (5): AssertionError: expected 404 to be less than 300 at :153
c2d4072281 (main, this branch's base) the same red at :153
30629ffe1f (this change) Tests 5 passed (5)
2ecc76b48e (head: this change merged with main at fcb40ad673) Tests 5 passed (5), with the same matching NO records line for legacy_match_all_3896
  • Without the organization on the row: on the committed change, deleting only the organization_id: organizationId, line turns the case red again, with expected 404 to be less than 300.
    • The mutation went through scripts/ablation-replace.mjs: anchor count 1 to 0, blob c22aa9f438f5 to c129bbc072f1.
    • The restore was proven: the blob equals HEAD (c22aa9f438f5), and git diff HEAD is empty.
  • The gate's own invocation: OS_TEST_SHARD=1/3 pnpm turbo run test --filter=@objectstack/dogfood ran on 2ecc76b48e. The result was Test Files 96 passed (96), Tests 772 passed (772), Tasks: 67 successful, 67 total.
    • VITEST_MAX_WORKERS was 2 here, where the runner's computed cap is 3. That is a concurrency difference only.
    • The file falls in shard 1. Computed with vitest 4.1.11's own shard algorithm over this tree's 287 files: shard 1 holds 96 files, including this one. The 772 matches the red run's count.
  • Variants: the dogfood vitest projects are isolated and shared-showcase, and this file runs only in isolated (it is not in SHARED_SHOWCASE). The two variants run are the file alone and its gate shard, shown above. The file's one boot is posture single, with the Default Organization.

Gates (head 2ecc76b48e)

  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 56 commands. All 56 ran, each with its exit code captured before any pipe.
    • 55 exited 0 on the first run.
    • pnpm check:dual-build-cjs-loads first answered PREREQUISITE NOT MET (exit 3), because this worktree had no dist/ for 8 packages outside the dogfood closure. After building those packages, it exited 0 ("112 published require entry point(s) across 69 package(s) load").
  • The 11 declared-WIDE families (check:init-service-contract, check:live-db-isolation, check:meta-type-normalized, check:optional-error-sink, check:resume-authority-declared, check:route-envelope, check:runner-env-posture, check:settings-bind-window, check:startup-registry-verdict, check:verify-stand-in, check:wildcard-fallthrough) all exited 0.
  • Reconciliation, --ran with the exit codes recorded: Run reconciliation — 56 derived, 56 run, 0 NOT-MEASURED, 0 UNRUN. It derives the zero from the 56 recorded exit codes.
  • pnpm --filter @objectstack/dogfood run typecheck: exit 0. The tsc program lists this file (--listFilesOnly, 1 hit).
  • pnpm lint (eslint . --no-inline-config) over the whole tree: exit 0, with no findings.
  • Dogfood Regression Gate does not run on pull_request or merge_group. Its first CI reading of this change is main's push and hourly battery after the merge, so the local red-then-green above is the pre-merge reading.

Changeset

skip-changeset: the diff is one test file in @objectstack/dogfood, a private: true package that publishes nothing. No published package's files[] changes.

Acceptance notes

  • The dispatch named "isolated and group" variants. As measured, the vitest projects are isolated and shared-showcase, and the file's boot is posture single. No group posture boot is in this file. The gate's grouping is its shard, and both the file alone and its shard ran green.
  • The organization is read through the session (GET /auth/get-session), not through sys_member. resolveAuthzContext reads session.activeOrganizationId into the request context's tenantId (packages/core/src/security/resolve-authz-context.ts), and SharingRuleService.callerOrgId reads that value back. So the row lands in the organization that the evaluate request is scoped to.

Generated by Claude Code

…rganization the admin acts in

The case "a criteria-less rule already IN the table shares nothing and loses
its grants" wrote its legacy row at the driver seam with no organization_id.
Since the organization-less readers of sharing rules retired (ADR-0131 D1/D8,
7cacad5), no admin read resolves such a row, so POST
/sharing/rules/srule_3896_legacy/evaluate answered 404 before the criteria
guard the case pins was reached.

The row now carries the admin's active organization, read off the admin's
own session: the shape a pre-gate row has once the organization-ownership
ceremony attributes it (ADR-0131 D10). Every assertion is unchanged: evaluate
answers below 300, matches 0 records, and materialises no grant.

Claude-Session: https://claude.ai/code/session_01LmjU2x1faLZ39DVTFyVca6
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json a8b44d407028cde9886b193f1add17a53437b03c → packageMentionDocs.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT

domain:cli seat 2 (#22648) · os-justin · session session_01LmjU2x1faLZ39DVTFyVca6 · 2026-10-20T14:07Z · head 2ecc76b48e1c689daf93847c378ad8547b27e7e0 · claim 6291463478 → report 6292746038. No contract face (Clause-②: no, a test file only), so no review of record is owed.

Check Reading
Shape Draft, base main. First line Fixes #24879; Clause-②: no line-initial. Assignee os-justin = the card's. skip-changeset is applied and correct: one test file in a private package.
Surface 1 file, sharing-rule-criteria-required.dogfood.test.ts (+16 / −0), inside the claim. The legacy row gains organization_id, read off the admin's own session. No assertion moves, and no product file changes. PR #24828's retirement and packages/plugins/plugin-sharing/** are untouched. check-governed-merges.mjs --pr 24913: NOT governed.
Mechanism Read at source: sharing-rule-service.ts:1104–:1121. findRuleRow scopes the by-id read through adminOrgScope (own organization only), so a row with no organization is unreachable to an admin's evaluate. Stamped with the admin's activeOrganizationId, the row is reached, and the case pins what it pinned before: a criteria-less legacy rule matches 0 records and materialises no grant. No id is hard-coded.
Evidence Green on abd5acdaf7 (7cacad5348^, 5/5); red on 7cacad5348 and on main c2d4072281 at :153 (expected 404 to be less than 300); green on the fix and on the head (5/5). With the stamp ablated on the fix, the same 404 returns, and the file was restored hash-equal. Gate shard 1/3 on the head: 96 files / 772 tests passed, with this file in it.
Gates Local: 56/56 derived families and the 11 Declared WIDE population families exit 0, 0 UNRUN; pnpm lint exit 0. Check-runs on this head (40, latest per name), read at this act: 23 success, 9 skipped (the dogfood shards among them, which run on main's battery), 8 in_progress (Lint lanes, Test Core 1–3). Landing waits on all of them.

Accepted deviations:

  • The shard ran at 2 workers, not the computed 3; the file set is the same.
  • check:dual-build-cjs-loads first exited 3 (prerequisite) and exited 0 after the builds it named.
  • 7cacad5348 itself was also run, which pins the cause to that commit.
  • The merge commit 2ecc76b48e carries no trailer pair; the pre-push hook accepted it.

Landing: this is this lane's main-red card. It goes through the merge queue by this seat once every check on this head reads success (or an expected skip). Its main-side reading is the first hourly run carrying the merge, and the lane's main-red hold lifts on that green reading.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 20, 2026 14:20
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 20, 2026 14:20
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 20, 2026
Merged via the queue into main with commit e2c2355 Oct 20, 2026
48 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-24879-sharing-rule-legacy-row-org branch October 20, 2026 14:49
os-steve pushed a commit that referenced this pull request Oct 20, 2026
… into 7b-0

Conflicts in seven fixture files take #24893's resolution (4dadd7e): where
7a-2 now writes the grant with an organization the pre-18 relax goes; where
main still lands an organization-less row the relax stays.
sharing-rule-criteria-required takes main's version verbatim (both sides had
added the organization key). plugin-webhooks' new real-SqlDriver case gets the
lean engine's Default Organization.

Claude-Session: https://claude.ai/code/session_018EszgtA3V2KXBX5tf59Hi4
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

hourly full run: red on main (CI)

2 participants