Skip to content

MedcareBridge = UnifiedBridge<HealthcarePort> + FieldMask role projection + Fisher-z clamp fix#582

Merged
AdaWorldAPI merged 4 commits into
mainfrom
claude/medcare-bridge-lance-graph-wmx76z
Jun 21, 2026
Merged

MedcareBridge = UnifiedBridge<HealthcarePort> + FieldMask role projection + Fisher-z clamp fix#582
AdaWorldAPI merged 4 commits into
mainfrom
claude/medcare-bridge-lance-graph-wmx76z

Conversation

@AdaWorldAPI

@AdaWorldAPI AdaWorldAPI commented Jun 21, 2026

Copy link
Copy Markdown
Owner

What

Three additive changes to the reusable spine (contract + rbac + ontology bridges), all keeping lance-graph agnostic of anything medical.

Commits

  • ddb6c84 — collapse the last bespoke bridge: MedcareBridge = UnifiedBridge<HealthcarePort> (a generic alias over the published harness). Conformance test + 295 ontology tests green.
  • e1012aefix(contract): loosen the Fisher-z clamp ±0.999 → ±0.9999 in Distance::similarity_z so a perfect self-match round-trips to ≈0.99986 (the ±0.999 bound made "self ≈ 1.0" mathematically unreachable). Pure numerical guard; existing distance tests unaffected.
  • 8b35dc0feat(rbac): a role carries a FieldMask projection, not a depth level. RBAC is classid :: role :: membership where the role IS a distinct projection of the class — not graduated access. Adds FieldMask::{FULL, intersect, is_disjoint} (contract) + PermissionSpec.projection / with_projection / projects (rbac, default FULL). The projection feeds the existing ClassView::render_rows, so the field basis is pulled via lance-graph-ogar's OgarClassView with no new code. Consumers hand-roll the distinctness enforcement; the slot is reusable here.

Tests

lance-graph-contract 715 + 7 + 8 · lance-graph-rbac 15 (incl. a disjoint-projections test) · lance-graph-ontology 295 + conformance · clippy clean.

Coordinated with

  • OGAR#<Health domain> — provides HealthcarePort + the class field basis.
  • medcare-rs#<HIPAA RBAC> — hand-rolls the clinical-role distinctness on top of PermissionSpec.projection.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EYvNjD8M8LMNYbRy3gq2FP


Generated by Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Role-based permissions now support field-level projection masking to control field visibility per role
    • Enhanced field mask utilities with intersection and disjoint-check operations
  • Bug Fixes

    • Improved distance similarity calculation clamping precision for enhanced accuracy
  • Refactor

    • Streamlined Healthcare namespace bridge implementation using unified bridge architecture
  • Chores

    • Updated ontology dependencies for healthcare integration
    • Enhanced bridge module documentation and descriptions

claude added 3 commits June 21, 2026 09:26
Collapse the last bespoke per-tenant bridge that #570 deferred. With
Healthcare now promoted into the OGAR codebook (0x09XX) + a
HealthcarePort PortSpec, MedcareBridge becomes a type alias over the
generic UnifiedBridge harness — same way OpenProject/Redmine collapsed.

- medcare_bridge.rs: drop the bespoke struct + hand-written
  NamespaceBridge/BridgeFromRegistry impls; `type MedcareBridge =
  UnifiedBridge<HealthcarePort>`. NAMESPACE mirrors
  HealthcarePort::NAMESPACE. 8 co-located tests mirroring
  openproject_bridge::tests (constructor ok/err, bridge_id="medcare",
  g_lock, Patient->0x0901 codebook synth, seeded ctx_id=2, per-alias
  resolution, non-codebook fallback to registry).
- mod.rs: re-export HealthcarePort; move MedcareBridge from the
  "legacy struct" list to the OGAR-driven-ports list.
- Cargo.toml: repoint ogar-vocab git dep to the
  claude/medcare-bridge-lance-graph-wmx76z OGAR branch (carries
  HealthcarePort + the Health codebook). Cargo.lock updated.
- openproject_bridge_scope_lock.rs: fix a #570 latent defect — the
  construction-failure test formatted a Result<Bridge, Error> with
  {:?} but UnifiedBridge<P> is intentionally not Debug; assert is_err()
  without formatting the Ok value.

Authorization/audit path is unaffected: it resolves via row()
(registry-backed, not overridden by UnifiedBridge), so codebook
synthesis on entity() doesn't change canonical-name keying.
295 ontology lib tests + integration + consumer-conformance E1
(medcare_bridge_conforms) green; clippy clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYvNjD8M8LMNYbRy3gq2FP
…eads ~1

`Distance::similarity_z` clamps the similarity away from ±1 to keep the
`atanh` (the `ln` term) finite. The bound was ±0.999, which made
`tanh(atanh(0.999)) = 0.999` the maximum value `cohort_similarity_z`
could ever return — so a perfect self-match read ~0.99899, and any
"self ≈ 1.0" assertion (`s > 0.999`) was unreachable.

±0.9999 keeps atanh finite (≈4.95) while letting a self-match round-trip
to ≈0.99986, which reads as "essentially identical". Pure numerical
guard, no semantic change for moderate similarities; the existing
distance tests (s=0.8 roundtrip, z=0.5 averaging, sign-only checks) are
unaffected. Fixes medcare-analytics graph_contract::cohort_similarity_z_
self_returns_one (latent — the lance-phase2-rbac suite had never
compiled in the dev env until protoc was installed this session).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYvNjD8M8LMNYbRy3gq2FP
… depth levels

RBAC is classid :: role :: membership, where the role IS a distinct
projection of the class — not a graduated access level. PermissionSpec
already had max_depth (a scalar level: Identity < … < Full), which only
expresses more-vs-less of the same fields. It could not express that two
roles see DISJOINT views of one class — the actual HIPAA mechanism
(health-personnel sees the clinical histogram; invoice sees billing
fields; research sees de-identified aggregate — and that the research
cross-correlation would be unlawful in the invoice purpose).

- contract FieldMask: add FULL (all positions), intersect, is_disjoint —
  the ops a projection + a distinctness check need.
- rbac PermissionSpec: add `projection: FieldMask` (default FULL = no
  narrowing, depth governs), `with_projection(mask)` builder, `projects(n)`
  accessor. The projection is resolved against the class's ClassView field
  basis (lance-graph-ogar pulls OgarClassView for that basis).

The projection SLOT is reusable here; the consumer (medcare-rs) hand-rolls
the distinctness ENFORCEMENT — the three clinical roles' masks, and the
invariant that the research projection is disjoint from the identifier
fields. Test: two same-depth roles on one class with disjoint projections.
lance-graph-rbac 15 tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYvNjD8M8LMNYbRy3gq2FP
@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Three functional areas are updated: FieldMask in lance-graph-contract gains FULL, intersect, and is_disjoint; PermissionSpec in lance-graph-rbac adds a projection: FieldMask field with builder and query methods defaulting to FULL. MedcareBridge in lance-graph-ontology is migrated from a bespoke struct to a UnifiedBridge<HealthcarePort> type alias with a rewritten test suite and updated ogar-vocab branch pin. Distance::similarity_z clamp bounds tighten from ±0.999 to ±0.9999.

Changes

FieldMask Primitives and PermissionSpec Projection

Layer / File(s) Summary
FieldMask FULL, intersect, and is_disjoint
crates/lance-graph-contract/src/class_view.rs
Adds FieldMask::FULL constant and two bitmask combinators: intersect (bitwise AND) and is_disjoint (no shared set bits).
PermissionSpec projection field and API
crates/lance-graph-rbac/src/permission.rs
Adds projection: FieldMask to PermissionSpec, defaulted to FieldMask::FULL in all constructors; adds with_projection builder and projects(n) query method; tests verify default and disjoint projection behavior.

MedcareBridge Type Alias Migration

Layer / File(s) Summary
MedcareBridge alias, NAMESPACE, re-exports, and module wiring
crates/lance-graph-ontology/Cargo.toml, crates/lance-graph-ontology/src/bridges/medcare_bridge.rs, crates/lance-graph-ontology/src/bridges/mod.rs
Replaces MedcareBridge struct with pub type MedcareBridge = UnifiedBridge<HealthcarePort>; derives NAMESPACE from HealthcarePort::NAMESPACE; re-exports HealthcarePort; repins ogar-vocab to claude/medcare-bridge-lance-graph-wmx76z; updates module-level docs.
MedcareBridge test suite for alias behavior
crates/lance-graph-ontology/src/bridges/medcare_bridge.rs
Rewrites tests: registry_with_healthcare() helper seeds an in-memory registry; tests cover constructor success/failure, bridge_id/g_lock identity, Patient entity resolution to class_ids::PATIENT, full HealthcarePort::aliases() loop, and NotInScope fallback.

Minor Fixes

Layer / File(s) Summary
similarity_z clamp and OpenProject test assertion
crates/lance-graph-contract/src/distance.rs, crates/lance-graph-ontology/tests/openproject_bridge_scope_lock.rs
Widens similarity_z pre-transform clamp from ±0.999 to ±0.9999; removes {result:?} Debug format interpolation from the OpenProject bridge construction failure test.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • AdaWorldAPI/lance-graph#441: Extends FieldMask presence-bit API in the same class_view.rs file, directly related to the FULL/intersect/is_disjoint additions in this PR.
  • AdaWorldAPI/lance-graph#570: Introduces the UnifiedBridge<P: PortSpec> harness and the bridges module refactors that this PR's MedcareBridge type alias migration directly builds on.

Poem

🐇 A mask of FULL bits, neat and bright,
Fields intersect with bitwise might.
MedcareBridge sheds its heavy shell,
A slim type alias serves just as well.
The clamp now grips at four-nine's place—
More room for similarity's grace! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title comprehensively and accurately reflects the three main changes: MedcareBridge refactoring, FieldMask role projection feature, and Fisher-z clamp adjustment.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8b35dc0c6c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


/// MedCare `NamespaceBridge` — alias over the generic harness, locked to
/// the `Healthcare` namespace via [`HealthcarePort`].
pub type MedcareBridge = UnifiedBridge<HealthcarePort>;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep MedCare codebook aliases row-backed

When this alias opts MedCare into UnifiedBridge's codebook entity() path, Healthcare aliases such as Diagnosis can resolve from HealthcarePort even when the registry only has the namespace. The existing authorization/audit path in lance-graph-callcenter calls NamespaceBridge::row(public_name), and the default row() still requires an actual registry row with bridge_id == "medcare"; normal TTL hydration files rows under "ogit", and the new fixture only seeds Patient. In that setup the advertised codebook aliases resolve via entity() but fail before policy evaluation or audit, so either synthesize/override row() for these aliases or seed medcare rows for every alias.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid, and confirmed concretely: TTL hydration files mapping rows under bridge_id = "ogit" (registry.rs:139), while the default NamespaceBridge::row() filters by the bridge's own id ("medcare") — per-bridge rows come from a separate append_mapping step, not hydration. So entity() (codebook synthesis) and row() (registry-backed, the authz/audit path) can diverge for a codebook alias.

But this is a property of the shared UnifiedBridge<P> harness (lance-graph#570), not introduced by this PR: MedcareBridge is literally type MedcareBridge = UnifiedBridge<HealthcarePort>, identical to the already-merged OpenProjectBridge/RedmineBridge — none of the three override row(). The minimal fixture seeds only Patient via TTL to exercise namespace registration + entity() resolution + the not-in-scope fallback, not the full authz path.

The real fix — row() synthesizing from the codebook when no per-bridge mapping row exists — belongs in UnifiedBridge<P> (it would cover all three bridges) and touches the authz/audit path, so it's a deliberate harness change rather than something to slip into this alias PR (a type alias can't override row() anyway). Leaving this thread open as the tracking item — happy to do the harness change as a follow-up if you'd like.


Generated by Claude Code

…-lance-graph-wmx76z

# Conflicts:
#	Cargo.lock

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/lance-graph-ontology/src/bridges/medcare_bridge.rs`:
- Around line 79-88: The test helper function has a resource leak caused by
`std::mem::forget(tmp)` which prevents the temporary directory from being
cleaned up. Determine whether the registry internalized the data during
`hydrate_once_sync` call: if yes, simply remove the `std::mem::forget(tmp)` line
and let the TempDir drop naturally when the function returns; if the files must
persist, change the function signature to return a tuple containing both the
Arc<OntologyRegistry> and the TempDir, then update all callers to destructure
the tuple and hold the TempDir guard for the test's lifetime to keep the
directory alive.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 12c691aa-5d0f-49ea-b840-23c1136699a8

📥 Commits

Reviewing files that changed from the base of the PR and between 96c1249 and 4417a6f.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • crates/lance-graph-contract/src/class_view.rs
  • crates/lance-graph-contract/src/distance.rs
  • crates/lance-graph-ontology/Cargo.toml
  • crates/lance-graph-ontology/src/bridges/medcare_bridge.rs
  • crates/lance-graph-ontology/src/bridges/mod.rs
  • crates/lance-graph-ontology/tests/openproject_bridge_scope_lock.rs
  • crates/lance-graph-rbac/src/permission.rs

Comment thread crates/lance-graph-ontology/src/bridges/medcare_bridge.rs
@AdaWorldAPI AdaWorldAPI merged commit 52edeb0 into main Jun 21, 2026
6 checks passed
AdaWorldAPI pushed a commit that referenced this pull request Jun 21, 2026
CodeRabbit (PR #582): the test helper leaked a temp dir via
std::mem::forget(tmp) on every call. hydrate_once_sync parses the TTL into
the in-memory OntologyRegistry, so the dir isn't needed afterward — let it
drop. medcare_bridge tests 8/8 green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYvNjD8M8LMNYbRy3gq2FP
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants