fix(core): the rules export must contain the rules the Brain serves - #187
Conversation
Closes the open finding from #186: "Download rules bundle" shipped a strictly narrower set than kra.ts injects. Two things are called "scope" and the distinction is the fix. Under DataScope "all" the V1 helper already returns everything the caller owns. The gap was DataScope "project" — buildRulesBundle's default — where it resolved on ownerProjectId alone and never consulted Knowledge.scope, so it could not filter to a project WHILE admitting the caller's user-scoped rows from elsewhere. Fixed with an owner-anchored includeUserScopeAcrossProjects opt-in on V1, always enabled by the exporter. Not exposed as a parameter: there is no reading of "export my rules" that wants less than you are served. Deliberately NOT the V1->V2 migration I originally suggested. Checking before executing showed V2's `visibility: 'project'` arm carries no ownerUserId predicate — that absence is what makes Phase-4 org sharing work — so migrating a personal surface to it would ALSO start returning teammates' rules. That is a product decision about team sharing, not this defect, and it would have shipped inside a change labelled "finish the migration". Dashboard and graph keep the project-scoped view on purpose. They are browsing surfaces where project focus is the point, consistent with KNOWLEDGE §12.19's retrieval-is-wider-than-listing rule. A rules bundle is different in kind — it is the agent's configuration. Tests pin all four properties: closed by default, opened when opted in, no-op under DataScope "all", and the ownerUserId anchor present both on the outer AND and inside the new disjunct so it is safe read alone. GUIDELINES now records the general rule this produced: migrate a surface to V2 when you want org visibility there; add an owner-anchored opt-in to V1 when you only want the caller's own rows to reach further. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Rqj5y9fT3XPUqnqKyustp9
|
Warning Review limit reached
Next review available in: 30 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…188) export surface is empty for everyone Measured the #187 fix against the live corpus after deploying, and the measurement contradicted my own framing. The fix is correct: the base clause now admits 183 rows instead of 146 for a Brain Platform-scoped export, matching retrieval's reach. But buildRulesBundle ALSO filters tags: { has: "rules-export" }, and zero rows carry that tag for any user — so the bundle is empty regardless and nothing user-visible changed. The PR described a live symptom; there isn't one. Latent-correct, not observable. Corrected in place. That measurement turned up something larger, now recorded as open: "Download rules bundle" returns nothing for everyone. Exactly one production path writes the rules-export tag — autoskill.ts:801, on proposal APPROVAL — and all 4 proposals on the reference instance are pending. The demo seed tags 4 rows, but that is a dev fixture. Not obviously a bug: invariant 8 requires approval before autoskill writes anything, so an unused queue legitimately yields an empty export. But it means the export surface has never been exercised by real usage, and it raises a product question worth answering deliberately — should "export my rules" mean approved autoskill rules only (today), or the rules the Brain actually serves you, which is what the button label implies? Sixth imprecision of this session caught by verifying rather than remembering. The pattern holds: the finding was real, the claim about its impact was not. Claude-Session: https://claude.ai/code/session_01Rqj5y9fT3XPUqnqKyustp9 Co-authored-by: Claude <noreply@anthropic.com>
Closes the open finding from #186: the default "Download rules bundle" shipped a strictly narrower set than
kra.tsinjects into your sessions.The fix, and why it isn't the migration I originally proposed
I suggested "migrate the three V1 call sites to V2". Checking before executing showed that would have been wrong:
ownerUserIdanchoringbuildKnowledgeWherebase = {ownerUserId}ANDed over every branch — strictly your own rows{visibility:'project', ownerProjectId}— no owner predicate, by design (Phase-4 org sharing)Migrating a personal surface to V2 would therefore also start returning teammates' rules — a product decision about team sharing, shipped inside a change labelled "finish the migration". Exactly the kind of thing that's hard to spot in review because the diff looks like cleanup.
So: an owner-anchored
includeUserScopeAcrossProjectsopt-in on V1, always enabled by the exporter. Not a parameter — there's no reading of "export my rules" that wants less than you're served.Scoped to the exporter on purpose
Dashboard and graph keep the project-scoped view. They're browsing surfaces where project focus is the point — the same retrieval-is-wider-than-listing distinction
KNOWLEDGE §12.19already draws. A rules bundle is different in kind: it's the agent's configuration, so it has to match what the agent gets.The general rule, now in GUIDELINES
Test plan
DataScope: "all"(which already returns everything owned) ·ownerUserIdpresent both on the outerANDand inside the new disjunct, so it's safe read in isolation.exporter.test.tsrelies on CI — it imports@brain/db, so it can't load under standalone vitest in this checkout. That's the suite most relevant to this change, so CI is the real gate here.🤖 Generated with Claude Code
https://claude.ai/code/session_01Rqj5y9fT3XPUqnqKyustp9