Sub-scope 02 (objectstorage) control/** - canonical codec + durable record types
revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5
generatedAt=2026-08-30T02:42:36+00:00

=== OWNED FILES ===
2aad9351e0ff5ed233e9214d3a1f4cb00e08856d control/CanonicalJsonObjectControlRecordCodec.java 898
181741da87e8e2cb446a12357fb92e253f1797f2 control/CanonicalJsonReader.java 144
cb68ae97f9f05107a889aa6c6c8ee9c8b902163d control/CanonicalJsonWriter.java 90
fb3b7ff53be9c5cb4e15f87d0fb4062f3a5fb88f control/ControlRecordSupport.java 37
66afca559b3bbfe7339c164275be64261063429a control/ObjectControlConflictException.java 11
afb47e404c79ce53c833758d0e09cff6584c3a4a control/ObjectControlCorruptionException.java 15
5e557c1346e0b608a64bde312f9f7ea753b1ae5e control/ObjectControlMutation.java 13
f11454db71aee82a0121da9815085539c6ee1e21 control/ObjectControlRecord.java 42
0d46ec38359f4b8a67c9894bc7dd84666e78bf86 control/ObjectControlRecordCodec.java 9
8952f710cdcb1e9ac0dfba38a8c38a59b8a330a9 control/ObjectControlRecordEnvelope.java 45
00219ff8fa7400ec15dd5342ac625e3450ffa651 control/ObjectControlStore.java 22
3c5092718ba9b840525734cd8c8c0e1d2265d721 control/ObjectControlVersion.java 18
e74088f13b773f1e500a7906a5ee0788341f3afc control/ObjectDirectMultipartGrantRecord.java 96
d7ee355f993afad82dccf31980ceacaf4aafecd8 control/ObjectDirectMultipartSessionRecord.java 198
2e8b26782800b119eec56a851c4c49fd392d770e control/ObjectDirectSessionRecord.java 32
33e0de98997a246d2ca4d73027c8d55bf60ceed2 control/ObjectManifestRecord.java 53
b33587f0c5ee6df490172334130397310cd32fb7 control/ObjectMultipartPartRecord.java 41
057db5996cc3d1bd04f2df1039c1ad7e7575f6b3 control/ObjectMultipartSessionRecord.java 46
9d777251edc5e12077f959bb48f9426319060925 control/ObjectOperationRecord.java 210
cec085f7ba744dbb0f549e50eed0db2c2f874f20 control/ObjectPublicationHandoffRecord.java 188
a72bfdafe079cacc721a5d7c90fb3fc98a82e303 control/ObjectReferencePointerRecord.java 32
6c38f41ba9826a83290ae1e068d66b2f5e4363fa control/ObjectReferenceRecord.java 39
fb3f5735058c2e2b623a2d5923f42242edee4bae control/ObjectStagedObjectRecord.java 180
c1c1c83a2e5ac08da148e92a047bd8c7ddc8aec3 control/UnsupportedObjectControlSchemaException.java 11
f8eee5cf1a763bb3b40401481d798691a2207b12 test/control/ObjectControlRecordCodecTest.java 339
main LOC:  2470 total

=== 8.1 reachability: does any control type escape the leaf? ===
$ git grep -rln 'objectstorage.control' -- . | grep -v "^adapter/outbound/objectstorage/"
exit=1

$ grep -c 'public' adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/ObjectControlRecord.java adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/ObjectControlStore.java
adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/ObjectControlRecord.java:1
adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/ObjectControlStore.java:2
exit=0

=== 8.2 canonical strictness: what the reader and writer refuse ===
$ grep -n 'printable ASCII only\|character < 0x20 || character > 0x7e' adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/CanonicalJsonWriter.java adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/CanonicalJsonReader.java adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/ControlRecordSupport.java
adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/CanonicalJsonWriter.java:82:      } else if (character < 0x20 || character > 0x7e) {
adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/CanonicalJsonWriter.java:83:        throw new IllegalArgumentException("canonical JSON supports printable ASCII only");
adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/CanonicalJsonReader.java:119:      } else if (character < 0x20 || character > 0x7e) {
adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/ControlRecordSupport.java:25:        || value.chars().anyMatch(character -> character < 0x20 || character > 0x7e)) {
exit=0

$ grep -n 'private void field' -A 10 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/CanonicalJsonReader.java
91:  private void field(String expectedName) {
92-    if (first) {
93-      first = false;
94-    } else {
95-      expect(',');
96-    }
97-    if (!quoted().equals(expectedName)) {
98-      throw corrupt();
99-    }
100-    expect(':');
101-  }
exit=0

$ grep -n 'public void end' -A 6 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/CanonicalJsonReader.java
84:  public void end() {
85-    expect('}');
86-    if (cursor != input.length()) {
87-      throw corrupt();
88-    }
89-  }
90-
exit=0

$ grep -n 'digitStart == cursor' -B 6 -A 4 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/CanonicalJsonReader.java
53-      cursor++;
54-    }
55-    int digitStart = cursor;
56-    while (cursor < input.length() && input.charAt(cursor) >= '0' && input.charAt(cursor) <= '9') {
57-      cursor++;
58-    }
59:    if (digitStart == cursor
60-        || (input.charAt(digitStart) == '0' && cursor - digitStart > 1)
61-        || (negative && input.charAt(digitStart) == '0')) {
62-      throw corrupt();
63-    }
exit=0

=== 8.2b envelope: digest + canonical Base64 round trip ===
$ grep -n 'Base64.getEncoder().encodeToString(payload).equals(base64Payload)' -B 8 -A 6 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/CanonicalJsonObjectControlRecordCodec.java
81-    }
82-    byte[] payload;
83-    try {
84-      payload = Base64.getDecoder().decode(base64Payload);
85-    } catch (IllegalArgumentException exception) {
86-      throw new ObjectControlCorruptionException(
87-          "control payload is not canonical Base64", exception);
88-    }
89:    if (!Base64.getEncoder().encodeToString(payload).equals(base64Payload)
90-        || !MessageDigest.isEqual(
91-            digest.getBytes(StandardCharsets.US_ASCII),
92-            sha256Hex(payload).getBytes(StandardCharsets.US_ASCII))) {
93-      throw corrupt();
94-    }
95-    ObjectControlRecord record = decodePayload(payload);
exit=0

$ grep -n 'MAXIMUM_ENVELOPE_BYTES\|MAXIMUM_TERMINAL_RECEIPT_BYTES\|MAXIMUM_PART_BYTES\|enforceFamilySize' adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/CanonicalJsonObjectControlRecordCodec.java
47:  private static final int MAXIMUM_ENVELOPE_BYTES = 64 * 1024;
48:  private static final int MAXIMUM_TERMINAL_RECEIPT_BYTES = 16 * 1024;
49:  private static final int MAXIMUM_PART_BYTES = 4 * 1024;
55:    enforceFamilySize(record, payload.length);
72:    if (encoded == null || encoded.length == 0 || encoded.length > MAXIMUM_ENVELOPE_BYTES) {
96:    enforceFamilySize(record, payload.length);
107:    if (encoded.length > MAXIMUM_ENVELOPE_BYTES) {
885:  private static void enforceFamilySize(ObjectControlRecord record, int payloadLength) {
888:            ? MAXIMUM_PART_BYTES
889:            : record.terminal() ? MAXIMUM_TERMINAL_RECEIPT_BYTES : MAXIMUM_ENVELOPE_BYTES;
exit=0

=== 8.2c the reader decodes bytes leniently; what closes that? ===
$ grep -n 'new String(bytes, StandardCharsets.UTF_8)' -B 4 -A 3 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/CanonicalJsonReader.java
12-  public CanonicalJsonReader(byte[] bytes) {
13-    if (bytes == null) {
14-      throw corrupt();
15-    }
16:    input = new String(bytes, StandardCharsets.UTF_8);
17-    expect('{');
18-  }
19-
exit=0

$ grep -n 'character < 0x20 || character > 0x7e' -B 3 -A 2 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/CanonicalJsonReader.java
116-        if (character != '"' && character != '\\') {
117-          throw corrupt();
118-        }
119:      } else if (character < 0x20 || character > 0x7e) {
120-        throw corrupt();
121-      }
exit=0

=== 8.3 sealed family + exhaustive switch ===
$ grep -n 'sealed interface ObjectControlRecord' -A 14 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/ObjectControlRecord.java
4:public sealed interface ObjectControlRecord
5-    permits ObjectDirectSessionRecord,
6-        ObjectDirectMultipartGrantRecord,
7-        ObjectDirectMultipartSessionRecord,
8-        ObjectManifestRecord,
9-        ObjectMultipartPartRecord,
10-        ObjectMultipartSessionRecord,
11-        ObjectOperationRecord,
12-        ObjectPublicationHandoffRecord,
13-        ObjectReferencePointerRecord,
14-        ObjectReferenceRecord,
15-        ObjectStagedObjectRecord {
16-
17-  int schemaVersion();
18-
exit=0

$ grep -n 'return switch (record)' -A 14 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/CanonicalJsonObjectControlRecordCodec.java
128:    return switch (record) {
129-      case ObjectDirectSessionRecord direct -> directSession(writer, direct);
130-      case ObjectDirectMultipartSessionRecord session -> directMultipartSession(writer, session);
131-      case ObjectDirectMultipartGrantRecord grant -> directMultipartGrant(writer, grant);
132-      case ObjectOperationRecord operation -> operation(writer, operation);
133-      case ObjectManifestRecord manifest -> manifest(writer, manifest);
134-      case ObjectReferencePointerRecord pointer -> pointer(writer, pointer);
135-      case ObjectReferenceRecord reference -> reference(writer, reference);
136-      case ObjectStagedObjectRecord staged -> staged(writer, staged);
137-      case ObjectPublicationHandoffRecord handoff -> handoff(writer, handoff);
138-      case ObjectMultipartSessionRecord session -> session(writer, session);
139-      case ObjectMultipartPartRecord part -> part(writer, part);
140-    };
141-  }
142-
exit=0

$ grep -n 'enum Family' -A 14 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/ObjectControlRecord.java | grep -c ','
10
exit=0

=== 8.3b LIST is deliberately absent ===
$ grep -n 'LIST is deliberately absent' -B 2 -A 8 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/ObjectControlStore.java
4-import java.util.Optional;
5-
6:/** Provider-neutral exact-lookup/create/CAS control storage. LIST is deliberately absent. */
7-public interface ObjectControlStore {
8-
9-  Optional<StoredControlRecord> read(String key);
10-
11-  StoredControlRecord create(String key, ObjectControlRecord record);
12-
13-  StoredControlRecord compareAndSet(String key, ObjectControlMutation mutation);
14-
exit=0

$ git grep -rn 'interface ObjectControlStore' -A 8 -- 'adapter/outbound/objectstorage/src/main' | head -12
fatal: unable to resolve revision: -A
exit=0

=== 8.4 record invariants: do the compact constructors re-derive rather than trust? ===
$ grep -n 'actualPolicyDigest' -B 6 -A 4 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/ObjectOperationRecord.java
40-    requestFingerprint = ControlRecordSupport.hexDigest("requestFingerprint", requestFingerprint);
41-    operationKind = ControlRecordSupport.bounded("operationKind", operationKind, 64);
42-    Objects.requireNonNull(route, "route must be non-null");
43-    Objects.requireNonNull(policySnapshot, "policySnapshot must be non-null");
44-    policySnapshotDigest =
45-        ControlRecordSupport.hexDigest("policySnapshotDigest", policySnapshotDigest);
46:    String actualPolicyDigest =
47-        new CanonicalJsonObjectControlRecordCodec()
48-            .sha256Hex(ObjectPolicySnapshotCodec.encode(policySnapshot));
49:    if (!actualPolicyDigest.equals(policySnapshotDigest)) {
50-      throw new IllegalArgumentException("policySnapshotDigest does not match the snapshot");
51-    }
52-    if (expectedContentIdentity != null
53-        && expectedContentIdentity.exactLength() > policySnapshot.maximumObjectBytes()) {
exit=0

$ grep -n 'pending effect and certainty do not agree' -B 4 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/ObjectOperationRecord.java
58-      throw new IllegalArgumentException("stateVersion must be positive");
59-    }
60-    Objects.requireNonNull(effectCertainty, "effectCertainty must be non-null");
61-    if ((pendingEffect == null) != (effectCertainty == ObjectEffectCertainty.NOT_SENT)) {
62:      throw new IllegalArgumentException("pending effect and certainty do not agree");
exit=0

$ grep -n 'active handoff lease is expired at write time\|cannot be released and abort-authorized' -B 4 adapter/outbound/objectstorage/src/main/java/dev/caskeleton/adapter/outbound/objectstorage/control/ObjectPublicationHandoffRecord.java
37-    }
38-    claimantDigest = ControlRecordSupport.hexDigest("claimantDigest", claimantDigest);
39-    Objects.requireNonNull(leaseExpiresAt, "leaseExpiresAt must be non-null");
40-    if (!released && !abortAuthorized && !leaseExpiresAt.isAfter(updatedAt)) {
41:      throw new IllegalArgumentException("active handoff lease is expired at write time");
42-    }
43-    if (released && abortAuthorized) {
44:      throw new IllegalArgumentException("handoff cannot be released and abort-authorized");
exit=0

$ grep -nE '@Test|  void ' adapter/outbound/objectstorage/src/test/java/dev/caskeleton/adapter/outbound/objectstorage/control/ObjectControlRecordCodecTest.java | head -30
57:  @Test
58:  void everyClosedRecordFamilyRoundTripsByteForByte() {
79:  @Test
80:  void operationGoldenEnvelopeIsFrozen() {
87:  @Test
88:  void everyRecordFamilyHasAFrozenGoldenEnvelopeDigest() {
104:  @Test
105:  void corruptionUnknownOuterFieldsTruncationAndOversizeFailClosed() {
124:  @Test
125:  void duplicateUnknownMissingAndReorderedPayloadFieldsFailClosed() {
144:  @Test
145:  void newerSchemaIsQuarantinedInsteadOfAppearingAbsent() {
exit=0

