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>
61 lines
2.9 KiB
Java
61 lines
2.9 KiB
Java
import dev.caskeleton.adapter.outbound.notification.core.FailOpenNotificationProvider;
|
|
import dev.caskeleton.adapter.outbound.notification.core.NotificationProvider;
|
|
import dev.caskeleton.adapter.outbound.support.FailOpenDependencyLogger;
|
|
import dev.caskeleton.application.notification.Channel;
|
|
import dev.caskeleton.application.notification.Notification;
|
|
import java.lang.reflect.Proxy;
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
import org.slf4j.Logger;
|
|
|
|
public class NotificationLoggerFailureProbe {
|
|
private static Logger loggerThatThrowsOn(String methodToThrow, AtomicInteger debug, AtomicInteger warn) {
|
|
return (Logger) Proxy.newProxyInstance(
|
|
NotificationLoggerFailureProbe.class.getClassLoader(),
|
|
new Class<?>[] {Logger.class},
|
|
(proxy, method, args) -> {
|
|
if (method.getName().equals("debug")) debug.incrementAndGet();
|
|
if (method.getName().equals("warn")) warn.incrementAndGet();
|
|
if (method.getName().equals(methodToThrow)) {
|
|
throw new IllegalStateException("logger-" + methodToThrow + "-failed");
|
|
}
|
|
if (method.getReturnType() == boolean.class) return true;
|
|
if (method.getReturnType() == String.class) return "probe.notification";
|
|
return null;
|
|
});
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
Notification n = new Notification("secret@gmail.com", "subject", "body");
|
|
|
|
AtomicInteger sends = new AtomicInteger();
|
|
AtomicInteger debug = new AtomicInteger();
|
|
AtomicInteger warn = new AtomicInteger();
|
|
NotificationProvider successful = new NotificationProvider() {
|
|
public Channel channel() { return Channel.EMAIL; }
|
|
public String providerId() { return "google-email"; }
|
|
public void send(Notification ignored) { sends.incrementAndGet(); }
|
|
};
|
|
var successPath = new FailOpenNotificationProvider(
|
|
successful, new FailOpenDependencyLogger(loggerThatThrowsOn("debug", debug, warn)));
|
|
successPath.send(n);
|
|
System.out.printf("SUCCESS_PATH sends=%d debugCalls=%d warnCalls=%d%n", sends.get(), debug.get(), warn.get());
|
|
|
|
AtomicInteger failDebug = new AtomicInteger();
|
|
AtomicInteger failWarn = new AtomicInteger();
|
|
NotificationProvider failing = new NotificationProvider() {
|
|
public Channel channel() { return Channel.EMAIL; }
|
|
public String providerId() { return "google-email"; }
|
|
public void send(Notification ignored) { throw new RuntimeException("provider-failed"); }
|
|
};
|
|
var failurePath = new FailOpenNotificationProvider(
|
|
failing, new FailOpenDependencyLogger(loggerThatThrowsOn("warn", failDebug, failWarn)));
|
|
try {
|
|
failurePath.send(n);
|
|
System.out.println("FAILURE_PATH propagated=none");
|
|
} catch (RuntimeException ex) {
|
|
System.out.printf("FAILURE_PATH propagated=%s:%s warnCalls=%d%n",
|
|
ex.getClass().getSimpleName(), ex.getMessage(), failWarn.get());
|
|
}
|
|
}
|
|
}
|