Skip to content

promote: dev history slice 2 of 4 - #31

Merged
BeforeLights merged 75 commits into
mainfrom
promote/dev-20260803-02
Aug 3, 2026
Merged

promote: dev history slice 2 of 4#31
BeforeLights merged 75 commits into
mainfrom
promote/dev-20260803-02

Conversation

@BeforeLights

@BeforeLights BeforeLights commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Promotes the second ordered DataBreeze dev-history slice to main. This boundary contains 75 commits after promotion slice 1, remains within the approved exceptional ceiling of 79, and preserves merge commits. CodeRabbit policy: allow exactly one automatic full review on this PR, reproduce each claim, fix valid findings on dev in focused commits, document rejected findings, and do not request a rerun. This is an intermediate promotion boundary; main is not releaseable until all four slices and coordinated release gates pass.

Summary by CodeRabbit

  • New Features
    • Added governed artifact uploads, exports, retention requests, admission, lineage, and placement updates.
    • Added dataset versioning, quality results, profiling, metadata-only exports, publishing, and compatibility checks.
    • Added protected-document unlock workflows with bounded retries and opaque, single-use handles.
    • Added spreadsheet auditing with formula analysis, safety limits, blocked-feature reporting, and value-free results.
    • Added inbox triage metadata for assignees, labels, priorities, due dates, and revision-aware updates.
  • Security & Reliability
    • Added tenant-scoped visibility, immutable records, validation, idempotency, rollback behavior, and structured error responses.
  • Documentation
    • Added a complete API contract and release evidence.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds versioned immutable domain contracts, deterministic engine processors, tenant-scoped IAE, DSM, and spreadsheet-audit workflows, OpenAPI definitions, Prisma persistence, NestJS modules, and integration tests.

Changes

Platform foundations

Layer / File(s) Summary
Versioned domain contracts
packages/domain/src/*
Adds validated immutable contracts and revision-controlled workflows for artifacts, uploads, retention, datasets, protected documents, and spreadsheet audits.
Engine evaluators and manifests
services/engine/src/databreeze_engine/processors/*
Adds deterministic dataset-quality evaluation and resource-bounded, value-free spreadsheet auditing with immutable manifests.
Domain exports and contract validation
packages/domain/package.json, packages/domain/src/v1.ts, packages/domain/test/*
Publishes the new versioned modules and validates their schemas, exports, immutability, and rejection codes.
Database schemas and migrations
services/api/prisma/schema/*, services/api/prisma/migrations/*
Adds durable records and indexes for retention, exports, uploads, quality results, profiles, protected-document unlocks, inbox metadata, and spreadsheet audits.
IAE workflows and persistence
services/api/src/features/iae/*
Adds controllers, services, repository ports, in-memory adapters, Prisma adapters, upload storage, protected-document handles, and tenant-scoped immutable operations.
DSM workflows and API integration
services/api/src/features/dsm/*
Adds dataset version, quality, profile, and export services, repositories, controllers, DTOs, module wiring, pagination, and publication lookups.
Spreadsheet audit API and persistence
services/api/src/features/sa/*
Adds the spreadsheet-audit module, authenticated endpoints, tenant-scoped repository adapters, immutable storage, and transaction rollback.
API, module, and persistence validation
services/api/openapi/v1.json, services/api/test/*, docs/release-evidence/*
Adds the OpenAPI contract, module composition checks, endpoint and repository tests, migration assertions, and release evidence.
Estimated code review effort: 5 (Critical) ~120 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.03% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies this pull request as the promotion of development-history slice 2 of 4.
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.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch promote/dev-20260803-02

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

@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: 2

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
services/api/test/features/iae/prisma-artifact-intake-repository.test.ts (1)

56-61: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

The fixture create accepts duplicate ids.

create pushes unconditionally. Prisma rejects a duplicate primary key with P2002. The same weakness exists in services/api/test/features/iae/prisma-artifact-export-repository.test.ts. See the consolidated comment for the shared fix.

🤖 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 `@services/api/test/features/iae/prisma-artifact-intake-repository.test.ts`
around lines 56 - 61, The fixture create method in the Prisma artifact intake
repository test should enforce primary-key uniqueness before pushing a persisted
row, matching Prisma’s P2002 behavior for duplicate ids. Apply the same shared
fix to the corresponding create fixture in the artifact export repository test,
while preserving successful creation for unique ids.
🟡 Minor comments (29)
services/engine/src/databreeze_engine/processors/dataset_quality.py-51-64 (1)

51-64: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Require MISSING, NULL, and BLANK in stateCounts.

StateCounts does not enforce these keys at runtime. A malformed DatasetProfile can make _required_count raise KeyError. Enforce the keys in the model or return a controlled validation error. DatasetProfile contains aggregate metadata and fingerprints, not raw source values.

🤖 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 `@services/engine/src/databreeze_engine/processors/dataset_quality.py` around
lines 51 - 64, Update _required_count to safely handle missing MISSING, NULL, or
BLANK entries in summary.stateCounts, returning a controlled validation result
instead of raising KeyError. Preserve the existing count calculation when all
required keys are present, and keep profile_fingerprint unchanged.
services/api/src/features/sa/api/spreadsheet-audit.dto.ts-107-111 (1)

107-111: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

blockedReasons accepts duplicate values.

@ArrayMaxSize(3) matches the count of allowed enum members. The current rules still accept ['MACRO', 'MACRO', 'MACRO']. Add @ArrayUnique() to enforce the intended set semantics.

🛡️ Proposed validation fix
   `@IsArray`()
+  `@ArrayUnique`()
   `@ArrayMaxSize`(3)
   `@IsIn`(['MACRO', 'EXTERNAL_LINK', 'UNSUPPORTED_XML'], { each: true })
   blockedReasons!: Array<'MACRO' | 'EXTERNAL_LINK' | 'UNSUPPORTED_XML'>;

Add ArrayUnique to the class-validator import list.

🤖 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 `@services/api/src/features/sa/api/spreadsheet-audit.dto.ts` around lines 107 -
111, Update the blockedReasons validation in the DTO by importing ArrayUnique
from class-validator and adding `@ArrayUnique`() alongside the existing array
validators, so duplicate enum values are rejected while the current allowed
values and maximum size remain unchanged.
services/api/src/features/sa/adapter/in-memory-spreadsheet-audit-repository.adapter.ts-62-85 (1)

62-85: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Rollback can discard writes made outside the transaction.

withTransaction serializes only calls that enter through withTransaction. The public save method does not take the same tail lock. If a caller awaits save directly while a transaction is open, and the transaction then fails, this.results = before removes that write.

Route the non-transactional methods through the same queue, or document that the in-memory adapter supports one writer at a time.

♻️ Proposed serialization of direct writes
+  private enqueue<TValue>(work: () => Promise<TValue>): Promise<TValue> {
+    const previous = this.transactionTail;
+    let release!: () => void;
+    this.transactionTail = new Promise<void>((resolve) => {
+      release = resolve;
+    });
+    return previous.then(work).finally(release);
+  }

Then call this.enqueue(...) from save, and keep the transaction body using the unwrapped internal helpers.

🤖 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
`@services/api/src/features/sa/adapter/in-memory-spreadsheet-audit-repository.adapter.ts`
around lines 62 - 85, Update the in-memory spreadsheet audit repository’s
serialization so direct calls to save cannot overlap an active withTransaction
rollback. Route the public save method through the same transactionTail queue,
while keeping the transaction callback on unwrapped internal save/find/list
helpers to avoid nested queueing and deadlocks; preserve the existing rollback
and transaction ordering behavior.
services/api/src/features/sa/api/spreadsheet-audit.dto.ts-118-120 (1)

118-120: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Align createdAt validation with the UTC timestamp contract.

@IsISO8601({ strict: true }) still accepts date-only values and offsets. Add a pattern that requires the time component and uppercase Z; the domain rejects these values before Prisma persistence.

🤖 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 `@services/api/src/features/sa/api/spreadsheet-audit.dto.ts` around lines 118 -
120, Update the createdAt property decorators in the spreadsheet audit DTO to
enforce the UTC timestamp contract: retain strict ISO-8601 validation and add a
matching pattern requiring a time component and uppercase Z, rejecting date-only
values and offset timestamps before persistence.
services/api/openapi/v1.json-7376-7376 (1)

7376-7376: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Bound the remaining unbounded arrays.

Several array properties declare maxItems, for example labels at line 7284 and sheets at line 8188. Other arrays in the same document declare no upper bound: versionIds (line 7376), fields (line 7525), steps (line 7569), rules (line 7595), inputArtifactVersionIds (line 7641), evidenceIds (line 7713), and findings (line 7742). The Fastify bodyLimit of 65,536 bytes limits the total request size, so this is not an unbounded-memory hazard. It remains an inconsistent validation contract, and it produces the Checkov CKV_OPENAPI_21 finding. Add MaxArraySize-style decorators to the matching DTO properties so the generated document declares the same bound everywhere.

Also applies to: 7525-7525, 7569-7569, 7595-7595, 7641-7641, 7713-7713, 7742-7742

🤖 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 `@services/api/openapi/v1.json` at line 7376, Add the established
MaxArraySize-style validation to the DTO properties generating versionIds,
fields, steps, rules, inputArtifactVersionIds, evidenceIds, and findings, so the
OpenAPI document emits a consistent maxItems bound matching existing arrays such
as labels and sheets.

Source: Linters/SAST tools

services/api/test/features/iae/prisma-artifact-intake-repository.test.ts-174-177 (1)

174-177: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the persisted revision after the transition.

The read-back checks only state. The test is named for revisioned transitions, but an adapter that writes ROUTED and drops the revision increment still passes. Assert revision as well.

💚 Proposed fix
-  assert.equal(
-    (await repository.find(context(workspaceId, 'transition-read'), itemId))?.state,
-    'ROUTED',
-  );
+  const persisted = await repository.find(context(workspaceId, 'transition-read'), itemId);
+  assert.equal(persisted?.state, 'ROUTED');
+  assert.equal(persisted?.revision, 2);
🤖 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 `@services/api/test/features/iae/prisma-artifact-intake-repository.test.ts`
around lines 174 - 177, Update the read-back assertion in the revisioned
transition test to validate the persisted revision alongside the existing ROUTED
state check. Use the expected incremented revision value for the transition,
ensuring adapters that change state without persisting the revision increment
fail.
services/api/test/features/iae/inbox.controller.test.ts-106-106 (1)

106-106: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Add the case-insensitive flag to the content-leak assertion.

This assertion guards against content fields in the response. It uses /path|source|byte|excerpt/u without the i flag, so it does not match sourcePath, Excerpt, or other capitalized forms. The equivalent assertions in services/api/test/features/iae/artifact-upload.controller.test.ts use /iu. Align this one.

🛡️ Proposed fix
-    assert.doesNotMatch(accepted.body, /path|source|byte|excerpt/u);
+    assert.doesNotMatch(accepted.body, /path|source|byte|excerpt/iu);
🤖 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 `@services/api/test/features/iae/inbox.controller.test.ts` at line 106, Update
the content-leak assertion in the relevant inbox controller test to use the
case-insensitive regular-expression flag, matching the equivalent
artifact-upload assertion while preserving the existing prohibited terms.
services/api/openapi/v1.json-149-153 (1)

149-153: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Declare application/problem+json for the 503 response.

ProblemDetailsFilter sends readiness failures as application/problem+json, but the generated OpenAPI document declares application/json. Set this media type in HealthController.readinessStatus's @ApiServiceUnavailableResponse decorator.

🤖 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 `@services/api/openapi/v1.json` around lines 149 - 153, Update the
HealthController.readinessStatus `@ApiServiceUnavailableResponse` decorator to
declare application/problem+json for the 503 response instead of
application/json, keeping the ProblemDetails schema reference unchanged.
services/api/test/features/iae/artifact-upload.service.test.ts-99-100 (1)

99-100: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Return a session-lifecycle error for expired uploads.

issuePartTransfer delegates an EXPIRED session to storage, which returns UPLOAD_STORAGE_NOT_READY for every non-OPEN session. Add a distinct terminal code such as UPLOAD_SESSION_EXPIRED so clients can distinguish expiration from storage unavailability.

🤖 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 `@services/api/test/features/iae/artifact-upload.service.test.ts` around lines
99 - 100, Update issuePartTransfer to detect sessions in the EXPIRED state
before delegating to storage and return the distinct terminal code
UPLOAD_SESSION_EXPIRED; preserve UPLOAD_STORAGE_NOT_READY for other non-OPEN
sessions and storage failures.
packages/domain/src/artifact-export/v1.ts-66-73 (1)

66-73: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Validate the string after normalization and trimming.

text validates the raw input, then returns input.normalize('NFC').trim(). A whitespace-only string passes the length > 0 check and returns ''. The caller at Line 124 only rejects undefined, so an empty processorVersions entry enters a frozen manifest. Normalize and trim first, then apply the bounds check.

🐛 Proposed fix
 function text(input: unknown): string | undefined {
-  return typeof input === 'string' &&
-    input.length > 0 &&
-    input.length <= 128 &&
-    !/\p{Cc}/u.test(input)
-    ? input.normalize('NFC').trim()
-    : undefined;
+  if (typeof input !== 'string' || /\p{Cc}/u.test(input)) return undefined;
+  const value = input.normalize('NFC').trim();
+  return value.length > 0 && value.length <= 128 ? value : undefined;
 }
🤖 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 `@packages/domain/src/artifact-export/v1.ts` around lines 66 - 73, Update text
to normalize and trim string inputs before validating them. Apply the non-empty
and maximum-length checks, along with the control-character check, to the
normalized trimmed value so whitespace-only inputs return undefined while valid
text is returned unchanged.
packages/domain/test/public-api-v1.test.mjs-74-80 (1)

74-80: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the two missing schema-version constants.

This block asserts the schema version for six modules. The export list at Lines 29-30 also requires ./artifact-retention/v1 and ./artifact-export/v1. Their constants are not asserted here.

Both constants exist: ARTIFACT_RETENTION_SCHEMA_VERSION_V1 at packages/domain/src/artifact-retention/v1.ts Line 13, and ARTIFACT_EXPORT_SCHEMA_VERSION_V1 at packages/domain/src/artifact-export/v1.ts Line 12. If either is dropped from the aggregate re-export in packages/domain/src/v1.ts, this smoke test still passes and the break reaches consumers.

💚 Proposed fix
   assert.equal(typeof aggregate.parseTenantScopeV1, 'function');
   assert.equal(aggregate.ARTIFACT_UPLOAD_SCHEMA_VERSION_V1, 1);
   assert.equal(aggregate.PROTECTED_DOCUMENT_SCHEMA_VERSION_V1, 1);
+  assert.equal(aggregate.ARTIFACT_RETENTION_SCHEMA_VERSION_V1, 1);
+  assert.equal(aggregate.ARTIFACT_EXPORT_SCHEMA_VERSION_V1, 1);
🤖 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 `@packages/domain/test/public-api-v1.test.mjs` around lines 74 - 80, Add
assertions in the public API smoke-test block for
ARTIFACT_RETENTION_SCHEMA_VERSION_V1 and ARTIFACT_EXPORT_SCHEMA_VERSION_V1,
verifying each equals 1 alongside the existing schema-version constants.
packages/domain/test/dataset-profile-v1.test.mjs-46-54 (1)

46-54: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Isolate the count violation in the first negative case.

The override sets completeness: 'COMPLETE' and clears samplingSeed, but samplingMethod: 'HASHED_ROW_RESERVOIR_V1' still comes from base. Case 2 at Lines 55-58 shows that a sample-only field on a COMPLETE profile yields INVALID_SAMPLING. This input therefore violates two rules at once.

The assertion of INVALID_COUNT passes only while the count check runs before the sampling check inside createDatasetProfileV1. Reordering the checks, which preserves behavior, breaks this test. The test also does not prove the count rule alone is enforced. Clear samplingMethod so the input violates only the count rule.

💚 Proposed fix
     createDatasetProfileV1({
       ...base,
       completeness: 'COMPLETE',
+      samplingMethod: undefined,
       samplingSeed: undefined,
       rowCountScanned: 1001,
     }),
     { accepted: false, code: 'INVALID_COUNT' },
🤖 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 `@packages/domain/test/dataset-profile-v1.test.mjs` around lines 46 - 54,
Update the first negative test case in createDatasetProfileV1 to explicitly
clear samplingMethod alongside samplingSeed, ensuring the COMPLETE profile
violates only the row-count rule and continues asserting INVALID_COUNT.
packages/domain/test/spreadsheet-audit-v1.test.mjs-36-38 (1)

36-38: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Assert the value-free guarantee on the finding, not on the manifest root.

Lines 37-38 call Object.hasOwn against result.value, the top-level audit result. Raw workbook content would never appear there. It would appear on a finding.

build_spreadsheet_audit_manifest in services/engine/src/databreeze_engine/processors/spreadsheet_auditor_manifest.py at Lines 53-101 carries formulaFingerprint on each finding for exactly this reason: the raw formula must not travel. These two assertions pass regardless of whether that holds, so they give false confidence in the privacy control this test is named for.

🛡️ Proposed fix
   assert.equal(result.value.findings[0]?.address, 'C1');
-  assert.equal(Object.hasOwn(result.value, 'formula'), false);
-  assert.equal(Object.hasOwn(result.value, 'sourceValue'), false);
+  const finding = result.value.findings[0];
+  assert.equal(Object.hasOwn(finding, 'formula'), false);
+  assert.equal(Object.hasOwn(finding, 'sourceValue'), false);
+  assert.equal(finding.formulaFingerprint, 'b'.repeat(64));
+  assert.equal(Object.hasOwn(result.value.sheets[0], 'cells'), false);
🤖 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 `@packages/domain/test/spreadsheet-audit-v1.test.mjs` around lines 36 - 38,
Update the assertions in the spreadsheet audit test to check the first finding,
result.value.findings[0], rather than the top-level result.value. Verify that
the finding does not own formula or sourceValue, preserving the existing address
assertion and directly testing the value-free guarantee where raw workbook
content could appear.
packages/domain/src/artifact-upload/v1.ts-242-253 (1)

242-253: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Return a code that matches the rejection reason.

Line 249 rejects when now is earlier than session.expiresAt. The session has not expired at that point, so the transition is premature. The returned code is 'EXPIRED', which reports the opposite condition.

A sweeper cannot separate "the session is not due yet" from a genuine expiry state error. Use 'INVALID_TIMESTAMP', which is already in ArtifactUploadErrorCodeV1.

🐛 Proposed fix
   if (session.state !== 'OPEN') return rejected('INVALID_STATE');
-  if (Date.parse(timestampValue) < Date.parse(session.expiresAt)) return rejected('EXPIRED');
+  if (Date.parse(timestampValue) < Date.parse(session.expiresAt))
+    return rejected('INVALID_TIMESTAMP');
🤖 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 `@packages/domain/src/artifact-upload/v1.ts` around lines 242 - 253, Update
expireArtifactUploadSessionV1 so the branch where now precedes session.expiresAt
returns INVALID_TIMESTAMP instead of EXPIRED, preserving the existing validation
order and expiry transition behavior.
packages/domain/src/spreadsheet-audit/v1.ts-166-186 (1)

166-186: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Structural failures in sheet and finding are reported as 'INVALID_COUNT'.

sheet and finding return undefined for every failure cause. Lines 169-170 and 179-180 map that single undefined to 'INVALID_COUNT'.

The result is that a malformed cell address, a bad severity, an unknown kind, or a non-hex formulaFingerprint all report 'INVALID_COUNT', which describes none of them. The error union at lines 47-59 declares 'INVALID_COORDINATE', 'INVALID_SEVERITY', and 'INVALID_KIND', and no code path returns any of the three. Those three members are unreachable today.

The SA controller returns these codes to API clients, so a client cannot tell "too many sheets" apart from "bad cell address".

Return the specific code from the element parsers, or at minimum use a distinct code for a structurally invalid element.

🤖 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 `@packages/domain/src/spreadsheet-audit/v1.ts` around lines 166 - 186, Update
the sheet and finding validation flow around the sheet and finding parsers so
structural element failures preserve their specific rejection codes instead of
being collapsed to INVALID_COUNT. Return INVALID_COORDINATE, INVALID_SEVERITY,
or INVALID_KIND as appropriate for the corresponding malformed fields, while
retaining INVALID_COUNT for invalid collection sizes and preserving existing
duplicate and reference checks.
packages/domain/test/artifact-upload-v1.test.mjs-55-61 (1)

55-61: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Guard the completion result before you read .value.state.

completeArtifactUploadSessionV1 returns a discriminated union. The rejected branch carries code and no value. Line 59 reads .value.state without checking accepted first.

If completion ever returns a rejection, the expression evaluates undefined.state and the test aborts with a TypeError. The report then names a property access instead of the real cause, which is the rejection code.

Lines 28-29, 37-38, and 53-54 already use the guard pattern. Apply it here too.

💚 Proposed fix to keep the failure diagnostic useful
-  assert.equal(
-    completeArtifactUploadSessionV1(second.value, {
-      assembledSha256: base.expectedSha256,
-      expectedRevision: 3,
-    }).value.state,
-    'COMPLETED',
-  );
+  const completed = completeArtifactUploadSessionV1(second.value, {
+    assembledSha256: base.expectedSha256,
+    expectedRevision: 3,
+  });
+  assert.equal(completed.accepted, true);
+  if (!completed.accepted) return;
+  assert.equal(completed.value.state, 'COMPLETED');
🤖 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 `@packages/domain/test/artifact-upload-v1.test.mjs` around lines 55 - 61, Guard
the result of completeArtifactUploadSessionV1 before accessing value.state,
matching the accepted/result assertion pattern already used near lines 28-29,
37-38, and 53-54. Assert or validate accepted first so rejected results expose
their code rather than causing a TypeError, then read state only from the
accepted value.
packages/domain/src/protected-document/v1.ts-192-203 (1)

192-203: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Line 199 returns 'EXPIRED' for a request that has not expired.

The condition Date.parse(timestampValue) < Date.parse(request.expiresAt) is true when now is before expiresAt. In that branch the request is still live and must not be expired. The function correctly refuses, but it reports the code 'EXPIRED', which states the opposite of the real condition.

A caller that branches on code will read 'EXPIRED' and conclude the request already expired, while the request is in fact still valid. The error union at lines 41-52 already contains 'INVALID_STATE', which describes "the request is not yet expirable".

The control flow needs no change. Only the reported code is wrong.

🐛 Proposed fix for the inverted error code
   if (request.state !== 'REQUESTED') return rejected('INVALID_STATE');
-  if (Date.parse(timestampValue) < Date.parse(request.expiresAt)) return rejected('EXPIRED');
+  if (Date.parse(timestampValue) < Date.parse(request.expiresAt))
+    return rejected('INVALID_STATE');
🤖 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 `@packages/domain/src/protected-document/v1.ts` around lines 192 - 203, In
expireProtectedDocumentUnlockRequestV1, change only the rejection code for the
branch where the current timestamp is before request.expiresAt: return
INVALID_STATE instead of EXPIRED. Preserve the existing condition and all other
control flow unchanged.
packages/domain/src/dataset-profile/v1.ts-144-153 (1)

144-153: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Consider enforcing rowCountScanned <= resourceLimits.maxRows.

The factory validates rowCountScanned and maxRows independently. It never compares them. A profile that reports rowCountScanned: 50_000_000 with maxRows: 1_000 is accepted today. Line 10 states the profile is a "bounded, reproducible profiling disclosure", so the accepted value contradicts its own declared limit.

The file already enforces the comparable relation rowCountScanned <= rowCountAvailable at lines 145-146. If the bound is intended to be authoritative, add the matching check.

🐛 Proposed fix to enforce the declared row bound
   if (!maxRows || !maxBytes || !maxDurationMs) return rejected('INVALID_LIMITS');
+  if (rowCountScanned > maxRows) return rejected('INVALID_LIMITS');
   if (!profileFingerprint) return rejected('INVALID_HASH');
🤖 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 `@packages/domain/src/dataset-profile/v1.ts` around lines 144 - 153, Update the
validation flow around rowCountScanned, rowCountAvailable, and maxRows to reject
profiles when rowCountScanned exceeds the declared maxRows limit. Preserve the
existing INVALID_COUNT result for count-bound violations and ensure the
comparison occurs after maxRows is parsed and validated.
packages/domain/src/spreadsheet-audit/v1.ts-100-118 (1)

100-118: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Align the maxRow bound with the supported XLSX range.

XLSX supports 1,048,576 rows. A workbook with a cell at row 1,048,576 can produce maxRow=1_048_576, but the engine manifest and sheet reject it; the domain result then returns 'INVALID_COUNT'. Raise the bound to 1,048,576, or return a distinct resource-limit result when the 1,000,000 cap is intentional.

🤖 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 `@packages/domain/src/spreadsheet-audit/v1.ts` around lines 100 - 118, The
sheet validator’s maxRow limit is below the supported XLSX range. Update the
upper-bound check in sheet to accept values through 1,048,576, preserving the
existing maxColumn and formulaCount limits and validation behavior.
services/api/src/features/iae/api/inbox.controller.ts-89-92 (1)

89-92: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the unreachable branch in the mutationContext expression.

Line 89 returns when expectedRevision is undefined. At Line 92 the same condition is tested again, so the context branch is unreachable and expectedRevision is always a number at that point.

♻️ Proposed simplification
     if (expectedRevision === undefined)
       return Object.freeze({ accepted: false, code: 'INVALID_METADATA' as const });
-    const mutationContext =
-      expectedRevision === undefined ? context : Object.freeze({ ...context, expectedRevision });
+    const mutationContext = Object.freeze({ ...context, expectedRevision });
🤖 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 `@services/api/src/features/iae/api/inbox.controller.ts` around lines 89 - 92,
Remove the redundant expectedRevision === undefined conditional from the
mutationContext assignment in the surrounding controller method; after the
preceding early return, always create the frozen context by spreading context
and setting expectedRevision.
services/api/src/features/iae/adapter/prisma-artifact-export-repository.adapter.ts-99-115 (1)

99-115: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Align save with tenant visibility and concurrent-create handling.

  • save reads the global id without visible. A sibling-tenant manifest therefore produces IAE_IMMUTABLE_EXPORT_MANIFEST, while find returns undefined. Define whether global IDs intentionally expose this result, or apply the visibility rule before comparing.
  • Public save bypasses $transaction. Concurrent calls can both read no row, then the second create fails with a Prisma unique-constraint error. Use an atomic idempotency path and return IAE_IMMUTABLE_EXPORT_MANIFEST for the losing call.
🤖 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
`@services/api/src/features/iae/adapter/prisma-artifact-export-repository.adapter.ts`
around lines 99 - 115, The save method’s lookup and create flow must match
tenant visibility and handle concurrent idempotent writes. Update the findUnique
query to apply the same visible tenant-scope rule used by find, then wrap the
check-and-create path in the repository’s transaction mechanism and translate a
losing concurrent unique-constraint create into IAE_IMMUTABLE_EXPORT_MANIFEST,
while preserving the existing scope validation and identical-manifest no-op
behavior.
services/api/src/features/iae/adapter/prisma-artifact-lineage-repository.adapter.ts-119-127 (1)

119-127: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Select a visible lineage row before applying rowToDomain.

derivedArtifactVersionId has only a non-unique index. Duplicate rows across scopes are possible. The current findFirst can select an invisible row and return undefined while a visible row exists. Match the in-memory adapter by filtering matching rows with visible; do not use an exact-scope predicate that excludes visible parent or child scopes.

🤖 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
`@services/api/src/features/iae/adapter/prisma-artifact-lineage-repository.adapter.ts`
around lines 119 - 127, Update findByDerived to retrieve candidate lineage rows
for the derivedArtifactVersionId, select the first row satisfying
visible(context.tenantScope, row), and only then pass it to rowToDomain.
Preserve visibility matching across parent and child scopes, and return
undefined when no visible row exists.
services/api/src/features/iae/application/artifact-retention.service.ts-15-18 (1)

15-18: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Declared service error unions omit codes the services return. Both services declare a narrow error-code union and then return additional codes that only compile because the underlying domain result type permits them. Callers that switch on the declared union cannot handle every outcome.

  • services/api/src/features/iae/application/artifact-retention.service.ts#L15-L18: add INVALID_IDENTIFIER, INVALID_TIMESTAMP, INVALID_STATE, and INVALID_REVISION to ArtifactRetentionServiceErrorV1.
  • services/api/src/features/iae/application/content-placement.service.ts#L11-L14: add INVALID_IDENTIFIER to ContentPlacementServiceErrorV1, which line 32 returns.
🤖 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 `@services/api/src/features/iae/application/artifact-retention.service.ts`
around lines 15 - 18, Add INVALID_IDENTIFIER, INVALID_TIMESTAMP, INVALID_STATE,
and INVALID_REVISION to ArtifactRetentionServiceErrorV1 in
services/api/src/features/iae/application/artifact-retention.service.ts (lines
15-18). Also add INVALID_IDENTIFIER to ContentPlacementServiceErrorV1 in
services/api/src/features/iae/application/content-placement.service.ts (lines
11-14), so each declared result union includes every code returned by its
service.
services/api/src/features/iae/api/artifact-admission.controller.ts-35-44 (1)

35-44: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Map unavailable request context explicitly.

SessionRequestTenantContextAdapter already maps missing or invalid bearer credentials to HTTP 401 through ProblemDetailsFilter; it does not need UnauthorizedException. If UnavailableRequestTenantContextAdapter can be active in a deployed app, map its plain error to an explicit authentication or configuration response instead of HTTP 500.

🤖 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 `@services/api/src/features/iae/api/artifact-admission.controller.ts` around
lines 35 - 44, Update the request-context resolution in
ArtifactAdmissionController.admit to handle errors from
UnavailableRequestTenantContextAdapter explicitly instead of allowing them to
become HTTP 500. Map that plain unavailable-context error to the established
authentication or configuration response mechanism, while preserving
SessionRequestTenantContextAdapter’s existing 401 behavior and the remaining
admission flow.
services/api/src/features/iae/api/artifact-admission.dto.ts-18-21 (1)

18-21: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use @IsInt() for actualByteSize.

actualByteSize accepts fractional numbers because it uses @IsNumber(). maxByteSize on Line 32 uses @IsInt(). A byte count must be an integer. Align the two fields and add type: 'integer' to the OpenAPI metadata.

🐛 Proposed fix
-  `@ApiProperty`({ minimum: 0 })
-  `@IsNumber`()
+  `@ApiProperty`({ type: 'integer', minimum: 0 })
+  `@IsInt`()
   `@Min`(0)
   actualByteSize!: number;

Remove the now-unused IsNumber import on Line 6.

🤖 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 `@services/api/src/features/iae/api/artifact-admission.dto.ts` around lines 18
- 21, Update the actualByteSize property in the artifact admission DTO to use
`@IsInt`() instead of `@IsNumber`(), and add type: 'integer' to its `@ApiProperty`
metadata to match maxByteSize. Remove the unused IsNumber import.
services/api/src/features/iae/api/artifact-export.controller.ts-42-52 (1)

42-52: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Map failed result envelopes to HTTP errors. Both handlers return { accepted: false, code: ... } directly. The global filter handles exceptions only, so failures return HTTP 201 from create and HTTP 200 from get. Throw mapped HttpException instances or convert failed envelopes before responding.

🤖 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 `@services/api/src/features/iae/api/artifact-export.controller.ts` around lines
42 - 52, Update the create and get methods in the artifact export controller to
inspect the service result and convert any { accepted: false, code: ... }
envelope into the appropriate mapped HttpException before returning. Preserve
successful envelopes and existing status codes, ensuring failures are handled
through exception-based HTTP responses rather than returned directly.
services/api/src/features/iae/api/artifact-retention.dto.ts-5-23 (1)

5-23: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

@IsISO8601() accepts date-only values although Swagger declares date-time. Both DTOs document a date-time format but validate with the default, non-strict @IsISO8601(), which accepts 2026-08-03. The shared root cause is the missing strict option on every timestamp field.

  • services/api/src/features/iae/api/artifact-retention.dto.ts#L5-L23: pass { strict: true } to @IsISO8601() on evaluatedAt, workspaceRetentionUntil, resourceRetentionUntil, auditRetentionUntil, and recoveryWindowUntil.
  • services/api/src/features/iae/api/inbox-item.dto.ts#L63-L69: pass { strict: true } to @IsISO8601() on dueAt, and keep @IsOptional() so an explicit null still clears the value.
🤖 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 `@services/api/src/features/iae/api/artifact-retention.dto.ts` around lines 5 -
23, Update IsISO8601 validation to use strict mode for evaluatedAt,
workspaceRetentionUntil, resourceRetentionUntil, auditRetentionUntil, and
recoveryWindowUntil in
services/api/src/features/iae/api/artifact-retention.dto.ts:5-23, and for dueAt
in services/api/src/features/iae/api/inbox-item.dto.ts:63-69. Preserve
IsOptional on dueAt so explicit null remains valid.
services/api/src/features/dsm/adapter/prisma-dataset-profile-repository.adapter.ts-147-159 (1)

147-159: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Read-then-create in save depends on the transaction isolation level. All three adapters call findUnique and then create. Two concurrent requests for the same identifier can both observe no row and both attempt the insert. The primary-key constraint prevents duplicate rows, so the second request fails with a raw Prisma unique-constraint error instead of the intended DSM_IMMUTABLE_* error. Confirm the isolation level used by $transaction, or map the unique-constraint error to the immutability error.

  • services/api/src/features/dsm/adapter/prisma-dataset-profile-repository.adapter.ts#L147-L159: catch the unique-constraint failure from datasetProfileRecord.create and re-run the comparison, or translate it to DSM_IMMUTABLE_DATASET_PROFILE.
  • services/api/src/features/dsm/adapter/prisma-dataset-quality-repository.adapter.ts#L121-L133: apply the same handling for DSM_IMMUTABLE_QUALITY_RESULT.
  • services/api/src/features/dsm/adapter/prisma-dataset-version-repository.adapter.ts#L125-L137: apply the same handling for DSM_IMMUTABLE_DATASET_VERSION.
🤖 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
`@services/api/src/features/dsm/adapter/prisma-dataset-profile-repository.adapter.ts`
around lines 147 - 159, Handle concurrent insert conflicts in save: in
services/api/src/features/dsm/adapter/prisma-dataset-profile-repository.adapter.ts
lines 147-159, catch the unique-constraint failure from
datasetProfileRecord.create and re-check or translate it to
DSM_IMMUTABLE_DATASET_PROFILE; apply equivalent handling in
services/api/src/features/dsm/adapter/prisma-dataset-quality-repository.adapter.ts
lines 121-133 for DSM_IMMUTABLE_QUALITY_RESULT and
services/api/src/features/dsm/adapter/prisma-dataset-version-repository.adapter.ts
lines 125-137 for DSM_IMMUTABLE_DATASET_VERSION.
services/api/src/features/dsm/api/dataset-quality.dto.ts-53-60 (1)

53-60: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

value accepts any type despite the documented oneOf schema.

@Allow() disables validation entirely for value. The @ApiProperty documents oneOf: [{type:'string'},{type:'number'},{type:'boolean'}], but nothing enforces that at runtime. A caller can submit an object or array for value and it passes DTO validation. Since this DTO underpins a "value-free"/"safe value" audit contract, unvalidated arbitrary payloads reaching the domain layer weakens that guarantee unless createDatasetQualityResultV1 independently re-checks the type.

🛡️ Proposed fix using a custom validator
-import { ArrayMaxSize, Allow, IsArray, IsIn, IsInt, IsString, IsUUID, IsOptional, Matches, Max, MaxLength, Min, MinLength, ValidateNested } from 'class-validator';
+import { ArrayMaxSize, IsArray, IsIn, IsInt, IsString, IsUUID, IsOptional, Matches, Max, MaxLength, Min, MinLength, ValidateBy, ValidateNested } from 'class-validator';
 ...
   `@ApiProperty`({
     required: false,
     oneOf: [{ type: 'string' }, { type: 'number' }, { type: 'boolean' }],
   })
   `@IsOptional`()
-  `@Allow`()
+  `@ValidateBy`({
+    name: 'isSafeValuePrimitive',
+    validator: {
+      validate: (v) => ['string', 'number', 'boolean'].includes(typeof v),
+      defaultMessage: () => 'value must be a string, number, or boolean',
+    },
+  })
   value?: string | number | boolean;
🤖 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 `@services/api/src/features/dsm/api/dataset-quality.dto.ts` around lines 53 -
60, Replace the unrestricted `@Allow`() validation on DatasetQuality DTO property
value with runtime validation that accepts only string, number, or boolean
values while preserving optionality. Keep the ApiProperty oneOf schema aligned
with this constraint and ensure objects and arrays are rejected before reaching
createDatasetQualityResultV1.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: de11d1ba-a94d-4185-866f-f0c78038abbe

📥 Commits

Reviewing files that changed from the base of the PR and between 8695eed and 688896a.

📒 Files selected for processing (176)
  • docs/release-evidence/sa-spreadsheet-auditor-slice.md
  • packages/domain/package.json
  • packages/domain/src/artifact-export/v1.ts
  • packages/domain/src/artifact-intake/v1.ts
  • packages/domain/src/artifact-retention/v1.ts
  • packages/domain/src/artifact-upload/v1.ts
  • packages/domain/src/artifact/v1.ts
  • packages/domain/src/dataset-export/v1.ts
  • packages/domain/src/dataset-profile/v1.ts
  • packages/domain/src/dataset-quality/v1.ts
  • packages/domain/src/protected-document/v1.ts
  • packages/domain/src/spreadsheet-audit/v1.ts
  • packages/domain/src/v1.ts
  • packages/domain/test/artifact-export-v1.test.mjs
  • packages/domain/test/artifact-intake-v1.test.mjs
  • packages/domain/test/artifact-retention-v1.test.mjs
  • packages/domain/test/artifact-upload-v1.test.mjs
  • packages/domain/test/built-public-api-smoke.mjs
  • packages/domain/test/dataset-export-v1.test.mjs
  • packages/domain/test/dataset-profile-v1.test.mjs
  • packages/domain/test/dataset-quality-v1.test.mjs
  • packages/domain/test/protected-document-v1.test.mjs
  • packages/domain/test/public-api-v1.test.mjs
  • packages/domain/test/spreadsheet-audit-v1.test.mjs
  • services/api/openapi/v1.json
  • services/api/prisma/migrations/20260802230000_iae_retention_exports/migration.sql
  • services/api/prisma/migrations/20260802240000_iae_upload_sessions/migration.sql
  • services/api/prisma/migrations/20260802250000_dsm_quality_results/migration.sql
  • services/api/prisma/migrations/20260802260000_iae_inbox_metadata/migration.sql
  • services/api/prisma/migrations/20260802270000_dsm_profiles/migration.sql
  • services/api/prisma/migrations/20260802280000_iae_protected_document_unlocks/migration.sql
  • services/api/prisma/migrations/20260802290000_dsm_export_manifests/migration.sql
  • services/api/prisma/migrations/20260802300000_sa_spreadsheet_audits/migration.sql
  • services/api/prisma/schema/dsm.prisma
  • services/api/prisma/schema/iae.prisma
  • services/api/prisma/schema/platform.prisma
  • services/api/prisma/schema/sa.prisma
  • services/api/src/app.module.ts
  • services/api/src/bootstrap.ts
  • services/api/src/features/dsm/adapter/in-memory-dataset-export-repository.adapter.ts
  • services/api/src/features/dsm/adapter/in-memory-dataset-profile-repository.adapter.ts
  • services/api/src/features/dsm/adapter/in-memory-dataset-quality-repository.adapter.ts
  • services/api/src/features/dsm/adapter/in-memory-dataset-version-repository.adapter.ts
  • services/api/src/features/dsm/adapter/prisma-dataset-export-repository.adapter.ts
  • services/api/src/features/dsm/adapter/prisma-dataset-profile-repository.adapter.ts
  • services/api/src/features/dsm/adapter/prisma-dataset-quality-repository.adapter.ts
  • services/api/src/features/dsm/adapter/prisma-dataset-version-repository.adapter.ts
  • services/api/src/features/dsm/api/dataset-export.controller.ts
  • services/api/src/features/dsm/api/dataset-export.dto.ts
  • services/api/src/features/dsm/api/dataset-profile.controller.ts
  • services/api/src/features/dsm/api/dataset-profile.dto.ts
  • services/api/src/features/dsm/api/dataset-quality.controller.ts
  • services/api/src/features/dsm/api/dataset-quality.dto.ts
  • services/api/src/features/dsm/api/dataset-version.controller.ts
  • services/api/src/features/dsm/api/dataset-version.dto.ts
  • services/api/src/features/dsm/api/governed-dataset.controller.ts
  • services/api/src/features/dsm/api/governed-dataset.dto.ts
  • services/api/src/features/dsm/api/mapping.controller.ts
  • services/api/src/features/dsm/api/mapping.dto.ts
  • services/api/src/features/dsm/api/reference-entity.controller.ts
  • services/api/src/features/dsm/api/rule-set.controller.ts
  • services/api/src/features/dsm/application/dataset-export-repository.port.ts
  • services/api/src/features/dsm/application/dataset-export.service.ts
  • services/api/src/features/dsm/application/dataset-profile-repository.port.ts
  • services/api/src/features/dsm/application/dataset-profile.service.ts
  • services/api/src/features/dsm/application/dataset-quality-repository.port.ts
  • services/api/src/features/dsm/application/dataset-quality.service.ts
  • services/api/src/features/dsm/application/dataset-version-repository.port.ts
  • services/api/src/features/dsm/application/dataset-version.service.ts
  • services/api/src/features/dsm/application/governed-dataset.service.ts
  • services/api/src/features/dsm/application/reference-entity.service.ts
  • services/api/src/features/dsm/dsm.module.ts
  • services/api/src/features/iae/adapter/in-memory-artifact-export-repository.adapter.ts
  • services/api/src/features/iae/adapter/in-memory-artifact-intake-repository.adapter.ts
  • services/api/src/features/iae/adapter/in-memory-artifact-repository.adapter.ts
  • services/api/src/features/iae/adapter/in-memory-artifact-retention-repository.adapter.ts
  • services/api/src/features/iae/adapter/in-memory-artifact-upload-repository.adapter.ts
  • services/api/src/features/iae/adapter/in-memory-artifact-upload-storage.adapter.ts
  • services/api/src/features/iae/adapter/in-memory-protected-document-secret-input.adapter.ts
  • services/api/src/features/iae/adapter/in-memory-protected-document-unlock-repository.adapter.ts
  • services/api/src/features/iae/adapter/prisma-artifact-export-repository.adapter.ts
  • services/api/src/features/iae/adapter/prisma-artifact-intake-repository.adapter.ts
  • services/api/src/features/iae/adapter/prisma-artifact-lineage-repository.adapter.ts
  • services/api/src/features/iae/adapter/prisma-artifact-repository.adapter.ts
  • services/api/src/features/iae/adapter/prisma-artifact-retention-repository.adapter.ts
  • services/api/src/features/iae/adapter/prisma-artifact-upload-repository.adapter.ts
  • services/api/src/features/iae/adapter/prisma-evidence-grant-repository.adapter.ts
  • services/api/src/features/iae/adapter/prisma-protected-document-unlock-repository.adapter.ts
  • services/api/src/features/iae/api/artifact-admission.controller.ts
  • services/api/src/features/iae/api/artifact-admission.dto.ts
  • services/api/src/features/iae/api/artifact-export.controller.ts
  • services/api/src/features/iae/api/artifact-export.dto.ts
  • services/api/src/features/iae/api/artifact-lineage.controller.ts
  • services/api/src/features/iae/api/artifact-read.controller.ts
  • services/api/src/features/iae/api/artifact-retention.controller.ts
  • services/api/src/features/iae/api/artifact-retention.dto.ts
  • services/api/src/features/iae/api/artifact-upload.controller.ts
  • services/api/src/features/iae/api/artifact-upload.dto.ts
  • services/api/src/features/iae/api/content-placement.controller.ts
  • services/api/src/features/iae/api/content-placement.dto.ts
  • services/api/src/features/iae/api/inbox-item.dto.ts
  • services/api/src/features/iae/api/inbox.controller.ts
  • services/api/src/features/iae/api/protected-document-unlock.controller.ts
  • services/api/src/features/iae/api/protected-document-unlock.dto.ts
  • services/api/src/features/iae/application/artifact-admission.service.ts
  • services/api/src/features/iae/application/artifact-export-repository.port.ts
  • services/api/src/features/iae/application/artifact-export.service.ts
  • services/api/src/features/iae/application/artifact-intake.service.ts
  • services/api/src/features/iae/application/artifact-repository.port.ts
  • services/api/src/features/iae/application/artifact-retention-repository.port.ts
  • services/api/src/features/iae/application/artifact-retention.service.ts
  • services/api/src/features/iae/application/artifact-upload-repository.port.ts
  • services/api/src/features/iae/application/artifact-upload-storage.port.ts
  • services/api/src/features/iae/application/artifact-upload.service.ts
  • services/api/src/features/iae/application/content-placement.service.ts
  • services/api/src/features/iae/application/protected-document-secret-input.port.ts
  • services/api/src/features/iae/application/protected-document-unlock-repository.port.ts
  • services/api/src/features/iae/application/protected-document-unlock.service.ts
  • services/api/src/features/iae/iae.module.ts
  • services/api/src/features/sa/adapter/in-memory-spreadsheet-audit-repository.adapter.ts
  • services/api/src/features/sa/adapter/prisma-spreadsheet-audit-repository.adapter.ts
  • services/api/src/features/sa/api/spreadsheet-audit.controller.ts
  • services/api/src/features/sa/api/spreadsheet-audit.dto.ts
  • services/api/src/features/sa/application/spreadsheet-audit-repository.port.ts
  • services/api/src/features/sa/application/spreadsheet-audit.service.ts
  • services/api/src/features/sa/sa.module.ts
  • services/api/test/features/dsm/dataset-export.controller.test.ts
  • services/api/test/features/dsm/dataset-export.service.test.ts
  • services/api/test/features/dsm/dataset-profile.controller.test.ts
  • services/api/test/features/dsm/dataset-profile.pagination.test.ts
  • services/api/test/features/dsm/dataset-profile.service.test.ts
  • services/api/test/features/dsm/dataset-quality.controller.test.ts
  • services/api/test/features/dsm/dataset-quality.service.test.ts
  • services/api/test/features/dsm/dataset-version.controller.test.ts
  • services/api/test/features/dsm/governed-dataset.controller.test.ts
  • services/api/test/features/dsm/mapping.controller.test.ts
  • services/api/test/features/dsm/prisma-dataset-export-repository.test.ts
  • services/api/test/features/dsm/prisma-dataset-profile-repository.test.ts
  • services/api/test/features/dsm/prisma-dataset-quality-repository.test.ts
  • services/api/test/features/dsm/prisma-dataset-version-repository.test.ts
  • services/api/test/features/dsm/reference-entity.controller.test.ts
  • services/api/test/features/dsm/rule-set.controller.test.ts
  • services/api/test/features/foundation-module-composition.test.ts
  • services/api/test/features/iae/artifact-admission.controller.test.ts
  • services/api/test/features/iae/artifact-admission.service.test.ts
  • services/api/test/features/iae/artifact-export.service.test.ts
  • services/api/test/features/iae/artifact-intake-metadata.service.test.ts
  • services/api/test/features/iae/artifact-lineage.controller.test.ts
  • services/api/test/features/iae/artifact-read.controller.test.ts
  • services/api/test/features/iae/artifact-retention.service.test.ts
  • services/api/test/features/iae/artifact-upload-storage.adapter.test.ts
  • services/api/test/features/iae/artifact-upload.controller.test.ts
  • services/api/test/features/iae/artifact-upload.service.test.ts
  • services/api/test/features/iae/content-placement.service.test.ts
  • services/api/test/features/iae/inbox.controller.test.ts
  • services/api/test/features/iae/prisma-artifact-export-repository.test.ts
  • services/api/test/features/iae/prisma-artifact-intake-repository.test.ts
  • services/api/test/features/iae/prisma-artifact-lineage-repository.test.ts
  • services/api/test/features/iae/prisma-artifact-repository.test.ts
  • services/api/test/features/iae/prisma-artifact-retention-repository.test.ts
  • services/api/test/features/iae/prisma-artifact-upload-repository.test.ts
  • services/api/test/features/iae/prisma-evidence-grant-repository.test.ts
  • services/api/test/features/iae/prisma-protected-document-unlock-repository.test.ts
  • services/api/test/features/iae/protected-document-unlock.controller.test.ts
  • services/api/test/features/iae/protected-document-unlock.service.test.ts
  • services/api/test/features/sa/prisma-spreadsheet-audit-repository.test.ts
  • services/api/test/features/sa/spreadsheet-audit.controller.test.ts
  • services/api/test/features/sa/spreadsheet-audit.service.test.ts
  • services/api/test/openapi.test.ts
  • services/api/test/prisma-foundation.test.mjs
  • services/engine/src/databreeze_engine/processors/__init__.py
  • services/engine/src/databreeze_engine/processors/dataset_quality.py
  • services/engine/src/databreeze_engine/processors/spreadsheet_auditor.py
  • services/engine/src/databreeze_engine/processors/spreadsheet_auditor_manifest.py
  • services/engine/tests/test_dataset_quality.py
  • services/engine/tests/test_spreadsheet_auditor.py

BeforeLights added a commit that referenced this pull request Aug 3, 2026
Merge the 30-commit CodeRabbit PR #31 repair batch into dev. CodeRabbit was skipped on this base branch by policy.
@BeforeLights

Copy link
Copy Markdown
Contributor Author

CodeRabbit review 4842552845 has been fully reproduced: 29 findings accepted and fixed through merged dev PR #32; 3 findings rejected with evidence. Full disposition: https://github.com/DatabreezeService/databreeze-platform/blob/dev/docs/operations/coderabbit-pr-31-disposition.md. No second CodeRabbit review was requested or run on this promotion PR.

@BeforeLights
BeforeLights merged commit 56011dc into main Aug 3, 2026
16 checks passed
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.

1 participant