feat(asset-registry): add governed registry foundation#50
Conversation
|
Warning Review limit reached
Next review available in: 20 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: ASSERTIVE Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (25)
📝 WalkthroughWalkthroughChangesThe pull request adds an asset registry with draft, revision, review, release, availability, role, audit, and authorization models. It introduces REST endpoints, OpenFGA permissions, authorization convergence processing, immutable database storage, lifecycle orchestration, and integration tests covering governance and access behavior. Asset registry foundation
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant AssetRegistryController
participant AssetRegistryService
participant AssetRegistryCoordinator
participant Database
participant AuthorizationWorker
Client->>AssetRegistryController: submit asset lifecycle request
AssetRegistryController->>AssetRegistryService: resolve actor and delegate
AssetRegistryService->>AssetRegistryCoordinator: authorize and execute command
AssetRegistryCoordinator->>Database: persist asset state and authorization outbox
AssetRegistryCoordinator-->>AssetRegistryService: build AssetView
AssetRegistryService-->>AssetRegistryController: return result
AssetRegistryController-->>Client: HTTP response
AuthorizationWorker->>Database: load pending authorization candidates
AuthorizationWorker->>Database: apply projection state and mark readiness
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Actionable comments posted: 15
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/api/src/main/java/com/orgmemory/api/ApiExceptionHandler.java (1)
58-67: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd focused coverage for the new exception mappings.
Verify that
ApiExceptionHandlerTestscovers AssetNotFoundException → 404 with the opaque detail, AssetConflictException → 409, and AssetUnavailableException → 503. These mappings are security- and client-contract-sensitive.Also applies to: 88-91, 118-121
🤖 Prompt for 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. In `@apps/api/src/main/java/com/orgmemory/api/ApiExceptionHandler.java` around lines 58 - 67, Extend ApiExceptionHandlerTests with focused cases for the mappings in ApiExceptionHandler: verify AssetNotFoundException returns HTTP 404 with the opaque detail, AssetConflictException returns 409, and AssetUnavailableException returns 503. Keep the assertions targeted to status and response detail where applicable, covering the newly added exception handlers without altering unrelated behavior.
🤖 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 `@core/src/main/java/com/orgmemory/core/assetregistry/Asset.java`:
- Around line 30-34: Enforce the 128-character maximum for both namespace and
slug at the Asset domain boundary, including the coordinate() path, so
129-character values are rejected before persistence. Align the validation with
the existing nullable and column constraints while preserving valid coordinate
behavior.
In
`@core/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationCoordinator.java`:
- Around line 29-61: Add an attempt claim/token to the outbox authorization
flow: have startAttempt() generate and persist a unique claim for each selected
batch, include it in AssetAuthorizationBatch, and pass it through the
external-write completion path. Update complete() and recordFailure() to require
the batch claim matches the persisted claim before mutating those outbox
records, rejecting stale or competing attempts while preserving the existing
status updates.
- Around line 62-67: Update the authorization transition in complete() to
serialize it with pending-work creation in assignRole(), using an advisory lock,
per-asset pessimistic lock, or versioned conditional update with retry. Ensure
the countPending() check and asset.markAuthorizationReady()/save() occur within
the same protected transition so no new AssetAuthorizationOutbox can commit
between the check and readiness update.
In
`@core/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationOutbox.java`:
- Around line 74-87: Extend AssetAuthorizationOutbox retry handling around
startAttempt and recordFailure to persist nextAttemptAt using bounded backoff,
and make outbox selection process only PENDING records whose retry time is due.
Add a retry-limit policy that transitions permanently failing records to the
established terminal/dead-letter state instead of leaving them immediately
eligible forever, while preserving failure code and message truncation.
In
`@core/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationOutboxRepository.java`:
- Around line 28-35: Update findPending and the pendingAssets claim flow to
atomically transition selected rows from PENDING to an in-flight leased/claimed
status before the transaction ends and projection begins. Ensure startAttempt or
the surrounding repository/service operation performs this status change
together with the attempt increment, and make subsequent selection exclude
claimed rows so concurrent workers cannot project the same asset.
In
`@core/src/main/java/com/orgmemory/core/assetregistry/AssetRegistryCoordinator.java`:
- Around line 162-171: Update the catalog search flow in
AssetRegistryCoordinator to use a projection query that joins asset_drafts and
applies authorization, type, normalized text, and pagination predicates in the
database. Replace the per-asset requiredDraft call and in-memory filtering while
preserving the existing summary result shape and ordering.
- Around line 83-88: The exception translations discard their original causes.
In AssetRegistryCoordinator, update both DataIntegrityViolationException
handlers around assets.saveAndFlush and the corresponding handler near the
coordinator’s second conflict site to pass duplicate as the cause of
AssetConflictException; in
core/src/main/java/com/orgmemory/core/assetregistry/AssetRegistryCoordinator.java
lines 83-88 and 335-338, apply this change. In AssetRegistryService,
core/src/main/java/com/orgmemory/core/assetregistry/AssetRegistryService.java
lines 79-91, narrow the catch to UUID.fromString and pass the caught exception
as the cause of AssetUnavailableException.
- Around line 529-531: Replace the empty-history fallback in the availability
calculation with the existing strict currentAvailability accessor, so missing
history raises IllegalStateException instead of treating the release as
AVAILABLE. Preserve the latest-event availability behavior for non-empty
histories and reuse the established accessor rather than duplicating validation.
- Around line 221-239: Update the submit flow in AssetRegistryCoordinator around
the AssetRevision save to catch a unique-constraint
DataIntegrityViolationException from concurrent sequence allocation and
translate it into the existing AssetConflictException, matching the protection
already used by publish. Preserve normal revision creation and rethrow unrelated
data-integrity failures unchanged.
In `@core/src/main/java/com/orgmemory/core/assetregistry/AssetRelease.java`:
- Around line 139-147: Update versionLabel(String value) to reject normalized
labels exceeding 64 characters before returning or persisting them, while
preserving the existing format validation and error handling for valid-length
labels.
In `@core/src/main/java/com/orgmemory/core/assetregistry/AssetRevision.java`:
- Around line 61-69: Update AssetRevision construction and
AssetRegistryCoordinator.submit so title, summary, classification,
schemaVersion, and payload all come from the same canonicalized values used to
compute the digest, rather than raw draft metadata. Preserve organizationId,
assetId, and sequence handling, and add tests covering metadata normalization to
verify revision and release views match the digest.
In `@core/src/main/resources/db/migration/V2__asset_registry_foundation.sql`:
- Around line 292-310: Update asset_payload_references to enforce tenant
integrity by adding the appropriate composite foreign-key constraints tying
owner_id and organization_id to the owning revision/release tables, preserving
the owner_kind distinction; add an index covering organization_id, owner_kind,
and owner_id for owner lookups. Ensure the constraints prevent cross-tenant or
orphaned owners without changing the existing reference checks.
- Around line 183-197: Add the proposed composite index
idx_asset_review_decision_case on public.asset_review_decisions using
review_case_id and decided_at, placing it before the asset_releases definition
in the migration so AssetRegistryCoordinator.reviewView’s
findByReviewCaseIdOrderByDecidedAtAsc lookup is indexed.
In `@integrations/authorization-openfga/src/main/openfga/model.fga`:
- Around line 74-90: Update the asset permission definitions around
can_manage_roles, can_edit, can_submit_review, can_review, can_publish,
can_withdraw, and can_view so every capability is additionally gated by the
linked space’s corresponding permission. Reuse the existing space relation and
source-space permission mappings, ensuring local asset roles cannot grant
authority when the user lacks that permission on the knowledge_space.
In `@integrations/authorization-openfga/src/test/openfga/store.fga.yaml`:
- Around line 294-356: Extend the “Asset roles are explicit and separation of
duty stays in application policy” test to add denied Check assertions for
can_submit_review and can_withdraw, and denied ListObjects assertions for every
capability: can_manage_roles, can_edit, can_submit_review, can_review,
can_publish, can_withdraw, and can_use. Use a denied principal such as
user:unknown and assert empty results for each permission path, preserving the
existing positive coverage.
---
Outside diff comments:
In `@apps/api/src/main/java/com/orgmemory/api/ApiExceptionHandler.java`:
- Around line 58-67: Extend ApiExceptionHandlerTests with focused cases for the
mappings in ApiExceptionHandler: verify AssetNotFoundException returns HTTP 404
with the opaque detail, AssetConflictException returns 409, and
AssetUnavailableException returns 503. Keep the assertions targeted to status
and response detail where applicable, covering the newly added exception
handlers without altering unrelated behavior.
🪄 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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: a1b37fa7-da77-4f98-93f5-fffd33f2e9d7
⛔ Files ignored due to path filters (4)
contracts/openapi.jsonis excluded by!contracts/openapi.jsondocs/increments/active/2026-07-25-unified-asset-registry-definition/design.mdis excluded by!docs/**docs/increments/active/2026-07-25-unified-asset-registry-definition/gate-decisions.mdis excluded by!docs/**docs/increments/active/2026-07-25-unified-asset-registry-definition/plan.mdis excluded by!docs/**
📒 Files selected for processing (58)
apps/api/src/main/java/com/orgmemory/api/ApiExceptionHandler.javaapps/api/src/main/java/com/orgmemory/api/assetregistry/AssetRegistryController.javaapps/api/src/test/java/com/orgmemory/api/assetregistry/AssetRegistryIntegrationTests.javaapps/worker/src/main/java/com/orgmemory/worker/OrgMemoryWorkerApplication.javaapps/worker/src/main/java/com/orgmemory/worker/authorization/AssetAuthorizationConvergenceProperties.javaapps/worker/src/main/java/com/orgmemory/worker/authorization/AssetAuthorizationConvergenceScheduler.javaapps/worker/src/main/resources/application.ymlcore/src/main/java/com/orgmemory/core/assetregistry/Asset.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuditEvent.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuditEventRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationBatch.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationCandidate.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationConvergenceReport.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationConvergenceService.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationCoordinator.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationOutbox.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationOutboxRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationProjectionService.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationStatus.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationTarget.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAvailability.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetConflictException.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetDraft.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetDraftInput.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetDraftRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetNotFoundException.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetPayloadDigester.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetPortfolioState.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRegistryCoordinator.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRegistryService.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRelease.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReleaseAvailabilityEvent.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReleaseAvailabilityRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReleaseRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReviewCase.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReviewCaseRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReviewDecision.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReviewDecisionRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReviewDecisionType.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReviewState.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRevision.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRevisionRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRole.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRoleAssignment.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRoleAssignmentRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetSummary.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetType.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetTypeProfile.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetTypeProfileRegistry.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetUnavailableException.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetView.javacore/src/main/java/com/orgmemory/core/assetregistry/package-info.javacore/src/main/resources/db/migration/V2__asset_registry_foundation.sqlcore/src/test/java/com/orgmemory/core/assetregistry/AssetPayloadDigesterTests.javacore/src/test/java/com/orgmemory/core/assetregistry/AssetReviewLifecycleTests.javaintegrations/authorization-openfga/src/main/openfga/model.fgaintegrations/authorization-openfga/src/test/openfga/store.fga.yaml
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
- GitHub Check: PostgreSQL GraphRAG
- GitHub Check: Backend · Java 25
🧰 Additional context used
📓 Path-based instructions (6)
**/*
📄 CodeRabbit inference engine (CLAUDE.md)
**/*: Record current behavior in architecture/specification documentation only after it exists in code; keep intended behavior in vision, roadmap, or an active increment, and do not duplicate state.
Before using unfamiliar Spring Boot 4, Spring Modulith 2, Spring AI 2, Gradle, React, Vite, Tailwind, or TypeScript APIs, consult current official documentation via Context7 and the projectorgmemory-*verification skills.
Before retrieval, AI, MCP, permission, upload, graph, or export work, readdocs/guidelines/agent-safety.md.
Never commit.envfiles, provider keys, tokens, or customer data.
Run the relevant verification gates fromdocs/guidelines/testing-harness.md; use a terminating clean test as the context gate, and do not treatbootRunas verification.
Files:
core/src/main/java/com/orgmemory/core/assetregistry/AssetConflictException.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetNotFoundException.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationStatus.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAvailability.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetPortfolioState.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetTypeProfile.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetUnavailableException.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationTarget.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetSummary.javaapps/worker/src/main/java/com/orgmemory/worker/authorization/AssetAuthorizationConvergenceProperties.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuditEventRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationOutbox.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetType.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRoleAssignmentRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReviewDecisionType.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationConvergenceReport.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReleaseAvailabilityRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReviewState.javaapps/worker/src/main/resources/application.ymlcore/src/main/java/com/orgmemory/core/assetregistry/AssetReviewCaseRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReleaseRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRole.javacore/src/main/java/com/orgmemory/core/assetregistry/package-info.javaapps/worker/src/main/java/com/orgmemory/worker/authorization/AssetAuthorizationConvergenceScheduler.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetDraftRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetDraft.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationBatch.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRelease.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuditEvent.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReviewDecisionRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationCandidate.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationConvergenceService.javaintegrations/authorization-openfga/src/main/openfga/model.fgacore/src/test/java/com/orgmemory/core/assetregistry/AssetPayloadDigesterTests.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationProjectionService.javacore/src/test/java/com/orgmemory/core/assetregistry/AssetReviewLifecycleTests.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReviewCase.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetTypeProfileRegistry.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRevision.javacore/src/main/java/com/orgmemory/core/assetregistry/Asset.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetPayloadDigester.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReviewDecision.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRevisionRepository.javaintegrations/authorization-openfga/src/test/openfga/store.fga.yamlapps/worker/src/main/java/com/orgmemory/worker/OrgMemoryWorkerApplication.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationOutboxRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRoleAssignment.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReleaseAvailabilityEvent.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationCoordinator.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetView.javaapps/api/src/test/java/com/orgmemory/api/assetregistry/AssetRegistryIntegrationTests.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRegistryService.javaapps/api/src/main/java/com/orgmemory/api/ApiExceptionHandler.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRegistryCoordinator.javacore/src/main/resources/db/migration/V2__asset_registry_foundation.sqlapps/api/src/main/java/com/orgmemory/api/assetregistry/AssetRegistryController.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetDraftInput.java
**/*.{java,kt}
📄 CodeRabbit inference engine (CLAUDE.md)
JetBrains IDE inspection is a verification gate for the Java backend.
Files:
core/src/main/java/com/orgmemory/core/assetregistry/AssetConflictException.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetNotFoundException.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationStatus.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAvailability.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetPortfolioState.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetTypeProfile.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetUnavailableException.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationTarget.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetSummary.javaapps/worker/src/main/java/com/orgmemory/worker/authorization/AssetAuthorizationConvergenceProperties.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuditEventRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationOutbox.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetType.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRoleAssignmentRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReviewDecisionType.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationConvergenceReport.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReleaseAvailabilityRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReviewState.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReviewCaseRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReleaseRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRole.javacore/src/main/java/com/orgmemory/core/assetregistry/package-info.javaapps/worker/src/main/java/com/orgmemory/worker/authorization/AssetAuthorizationConvergenceScheduler.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetDraftRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetDraft.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationBatch.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRelease.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuditEvent.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReviewDecisionRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationCandidate.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationConvergenceService.javacore/src/test/java/com/orgmemory/core/assetregistry/AssetPayloadDigesterTests.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationProjectionService.javacore/src/test/java/com/orgmemory/core/assetregistry/AssetReviewLifecycleTests.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReviewCase.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetTypeProfileRegistry.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRevision.javacore/src/main/java/com/orgmemory/core/assetregistry/Asset.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetPayloadDigester.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReviewDecision.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRevisionRepository.javaapps/worker/src/main/java/com/orgmemory/worker/OrgMemoryWorkerApplication.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationOutboxRepository.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRoleAssignment.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetReleaseAvailabilityEvent.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationCoordinator.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetView.javaapps/api/src/test/java/com/orgmemory/api/assetregistry/AssetRegistryIntegrationTests.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRegistryService.javaapps/api/src/main/java/com/orgmemory/api/ApiExceptionHandler.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetRegistryCoordinator.javaapps/api/src/main/java/com/orgmemory/api/assetregistry/AssetRegistryController.javacore/src/main/java/com/orgmemory/core/assetregistry/AssetDraftInput.java
**/application*.{yml,yaml,properties}
📄 CodeRabbit inference engine (CLAUDE.md)
Keep JPA
ddl-auto=validate; pair JPA schema or entity changes with a Flyway migration.
Files:
apps/worker/src/main/resources/application.yml
integrations/authorization-openfga/**/*
⚙️ CodeRabbit configuration file
integrations/authorization-openfga/**/*: Source-native ACL is a hard ceiling. Flag any parent, organization, role,
or wildcard relation that can broaden source access. Require negative
Check and ListObjects coverage for every new permission path.
Files:
integrations/authorization-openfga/src/main/openfga/model.fgaintegrations/authorization-openfga/src/test/openfga/store.fga.yaml
apps/api/src/main/java/**/*.java
⚙️ CodeRabbit configuration file
apps/api/src/main/java/**/*.java: Enforce the browser-BFF and resource-server boundaries. Authentication
must resolve an active internal actor through the explicit issuer and
subject binding. Reject identity, tenant, roles, or permissions supplied
by request payloads, JWT email, or untrusted JWT role claims.
Files:
apps/api/src/main/java/com/orgmemory/api/ApiExceptionHandler.javaapps/api/src/main/java/com/orgmemory/api/assetregistry/AssetRegistryController.java
core/src/main/resources/db/migration/*.sql
⚙️ CodeRabbit configuration file
core/src/main/resources/db/migration/*.sql: The repository is pre-release: V1 is the intentionally resettable clean
baseline and development data carries no migration cost. Once a release
baseline is frozen, later Flyway migrations are immutable. Check tenant
isolation, foreign keys, uniqueness, indexes, append-only evidence
semantics, safe defaults, and PostgreSQL 18 plus pgvector compatibility.
Files:
core/src/main/resources/db/migration/V2__asset_registry_foundation.sql
🧠 Learnings (1)
📚 Learning: 2026-07-23T23:30:44.585Z
Learnt from: kl3inIT
Repo: kl3inIT/OrgMemory PR: 30
File: core/src/main/resources/db/migration/V32__evidence_scoped_graph_semantics.sql:0-0
Timestamp: 2026-07-23T23:30:44.585Z
Learning: For OrgMemory PostgreSQL Flyway migrations under core/src/main/resources/db/migration, do not recommend using `CREATE INDEX CONCURRENTLY` or `DROP INDEX CONCURRENTLY` inside application-owned Flyway migration SQL. Flyway’s schema-history connection may hold a transaction that can cause concurrent index operations to wait indefinitely (e.g., on a `virtualxid`), and docs/conventions.md forbids this pattern. If you need large production-table index replacement, pre-stage online index operations via the deployment pipeline (outside Flyway) rather than inside the migration; “ordinary” index replacement is acceptable for unreleased projections before production traffic.
Applied to files:
core/src/main/resources/db/migration/V2__asset_registry_foundation.sql
🪛 ast-grep (0.44.1)
apps/api/src/main/java/com/orgmemory/api/assetregistry/AssetRegistryController.java
[warning] 114-114: Avoid LDAP injections
Context: assets.search(actors.current(authentication), q, type)
Note: [CWE-90] Improper Neutralization of Special Elements used in an LDAP Query ('LDAP Injection'). Security best practice.
(ldap-injection-java)
🪛 PMD (7.26.0)
core/src/main/java/com/orgmemory/core/assetregistry/AssetRegistryService.java
[Medium] 89-90: PreserveStackTrace (Best Practices): Thrown exception does not preserve the stack trace of exception 'inconsistent' on all code paths
(PreserveStackTrace (Best Practices))
core/src/main/java/com/orgmemory/core/assetregistry/AssetRegistryCoordinator.java
[Medium] 86-87: PreserveStackTrace (Best Practices): Thrown exception does not preserve the stack trace of exception 'duplicate' on all code paths
(PreserveStackTrace (Best Practices))
[Medium] 336-337: PreserveStackTrace (Best Practices): Thrown exception does not preserve the stack trace of exception 'duplicate' on all code paths
(PreserveStackTrace (Best Practices))
🪛 SQLFluff (4.2.2)
core/src/main/resources/db/migration/V2__asset_registry_foundation.sql
[error] 39-40: CREATE INDEX should use CONCURRENTLY to avoid locking the table during the build.
(PG01)
[error] 81-82: CREATE INDEX should use CONCURRENTLY to avoid locking the table during the build.
(PG01)
[error] 264-265: CREATE INDEX should use CONCURRENTLY to avoid locking the table during the build.
(PG01)
[error] 343-344: CREATE INDEX should use CONCURRENTLY to avoid locking the table during the build.
(PG01)
[error] 369-370: CREATE INDEX should use CONCURRENTLY to avoid locking the table during the build.
(PG01)
🪛 Squawk (2.59.0)
core/src/main/resources/db/migration/V2__asset_registry_foundation.sql
[warning] 13-13: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 14-14: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 15-15: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 17-17: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 46-46: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 47-47: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 48-48: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 88-88: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 89-89: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 90-90: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 91-91: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 113-113: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 114-114: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 115-115: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 116-116: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 118-118: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 119-119: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 144-144: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 145-145: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 146-146: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 174-174: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 176-176: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 177-177: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 178-178: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 205-205: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 206-206: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 207-207: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 208-208: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 209-209: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 211-211: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 244-244: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 245-245: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 271-271: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 272-272: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 275-275: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 295-295: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 297-297: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 298-298: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 299-299: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 300-300: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 317-317: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 318-318: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 319-319: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 320-320: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 321-321: Using 32-bit integer fields can result in hitting the max int limit. Use 64-bit integer values instead to prevent hitting this limit.
(prefer-bigint-over-int)
[warning] 322-322: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 323-323: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 324-324: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 351-351: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
[warning] 352-352: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock, that will prevent all reads and writes to the table. Use a TEXT field with a CHECK constraint.
(prefer-text-field)
🔇 Additional comments (50)
apps/api/src/main/java/com/orgmemory/api/assetregistry/AssetRegistryController.java (2)
94-106: 🔒 Security & PrivacyVerify the actor and role-assignment trust boundaries.
The controller correctly calls
CurrentActorProvider, but verify thatcurrent(Authentication)binds an active internal actor by explicit issuer and subject. Also verify thatassignRoleauthorizes that derived actor and tenant server-side;principalType,principalId, androlemust remain target data, not caller identity or permission claims.As per path instructions, caller identity, tenant, roles, and permissions must not be trusted from request payloads or untrusted JWT claims.
Also applies to: 203-215
Source: Path instructions
1-93: LGTM!Also applies to: 109-202, 216-217
core/src/main/java/com/orgmemory/core/assetregistry/AssetUnavailableException.java (1)
1-12: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetAuditEvent.java (1)
13-63: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetAuditEventRepository.java (1)
3-7: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationBatch.java (1)
3-17: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationCandidate.java (1)
3-6: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationConvergenceReport.java (1)
3-13: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetDraft.java (1)
10-111: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetDraftRepository.java (1)
3-10: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetReviewDecision.java (1)
13-85: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetRole.java (1)
3-21: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationStatus.java (1)
1-6: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationTarget.java (1)
1-10: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetAvailability.java (1)
1-8: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetConflictException.java (1)
1-9: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetReviewCase.java (2)
13-54: LGTM!Also applies to: 69-100
56-67: 🗄️ Data Integrity & IntegrationVerify optimistic locking for review resolution.
decide()performs a read/check/write transition. IfBaseEntitydoes not provide@Versionand the repository does not lock this row, two reviewers can both observeIN_REVIEWand persist conflicting decisions. Verify the inherited mapping and add a concurrent-resolution test.core/src/main/java/com/orgmemory/core/assetregistry/AssetSummary.java (1)
1-14: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetType.java (1)
1-8: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetReleaseAvailabilityRepository.java (1)
1-17: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetRepository.java (1)
1-18: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetView.java (1)
1-115: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationCoordinator.java (1)
70-87: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetDraftInput.java (1)
3-8: 🗄️ Data Integrity & IntegrationVerify validation at the input boundary.
This record accepts null, blank, and oversized values, while
asset_draftsenforces non-null and length constraints andAssetRegistryCoordinator.submitconsumes these fields directly. Confirm equivalent controller/service validation exists and maps invalid requests to400; otherwise add DTO constraints and tests.Based on the supplied
AssetRegistryCoordinator.javaLines 218-250 and migration Lines 84-106.core/src/main/java/com/orgmemory/core/assetregistry/AssetNotFoundException.java (1)
3-8: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetPortfolioState.java (1)
3-8: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetReviewDecisionRepository.java (1)
7-10: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetReviewDecisionType.java (1)
3-8: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetReviewState.java (1)
3-9: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetRoleAssignmentRepository.java (1)
8-18: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetReviewCaseRepository.java (1)
8-21: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetReleaseAvailabilityEvent.java (1)
30-31: 🗄️ Data Integrity & IntegrationConfirm that empty availability reasons are intentional.
The constructor converts null or blank reasons to
"", even though the reason is surfaced as availability-history evidence. If deprecation or withdrawal reasons are required, this silently records unauditable transitions; use the same non-blank validation asAssetRevision.changeNote.Based on the supplied
AssetRegistryCoordinator.javaLines 519-547.Also applies to: 52-55
core/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationConvergenceService.java (1)
6-32: 📐 Maintainability & Code QualityComplete the mandated verification gates before merge.
Run JetBrains inspection for the changed Java scope and the configured terminating clean test gate; do not use
bootRunas verification. Reviewdocs/guidelines/agent-safety.mdfor these authorization-projection changes.
core/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationConvergenceService.java#L6-L32: include convergence logic in inspection and clean verification.core/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationOutboxRepository.java#L13-L46: include outbox locking/claim behavior in inspection and clean verification.apps/worker/src/main/java/com/orgmemory/worker/OrgMemoryWorkerApplication.java#L35-L42: include worker bean wiring in clean verification.apps/worker/src/main/java/com/orgmemory/worker/authorization/AssetAuthorizationConvergenceProperties.java#L7-L23: include property binding and validation in clean verification.apps/worker/src/main/java/com/orgmemory/worker/authorization/AssetAuthorizationConvergenceScheduler.java#L10-L47: include scheduled reconciliation wiring in clean verification.As per coding guidelines, “JetBrains IDE inspection is a verification gate” and verification must use “a terminating clean test” rather than
bootRun.Source: Coding guidelines
core/src/test/java/com/orgmemory/core/assetregistry/AssetPayloadDigesterTests.java (1)
14-32: 🎯 Functional CorrectnessJSON key sorting is already enabled.
SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYSis enabled on the Jackson mapper, and serializing the parsed payload map recursively sorts nested map keys for the canonical payload and envelope digest.core/src/main/java/com/orgmemory/core/assetregistry/AssetRevisionRepository.java (1)
10-27: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetRoleAssignment.java (1)
14-105: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetTypeProfile.java (1)
6-22: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetTypeProfileRegistry.java (1)
9-39: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetReleaseRepository.java (1)
10-30: LGTM!core/src/main/resources/db/migration/V2__asset_registry_foundation.sql (2)
1-8: LGTM!Also applies to: 372-392
10-40: LGTM!Also applies to: 42-82, 84-166, 199-265, 312-370
core/src/main/java/com/orgmemory/core/assetregistry/AssetPayloadDigester.java (1)
14-61: LGTM!core/src/main/java/com/orgmemory/core/assetregistry/AssetRegistryCoordinator.java (2)
357-396: LGTM!
260-282: 🩺 Stability & AvailabilityNo change needed.
AssetReviewCase.decidealready rejects non-IN_REVIEWstate and records the resolved state, while the coordinator enforces the relevant tenant/digest/permission rules.core/src/main/java/com/orgmemory/core/assetregistry/AssetRegistryService.java (1)
51-78: LGTM!Also applies to: 95-199
apps/api/src/test/java/com/orgmemory/api/assetregistry/AssetRegistryIntegrationTests.java (2)
103-447: LGTM!
49-62: 📐 Maintainability & Code QualityNo change needed;
test-foundation.sqlseeds the referenced space and actor rows, andclearAssetRegistry()only truncates asset tables.core/src/main/java/com/orgmemory/core/assetregistry/AssetAuthorizationProjectionService.java (2)
23-48: LGTM!
49-49: 🗄️ Data Integrity & Integration
policyVersion()is already the OpenFGA authorization model id.
| define space: [knowledge_space] | ||
| define owner: [user] | ||
| define backup_owner: [user] | ||
| define steward: [user, group#member] | ||
| define viewer: [user, group#member] | ||
| define editor: [user, group#member] | ||
| define reviewer: [user, group#member] | ||
| define publisher: [user, group#member] | ||
| define org_admin: administrator from organization | ||
|
|
||
| define can_manage_roles: owner or backup_owner or steward or org_admin | ||
| define can_edit: editor or steward or owner or backup_owner or org_admin | ||
| define can_submit_review: can_edit | ||
| define can_review: reviewer or org_admin | ||
| define can_publish: publisher or org_admin | ||
| define can_withdraw: publisher or owner or backup_owner or org_admin | ||
| define can_view: viewer or can_edit or can_review or can_publish |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
Enforce the knowledge-space ACL as an asset permission ceiling.
space is never used in these permissions. A user assigned any local asset role can obtain can_view/can_use (and potentially edit, review, or publish) even when denied on the linked knowledge_space. Gate each asset capability through the corresponding source-space permission rather than granting authority solely from local tuples.
As per path instructions, “Source-native ACL is a hard ceiling.”
🤖 Prompt for 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.
In `@integrations/authorization-openfga/src/main/openfga/model.fga` around lines
74 - 90, Update the asset permission definitions around can_manage_roles,
can_edit, can_submit_review, can_review, can_publish, can_withdraw, and can_view
so every capability is additionally gated by the linked space’s corresponding
permission. Reuse the existing space relation and source-space permission
mappings, ensuring local asset roles cannot grant authority when the user lacks
that permission on the knowledge_space.
Source: Path instructions
What changed
core.assetregistrySpring Modulith domain for mutable drafts, immutable revisions/reviews/releases, availability history, roles, audit, relations, and payload referencesassetmodel, authorization outbox projection, and worker convergenceWhy
PR 1 establishes the security and governance kernel needed by the Prompt, Work Instruction, and Capability Pack profiles in PR 2 without coupling the shared tables to one asset type.
Impact
Authorized callers can create, edit, submit, review, publish, search, read, deprecate, withdraw, and assign Asset roles. Type-specific rendering/execution, web surfaces, Assistant tools, and MCP remain intentionally excluded.
Validation
./gradlew.bat --no-daemon testpnpm -C web lint,typecheck, and productionbuildThe repository-defined PostgreSQL/AGE image was built locally before the full graph-rag PostgreSQL suite, matching CI.
Summary by CodeRabbit