The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.
Follows the import procedure in README.md.
source/ the originating repository verbatim — 78 documents, 28 SVGs,
8 manifests, plus .source-revision recording the commit
final/ the SSOT
document.md 729 lines written from the 29 experiment documents, not
concatenated: what was predicted, what was measured, and
where the measurement itself was wrong
evidence/raw 125 outputs, flattened to <experiment>__<file> because
the originals collided (01-baseline.txt appeared three
times) and the audit only globs the top level
evidence/meta one per raw file; command and exitCode are null and the
README says why rather than inventing them
evidence/browser 22 captures
assets/ three diagrams through techviz
.techviz/ their VizSpecs
A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.
Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.
verify-pipeline.py passes. audit-records.py reports no issues.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
141 lines
9.5 KiB
Plaintext
141 lines
9.5 KiB
Plaintext
Sub-scope 02 (outbound-messaging) envelope/** + JSON Schema meta 리소스 — manifest and probes
|
|
revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5
|
|
generatedAt=2026-08-30T06:27:52+00:00
|
|
|
|
=== OWNED FILES ===
|
|
758b7177a64804fe295e8be8b425f3808e91196e main/java/dev/caskeleton/adapter/outbound/messaging/envelope/DeterministicEnvelopeWriter.java 548
|
|
e0fd83434527d5a36b2a9810533b642c8f017787 main/java/dev/caskeleton/adapter/outbound/messaging/envelope/EnvelopeAdmissionLimits.java 56
|
|
63b3ba7a5de004c84241f54afd56198456522a70 main/java/dev/caskeleton/adapter/outbound/messaging/envelope/EnvelopeHashV1.java 36
|
|
5fa19d059d212146484fa2358a0105b182b08148 main/java/dev/caskeleton/adapter/outbound/messaging/envelope/JsonSchemaIntegrationEventEncoder.java 232
|
|
26eaddffcf160bb6a06c652e3943b576b627d518 main/java/dev/caskeleton/adapter/outbound/messaging/envelope/LocalJsonSchemaRegistry.java 701
|
|
3466e4660bd95fa55f817320609cef033f616445 main/resources/contracts/messaging/meta/draft-2020-12/authority.sha256 9
|
|
ca69923096f3a2e4fe5eb8152a92d87d146cf021 main/resources/contracts/messaging/meta/draft-2020-12/draft/2020-12/meta/applicator 48
|
|
2f6e056a9ac2399582eaf05985a26acf9161f213 main/resources/contracts/messaging/meta/draft-2020-12/draft/2020-12/meta/content 17
|
|
dfc092d9646e1ea89e4d771bfcf2a4ca87eeac75 main/resources/contracts/messaging/meta/draft-2020-12/draft/2020-12/meta/core 51
|
|
51ef7ea118c34e8ac3da66c973bae02b9e8325d8 main/resources/contracts/messaging/meta/draft-2020-12/draft/2020-12/meta/format-annotation 14
|
|
1a4f106cfe0b2df4784a39fae720762534a54cdf main/resources/contracts/messaging/meta/draft-2020-12/draft/2020-12/meta/format-assertion 11
|
|
05cbc22afde5ebe6ba84957ca412277bde1e4b08 main/resources/contracts/messaging/meta/draft-2020-12/draft/2020-12/meta/meta-data 37
|
|
5f62a3ffa20be07dc813d6b8a154fa8451d0dc61 main/resources/contracts/messaging/meta/draft-2020-12/draft/2020-12/meta/unevaluated 15
|
|
606b87ba2ec213d63b9e2035a6acc4edcb4b8357 main/resources/contracts/messaging/meta/draft-2020-12/draft/2020-12/meta/validation 98
|
|
d5e2d31c3c88e61f4c204cb6616887bba7e105dd main/resources/contracts/messaging/meta/draft-2020-12/draft/2020-12/schema 58
|
|
e0ac636a898cf0a7143df39a0fca9c6105a3c9c7 test/java/dev/caskeleton/adapter/outbound/messaging/envelope/EnvelopeAdversarialCorpusTest.java 334
|
|
3d960a923d7dc4684e9b039782cf7eef900071f2 test/java/dev/caskeleton/adapter/outbound/messaging/envelope/JsonSchemaIntegrationEventEncoderTest.java 413
|
|
ff105bfaa862fd89f992367f6397cb5e858780f7 test/java/dev/caskeleton/adapter/outbound/messaging/envelope/LocalJsonSchemaRegistryTest.java 393
|
|
e127ca96edb86ab9fe30438da19b72367fbe5324 test/resources/contracts/messaging/test.event/v1.invalid.json 13
|
|
74a3d91ae00a7e82ee5c3893847e9abe0debac16 test/resources/contracts/messaging/test.event/v1.schema.json 70
|
|
52c2bce0490fa5845f14227347ec7498a5eb8ca0 test/resources/contracts/messaging/test.event/v1.valid.json 15
|
|
|
|
main: 5 test: 3 resources: 13
|
|
=== 8.1 레지스트리가 외부 해석을 실제로 닫는가 ===
|
|
$ grep -n 'SchemaRegistryConfig\|schemaLoader\|uriFetcher\|disable\|cacheRefs\|SpecificationVersion' adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/envelope/LocalJsonSchemaRegistry.java | head -20
|
|
7:import com.networknt.schema.SchemaRegistryConfig;
|
|
8:import com.networknt.schema.SpecificationVersion;
|
|
405: SchemaRegistryConfig config =
|
|
406: SchemaRegistryConfig.builder()
|
|
410: .cacheRefs(true)
|
|
414: SpecificationVersion.DRAFT_2020_12,
|
|
exit=0
|
|
|
|
$ grep -n 'UNSUPPORTED_CLOSED_SUBSET_KEYWORDS' -A 3 -B 1 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/envelope/LocalJsonSchemaRegistry.java | head -20
|
|
57- "https://json-schema.org/draft/2020-12/vocab/content");
|
|
58: private static final Set<String> UNSUPPORTED_CLOSED_SUBSET_KEYWORDS =
|
|
59- Set.of("$anchor", "$dynamicRef", "$dynamicAnchor", "$recursiveRef", "$recursiveAnchor");
|
|
60- private static final String PINNED_AUTHORITY_ROOT = "contracts/messaging/meta/draft-2020-12/";
|
|
61- private static final String PINNED_AUTHORITY_MANIFEST =
|
|
--
|
|
300- }
|
|
301: for (String keyword : UNSUPPORTED_CLOSED_SUBSET_KEYWORDS) {
|
|
302- if (node.has(keyword)) {
|
|
303- throw new IllegalArgumentException(
|
|
304- keyword + " is unsupported by the closed local schema subset");
|
|
exit=0
|
|
|
|
$ grep -n 'KNOWN_VOCABULARIES' adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/envelope/LocalJsonSchemaRegistry.java
|
|
48: private static final Set<String> KNOWN_VOCABULARIES =
|
|
286: if (!KNOWN_VOCABULARIES.contains(entry.getKey())) {
|
|
exit=0
|
|
|
|
=== 8.2 핀 고정된 메타스키마 권위 해시 ===
|
|
$ cat adapter/outbound/messaging/src/main/resources/contracts/messaging/meta/draft-2020-12/authority.sha256
|
|
41da76f5afb7ce062d248f762463a92f7ca47e4e0f905b224ba6afeef91ded0f draft/2020-12/schema
|
|
c4a6e4147b91fef7fea6dc058cb1bf93402f7414b76578a8b16aaf1dad6aacef draft/2020-12/meta/applicator
|
|
08343747764e4a5814262793cf4d652057a7913863c5950d43297e8e1fdac5b6 draft/2020-12/meta/content
|
|
c2d12a8e4dd11d336dfc83a3f663aa4c69f0b49b3beb094ffeb25b5316f4803d draft/2020-12/meta/core
|
|
abc775adfefd89d22358170d9bf93f4ebd2349563bbbedd60f02bef7c812bcc0 draft/2020-12/meta/format-annotation
|
|
6a5a8e13c605e3eff51f9bf8da18078880d81ff1634e391760ccc2e16ee2146f draft/2020-12/meta/format-assertion
|
|
8f76d6e14f41b9b92ef933b708cdc5144c8b5268651ad11918485fb1754f1c76 draft/2020-12/meta/meta-data
|
|
2dbfbcb73994b670b0976492adee1fffb46c21682784d2f5a4ca561f9e2d0cb4 draft/2020-12/meta/unevaluated
|
|
7010a31e541f32d2be721e2de348df75c9b36876a3ed304877fc0abda1d37a58 draft/2020-12/meta/validation
|
|
exit=0
|
|
|
|
$ grep -n 'loadPinnedAuthority' -A 30 adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/envelope/LocalJsonSchemaRegistry.java | head -45
|
|
105: loadPinnedAuthority(mapper, LocalJsonSchemaRegistry.class.getClassLoader());
|
|
106-
|
|
107- Map<String, ParsedSource> parsedById = new LinkedHashMap<>();
|
|
108- Map<String, ParsedSource> parsedByResource = new LinkedHashMap<>();
|
|
109- exactSources.entrySet().stream()
|
|
110- .sorted(Map.Entry.comparingByKey())
|
|
111- .forEach(
|
|
112- entry -> {
|
|
113- SchemaSource source = entry.getValue();
|
|
114- if (source == null || !entry.getKey().equals(source.resourcePath())) {
|
|
115- throw new IllegalArgumentException(
|
|
116- "schema resource map key must equal its non-null exact source path");
|
|
117- }
|
|
118- ParsedSource parsed = parseAndCheck(source);
|
|
119- if (parsedByResource.putIfAbsent(source.resourcePath(), parsed) != null) {
|
|
120- throw new IllegalArgumentException(
|
|
121- "duplicate schema resource " + source.resourcePath());
|
|
122- }
|
|
123- if (parsedById.putIfAbsent(parsed.schemaId(), parsed) != null) {
|
|
124- throw new IllegalArgumentException("duplicate schema $id " + parsed.schemaId());
|
|
125- }
|
|
126- });
|
|
127-
|
|
128- validateAllReferences(parsedById);
|
|
129- SchemaRegistry registry = compileRegistry(parsedById);
|
|
130- validatePinnedAuthorityAgainstRuntime(registry, pinnedAuthority);
|
|
131- validateAgainstBundledMetaSchema(registry, parsedById.values());
|
|
132-
|
|
133- Map<String, CompiledSchema> byId = new LinkedHashMap<>();
|
|
134- Map<String, CompiledSchema> byResource = new LinkedHashMap<>();
|
|
135- parsedById.values().stream()
|
|
--
|
|
440: private static PinnedAuthority loadPinnedAuthority(ObjectMapper mapper, ClassLoader classLoader) {
|
|
441- byte[] manifestBytes = readRequiredClasspathBytes(classLoader, PINNED_AUTHORITY_MANIFEST);
|
|
442- String manifest;
|
|
443- try {
|
|
444- manifest =
|
|
445- StandardCharsets.UTF_8
|
|
446- .newDecoder()
|
|
447- .onMalformedInput(CodingErrorAction.REPORT)
|
|
448- .onUnmappableCharacter(CodingErrorAction.REPORT)
|
|
449- .decode(ByteBuffer.wrap(manifestBytes))
|
|
450- .toString();
|
|
451- } catch (CharacterCodingException exception) {
|
|
452- throw new IllegalArgumentException(
|
|
exit=0
|
|
|
|
=== 8.3 실행 probe: 매니페스트 해시가 실제 파일과 일치하는가 ===
|
|
$ cd adapter/outbound/messaging/src/main/resources/contracts/messaging/meta/draft-2020-12 && for f in draft/2020-12/schema draft/2020-12/meta/*; do printf '%s %s\n' "$(sha256sum "$f" | cut -d' ' -f1)" "$f"; done
|
|
41da76f5afb7ce062d248f762463a92f7ca47e4e0f905b224ba6afeef91ded0f draft/2020-12/schema
|
|
c4a6e4147b91fef7fea6dc058cb1bf93402f7414b76578a8b16aaf1dad6aacef draft/2020-12/meta/applicator
|
|
08343747764e4a5814262793cf4d652057a7913863c5950d43297e8e1fdac5b6 draft/2020-12/meta/content
|
|
c2d12a8e4dd11d336dfc83a3f663aa4c69f0b49b3beb094ffeb25b5316f4803d draft/2020-12/meta/core
|
|
abc775adfefd89d22358170d9bf93f4ebd2349563bbbedd60f02bef7c812bcc0 draft/2020-12/meta/format-annotation
|
|
6a5a8e13c605e3eff51f9bf8da18078880d81ff1634e391760ccc2e16ee2146f draft/2020-12/meta/format-assertion
|
|
8f76d6e14f41b9b92ef933b708cdc5144c8b5268651ad11918485fb1754f1c76 draft/2020-12/meta/meta-data
|
|
2dbfbcb73994b670b0976492adee1fffb46c21682784d2f5a4ca561f9e2d0cb4 draft/2020-12/meta/unevaluated
|
|
7010a31e541f32d2be721e2de348df75c9b36876a3ed304877fc0abda1d37a58 draft/2020-12/meta/validation
|
|
exit=0
|
|
|
|
=== 8.4 test 이름 ===
|
|
$ git ls-files 'adapter/outbound/messaging/src/test/java/dev/caskeleton/adapter/outbound/messaging/envelope' | xargs -n1 basename
|
|
basename: missing operand
|
|
Try 'basename --help' for more information.
|
|
exit=123
|
|
|
|
$ git grep -h ' void [a-z]' -- 'adapter/outbound/messaging/src/test/java/dev/caskeleton/adapter/outbound/messaging/envelope' | sed 's/^ *//'
|
|
exit=0
|
|
|