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>
3.3 KiB
3.3 KiB
kind, slug, title, topic, project, status, sourceRevision, rootTreeNode, decisionStatus, decidedOn, source
| kind | slug | title | topic | project | status | sourceRevision | rootTreeNode | decisionStatus | decidedOn | source | ||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| PROJECT_DECISION | completion-unknown-is-never-retried | completion-unknown은 자동으로도 수동으로도 재시도하지 않는다 | commit-ambiguity-as-a-result | clean-architecture-backend-template | 게시 전 | 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 | decision:completion-unknown-is-never-retried | ADOPTED | 2026-08-11 |
|
completion-unknown은 자동으로도 수동으로도 재시도하지 않는다
결정문
커밋 결과를 알 수 없는 실패는 자동으로도 수동으로도 재시도하지 않고 조정으로 넘긴다.
판단 이유
ADR 의 근거는 이 실패가 일시적인 것이 아니라 인식론적이라는 관찰이다. 연결이 커밋 도중에 끊기면 서버는 커밋했을 수도 있고 확인 응답만 유실됐을 수도 있으며, 드라이버는 그 둘을 구별하지 못한다.
커밋됐을 수도 있는 쓰기를 재시도하는 것은 이 플랫폼이 할 수 있는 가장 해로운 일이다. 재시도가 성공하면 중복이 생기고, 그 중복은 원래 실패보다 알아채기 어렵다.
그래서 이 예외는 좁은 조건에서만 만들어진다. 관측된 단계가 COMMITTING 이고, 동시에 SQLSTATE 나 예외 타입이 결과를 말해 주지 못하는 경우다.
그리고 이 불변식은 정책이 아니라 타입 수준에서 강제된다. completionUnknown 이면서 retryable 인 실패 컨텍스트는 생성자가 거부하므로 존재할 수 없다. 정책 버그가 그 조합을 만들 수 있는 경로 자체가 없다.
영향
감수하는 것
조정 큐가 생기고 그것을 읽는 운영 절차가 필요하다. 자동으로 해소되지 않는 항목이 쌓인다.
조정 큐가 무의미해지지 않도록 모호성 규칙을 좁게 유지해야 한다. 넓히면 평범한 풀 고갈과 서버 재시작이 큐로 밀려들고, 운영자는 큐를 읽지 않고 비우는 습관을 배운다.
실제로는 롤백된 트랜잭션도 조정으로 넘어간다. 드라이버가 말해 주지 않았으므로 구별할 수 없다.
얻는 것
중복 쓰기가 자동 경로에서 발생하지 않는다.
모르는 것이 상태로 남아서 나중에 사람이 판단할 재료가 보존된다.
근거
- pg_terminate_backend가 57P01로 도착하고 커밋 레코드는 이미 WAL에 있었다 이 결정이 다루는 실패가 실제로 어떤 모습인지 보여 주는 사례다.
- 모르는 것은 성공도 실패도 아닌 세 번째 결과여야 한다 이 결정이 전제하는 상태 어휘다.
- 위험한 조합은 정책이 아니라 생성자가 거부하게 만든다 이 결정을 타입 수준에서 강제하는 방법이다.
- 커밋 모호성 판정은 넓혀도 좁혀도 해롭다 이 결정의 조건을 어디에 둘지 정하는 기준이다.