Skip to content

fix(core): a bare read fetches scalars, not relations (#848) - #853

Merged
borisno2 merged 1 commit into
mainfrom
claude/funny-sagan-ptst09
Jul 31, 2026
Merged

fix(core): a bare read fetches scalars, not relations (#848)#853
borisno2 merged 1 commit into
mainfrom
claude/funny-sagan-ptst09

Conversation

@borisno2

Copy link
Copy Markdown
Member

Summary

Implementation

  • packages/core/src/context/index.ts: createFindUnique, createFindMany, and createGet (singleton) only call buildIncludeWithAccessControl when the caller supplied an include; a bare read sends include: undefined straight through. createGet gains the same fragment/include/sudo handling the other two reads already had.
  • packages/cli/src/generator/types.ts: generates a <List>GetArgs type for singleton lists and types get() to accept it (include/query/select), mirroring FindUniqueArgs.
  • Docs (docs/content/concepts/{queries,access-control}.md, docs/content/reference/context-api.md, packages/core/CLAUDE.md) updated to describe the new default; one example (examples/blog/test-context-nested-virtual.ts) fixed to pass an explicit include instead of relying on the old auto-include.
  • Existing regression coverage for Explicit include bypasses relation-level access filtering on reads — caller include REPLACES the access-controlled include #566 and Access control fails OPEN past include depth 5: caller includes pass through unscoped and nested rows skip field-read filtering #830 (caller-supplied-include behavior) is unmodified — only bare-read call sites in tests were updated. The #844 cycle-guard reproduction now demonstrates the cycle no longer occurs on the reporter's bare hook-issued read (with the mock's return value made to actually respect the include argument, so it faithfully models Prisma); the genuine two-list cycle regression is untouched and still throws.
  • New test coverage: packages/core/tests/bare-read-scalars.test.ts (bare vs. explicit-include behavior, including "no related query access is evaluated on a bare read") and a new describe block in packages/core/tests/singleton.test.ts for .get()'s new include support.

Test plan

  • pnpm test in packages/core — 923/923 passing
  • pnpm test in packages/cli — 323/323 passing
  • pnpm build for @opensaas/stack-core and @opensaas/stack-cli — clean
  • pnpm lint — clean (pre-existing unrelated warnings only)
  • pnpm manypkg fix — no changes
  • pnpm format — clean
  • Generated examples/blog types and typechecked the fixed example script against them
  • Changeset added (.changeset/silent-relations-detour.md, minor) leading with the silent nature of the break, both detection strategies, and the migration

Closes #848

🤖 Generated with Claude Code

https://claude.ai/code/session_01PifFTifspW7ud4ptUGK4Mx


Generated by Claude Code

A context.db read with no `include` (and no fragment `query`) used to
auto-include every readable relationship, recursing 5 levels deep and
evaluating every related list's query access along the way — the root
cause behind #566, #830, and #844. It now returns the row's own columns
plus its virtual fields only, matching Prisma's own semantics, for
findUnique, findMany, and a singleton's get() alike (get() also gains
caller-include support). Relations are fetched only when a caller names
them, at which point the existing #566/#830 merge-with-access-control
path is unchanged.

See docs/adr/0024-a-read-with-no-include-fetches-scalars-not-relations.md.

Closes #848

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PifFTifspW7ud4ptUGK4Mx
@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
stack-docs Ready Ready Preview Jul 31, 2026 11:30pm

@changeset-bot

changeset-bot Bot commented Jul 31, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ab288f3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@opensaas/stack-core Minor
@opensaas/stack-cli Minor
@opensaas/stack-auth Minor
@opensaas/stack-rag Minor
@opensaas/stack-storage Minor
@opensaas/stack-tiptap Minor
@opensaas/stack-ui Minor
@opensaas/stack-storage-s3 Minor
@opensaas/stack-storage-vercel Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Copy Markdown
Member Author

Self-review

Overview

Implements #848 / ADR-0024: a context.db read with no include (and no fragment query) now returns the row's own scalar columns plus its virtual fields only — it no longer auto-includes every readable relationship recursively. Applies uniformly to findUnique, findMany, and a singleton's .get() (which also gains caller-include support it never had), under sudo and under a session alike.

Correctness

  • The caller-include merge path (buildIncludeWithAccessControl + mergeIncludeWithAccessControl, carrying the Explicit include bypasses relation-level access filtering on reads — caller include REPLACES the access-controlled include #566/Access control fails OPEN past include depth 5: caller includes pass through unscoped and nested rows skip field-read filtering #830 fixes) is untouched — it is simply gated behind args.include being truthy instead of running unconditionally. findFirst is sugar over findMany and inherits the new behavior automatically; no separate change was needed there.
  • Verified the two hot spots called out in the issue: (1) related-list query access is no longer evaluated on a bare read — covered by a spy assertion in bare-read-scalars.test.ts; (2) the reporter's User → Account → Student cycle no longer reproduces on the hook's bare context.db.account.findMany(...) call — the test's mock was changed to condition its return value on the actual include argument (mirroring real Prisma) rather than always returning the full relation tree, since the old mock would have masked the fix.
  • stripVirtualFieldsFromInclude(undefined, ...) and mergeIncludeWithAccessControl with an empty caller include: {} were checked against existing behavior — both are unchanged from before this PR (an empty object was already truthy pre-PR, so include: {} already took the merge branch; that's pre-existing, not a regression here).

Test coverage

Risks / things I considered and ruled out

  • Silent behavior change: this is the core, accepted risk of the change (a read that returned post.author now returns no author key, no error) — called out explicitly as the lead of the changeset per ADR-0024, with both detection strategies and a migration example.
  • Generator surface: packages/cli's new <List>GetArgs type is only generated for isSingleton lists, and get()'s new args parameter is optional, so existing generated call sites (get() with no args) keep compiling and behaving the same.
  • MCP: the query CRUD tool already issues a bare findMany with no include — it inherits the new default with no code change, matching the issue's explicit instruction not to add an include there.

Verification run

  • packages/core: 923/923 tests passing
  • packages/cli: 323/323 tests passing
  • tsc clean for both packages
  • pnpm lint clean (pre-existing unrelated warnings only), pnpm manypkg fix no-op, pnpm format clean
  • Regenerated examples/blog and typechecked the fixed example script against the real generated types

No further changes identified as needed.


Generated by Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for Core Package Coverage (./packages/core)

Status Category Percentage Covered / Total
🟢 Lines 92.96% (🎯 65%) 1189 / 1279
🟢 Statements 91.44% (🎯 65%) 1272 / 1391
🟢 Functions 98.03% (🎯 62%) 200 / 204
🟢 Branches 82.43% (🎯 50%) 845 / 1025
File CoverageNo changed files found.
Generated in workflow #1564 for commit ab288f3 by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for UI Package Coverage (./packages/ui)

Status Category Percentage Covered / Total
🔵 Lines 76.72% 244 / 318
🔵 Statements 76.29% 251 / 329
🔵 Functions 69.15% 74 / 107
🔵 Branches 64.25% 160 / 249
File CoverageNo changed files found.
Generated in workflow #1564 for commit ab288f3 by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for CLI Package Coverage (./packages/cli)

Status Category Percentage Covered / Total
🔵 Lines 79.08% 1497 / 1893
🔵 Statements 78.75% 1557 / 1977
🔵 Functions 85.47% 206 / 241
🔵 Branches 67.14% 656 / 977
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/cli/src/generator/types.ts 92.7% 77.55% 94.44% 94.16% 13, 23, 32, 42, 70, 105-108, 159, 171, 174, 222, 265, 299, 303, 321, 347, 375, 382, 403, 410, 445, 553-557, 622-626, 661, 730, 917-934, 1167-1169, 1238-1241, 1358-1359
Generated in workflow #1564 for commit ab288f3 by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for Auth Package Coverage (./packages/auth)

Status Category Percentage Covered / Total
🔵 Lines 97.45% 115 / 118
🔵 Statements 97.52% 118 / 121
🔵 Functions 100% 38 / 38
🔵 Branches 92.85% 78 / 84
File CoverageNo changed files found.
Generated in workflow #1564 for commit ab288f3 by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for Storage Package Coverage (./packages/storage)

Status Category Percentage Covered / Total
🔵 Lines 78.57% 220 / 280
🔵 Statements 80.06% 245 / 306
🔵 Functions 86.07% 68 / 79
🔵 Branches 75.88% 214 / 282
File CoverageNo changed files found.
Generated in workflow #1564 for commit ab288f3 by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for RAG Package Coverage (./packages/rag)

Status Category Percentage Covered / Total
🔵 Lines 47.97% 355 / 740
🔵 Statements 48.14% 377 / 783
🔵 Functions 54.26% 70 / 129
🔵 Branches 42.55% 180 / 423
File CoverageNo changed files found.
Generated in workflow #1564 for commit ab288f3 by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for Storage S3 Package Coverage (./packages/storage-s3)

Status Category Percentage Covered / Total
🔵 Lines 100% 40 / 40
🔵 Statements 100% 40 / 40
🔵 Functions 100% 9 / 9
🔵 Branches 100% 19 / 19
File CoverageNo changed files found.
Generated in workflow #1564 for commit ab288f3 by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for Storage Vercel Package Coverage (./packages/storage-vercel)

Status Category Percentage Covered / Total
🔵 Lines 100% 68 / 68
🔵 Statements 100% 71 / 71
🔵 Functions 100% 15 / 15
🔵 Branches 97.87% 46 / 47
File CoverageNo changed files found.
Generated in workflow #1564 for commit ab288f3 by the Vitest Coverage Report Action

@borisno2
borisno2 merged commit d0c94a9 into main Jul 31, 2026
6 checks passed
@borisno2
borisno2 deleted the claude/funny-sagan-ptst09 branch July 31, 2026 23:57
@github-actions github-actions Bot mentioned this pull request Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants