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<String, CompiledObjectStorageDestination> 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<String, ObjectStorageProviderContribution> 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: * <p>{@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<LoadedReference> 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

