Sub-scope 01 (objectstorage) governance + config/** - manifest and probes revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5 generatedAt=2026-08-30T02:38:00+00:00 === OWNED FILES === 848a96fae0288a4f45f277e59519162098de42a6 CLAUDE.md 52 b009f7e1d21c68ae4cade2311d7aeb4a4daf3118 README.md 72 ad99e57d20a4be7df7ad4514dec20de86c595acc build.gradle 84 493644f4567e5fae94bc4d4dd45294957b2e66f1 gradle.lockfile 217 70535fba48e01ac6814e2afffc0498ddb5c009d6 config/CompiledObjectStorageDestination.java 21 9ae8d2fe0aa878b95d527455e91e90e663c533c7 config/CompiledObjectStorageProvider.java 53 69f0037741960803ae9fdd8e02de4e45e38796d0 config/LegacyObjectAdoptionSettings.java 41 1705a48cc64501e17e38c84a2f9ab51840bade70 config/LegacyObjectStorageActivationGuard.java 60 9bb2f57920e4ba27bbd357310c7b3467bc3dfbce config/ObjectStorageBindingCompiler.java 276 d8648f156810a06d9ed4158f9503d1a5312dc721 config/ObjectStorageCapabilityAssembler.java 132 cd1d0f00b8cb2e1206060fa483910e53fb1270c9 config/ObjectStorageCapabilityConfig.java 164 346fd88cf5030a6a1efe5a4fc66880ecfc547096 config/ObjectStorageCapabilitySettings.java 49 eb8e5a2d35b58d1bbda8c9a52e5d97251a8c8658 config/ObjectStorageDestinationSettings.java 46 8ff739407bc795f04c9ba04ac2c425392a450ddf config/ObjectStorageLegacyMigrationConfig.java 37 784343e77bf981a8c76f72b27ebec0272d5c17b2 config/ObjectStorageMaintenanceCapabilityConfig.java 10 da0692f4cc012c5ba9f161d5c8cb23c27f730a8e config/ObjectStorageProviderContribution.java 28 58ea89e50d3918f14faeae29a5cfa38ee479dacb config/ObjectStorageProviderSettings.java 13 41a53fae2eaec8f6fc965447f3428c947e4afde2 config/ObjectStorageScanMaintenanceConfig.java 20 2c0559b1d5e051771648f91c5885625d41ab1340 config/RoutingObjectDirectGrantAdapter.java 10 57723eb8d8f3fd8e81f90fee380540c089b9277c config/RoutingObjectMutationAdapter.java 523 24ed0f52e84a38abbfc797e42f05a00625eea0de config/RoutingObjectReadAdapter.java 147 85aaa9a830aeea0452c32e96c08efbda553f9fb9 config/RoutingObjectScanMaintenanceAdapter.java 147 192666945aceeef3e34cd16fb911f9cd2a5bf54b config/SelectedObjectStorageProviderFactory.java 98 8474c92e55cb29df477bd0698526be48ec51f163 test/config/ObjectStorageBindingCompilerTest.java 167 11f1d10fac90b601d6e6cf3858305701787fc610 test/config/ObjectStorageCapabilityConfigTest.java 480 4effeb8c4acb65b6a19e9f0328634db76d35eb63 test/config/ObjectStorageLegacyMigrationConfigTest.java 66 b455e7675c64ab00bf1a7c40db14b0a9c06b2d06 test/config/ObjectStorageScanMaintenanceConfigTest.java 56 5db09bc83df4af94c03719828e29ba7b7be0557e test/config/RoutingObjectStorageAdapterTest.java 154 === 8.1 reachability: how the configs load and what they gate === $ git ls-files 'adapter/outbound/objectstorage' | grep -i 'META-INF\|imports\|spring.factories' exit=1 $ git grep -rn 'ObjectStorageCapabilityConfig\|ObjectStorageScanMaintenanceConfig\|ObjectStorageMaintenanceCapabilityConfig\|ObjectStorageLegacyMigrationConfig' -- . | grep -v "^adapter/outbound/objectstorage/" | head exit=0 $ grep -rn 'objectstorage' app-bootstrap/src/main/java/dev/caskeleton/bootstrap/CaSkeletonApplication.java sample-portfolio/src/main/java/dev/caskeleton/sample/portfolio/*.java 2>/dev/null | head app-bootstrap/src/main/java/dev/caskeleton/bootstrap/CaSkeletonApplication.java:76: "dev.caskeleton.adapter.outbound.objectstorage", exit=0 $ git grep -rn 'app.object-storage' -- sample-portfolio/src/main/resources app-bootstrap/src/main/resources 2>/dev/null | head -20 exit=0 === 8.2 the four claims README makes about composition === --- (a) no direct-grant port is registered $ grep -n 'class RoutingObjectDirectGrantAdapter' -A 4 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/config/RoutingObjectDirectGrantAdapter.java 7:public final class RoutingObjectDirectGrantAdapter { 8- 9- private RoutingObjectDirectGrantAdapter() {} 10-} exit=0 $ git grep -rn 'RoutingObjectDirectGrantAdapter' -- 'adapter/outbound/objectstorage/src' | grep -v 'RoutingObjectDirectGrantAdapter.java' exit=1 --- (b) scanner and privileged purge remain separate and empty $ cat adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/config/ObjectStorageMaintenanceCapabilityConfig.java package dev.caskeleton.adapter.outbound.objectstorage.config; import org.springframework.context.annotation.Configuration; /** * Separate privileged composition boundary. Batch B intentionally contributes no purge or scanner * maintenance bean. */ @Configuration(proxyBeanMethods = false) public class ObjectStorageMaintenanceCapabilityConfig {} exit=0 $ grep -n '@Bean' -A 6 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/config/ObjectStorageScanMaintenanceConfig.java 11: @Bean 12- @ConditionalOnProperty( 13- prefix = "app.object-storage.scan-maintenance", 14- name = "enabled", 15- havingValue = "true") 16- public RoutingObjectScanMaintenanceAdapter routingObjectScanMaintenanceAdapter( 17- ObjectStorageCapabilityAssembler.AssembledCapability capability) { exit=0 --- (c) filesystem-local-dev rejected under prod/production $ grep -n 'filesystem-local-dev is rejected\|productionProfileActive' -B 3 -A 6 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/config/ObjectStorageBindingCompiler.java 122- if (compiled.put(providerId, provider) != null) { 123- throw invalid(); 124- } 125: if ("filesystem-local-dev".equals(providerType) && productionProfileActive()) { 126: throw new IllegalArgumentException("filesystem-local-dev is rejected in production"); 127- } 128- } 129- return Map.copyOf(compiled); 130- } 131- 132- private Map compileDestinations( -- 234- } 235- } 236- 237: private boolean productionProfileActive() { 238- return activeProfiles.stream() 239- .map(profile -> profile.toLowerCase(Locale.ROOT)) 240- .anyMatch(profile -> profile.equals("prod") || profile.equals("production")); 241- } 242- 243- private static String canonicalId(String label, String value) { exit=0 --- (d) mixing old alias with canonical settings fails startup without echoing values $ grep -n 'cannot be combined' -B 8 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/config/LegacyObjectStorageActivationGuard.java 14- private static final String CANONICAL_PREFIX = "app.object-storage."; 15- 16- @Override 17- public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { 18- boolean legacy = hasPrefix(context, LEGACY_PREFIX); 19- boolean canonical = hasPrefix(context, CANONICAL_PREFIX); 20- if (legacy && canonical) { 21- throw new IllegalStateException( 22: "legacy and canonical object-storage configuration cannot be combined"); exit=0 === 8.2b compile-before-construct: is that ordering real? === $ grep -n 'compiler.compile(settings)' -A 6 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/config/ObjectStorageCapabilityAssembler.java 25: ObjectStorageBindingCompiler.CompiledBindings bindings = compiler.compile(settings); 26- if (bindings.destinations().isEmpty()) { 27- throw new IllegalArgumentException("disabled capability cannot be assembled"); 28- } 29- Map byType = new LinkedHashMap<>(); 30- for (ObjectStorageProviderContribution contribution : contributions) { 31- for (String providerType : contribution.providerTypes()) { exit=0 $ grep -n 'contribution.create(provider)' -B 6 -A 8 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/config/ObjectStorageCapabilityAssembler.java 42- CompiledObjectStorageProvider provider = 43- Objects.requireNonNull(bindings.providers().get(destination.providerId())); 44- ObjectStorageProviderContribution contribution = byType.get(provider.providerType()); 45- if (contribution == null) { 46- throw new IllegalArgumentException("selected provider contribution is unavailable"); 47- } 48: SelectedObjectStorageProviderFactory factory = contribution.create(provider); 49- constructed.add(factory); 50- selected.put(provider.providerId(), factory); 51- } 52- return new AssembledCapability(bindings, selected); 53- } catch (RuntimeException exception) { 54- for (int index = constructed.size() - 1; index >= 0; index--) { 55- constructed.get(index).close(); 56- } exit=0 $ grep -n 'must not resolve credentials' -B 3 -A 3 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/config/ObjectStorageProviderContribution.java 6-/** 7- * Side-effect-free descriptor plus an explicitly selected provider construction seam. 8- * 9: *

{@link #describe} must not resolve credentials, create files, clients, threads, or schedulers. 10- * {@link #create} owns cleanup of every partial allocation before it throws; after a successful 11- * return the assembler owns the returned lifecycle exactly once. 12- */ exit=0 === 8.3 duplicate mechanism: two legacy activation paths === $ grep -rn 'LEGACY_PREFIX\|app.object-storage.legacy' adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/config/*.java | head -12 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/config/LegacyObjectAdoptionSettings.java:9:@ConfigurationProperties(prefix = "app.object-storage.legacy-adoption") adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/config/LegacyObjectStorageActivationGuard.java:13: private static final String LEGACY_PREFIX = "ca-skeleton.objectstorage."; adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/config/LegacyObjectStorageActivationGuard.java:18: boolean legacy = hasPrefix(context, LEGACY_PREFIX); adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/config/LegacyObjectStorageActivationGuard.java:41: if (LEGACY_PREFIX.equals(prefix)) { adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/config/ObjectStorageCapabilityConfig.java:90: prefix = "app.object-storage.legacy", adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/config/ObjectStorageCapabilityConfig.java:115: prefix = "app.object-storage.legacy", adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/config/ObjectStorageLegacyMigrationConfig.java:22: prefix = "app.object-storage.legacy-adoption", exit=0 $ git grep -rn 'LegacyObjectStorageActivationGuard' -- 'adapter/outbound/objectstorage/src' | grep -v 'LegacyObjectStorageActivationGuard.java' adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/ObjectStorageConfig.java:30: dev.caskeleton.adapter.outbound.objectstorage.config.LegacyObjectStorageActivationGuard.class) exit=0 === 8.4 the readiness registry the build declares as a test input === $ grep -n 'objectStorageReadinessRegistry' -A 6 adapter/outbound/objectstorage/build.gradle 45:def objectStorageReadinessRegistry = rootProject.projectDir.parentFile.toPath() 46- .resolve('docs/registries/object-storage-readiness.yaml').toFile() 47-tasks.named('test') { 48: inputs.file(objectStorageReadinessRegistry) 49- .withPathSensitivity(PathSensitivity.RELATIVE) 50: systemProperty 'objectstorage.readiness.registry', objectStorageReadinessRegistry.absolutePath 51-} 52- 53-def objectStorageMinioContractQualification = registerStrictQualificationTest( 54- name: 'objectStorageMinioContractTest', 55- sourceSet: sourceSets.objectStorageMinioContractTest, 56- requiredClasses: [ exit=0 $ ls -l ../docs/registries/object-storage-readiness.yaml 2>&1 -rw-rw-r-- 1 ubuntu ubuntu 4319 Aug 1 23:21 ../docs/registries/object-storage-readiness.yaml exit=0 $ git grep -rln 'object-storage-readiness' -- 'adapter/outbound/objectstorage/src' ../docs | head ../docs/superpowers/plans/2026-07-28-objectstorage-production-capability.md exit=0 === 8.4b the unguarded split in the read router === $ grep -n 'canonicalText().split' -B 3 -A 3 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/config/RoutingObjectReadAdapter.java 100- } 101- 102- private Optional load(ObjectReference reference) { 103: String routeToken = reference.canonicalText().split("\\.", -1)[1]; 104- ObjectStorageCapabilityAssembler.DestinationRuntime runtime = capability.route(routeToken); 105- ObjectControlStore control = runtime.providerFactory().controlStore(); 106- ObjectReferencePointerRecord pointer = exit=0 $ git grep -rn 'canonicalText' -- application-core/src/main/java/dev/caskeleton/application/objectstorage/model/ObjectReference.java | head exit=0 === 8.2c the production-profile deny check: which names does it recognise? === $ grep -rn 'prod\|production' adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/config/ObjectStorageBindingCompiler.java | grep -i profile 125: if ("filesystem-local-dev".equals(providerType) && productionProfileActive()) { 237: private boolean productionProfileActive() { 240: .anyMatch(profile -> profile.equals("prod") || profile.equals("production")); exit=0 --- how other leaves in this repo detect a production profile $ git grep -rn 'equals("prod")\|equalsIgnoreCase("prod")\|"production"' -- '*/src/main/java' | grep -iE 'profile' | head -12 exit=0 --- profile names the repo actually ships $ ls -1 app-bootstrap/src/main/resources/ sample-portfolio/src/main/resources/ 2>/dev/null | grep -i 'application-' | head -20 application-dev.yml application-local.yml application-prod.yml exit=0 $ git grep -rn 'spring.profiles.active' -- . 2>/dev/null | grep -v Binary | head -10 app-bootstrap/src/main/java/dev/caskeleton/bootstrap/logging/ResolvedProfileLoggingContextListener.java:15: * because Logback initialises before {@code spring.profiles.active} resolves and binding to that app-bootstrap/src/main/resources/logback-spring.xml:9: Reads the environment variable, not spring.profiles.active. app-bootstrap/src/main/resources/logback-spring.xml:12: the environment stamps log lines with the stale one. Binding to spring.profiles.active was app-bootstrap/src/test/java/dev/caskeleton/bootstrap/autoconfigure/fileserver/FileserverRuntimeAssemblyTest.java:148: .withPropertyValues("spring.profiles.active=prod") app-bootstrap/src/test/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/UnsafeStartupConfigurationTest.java:46: "spring.profiles.active=prod", "app.httpclient.clients[0].tls.trust-all=true") app-bootstrap/src/test/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/UnsafeStartupConfigurationTest.java:58: "spring.profiles.active=prod", app-bootstrap/src/test/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/UnsafeStartupConfigurationTest.java:79: "spring.profiles.active=prod", "app.httpclient.clients[0].transport=SIMPLE") app-bootstrap/src/test/java/dev/caskeleton/bootstrap/contract/StructuredLogFieldContractTest.java:79: .doesNotContain("source=\"spring.profiles.active\"") app-bootstrap/src/test/java/dev/caskeleton/bootstrap/logging/LogProfileDriftCharacterizationTest.java:20: * {@code spring.profiles.active} yields an empty string: Logback initialises before that property app-bootstrap/src/test/java/dev/caskeleton/bootstrap/runtime/OperationalContractRuntimeTest.java:73: "spring.profiles.active=test", exit=0 === 8.4c the readiness registry: rows and the test that reads it === $ ls -l ../docs/registries/object-storage-readiness.yaml -rw-rw-r-- 1 ubuntu ubuntu 4319 Aug 1 23:21 ../docs/registries/object-storage-readiness.yaml exit=0 $ head -30 ../docs/registries/object-storage-readiness.yaml # Repository owner test: dev.caskeleton.bootstrap.contract.ContractRegistrySchemaGovernanceTest # Owner Gradle path: :app-bootstrap:test # Semantic owner test: dev.caskeleton.adapter.outbound.objectstorage.readiness.ObjectStorageReadinessRegistryTest # Semantic owner Gradle path: :adapter:outbound:objectstorage:test 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: exit=0 $ git grep -rln 'object-storage-readiness' -- 'adapter/outbound/objectstorage/src' exit=1 === 8.4d ObjectReference canonical text shape (the unguarded split) === $ find . -name 'ObjectReference.java' -path '*objectstorage*' | head ./application-core/src/main/java/dev/caskeleton/application/objectstorage/identity/ObjectReference.java exit=0 $ grep -n 'canonicalText\|record ObjectReference\|matches\|split' $(find . -name 'ObjectReference.java' -path '*objectstorage*' | head -1) | head -20 8: private final String canonicalText; 10: private ObjectReference(String canonicalText) { 11: this.canonicalText = ObjectIdentitySupport.requireRouted(canonicalText, "osr1"); 14: public static ObjectReference parse(String canonicalText) { 15: return new ObjectReference(canonicalText); 18: public String canonicalText() { 19: return canonicalText; 23: return ObjectIdentitySupport.redactedLogToken(canonicalText); 33: return other instanceof ObjectReference that && canonicalText.equals(that.canonicalText); 38: return Objects.hash(canonicalText); exit=0