feat: add object storage production capability
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
# Object Storage Batch A Checkpoint
|
||||
|
||||
- Date: 2026-07-28
|
||||
- Branch: `codex/objectstorage-production-capability`
|
||||
- Worktree:
|
||||
`/home/donghyeon/workspace/clean-architecture-backend-template-objectstorage`
|
||||
- Claimed level: R0 application contract only
|
||||
- Provider readiness advanced: no
|
||||
|
||||
## Implemented scope
|
||||
|
||||
- Characterized the legacy caller-key overwrite, whole-object materialization, locator exposure,
|
||||
eager filesystem directory creation, optional S3 bucket provisioning, and Poster transaction/API
|
||||
coupling without changing those behaviors.
|
||||
- Added provider-neutral identities, opaque checked references/handles, bounded streaming
|
||||
callbacks, content identity, digest/range values, requests, receipts, outcomes, and narrow ports
|
||||
under `dev.caskeleton.application.objectstorage`.
|
||||
- Required an `ObjectOperationKey` on mutation requests and separated normal publication,
|
||||
scan-maintenance, purge-maintenance, direct, and staged privilege surfaces.
|
||||
- Added recursive contract-purity tests and an ArchUnit freeze for the one existing sample legacy
|
||||
import.
|
||||
- Marked the legacy `ObjectStoragePort` and `StoredObject` as removal boundaries without adapting
|
||||
new semantic calls back to raw keys.
|
||||
|
||||
No provider-neutral kernel, canonical namespace/control codec, local R1 provider, S3/MinIO
|
||||
qualification, sample migration, or R2 readiness claim is included.
|
||||
|
||||
## TDD evidence
|
||||
|
||||
The planned RED checks failed only for the intentionally missing types or removal annotations:
|
||||
|
||||
- `ObjectStorageIdentityContractTest`: missing identity types before Task 2 implementation.
|
||||
- `ObjectContentContractTest` and `ObjectStorageValueContractTest`: missing content/value types
|
||||
before Task 3 implementation.
|
||||
- `ObjectStoragePortContractTest`: missing request/receipt/port family before Task 4 implementation.
|
||||
- `ObjectStorageArchitectureContractTest`: missing legacy removal annotations before Task 5
|
||||
implementation.
|
||||
|
||||
An initial ArchUnit DSL compilation error was a test-authoring error, not accepted as a RED result;
|
||||
the rule was corrected and rerun.
|
||||
|
||||
## GREEN verification
|
||||
|
||||
All commands ran from `src/` and completed with `BUILD SUCCESSFUL`:
|
||||
|
||||
```bash
|
||||
./gradlew :application-core:resolveAndLockAll --write-locks
|
||||
./gradlew :application-core:verifyDependencyLocks --console=plain
|
||||
./gradlew :application-core:test --tests '*ObjectStorageIdentityContractTest' --console=plain
|
||||
./gradlew :application-core:test \
|
||||
--tests '*ObjectContentContractTest' \
|
||||
--tests '*ObjectStorageValueContractTest' --console=plain
|
||||
./gradlew :application-core:test --tests '*ObjectStoragePortContractTest' --console=plain
|
||||
./gradlew :application-core:test \
|
||||
--tests '*ObjectStorageArchitectureContractTest' --console=plain
|
||||
./gradlew :app-bootstrap:test --tests '*CleanArchitectureTest' --console=plain
|
||||
./gradlew :application-core:check --console=plain
|
||||
./gradlew verifyCleanArchitectureDependencies --console=plain
|
||||
./gradlew :adapter:outbound:objectstorage:test :sample-portfolio:test --console=plain
|
||||
```
|
||||
|
||||
The final combined legacy focused suites completed in 27 seconds. Deprecation-for-removal warnings
|
||||
are expected evidence that legacy consumers remain visible; they are not suppressed.
|
||||
|
||||
## LLM Wiki capture
|
||||
|
||||
The canonical vault required by repository policy,
|
||||
`/home/donghyeon/workspace/ai-tool/llm-wiki-private/`, and its parent
|
||||
`/home/donghyeon/workspace/ai-tool/` do not exist in this environment. Therefore the required
|
||||
`raw/branch-notes/codex-objectstorage-production-capability.md` could not be created or updated.
|
||||
No similarly named non-canonical clone was used. This exact access block is recorded in both the
|
||||
plan and design headers and here at the Batch A boundary.
|
||||
|
||||
## Remaining gates and risks
|
||||
|
||||
- External broker and REST consumers and deployed legacy data were not inspected; Gate A remains
|
||||
blocked for legacy removal or public API versioning.
|
||||
- The new contracts have no provider implementation yet.
|
||||
- The current legacy adapter retains whole-object and raw-locator behavior by design until the
|
||||
later migration batch.
|
||||
- No readiness registry row is promoted by this checkpoint.
|
||||
@@ -0,0 +1,109 @@
|
||||
# Object Storage Batch B Checkpoint
|
||||
|
||||
- Date: 2026-07-28
|
||||
- Branch: `codex/objectstorage-production-capability`
|
||||
- Worktree:
|
||||
`/home/donghyeon/workspace/clean-architecture-backend-template-objectstorage`
|
||||
- Evidence grade: repository-local non-skipping unit/contract/application-context tests
|
||||
- Advanced cards: local managed single upload R1, local managed download R1
|
||||
- R2 or production-provider readiness advanced: no
|
||||
|
||||
## Implemented scope
|
||||
|
||||
- Added deterministic data/control namespaces, opaque reference/handle codecs, canonical request
|
||||
fingerprints, frozen binding/policy revisions, and bounded operation epochs.
|
||||
- Added six strict canonical JSON control-record families with fixed field order, outer SHA-256
|
||||
envelopes, schema/size checks, corruption rejection, and checked-in golden digests.
|
||||
- Added provider-neutral publication, scan, reference, direct-session, multipart, and pending-effect
|
||||
state transitions with same-operation replay and conflicting-intent rejection.
|
||||
- Added a provider contract and `filesystem-local-dev` implementation with bounded streaming,
|
||||
immutable exclusive create, SHA-256 verification, exact inspect/version, full/range transfer,
|
||||
conditional retirement, create resolution, restrictive permissions, and path/symlink
|
||||
confinement.
|
||||
- Added single-process exact-version control CAS and restart/corruption/fault characterization.
|
||||
Logical control keys use `.record` physical leaves locally so object-store-valid prefix/leaf key
|
||||
pairs cannot collide as filesystem file/directory paths.
|
||||
- Added constructor-bound `app.object-storage` settings and compile-before-construction
|
||||
provider/destination/route/policy binding. The capability is disabled by default and
|
||||
`filesystem-local-dev` is rejected for `prod`/`production`.
|
||||
- Added disabled, unselected, invalid, selected-success, selected-construction-failure, close,
|
||||
legacy-only, and namespace-separated dual-run composition tests.
|
||||
- Added semantic routing evidence for publish, replay without producer invocation, inspect,
|
||||
full transfer, absent reference, and exact retained route lookup.
|
||||
- Added the exact nine-card readiness registry. Only local managed single upload/download are R1;
|
||||
direct, multipart, quarantine, retention, and production reconciliation remain R0.
|
||||
|
||||
## TDD and defect evidence
|
||||
|
||||
Planned RED checks failed for the intentionally absent codec/kernel/provider/settings/readiness
|
||||
types before each implementation. Additional tests found and drove these corrections:
|
||||
|
||||
- Local control keys may legally have both a leaf and a child in object storage, while a filesystem
|
||||
cannot have both `reference` and `reference/lifecycle`; local physical `.record` mapping fixed the
|
||||
collision without changing logical keys.
|
||||
- `ObjectInspectionPort.inspect` initially threw for an absent known-route reference; it now
|
||||
returns `Optional.empty()` while incomplete/corrupt evidence still fails closed.
|
||||
- The application purity test initially scanned its own test output after a full `check`; it now
|
||||
derives the production class root from a production contract type.
|
||||
- The general B7 ArchUnit rule initially classified objectstorage provider-internal SPI/control
|
||||
return values as public adapter responses. The existing negative fixture remains active, while a
|
||||
dedicated non-empty rule now checks the actual objectstorage `*Adapter` semantic boundaries.
|
||||
|
||||
No skipped Docker or external-service test is used as Batch B readiness evidence.
|
||||
|
||||
## GREEN verification
|
||||
|
||||
All commands ran from `src/` unless noted and completed with `BUILD SUCCESSFUL` after the documented
|
||||
RED/fix cycles:
|
||||
|
||||
```bash
|
||||
./gradlew :adapter:outbound:objectstorage:verifyDependencyLocks --console=plain
|
||||
./gradlew :adapter:outbound:objectstorage:test \
|
||||
--tests '*ObjectNamespaceCodecTest' \
|
||||
--tests '*ObjectRequestFingerprintCodecTest' \
|
||||
--tests '*ObjectOperationEpochTest' --console=plain
|
||||
./gradlew :adapter:outbound:objectstorage:test \
|
||||
--tests '*ObjectControlRecordCodecTest' \
|
||||
--tests '*ObjectOperationStateMachineTest' \
|
||||
--tests '*ObjectOperationKernelTest' --console=plain
|
||||
./gradlew :adapter:outbound:objectstorage:test \
|
||||
--tests '*ObjectStorageProviderContract' \
|
||||
--tests '*LocalDevObjectStorageProviderTest' \
|
||||
--tests '*LocalDevObjectStorageRecoveryTest' --console=plain
|
||||
./gradlew :adapter:outbound:objectstorage:test \
|
||||
--tests '*ObjectStorageBindingCompilerTest' \
|
||||
--tests '*ObjectStorageCapabilityConfigTest' \
|
||||
--tests '*RoutingObjectStorageAdapterTest' --console=plain
|
||||
./gradlew :adapter:outbound:objectstorage:test \
|
||||
--tests '*ObjectStorageReadinessRegistryTest' --console=plain
|
||||
./gradlew :sample-portfolio:test --console=plain
|
||||
./gradlew :application-core:check \
|
||||
:adapter:outbound:objectstorage:check --console=plain
|
||||
./gradlew :app-bootstrap:test --tests '*CleanArchitectureTest' --console=plain
|
||||
./gradlew verifyCleanArchitectureDependencies --console=plain
|
||||
```
|
||||
|
||||
The final combined application/objectstorage checkpoint completed in 23 seconds. The focused
|
||||
Clean Architecture suite and dependency verification also passed.
|
||||
|
||||
## LLM Wiki capture
|
||||
|
||||
The canonical vault required by repository policy,
|
||||
`/home/donghyeon/workspace/ai-tool/llm-wiki-private/`, and its parent
|
||||
`/home/donghyeon/workspace/ai-tool/` do not exist in this environment. Therefore the required
|
||||
`raw/branch-notes/codex-objectstorage-production-capability.md` and any derived raw documents could
|
||||
not be created or updated. No similarly named non-canonical clone was used. This exact access block
|
||||
is recorded in the plan/design status and at this Batch B boundary.
|
||||
|
||||
## Remaining gates and risks
|
||||
|
||||
- `filesystem-local-dev` has no multi-node linearizability or power-loss durability evidence and is
|
||||
forbidden in production profiles.
|
||||
- The canonical S3/MinIO provider contribution, async bounded transport, provider qualification,
|
||||
response-loss fault tests, and protected AWS evidence are not implemented.
|
||||
- Direct grants, multipart, quarantine/scan, retention/legal hold, privileged purge, reapers, and
|
||||
production reconciliation remain R0.
|
||||
- The sample Poster workflow still uses the deprecated whole-`byte[]` port and transaction-coupled
|
||||
legacy choreography. It is explicitly activated only in sample local/test configuration.
|
||||
- External API/broker consumers and deployed legacy data remain uninspected, so Gate A still blocks
|
||||
destructive migration or legacy removal.
|
||||
@@ -0,0 +1,84 @@
|
||||
# Object Storage Batch C Checkpoint
|
||||
|
||||
- Date: 2026-07-28
|
||||
- Branch: `codex/objectstorage-production-capability`
|
||||
- Worktree:
|
||||
`/home/donghyeon/workspace/clean-architecture-backend-template-objectstorage`
|
||||
- Evidence grade: repository-local tests plus digest-pinned single-node MinIO/Toxiproxy tests
|
||||
- AWS execution: not authorized; source set compiled only
|
||||
- Production-provider readiness advanced: no
|
||||
|
||||
## Implemented scope
|
||||
|
||||
- Added exact AWS S3 and MinIO provider bindings, bounded evidence descriptors, qualifier/error
|
||||
mapping, secret references, endpoint/owner/addressing validation, and selected-only lifecycle
|
||||
construction.
|
||||
- Added bounded async request/response bridges and the managed S3 put, inspect, full/range download,
|
||||
checksum, exact-version, cancellation, and content-length paths.
|
||||
- Added canonical conditional S3 control storage and operation response-loss resolution. Provider
|
||||
ETags remain adapter-private and are never exposed as logical versions.
|
||||
- Added low-level managed multipart planning, sharded immutable part ledgers, initiate-before-I/O
|
||||
state, explicit create/upload/list/complete/abort calls, and exact completion verification.
|
||||
- Added non-skipping MinIO contract/fault lanes, an AWS compile-only qualification lane, a protected
|
||||
workflow, and gate-matrix coverage.
|
||||
|
||||
The exact MinIO image is
|
||||
`minio/minio@sha256:4c4a4876193f030c81f57aabb22bcb9a73462010eb61fcab66908e03e5484af8`.
|
||||
The exact Toxiproxy image is
|
||||
`ghcr.io/shopify/toxiproxy@sha256:9378ed52a28bc50edc1350f936f518f31fa95f0d15917d6eb40b8e376d1a214e`.
|
||||
|
||||
## Exact MinIO finding
|
||||
|
||||
Real-provider tests proved an asymmetric conditional profile:
|
||||
|
||||
- `PutObject If-None-Match: *` was accepted but overwrote an existing object.
|
||||
- stale `PutObject If-Match` was rejected with HTTP 412.
|
||||
- `CompleteMultipartUpload If-None-Match: *` was accepted and overwrote an existing object.
|
||||
- checksum, HEAD, and range behavior passed the exercised contract.
|
||||
|
||||
Because immutable create and create-if-absent control CAS cannot be proven, the exact MinIO managed
|
||||
and direct mutation profiles remain `UNSUPPORTED`. The implementation does not emulate missing
|
||||
atomicity with HEAD followed by an unconditional write and does not promote a readiness card.
|
||||
|
||||
## TDD and verification
|
||||
|
||||
The task-focused RED runs first failed on the planned absent binding, bridge, conditional store,
|
||||
multipart, and qualification types. Provider qualification then found the real MinIO conditional
|
||||
behavior above; the descriptor and negative contract were changed instead of weakening the
|
||||
contract.
|
||||
|
||||
Commands completed with `BUILD SUCCESSFUL`:
|
||||
|
||||
```bash
|
||||
cd src
|
||||
./gradlew :adapter:outbound:objectstorage:test \
|
||||
--tests '*S3ProviderBindingTest' \
|
||||
--tests '*S3ProviderQualifierTest' \
|
||||
--tests '*S3ProviderCompositionTest' --console=plain
|
||||
./gradlew :adapter:outbound:objectstorage:objectStorageMinioContractTest --console=plain
|
||||
./gradlew :adapter:outbound:objectstorage:objectStorageMinioFaultTest --console=plain
|
||||
./gradlew :adapter:outbound:objectstorage:objectStorageAwsQualificationTestClasses --console=plain
|
||||
./gradlew :adapter:outbound:objectstorage:check --console=plain
|
||||
./gradlew :adapter:outbound:objectstorage:verifyDependencyLocks \
|
||||
verifyCleanArchitectureDependencies --console=plain
|
||||
bash ../.github/scripts/verify-gate-matrix.sh
|
||||
```
|
||||
|
||||
The gate matrix reports 22 gates: 21 verified and the protected AWS qualification gate explicitly
|
||||
`delegated-pending`.
|
||||
|
||||
## LLM Wiki capture
|
||||
|
||||
The canonical vault `/home/donghyeon/workspace/ai-tool/llm-wiki-private/` and its parent
|
||||
`/home/donghyeon/workspace/ai-tool/` do not exist in this environment. The required
|
||||
`raw/branch-notes/codex-objectstorage-production-capability.md` and derived raw documents could not
|
||||
be created or updated. No similarly named non-canonical clone was used.
|
||||
|
||||
## Remaining risks
|
||||
|
||||
- No AWS request was executed, so there is no observed AWS provider claim.
|
||||
- The pinned MinIO topology is a local single-node container and is not production TLS,
|
||||
multi-node, durability, or linearizability evidence.
|
||||
- The detailed managed multipart fault matrix is not exhaustive enough for R2.
|
||||
- No sample migration, public API, scan/publication choreography, retention, purge, or reaper is
|
||||
included in this checkpoint.
|
||||
@@ -0,0 +1,104 @@
|
||||
# Object Storage Batch D Checkpoint
|
||||
|
||||
- Date: 2026-07-28
|
||||
- Branch: `codex/objectstorage-production-capability`
|
||||
- Worktree:
|
||||
`/home/donghyeon/workspace/clean-architecture-backend-template-objectstorage`
|
||||
- Scope: direct-transfer provider/application primitives only
|
||||
- Public endpoint: none
|
||||
- Readiness advanced: no; all direct cards remain R0
|
||||
|
||||
## Implemented scope
|
||||
|
||||
- Added direct single-upload session policy, durable prepared/issued transitions, bearer
|
||||
redaction, exact completion verification, published-version download resolution, and an
|
||||
S3-presigner lifecycle owned by the selected provider.
|
||||
- Added direct multipart durable session and part-grant families, opaque acknowledgement tokens,
|
||||
sharded part records, admission-close/expiry fencing, exact ledger validation, completion/abort
|
||||
states, response-loss resolution, and persisted terminal exact-version replay.
|
||||
- Added direct S3 initiate/discovery, exact-part presign, `ListParts` acknowledgement, conditional
|
||||
complete followed by exact HEAD verification, and abort resolution.
|
||||
- Registered direct single and multipart delegates only when their exact compiled capability is
|
||||
selected. One presigner is constructed and closed exactly once.
|
||||
- Added golden canonical envelopes for the direct session, direct multipart session, and direct
|
||||
multipart grant families.
|
||||
- Fixed `MultipartCompleteRequest` null validation so valid immutable `List.of(...)` input no longer
|
||||
throws from `contains(null)`.
|
||||
|
||||
## Qualification truth
|
||||
|
||||
The exact MinIO release cannot prove create-only PUT or create-only multipart completion, so both
|
||||
direct profiles are explicitly `UNSUPPORTED`. The direct MinIO contract/fault lanes are negative
|
||||
admission tests: they prove no bearer or multipart mutation enters an unsupported profile. No test
|
||||
skip is used as positive evidence.
|
||||
|
||||
The AWS managed/direct source sets compile, but no AWS call was made and no AWS evidence row was
|
||||
published. No inbound controller, authorization surface, CORS runtime configuration, or public
|
||||
direct API exists.
|
||||
|
||||
## Verification
|
||||
|
||||
Commands completed with `BUILD SUCCESSFUL`:
|
||||
|
||||
```bash
|
||||
cd src
|
||||
./gradlew :adapter:outbound:objectstorage:test \
|
||||
--tests '*DirectTransferCoordinatorTest' \
|
||||
--tests '*PresignedGrantRedactionTest' \
|
||||
--tests '*S3DirectTransferProviderTest' \
|
||||
--tests '*ObjectControlRecordCodecTest' \
|
||||
--tests '*S3ProviderCompositionTest' --console=plain
|
||||
./gradlew :adapter:outbound:objectstorage:test \
|
||||
--tests '*DirectMultipartCoordinatorTest' \
|
||||
--tests '*DirectMultipartRaceTest' \
|
||||
--tests '*S3DirectMultipartProviderTest' \
|
||||
--tests '*ObjectControlRecordCodecTest' \
|
||||
--tests '*S3ProviderCompositionTest' --console=plain
|
||||
./gradlew \
|
||||
:adapter:outbound:objectstorage:objectStorageMinioContractTest \
|
||||
:adapter:outbound:objectstorage:objectStorageMinioFaultTest \
|
||||
--tests '*DirectTransfer*' --console=plain
|
||||
./gradlew :adapter:outbound:objectstorage:test \
|
||||
--tests '*DirectTransferCorsContractTest' --console=plain
|
||||
./gradlew :adapter:outbound:objectstorage:objectStorageAwsQualificationTestClasses --console=plain
|
||||
./gradlew :adapter:outbound:objectstorage:check --console=plain
|
||||
./gradlew :adapter:outbound:objectstorage:verifyDependencyLocks \
|
||||
verifyCleanArchitectureDependencies --console=plain
|
||||
./gradlew \
|
||||
:adapter:outbound:objectstorage:objectStorageMinioContractTest \
|
||||
:adapter:outbound:objectstorage:objectStorageMinioFaultTest --console=plain
|
||||
bash ../.github/scripts/verify-gate-matrix.sh
|
||||
./gradlew test --console=plain
|
||||
./gradlew check --console=plain
|
||||
```
|
||||
|
||||
The module `check` includes unit tests, Checkstyle, Spotless, SpotBugs, architecture, configuration
|
||||
processor, environment-key, and repository-wide policy checks. Existing test-only compiler
|
||||
warnings remain non-failing. The final repository-wide test run completed 79 tasks and the final
|
||||
repository-wide check completed 214 tasks.
|
||||
|
||||
## Deliberate limitations
|
||||
|
||||
- Issued bearer material is process-local. A restart fails closed instead of reconstructing or
|
||||
reissuing an already-issued bearer.
|
||||
- The signing clock/window is stored and bounded, but AWS SDK presigner query timing is not driven
|
||||
by the injected application clock.
|
||||
- The direct multipart recovery/race matrix covers its principal fences and completion response
|
||||
loss but is not exhaustive enough for an R2 claim.
|
||||
- Retention/Object Lock grant headers and a provider-enforced direct-single hard size ceiling are
|
||||
not qualified.
|
||||
- No public endpoint exists, so CORS evidence is a pure contract and no direct card may exceed R0
|
||||
in the current registry.
|
||||
|
||||
## Approval Gate A
|
||||
|
||||
Tasks 20–24 remain blocked until the user explicitly approves scanner ownership, the sample's
|
||||
first publication profile, the additive asynchronous API/status contract, and digest transport.
|
||||
No scan/publication/sample endpoint implementation was started.
|
||||
|
||||
## LLM Wiki capture
|
||||
|
||||
The canonical vault `/home/donghyeon/workspace/ai-tool/llm-wiki-private/` and its parent
|
||||
`/home/donghyeon/workspace/ai-tool/` do not exist in this environment. The required
|
||||
`raw/branch-notes/codex-objectstorage-production-capability.md` and derived raw documents could not
|
||||
be created or updated. No similarly named non-canonical clone was used.
|
||||
@@ -0,0 +1,92 @@
|
||||
# Object Storage Batch E Pause Checkpoint
|
||||
|
||||
- Recorded: 2026-07-29 (Asia/Seoul)
|
||||
- Branch: `codex/objectstorage-production-capability`
|
||||
- Worktree:
|
||||
`/home/donghyeon/workspace/clean-architecture-backend-template-objectstorage`
|
||||
- Status: implementation in progress; intentionally paused at the user's request
|
||||
- Evidence grade: local unit/integration/architecture evidence only; no AWS R2 evidence
|
||||
|
||||
## Implemented at this checkpoint
|
||||
|
||||
- Staged integrity verification, fake-scanner routing, publication handoff fencing, and stable
|
||||
replay receipts.
|
||||
- Additive Poster V7 dual-read schema, upload/retirement intents, HMAC-sanitized idempotency scope,
|
||||
PostgreSQL atomic claim SPI, and forward-only migration qualification lane.
|
||||
- Short-transaction Poster image publication flow and additive locator-free `202` API under the
|
||||
AIP-122-compatible `/posters/{id}/imagePublications` collection.
|
||||
- Exact-reference/version logical retirement enqueue, lease/fence takeover, response-loss retry,
|
||||
Poster deletion survival, and disabled-by-default worker composition.
|
||||
- Isolated legacy migration contracts, report-only inspection, two-distinct-approver Ed25519
|
||||
approval verification, nonce replay boundary, and explicit maintenance-only composition.
|
||||
|
||||
## Verification completed
|
||||
|
||||
The following focused command passed after the final architecture fixes:
|
||||
|
||||
```bash
|
||||
cd src
|
||||
./gradlew \
|
||||
:sample-portfolio:spotlessApply \
|
||||
:sample-portfolio:test --tests '*PosterImagePublicationControllerWireTest' \
|
||||
:app-bootstrap:test --tests '*CleanArchitectureTest' \
|
||||
--console=plain
|
||||
```
|
||||
|
||||
The following focused suites also passed during this checkpoint:
|
||||
|
||||
```bash
|
||||
./gradlew :adapter:outbound:objectstorage:test \
|
||||
--tests '*LegacyObjectAdoptionServiceTest' \
|
||||
--tests '*LegacyAdoptionApprovalVerifierTest' \
|
||||
--tests '*ObjectStorageLegacyMigrationConfigTest' --console=plain
|
||||
|
||||
./gradlew :sample-portfolio:test \
|
||||
--tests '*DeletePosterImageRetirementTest' \
|
||||
--tests '*PosterImageRetirementCrashMatrixTest' \
|
||||
--tests '*PosterImageRetirementConfigTest' \
|
||||
--tests '*LegacyPosterImageUploadCharacterizationTest' --console=plain
|
||||
|
||||
./gradlew :sample-portfolio:test \
|
||||
--tests '*SampleApplicationContextTest' \
|
||||
:sample-portfolio:posterImageMigrationTest --console=plain
|
||||
```
|
||||
|
||||
The migration lane included
|
||||
`PosterImageRetirementQualificationTest`, which proved that an exact retirement row survives
|
||||
deletion of its Poster row.
|
||||
|
||||
## Failures found and resolved
|
||||
|
||||
- `spotlessJavaCheck` initially found formatting drift in newly changed application-core and
|
||||
persistence files. The owner-module Spotless apply tasks fixed it.
|
||||
- `SampleApplicationContextTest` initially failed because Spring's persistence exception advisor
|
||||
could not CGLIB-proxy the final `PosterImageAttachmentCasRepository`. Removing `final` fixed the
|
||||
context; the focused context suite then passed.
|
||||
- `CleanArchitectureTest` initially rejected an application-core return type from the sample domain
|
||||
and the kebab-case `image-publications` path. Conversion moved back to the application use case,
|
||||
and the endpoint changed to the repository's AIP-122-compatible `imagePublications` segment. The
|
||||
complete focused architecture suite then passed.
|
||||
|
||||
## Not yet re-run / not complete
|
||||
|
||||
- The combined Batch E checkpoint command stopped on the two architecture failures above before all
|
||||
requested root tasks could complete. The focused failing suites passed after the fixes, but
|
||||
`:sample-portfolio:check`, `verifyPublicPathSnapshot`, and the full combined Batch E command have
|
||||
not been re-run after those final fixes.
|
||||
- The complete repository `./gradlew test` and `./gradlew check` have not been re-run after the
|
||||
Batch E additions.
|
||||
- The legacy adoption runner/configuration is not yet wired to a production legacy inspector,
|
||||
permission-checked trust-key loader, or durable control-record replay-store implementation.
|
||||
- Tasks 25–30 (Batch F) have not started in this continuation.
|
||||
- Actual AWS qualification is blocked by Approval Gate B: no approved account, bucket/namespaces,
|
||||
workload roles, signed deployment attestation, or mutation/test authority was supplied.
|
||||
- No readiness card was promoted. Local/MinIO ceilings and unsupported conditional behavior remain
|
||||
unchanged.
|
||||
|
||||
## Wiki capture
|
||||
|
||||
The canonical vault
|
||||
`/home/donghyeon/workspace/ai-tool/llm-wiki-private/` is absent in this environment. Therefore the
|
||||
required branch note and derived raw documents could not be written. No non-canonical substitute
|
||||
was used.
|
||||
@@ -0,0 +1,73 @@
|
||||
# Object Storage Phase 0 Inventory
|
||||
|
||||
- Captured: 2026-07-28
|
||||
- Branch: `codex/objectstorage-production-capability`
|
||||
- Scope: repository-local source, tests, configuration, migrations, and documentation
|
||||
- Evidence grade: repository-local only; deployed data, broker subscribers, and external REST
|
||||
consumers were not inspected
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
rg -n 'application\.storage|ObjectStoragePort|StoredObject|ca-skeleton\.objectstorage|file://|s3://' \
|
||||
src docs
|
||||
rg -n 'image_key|posters/.*/image' src/sample-portfolio
|
||||
rg -n 'poster\.image-attached|StoredObjectResponse|PosterResponse|imageKey' \
|
||||
src/sample-portfolio docs
|
||||
```
|
||||
|
||||
The commands completed successfully in the isolated worktree. Results are classified below.
|
||||
Documentation hits in the Object Storage design/plan describe the migration and are not runtime
|
||||
consumers. The `s3://bucket/key-1` fixture in
|
||||
`IdempotencyStoreAdapterTest` belongs to the generic idempotency response-reference test and is not
|
||||
an Object Storage legacy-port consumer.
|
||||
|
||||
## Repository-local runtime inventory
|
||||
|
||||
| Contract/data | Producer | Repository-local consumers | Classification |
|
||||
| --- | --- | --- | --- |
|
||||
| `ObjectStoragePort` / `StoredObject` | `application-core/application/storage` | filesystem and S3 adapters, `UploadPosterImageUseCase`, `PosterController`/`PosterWebMapper` | legacy runtime contract |
|
||||
| `ca-skeleton.objectstorage.*` | `ObjectStorageSettings` / `ObjectStorageConfig` | sample runtime through its objectstorage runtime dependency | legacy runtime configuration |
|
||||
| `file://` receipt | `FilesystemObjectStorageAdapter` | `StoredObjectResponse.location` through `PosterWebMapper` | public legacy locator |
|
||||
| `s3://bucket/key` receipt | `S3ObjectStorageAdapter` | `StoredObjectResponse.location` through `PosterWebMapper` | public legacy locator |
|
||||
| `/posters/{id}/image` | `PosterController` | repository tests and the generated/public HTTP contract | legacy inbound API |
|
||||
| `StoredObjectResponse` | `PosterController` / `PosterWebMapper` | HTTP caller, with `key`, `size`, `contentType`, and `location` | legacy response DTO |
|
||||
| `PosterResponse.imageKey` | `PosterWebMapper` | list/get/create/update/publish/archive HTTP responses | legacy general response field |
|
||||
| `poster.image-attached` | `PosterEventPublisher` | no subscriber found in this repository | versionless broker event; external consumers unknown |
|
||||
| `poster.image-attached.imageKey` | `PosterImageAttached` and publisher JSON | no subscriber found in this repository | raw locator-shaped event field |
|
||||
| `poster.image_key` | Flyway V6, `PosterEntity`, persistence mapper | `Poster` aggregate and repository adapter | stored-data schema |
|
||||
| `posters/{id}/image` key | `UploadPosterImageUseCase` | aggregate `imageKey`, event payload, DB row, HTTP response | deterministic overwriteable legacy key |
|
||||
|
||||
## Executable characterization
|
||||
|
||||
The following tests pin the current behavior without approving it as the target design:
|
||||
|
||||
- `LegacyObjectStorageBehaviorTest`
|
||||
- caller-selected keys overwrite;
|
||||
- `get` returns `Optional<byte[]>` and materializes the whole object;
|
||||
- receipts expose `file://` and `s3://` locators.
|
||||
- `LegacyObjectStorageConfigTest`
|
||||
- missing backend configuration selects filesystem;
|
||||
- context creation creates the filesystem directory before the first write;
|
||||
- `autoCreateBucket=true` probes and creates a missing bucket during S3 bean construction.
|
||||
- `LegacyPosterImageUploadCharacterizationTest`
|
||||
- remote storage is called while `TransactionPort.inWrite` is active;
|
||||
- the controller calls `MultipartFile.getBytes`;
|
||||
- the response exposes raw key and provider location;
|
||||
- Poster deletion leaves the legacy object untouched.
|
||||
|
||||
## External inventory gap and Gate A
|
||||
|
||||
Repository search does not prove that the following have no deployed consumers:
|
||||
|
||||
- `POST /posters/{id}/image`;
|
||||
- `StoredObjectResponse.key` and `.location`;
|
||||
- `PosterResponse.imageKey`;
|
||||
- broker event type `poster.image-attached` and its `imageKey` payload;
|
||||
- rows already stored in `poster.image_key`;
|
||||
- filesystem/S3 objects already written under `posters/{id}/image`.
|
||||
|
||||
No deployed database, object namespace, access log, API client catalog, broker consumer group, schema
|
||||
registry, or owning team approval was inspected. Therefore removal, in-place field rename, event
|
||||
payload replacement, or legacy-object deletion remains blocked. Approval Gate A must obtain owner
|
||||
and consumer evidence and choose an additive/versioned migration contract.
|
||||
@@ -0,0 +1,114 @@
|
||||
schema_version: 1
|
||||
claims:
|
||||
- card_id: object-storage-managed-upload-single
|
||||
provider_type: filesystem-local-dev
|
||||
provider_version: jdk-21
|
||||
destination_profile: local-managed-integrity
|
||||
claimed_level: R1
|
||||
evidence_revision: batch-b-local-r1
|
||||
evidence_expires_on: ""
|
||||
required_tasks:
|
||||
- ":adapter:outbound:objectstorage:check"
|
||||
limitations:
|
||||
- single-process control CAS only; no multi-node linearizability
|
||||
- fsync and atomic move tests do not prove power-loss durability
|
||||
- local development provider is forbidden in production profiles
|
||||
|
||||
- card_id: object-storage-managed-upload-multipart
|
||||
provider_type: filesystem-local-dev
|
||||
provider_version: jdk-21
|
||||
destination_profile: local-unimplemented
|
||||
claimed_level: R0
|
||||
evidence_revision: batch-b-contract-r0
|
||||
evidence_expires_on: ""
|
||||
required_tasks:
|
||||
- ":application-core:check"
|
||||
limitations:
|
||||
- multipart publication protocol is not implemented
|
||||
|
||||
- card_id: object-storage-managed-download
|
||||
provider_type: filesystem-local-dev
|
||||
provider_version: jdk-21
|
||||
destination_profile: local-managed-integrity
|
||||
claimed_level: R1
|
||||
evidence_revision: batch-b-local-r1
|
||||
evidence_expires_on: ""
|
||||
required_tasks:
|
||||
- ":adapter:outbound:objectstorage:check"
|
||||
limitations:
|
||||
- local functional full and range reads are not production-provider qualification
|
||||
- no multi-node or power-loss durability claim
|
||||
|
||||
- card_id: object-storage-direct-upload-single
|
||||
provider_type: filesystem-local-dev
|
||||
provider_version: jdk-21
|
||||
destination_profile: local-unimplemented
|
||||
claimed_level: R0
|
||||
evidence_revision: batch-b-contract-r0
|
||||
evidence_expires_on: ""
|
||||
required_tasks:
|
||||
- ":application-core:check"
|
||||
limitations:
|
||||
- direct grant provider and public inbound endpoint are not implemented
|
||||
|
||||
- card_id: object-storage-direct-upload-multipart
|
||||
provider_type: filesystem-local-dev
|
||||
provider_version: jdk-21
|
||||
destination_profile: local-unimplemented
|
||||
claimed_level: R0
|
||||
evidence_revision: batch-b-contract-r0
|
||||
evidence_expires_on: ""
|
||||
required_tasks:
|
||||
- ":application-core:check"
|
||||
limitations:
|
||||
- direct multipart session and public inbound endpoint are not implemented
|
||||
|
||||
- card_id: object-storage-direct-download
|
||||
provider_type: filesystem-local-dev
|
||||
provider_version: jdk-21
|
||||
destination_profile: local-unimplemented
|
||||
claimed_level: R0
|
||||
evidence_revision: batch-b-contract-r0
|
||||
evidence_expires_on: ""
|
||||
required_tasks:
|
||||
- ":application-core:check"
|
||||
limitations:
|
||||
- direct download grant and public inbound endpoint are not implemented
|
||||
|
||||
- card_id: object-storage-quarantine-publication
|
||||
provider_type: filesystem-local-dev
|
||||
provider_version: jdk-21
|
||||
destination_profile: local-unimplemented
|
||||
claimed_level: R0
|
||||
evidence_revision: batch-b-contract-r0
|
||||
evidence_expires_on: ""
|
||||
required_tasks:
|
||||
- ":application-core:check"
|
||||
limitations:
|
||||
- scanner handoff and verdict fencing are not implemented
|
||||
|
||||
- card_id: object-storage-retention
|
||||
provider_type: filesystem-local-dev
|
||||
provider_version: jdk-21
|
||||
destination_profile: local-unimplemented
|
||||
claimed_level: R0
|
||||
evidence_revision: batch-b-contract-r0
|
||||
evidence_expires_on: ""
|
||||
required_tasks:
|
||||
- ":application-core:check"
|
||||
limitations:
|
||||
- retention and legal-hold provider enforcement are not implemented
|
||||
- privileged purge composition remains intentionally empty
|
||||
|
||||
- card_id: object-storage-reconciliation
|
||||
provider_type: filesystem-local-dev
|
||||
provider_version: jdk-21
|
||||
destination_profile: local-unimplemented
|
||||
claimed_level: R0
|
||||
evidence_revision: batch-b-contract-r0
|
||||
evidence_expires_on: ""
|
||||
required_tasks:
|
||||
- ":application-core:check"
|
||||
limitations:
|
||||
- local create resolution is single-process functional evidence only
|
||||
- production response-loss and multi-node reconciliation are not implemented
|
||||
File diff suppressed because it is too large
Load Diff
@@ -949,6 +949,13 @@ and durable interfaces are explicit.
|
||||
|
||||
### 13.3 Object storage
|
||||
|
||||
The authoritative implementation-level design for this capability is
|
||||
[Object Storage Production Capability Deep Design](2026-07-28-objectstorage-production-capability-design.md).
|
||||
Its ordered RED–GREEN execution batches and promotion gates are in the
|
||||
[Object Storage Production Capability Implementation Plan](../plans/2026-07-28-objectstorage-production-capability.md).
|
||||
This subsection is only the cross-capability baseline; the dedicated design governs when details
|
||||
differ.
|
||||
|
||||
Replace whole-object `byte[]` as the only path with:
|
||||
|
||||
- streaming upload/download and range reads;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user