Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
b3d0000
fix(local): require successful bootstrap readiness
BeforeLights Aug 3, 2026
5dfa1d2
docs(foundation): verify live local infrastructure
BeforeLights Aug 3, 2026
5952e37
build(infra): pin the OpenTofu validation release
BeforeLights Aug 3, 2026
815d180
style(infra): normalize OpenTofu sources
BeforeLights Aug 3, 2026
57e7c79
build(infra): lock the AWS provider selection
BeforeLights Aug 3, 2026
651425a
feat(infra): add containerized OpenTofu validation
BeforeLights Aug 3, 2026
c18c7b0
test(infra): exercise credential-free alpha planning
BeforeLights Aug 3, 2026
cc87032
docs(foundation): verify portable AWS validation
BeforeLights Aug 3, 2026
9a54b16
Merge PR #30: close promotion review and foundation gates
BeforeLights Aug 3, 2026
68e0e4a
fix(iae): bind admission to repository artifacts
BeforeLights Aug 3, 2026
069c0cd
fix(engine): bound spreadsheet XML reads
BeforeLights Aug 3, 2026
718b406
test(iae): emulate Prisma uniqueness in fixtures
BeforeLights Aug 3, 2026
5ed2cb4
fix(engine): tolerate sparse quality state counts
BeforeLights Aug 3, 2026
96553d0
fix(sa): reject duplicate blocked reasons
BeforeLights Aug 3, 2026
6d67783
fix(sa): serialize in-memory audit writes
BeforeLights Aug 3, 2026
8b31681
fix(sa): require strict UTC audit timestamps
BeforeLights Aug 3, 2026
3bfe600
fix(api): publish bounded collection contracts
BeforeLights Aug 3, 2026
fd508f9
test(iae): verify intake transition revisions
BeforeLights Aug 3, 2026
812e0c5
test(iae): harden inbox content leak assertions
BeforeLights Aug 3, 2026
42ff542
fix(api): document readiness problems by media type
BeforeLights Aug 3, 2026
f4af924
fix(iae): disclose expired upload transfers
BeforeLights Aug 3, 2026
e5c4976
fix(domain): validate normalized export text
BeforeLights Aug 3, 2026
533e7b7
test(domain): verify aggregate governance exports
BeforeLights Aug 3, 2026
eec8df5
test(sa): assert value-free finding payloads
BeforeLights Aug 3, 2026
6173abf
fix(domain): classify premature upload expiry
BeforeLights Aug 3, 2026
3f769e2
fix(sa): preserve finding validation errors
BeforeLights Aug 3, 2026
adb45ef
test(domain): guard completed upload results
BeforeLights Aug 3, 2026
d477368
fix(domain): classify premature unlock expiry
BeforeLights Aug 3, 2026
afb3fdc
fix(dsm): enforce dataset profile row budgets
BeforeLights Aug 3, 2026
3311f2a
fix(sa): support complete XLSX row geometry
BeforeLights Aug 3, 2026
4a4c781
refactor(iae): simplify inbox revision context
BeforeLights Aug 3, 2026
34495dd
fix(iae): harden export manifest persistence
BeforeLights Aug 3, 2026
5c0b1d4
fix(api): map unavailable tenant context safely
BeforeLights Aug 3, 2026
b6603eb
fix(iae): require integer admission byte sizes
BeforeLights Aug 3, 2026
c59b5b0
fix(iae): map export rejections to HTTP problems
BeforeLights Aug 3, 2026
ea3c4ed
fix(iae): require strict UTC governance dates
BeforeLights Aug 3, 2026
bc9e266
fix(dsm): translate immutable create races
BeforeLights Aug 3, 2026
e634d65
fix(dsm): constrain quality values to scalars
BeforeLights Aug 3, 2026
83fbeec
docs(review): record PR 31 dispositions
BeforeLights Aug 3, 2026
e0569f6
Merge PR #32: resolve promotion review findings
BeforeLights Aug 3, 2026
843a85d
fix(iae): forward artifact scan state
BeforeLights Aug 3, 2026
5a9cff1
fix(dso): require sequential capability revisions
BeforeLights Aug 3, 2026
0fc77d6
fix(iae): block quarantined evidence handles
BeforeLights Aug 3, 2026
2886d00
fix(iae): normalize evidence sheet lookup
BeforeLights Aug 3, 2026
4c8bd91
fix(iae): authorize persisted placement scope
BeforeLights Aug 3, 2026
677d981
fix(iam): align in-memory MFA revisions
BeforeLights Aug 3, 2026
924c48b
test(iae): enforce lineage uniqueness in fixture
BeforeLights Aug 3, 2026
55d0c6c
test(iae): bind lineage index assertion
BeforeLights Aug 3, 2026
151524e
fix(sa): group formula gaps by family
BeforeLights Aug 3, 2026
454043b
test(iam): prove bootstrap transaction client
BeforeLights Aug 3, 2026
71acbc9
test(api): prove foundation option forwarding
BeforeLights Aug 3, 2026
32b6ace
test(iae): fail closed on retention authorization
BeforeLights Aug 3, 2026
9702160
fix(iae): derive deletion requester from session
BeforeLights Aug 3, 2026
2fa1e6e
docs(review): record PR 33 dispositions
BeforeLights Aug 3, 2026
cfdb786
style(review): format promotion fixes
BeforeLights Aug 3, 2026
ea7fdab
Merge review fixes for promotion PR #33
BeforeLights Aug 3, 2026
8eccfa4
fix(android): fail closed on hostile telemetry maps
BeforeLights Aug 3, 2026
18f4a36
promote: merge dev slice 5 into main
BeforeLights Aug 3, 2026
2ff9018
fix(infra): tighten OpenTofu semantic version checks
BeforeLights Aug 3, 2026
1ff27ff
test(infra): cover strict OpenTofu version pins
BeforeLights Aug 3, 2026
7be00e3
fix(infra): make OpenTofu validation mounts read-only
BeforeLights Aug 3, 2026
238f619
test(infra): assert OpenTofu safety wording and mounts
BeforeLights Aug 3, 2026
1790f0d
fix(api): align OpenAPI timestamp and integer schemas
BeforeLights Aug 3, 2026
8622586
chore(api): regenerate OpenAPI schema
BeforeLights Aug 3, 2026
4aecc99
test(api): lock OpenAPI validator parity
BeforeLights Aug 3, 2026
dff8f01
fix(iae): map duplicate lineage conflicts
BeforeLights Aug 3, 2026
2ded1f7
test(iae): cover repository lineage conflict mapping
BeforeLights Aug 3, 2026
c3c34f7
docs(ops): record PR 37 review disposition
BeforeLights Aug 3, 2026
2201a3f
fix(test): accept wrapped OpenTofu help text
BeforeLights Aug 3, 2026
c2d0bf0
style: format review fixes
BeforeLights Aug 3, 2026
01bf508
fix: reconcile CodeRabbit PR 37 findings
BeforeLights Aug 3, 2026
3d27012
fix(dsm): reject null quality values
BeforeLights Aug 3, 2026
ffcaffb
fix(dsm): guard tenant visibility before persisted decoding
BeforeLights Aug 3, 2026
6324072
test(android): assert telemetry cause suppression
BeforeLights Aug 3, 2026
7255556
refactor(api): centralize Prisma unique constraint checks
BeforeLights Aug 3, 2026
7da3e77
fix(iae): revalidate upload transfers after issuance
BeforeLights Aug 3, 2026
0d0c57f
docs(ops): record PR 37 follow-up dispositions
BeforeLights Aug 3, 2026
3c22c78
fix: reconcile CodeRabbit PR 37 follow-ups
BeforeLights Aug 3, 2026
41af8fd
fix(api): close final promotion review findings
BeforeLights Aug 3, 2026
9f5cc05
fix: reconcile final CodeRabbit findings
BeforeLights Aug 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
*.yaml text eol=lf
*.yml text eol=lf
*.toml text eol=lf
*.hcl text eol=lf
*.ts text eol=lf
*.tsx text eol=lf
*.css text eol=lf
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ object TelemetryContract {

fun sanitizeAttributes(input: Map<String, Any?>): Map<String, Any> {
val result = linkedMapOf<String, Any>()
input.forEach { (key, value) ->
val entries = readAttributeEntries(input) ?: return emptyMap()
entries.forEach { (key, value) ->
require(key.matches(Regex("^[A-Za-z][A-Za-z0-9]{0,63}$"))) {
"invalid telemetry key"
}
Expand All @@ -62,13 +63,22 @@ object TelemetryContract {
}

fun assertSafeAttributes(input: Map<String, Any?>) {
input.forEach { (key, value) ->
val entries = readAttributeEntries(input)
?: throw IllegalArgumentException("telemetry attributes are not readable")
entries.forEach { (key, value) ->
require(key in SafeAttributeKeys && safeScalar(key, value) != null) {
"telemetry attribute is not allowed: $key"
}
}
}

private fun readAttributeEntries(input: Map<String, Any?>): List<Pair<String, Any?>>? =
try {
input.entries.map { entry -> entry.key to entry.value }
} catch (_: Exception) {
null
}

private fun safeScalar(key: String, value: Any?): Any? {
if (key == "sampled") return value as? Boolean
if (key in numericKeys || key == "status") {
Expand Down Expand Up @@ -148,9 +158,14 @@ object TelemetryContract {
}

private fun singleHeader(headers: Map<String, List<String>>, name: String): String? {
val values = headers.entries
.filter { it.key.lowercase() == name }
.flatMap { it.value }
val entries = try {
headers.entries.map { entry -> entry.key to entry.value.toList() }
} catch (_: Exception) {
throw IllegalArgumentException("telemetry headers are not readable")
}
val values = entries
.filter { it.first.lowercase() == name }
.flatMap { it.second }
require(values.size <= 1) { "ambiguous telemetry $name header" }
return values.singleOrNull()?.also { require(it.isNotEmpty()) { "empty telemetry $name header" } }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.databreeze.android.telemetry.CorrelationContext
import com.databreeze.android.telemetry.TelemetryContract
import org.junit.Assert.assertEquals
import org.junit.Assert.assertThrows
import org.junit.Assert.assertTrue
import org.junit.Test

class TelemetryContractTest {
Expand Down Expand Up @@ -73,4 +74,29 @@ class TelemetryContractTest {
)
}
}

@Test
fun providerBackedMapsFailClosedWithoutLeakingTheirCause() {
val hostileAttributes = object : Map<String, Any?> by emptyMap() {
override val entries: Set<Map.Entry<String, Any?>>
get() = throw IllegalStateException("provider attribute cause")
}
assertEquals(emptyMap<String, Any>(), TelemetryContract.sanitizeAttributes(hostileAttributes))
val attributeError = assertThrows(IllegalArgumentException::class.java) {
TelemetryContract.assertSafeAttributes(hostileAttributes)
}
assertEquals("telemetry attributes are not readable", attributeError.message)
assertTrue(attributeError.cause == null)

val hostileHeaders = object : Map<String, List<String>> by emptyMap() {
override val entries: Set<Map.Entry<String, List<String>>>
get() = throw IllegalStateException("provider header cause")
}
val headerError = assertThrows(IllegalArgumentException::class.java) {
TelemetryContract.correlationFromHeaders(hostileHeaders)
}
assertTrue(headerError.message.orEmpty().contains("not readable"))
assertTrue(!headerError.message.orEmpty().contains("provider header cause"))
assertTrue(headerError.cause == null)
}
}
50 changes: 50 additions & 0 deletions docs/operations/coderabbit-pr-31-disposition.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# CodeRabbit PR 31 Disposition

Date: 2026-08-03
Promotion PR: [#31](https://github.com/DatabreezeService/databreeze-platform/pull/31)
Automatic review ID: `4842552845`
Reviewed range: `8695eed4bd5b988af9f4bea17e724ef5e1ac101d..688896af0af45281f8d9f379837d95abed04ac6c`

CodeRabbit ran once automatically on the promotion PR. No manual review or rerun was requested. All 32 code findings were reproduced against the current `dev` state: 29 were accepted and fixed with regression coverage, and 3 were rejected after checking the later invariants and public result types.

| ID | Finding | Disposition | Evidence |
|---|---|---|---|
| I-01 | Request input could replace the repository-loaded artifact during admission. | Accepted and fixed. The trusted artifact is applied last and a runtime-key injection regression test proves the stored version remains authoritative. | `68e0e4a` |
| I-02 | XLSX XML members were fully decompressed before the size check. | Accepted and fixed. XML members now use a bounded `ZipExtFile` read and tests reject use of unbounded `ZipFile.read`. | `069c0cd` |
| O-01 | Prisma intake and export fixtures accepted duplicate primary keys. | Accepted and fixed. Both fixtures now emulate Prisma `P2002` behavior. | `718b406` |
| M-01 | Sparse quality `stateCounts` could raise `KeyError`. | Accepted and fixed with zero defaults and a sparse-profile regression test. | `5ed2cb4` |
| M-02 | Spreadsheet `blockedReasons` accepted duplicates. | Accepted and fixed with `ArrayUnique`. | `96553d0` |
| M-03 | A direct in-memory spreadsheet-audit save could be discarded by transaction rollback. | Accepted and fixed. Public saves use the transaction queue and callbacks use unwrapped helpers. | `6d67783` |
| M-04 | Spreadsheet-audit `createdAt` accepted non-UTC timestamps. | Accepted and fixed with strict ISO validation and an uppercase-`Z` timestamp pattern. | `8b31681` |
| M-05 | Several request arrays lacked matching runtime and OpenAPI bounds. | Accepted and fixed for version IDs, fields, mapping steps, rules, artifact inputs, evidence IDs, and findings. | `3bfe600` |
| M-06 | The intake transition test did not verify the persisted revision. | Accepted and fixed. | `fd508f9` |
| M-07 | Inbox content-leak assertions were case-sensitive. | Accepted and fixed. | `812e0c5` |
| M-08 | Readiness 503 responses documented the wrong media type. | Accepted and fixed as `application/problem+json`, with a generated-contract assertion. | `42ff542` |
| M-09 | Expired upload transfer requests were reported as generic storage unavailability. | Accepted and fixed with `UPLOAD_SESSION_EXPIRED`. | `f4af924` |
| M-10 | Export processor-version text was validated before normalization and trimming. | Accepted and fixed; empty normalized text is rejected and valid trimmed text is retained. | `e5c4976` |
| M-11 | Aggregate public API smoke coverage omitted retention and export schema versions. | Accepted and fixed. | `533e7b7` |
| M-12 | The dataset-profile negative test allegedly mixed a sampling error with its count error. | Rejected. `samplingMethod` is required for both completeness modes; the fixture removes only the sample seed when switching to `COMPLETE`, so the first negative case already isolates `INVALID_COUNT`. Clearing `samplingMethod` would create the ambiguity the comment sought to remove. | `packages/domain/test/dataset-profile-v1.test.mjs` |
| M-13 | The spreadsheet value-free test inspected the manifest root rather than the finding. | Accepted and fixed. | `eec8df5` |
| M-14 | Premature upload expiration returned `EXPIRED`. | Accepted and fixed as `INVALID_TIMESTAMP`. | `6173abf` |
| M-15 | Spreadsheet finding parser errors collapsed into `INVALID_COUNT`. | Accepted and fixed. Coordinate, kind, severity, identifier, and hash errors now retain their structural codes. | `3f769e2` |
| M-16 | The upload completion test read `.value` without proving acceptance. | Accepted and fixed. | `adb45ef` |
| M-17 | Premature protected-document expiration returned `EXPIRED`. | Accepted and fixed as `INVALID_STATE`. | `d477368` |
| M-18 | Dataset profiles allowed `rowCountScanned` above `resourceLimits.maxRows`. | Accepted and fixed. | `afb3fdc` |
| M-19 | Spreadsheet `maxRow` stopped below the XLSX row limit. | Accepted and fixed across domain validation, DTO validation, and generated OpenAPI at 1,048,576. | `3311f2a` |
| M-20 | Inbox mutation context contained an unreachable conditional branch. | Accepted and simplified after the existing undefined guard. | `4a4c781` |
| M-21 | Prisma export saves lacked visibility-safe collision handling, transaction-wrapped direct saves, and create-race translation. | Accepted and fixed with tenant-safe checks and stable immutable-manifest errors. | `34495dd` |
| M-22 | Artifact-lineage lookup should use `findMany` to select a visible row. | Rejected against current `dev`. Later commits `68e69df` and `6431c9a` enforce one globally unique lineage per derived version; the unique lookup then checks tenant visibility. `findMany` would weaken that invariant and conceal duplicate persisted state. | `services/api/src/features/iae/adapter/prisma-artifact-lineage-repository.adapter.ts` |
| M-23 | Retention and content-placement service-only error unions omitted domain result codes. | Rejected. `ArtifactRetentionServiceResultV1` already includes `ArtifactRetentionResultV1`, and `ContentPlacementServiceResultV1` already includes `ArtifactResultV1`; both public unions therefore expose the cited codes without duplicating them in their service-only error aliases. | Service result type definitions |
| M-24 | The default request-tenant-context adapter produced a generic 500. | Accepted and fixed. The shared problem error now maps the unconfigured provider to retryable `AUTHENTICATION_UNAVAILABLE`/503. | `5c0b1d4` |
| M-25 | Artifact admission accepted fractional byte sizes at the DTO boundary. | Accepted and fixed with integer runtime validation and OpenAPI type. | `b6603eb` |
| M-26 | Artifact-export controllers returned failed service envelopes with HTTP 200. | Accepted and fixed. Invalid requests map to 400 problems and missing resources to 404 problems. | `c59b5b0` |
| M-27 | Retention and inbox date-time DTOs accepted date-only or offset values. | Accepted and fixed with strict ISO/UTC validation while preserving nullable inbox `dueAt`. | `ea3c4ed` |
| M-28 | DSM immutable repositories leaked Prisma create races. | Accepted and fixed for dataset profiles, quality results, and dataset versions by translating `P2002` into their stable immutable error codes. | `bc9e266` |
| M-29 | Dataset quality safe values accepted objects and arrays despite the scalar OpenAPI contract. | Accepted and fixed with a finite scalar validator and an object-injection regression test. | `e634d65` |

## Release handling

- Fixes are applied through a dedicated PR to `dev`; CodeRabbit is not invoked on that PR.
- After the fix PR merges, the two critical inline discussions receive the fixing commit references and the promotion PR receives a link to this disposition.
- PR #31 remains a historical promotion slice. It receives no second CodeRabbit run and is merged only after the repair PR and required checks pass.
- The generic docstring-coverage warning was not treated as a code finding: it did not identify a changed runtime defect, and bulk comments would add noise without improving the reviewed behavior.
37 changes: 37 additions & 0 deletions docs/operations/coderabbit-pr-33-disposition.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# CodeRabbit disposition for promotion PR 33

Promotion PR [#33](https://github.com/DatabreezeService/databreeze-platform/pull/33)
received exactly one automatic CodeRabbit review (`4843018511`) for the
historical range `56011dc633fe8d999d96a6ea26fdc64319447a8e..12d92716ad287544e0d6149925e0496273306d51`.
The review contained seven inline findings and eight review-body findings. Each
claim was reproduced against current `dev` before disposition. CodeRabbit was
not invoked again.

| ID | Claim | Disposition | Evidence |
|---|---|---|---|
| CR33-01 | Spreadsheet evidence lookup compared canonical coordinates with an unnormalized geometry name. | Accepted and fixed. | `2886d00`; domain regression for a whitespace-normalized sheet name. |
| CR33-02 | Placement mutation authorized the caller-supplied scope instead of the persisted placement scope. | Accepted and fixed in both adapters. | `4c8bd91`; Prisma and in-memory sibling-workspace mutation regressions. |
| CR33-03 | In-memory MFA state allowed record removal and invalid initial revisions. | Accepted and fixed to match the Prisma invariants. | `677d981`; factor and recovery-code removal/new-revision regressions. |
| CR33-04 | Prisma MFA updates were not revision-conditional. | Rejected as already resolved on current `dev`. | `e668bd4` uses `updateMany` with the prior revision and requires `count === 1` for factors and recovery codes; existing race tests pass. |
| CR33-05 | The lineage repository test double did not enforce the derived-version unique constraint. | Accepted and fixed. | `924c48b`; the fake reports a Prisma-style `P2002` and retains one row. |
| CR33-06 | The migration test asserted only the lineage index name. | Accepted and fixed. | `55d0c6c`; the assertion binds the unique index, schema-qualified relation, and column. |
| CR33-07 | Formula-gap detection paired rows before grouping by formula family. | Accepted and fixed. | `151524e`; a different intervening formula now produces the expected value-free gap finding. |
| CR33-08 | The public Prisma artifact adapter dropped an optional scan state. | Accepted and fixed. | `843a85d`; direct adapter regression proves `PENDING` to `CLEAN` persistence. |
| CR33-09 | Capability and grant replacements did not require exactly one revision step. | Accepted and fixed. | `5a9cff1`; invalid same/skipped revisions fail with `DSO_REVISION_CONFLICT`. |
| CR33-10 | Quarantined evidence could resolve to a live placement handle. | Accepted and fixed. | `0fc77d6`; quarantined cloud evidence resolves only to `UNAVAILABLE`. |
| CR33-11 | The bootstrap test passed the base client as its transaction client. | Accepted and strengthened. | `454043b`; a distinct transaction client records all four hierarchy writes. |
| CR33-12 | The application composition test did not prove audit and entitlement option forwarding. | Accepted and strengthened. | `71acbc9`; child-module providers retain the exact repository identities. |
| CR33-13 | The lineage unique index should be built concurrently. | Rejected for this migration stage. | Plan 010 introduces no customer workflow or production data migration; ADR-0002 uses ordinary Prisma SQL migrations. `CREATE INDEX CONCURRENTLY` cannot run in Prisma's ordinary transactional migration path, while the production expand/migrate/verify/contract gate remains in Plan 400. |
| CR33-14 | A retention test could pass without asserting failed authorization. | Accepted and strengthened. | `32b6ace`; the unexpected result branch now fails explicitly. |
| CR33-15 | `requestedBy` remained required although attribution uses the authenticated actor. | Accepted and fixed compatibly. | `9702160`; the field is optional/deprecated, omission succeeds, generated OpenAPI records authenticated attribution. |

The generic docstring-coverage warning is informational rather than a repository
gate: DataBreeze has no accepted 80% docstring requirement, and adding comments
solely to satisfy an external heuristic would not repair behavior. Existing
documentation and lint/type/test gates remain authoritative.

The accepted changes are collected on `fix/coderabbit-promotion-33`. They are
not pushed directly into the historical promotion branch, so PR 33's reviewed
commit range remains immutable. They will enter `dev` through the next
30–50-commit feature batch and reach `main` through a later single-review
promotion slice.
46 changes: 46 additions & 0 deletions docs/operations/coderabbit-pr-37-disposition.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# CodeRabbit PR #37 disposition

Review run: `d034f311-c043-4139-8372-ed69b774a83f`
Review policy: one automatic review run for this promotion PR; no rerun.

After the fixes were pushed, the CodeRabbit app automatically queued a
follow-up status check (`6fd78011-f34d-414f-a9a8-2a696e772375`). No review was
manually invoked; its two additional findings were verified and included below.

All seven inline findings were valid and are addressed below. The same review
body also contained three outside-diff findings and two nitpicks. Those were
verified against the current code and addressed where they described an
observable correctness, isolation, or test gap. The general walkthrough/
docstring coverage warning was not adopted because the repository has no
accepted coverage threshold for that warning and the promotion gate is the
executable repository check plus focused tests.

| Comment | Disposition | Fix commit | Evidence |
| --- | --- | --- | --- |
| OpenTofu README init should use `-lockfile=readonly` | Accepted | `7be00e3` | `infrastructure/aws/README.md` documents the locked native initialization command. |
| OpenAPI timestamp and integer schemas did not match runtime validation | Accepted | `1790f0d`, `8622586`, `4aecc99` | DTO patterns/types, regenerated `services/api/openapi/v1.json`, and parity assertions in `services/api/test/openapi.test.ts`. |
| Duplicate derived lineage P2002 escaped the repository port | Accepted | `dff8f01`, `2ded1f7` | P2002 maps to `IAE_DERIVED_LINEAGE_CONFLICT`; repository-save race test covers the path. |
| OpenTofu version checks allowed leading-zero components | Accepted | `2ff9018`, `1ff27ff` | Both validators use strict SemVer components; acceptance/rejection cases are tested. |
| Validation help/success wording understated the mocked plan test | Accepted | `7be00e3`, `238f619` | Help and source assertions describe mocked plan testing and no apply. |
| OpenTofu source mount was writable | Accepted | `7be00e3`, `238f619` | The container source bind is explicitly `readonly`; the test asserts the mount. |
| Infrastructure test did not verify the read-only mount | Accepted | `238f619` | Test asserts the mount, README lockfile option, and safety wording. |

## Outside-diff and nitpick follow-ups

| Finding | Disposition | Fix commit | Evidence |
| --- | --- | --- | --- |
| `DatasetQualitySafeValueDto.value` skipped validation for `null` | Accepted | `3d27012` | `ValidateIf` keeps `undefined` optional while rejecting `null`; the controller test covers the nested null payload. |
| DSM version/profile/quality saves decoded a sibling row before checking visibility | Accepted | `ffcaffb` | All three Prisma adapters check tenant visibility before `rowToDomain`; malformed sibling-row tests expect the stable immutable error. |
| Upload transfer issuance could use a stale session around expiry | Accepted | `7da3e77` | Issuance runs in the repository transaction, re-reads the session, aborts the storage grant on state/revision change, and has a simulated expiry race test. |
| Android telemetry tests did not assert exception causes were absent | Accepted | `6324072` | Tests assert both provider-backed exception causes are `null`. |
| Prisma P2002 predicates were duplicated across feature adapters | Accepted | `7255556` | The predicate now lives in `src/platform/prisma-error.ts`; DSM and IAE adapters share it. |

## Automatic follow-up findings

| Finding | Disposition | Fix commit | Evidence |
| --- | --- | --- | --- |
| Lineage P2002 handling treated every unique conflict as a derived-version conflict | Accepted | final review-fix commit | P2002 `meta.target` distinguishes `id` from `derivedArtifactVersionId`; same-ID races re-run immutable comparison and have a regression fixture. |
| `AdmitArtifactDto.maxByteSize` was documented as a number despite `@IsInt()` | Accepted | final review-fix commit | DTO metadata, regenerated OpenAPI, and assertions now document both byte-size fields as integers. |

No review comment authorized applying infrastructure or changing provider
boundaries; those remain outside this promotion slice.
Loading
Loading