diff --git a/.opencode/agents/architect.md b/.opencode/agents/architect.md index f3a344f..c5745d3 100644 --- a/.opencode/agents/architect.md +++ b/.opencode/agents/architect.md @@ -241,9 +241,49 @@ last_updated: 2026-05-29 5. **WHAT not HOW**: Specs describe components and interfaces. ADRs explain why. Neither describes code-level implementation. 6. **No historical artifacts**: Specs describe what IS, not what WAS. Changelogs - and migration notes belong in commit messages or separate migration docs. + and migration notes belong in commit messages or separate migration docs. 7. **Lifecycle states**: Every doc has a status. Draft → reviewed → stable → deprecated. Stale `draft` docs are a sign of unfinished work. +8. **Decisions are made, not deferred**: An open question that has a clear + answer is resolved, not left "open" with hedging language like "v1 default" + or "can be revisited later." If the decision is made, mark it resolved. If + the decision genuinely can't be made yet (the use case isn't concrete, + the options aren't clear), leave it open — but say *why* it can't be made, + not "we'll decide later." The architect's job is to make architecture + decisions, not to defer them to the implementation agent. + +## Door Types and Decision Urgency + +ADR-009 classifies decisions by **reversal cost** (one-way vs two-way), not by +urgency. This distinction is important: + +- **One-way door**: Getting it wrong is expensive (rewrites across crates, + permanently closed capabilities). Requires an ADR before implementation. + Gets the deliberation it deserves. +- **Two-way door**: Getting it wrong is recoverable (cheap revert, additive + change). Still requires a decision — pick the simplest option that works, + implement it, revert if needed. The decision is made; what's cheap is the + reversal, not the decision. + +**Door type ≠ deferral.** A two-way door is not a license to leave a decision +unmade. Using "it's a two-way door" as a reason to defer an architectural +decision is the specific anti-pattern this framework was tightened to prevent +(see ADR-009 §"What this framework is NOT"). The decision compounds — downstream +code builds on whatever the implementation picked by default, making the "cheap +reversal" expensive. + +**Architecture decisions are the architect's, regardless of door type.** The +implementation agent makes implementation decisions (variable names, loop +order, which library to use for a concrete task). If a decision affects the +system's structure, constraints, or API surface, it's an architecture decision +— even if it's a two-way door. A two-way architecture decision is still made by +the architect; it just doesn't need a POC or extensive deliberation first. + +**Deferral is separate.** Sometimes a decision genuinely doesn't need to be +made yet because the use case isn't concrete (scope management). That's a valid +scoping judgment, but it's a different concept from door type, and it should be +stated explicitly as "not needed for the current scope" rather than "two-way +door, decide later." ## Anti-Patterns to Avoid @@ -258,6 +298,17 @@ last_updated: 2026-05-29 6. **Missing ADR for a visible choice**: If a reader would ask "why X over Y?", write an ADR 7. **No README index**: Without the index table, ADRs and docs are unfindable +8. **Door type as deferral**: Using "two-way door" as a reason to leave an + architectural decision unmade. Door type classifies reversal cost, not + urgency. A two-way door is a decision you make now and can revert later — + not a decision to defer. If the decision is made, mark the OQ resolved. If + it genuinely can't be made yet, say why (scope, missing information), not + "we'll decide later." +9. **Hedging language in resolved decisions**: Phrases like "v1 default", + "phase_n", "when x arrives", "can be revisited" on decisions that are + actually made. If the decision is made, state it cleanly. Reserve temporal + language for decisions that are genuinely deferred by scope — and even + then, say "not needed for the current scope" rather than "v1." ## When to Redirect diff --git a/docs/architecture/decisions/009-one-way-door-decision-framework.md b/docs/architecture/decisions/009-one-way-door-decision-framework.md index 62d99d0..53f9269 100644 --- a/docs/architecture/decisions/009-one-way-door-decision-framework.md +++ b/docs/architecture/decisions/009-one-way-door-decision-framework.md @@ -16,23 +16,31 @@ Without an explicit framework, one-way doors can be treated as casually as two-w ### Classification -Every architectural decision is classified as one of: +Every architectural decision is classified by **reversal cost** — how expensive it is to undo if you got it wrong: -**One-way door** — Reversing this decision requires rewriting significant code across multiple crates or permanently closes a capability door. Examples: +**One-way door** — Reversing this decision requires rewriting significant code across multiple crates or permanently closes a capability door. Getting it wrong is expensive. Examples: - BiStream as a concrete quinn type (closes WASM door permanently) - alknet-vault pulled into alknet-core as a dependency (loses standalone property permanently) - ProtocolHandler signature changes (every handler must be rewritten) -**Two-way door** — Reversing this decision is cheap or additive. Examples: +**Two-way door** — Reversing this decision is cheap or additive. Getting it wrong is recoverable. Examples: - Static vs dynamic handler registration (can add ArcSwap later) - Single transport vs multi-transport endpoint (can add transport trait later) - Call protocol stream model (can add multiplexing later) ### Process -- **One-way doors** require an ADR before implementation. If the right choice is unclear, validate with a POC before writing the ADR. If a POC can't resolve the uncertainty within a reasonable timebox, default to the option that keeps more doors open. -- **Two-way doors** can be decided during implementation. Start with the simplest option and add complexity when needed. Note the decision in a commit message or a brief ADR if the context is worth capturing, but don't block on it. -- When in doubt, classify up. If it's unclear whether a door is one-way or two-way, treat it as one-way until proven otherwise. +- **One-way doors** require an ADR before implementation. If the right choice is unclear, validate with a POC before writing the ADR. If a POC can't resolve the uncertainty within a reasonable timebox, default to the option that keeps more doors open. One-way doors get the deliberation they deserve because getting them wrong is expensive. +- **Two-way doors** still require a decision — pick the simplest option that works, implement it, and move on. If it turns out wrong, revert and try the alternative. The decision is made; what's cheap is the reversal. Note the decision in a commit message or a brief ADR if the context is worth capturing, but don't block on it. +- When in doubt about which classification applies, classify up. If it's unclear whether a door is one-way or two-way, treat it as one-way until proven otherwise. + +### What this framework is NOT + +This framework classifies decisions by **reversal cost**, not by **urgency**. It does not say "two-way doors can be deferred." A two-way door is a decision you make now and can revert later if needed — it's not a license to leave the decision unmade. + +- **Deferral** is a separate concept: sometimes a decision genuinely doesn't need to be made yet because the use case isn't concrete (scope management). That's valid, but it's a scoping judgment, not a door-type classification. +- **Conflating the two** — using "it's a two-way door" as a reason to defer an architectural decision — leads to decisions that compound into a mess. The decision gets made by default (the implementation picks something), and downstream code builds on it, making the "cheap reversal" expensive. +- **The architect's role**: architecture decisions (one-way OR two-way) are for the architect to make, not the implementation agent. The implementation agent makes implementation decisions (variable names, loop order, which library to use for a parsed task). If a decision affects the system's structure, constraints, or API surface, it's an architecture decision regardless of its door type. ### WASM as a design constraint @@ -46,10 +54,10 @@ This is not "WASM support now." It's "don't close the WASM door accidentally." ## Consequences **Positive:** -- One-way doors get the deliberation they deserve — ADRs, POCs, explicit justification -- Two-way doors don't block progress — start simple, add complexity when needed +- One-way doors get the deliberation they deserve — ADRs, POCs, explicit justification — because getting them wrong is expensive +- Two-way doors don't block progress — decide, implement, revert if needed — because getting them wrong is recoverable - WASM compatibility is preserved as a constraint, not treated as an active deliverable -- The framework creates a shared vocabulary for discussing decision urgency ("is this a one-way door?") +- The framework creates a shared vocabulary for discussing reversal cost ("is this a one-way door?") **Negative:** - Classification requires judgment — some decisions are genuinely ambiguous (mitigated: classify up when in doubt) diff --git a/docs/architecture/open-questions.md b/docs/architecture/open-questions.md index 25ec24e..e4c7d3a 100644 --- a/docs/architecture/open-questions.md +++ b/docs/architecture/open-questions.md @@ -7,9 +7,11 @@ last_updated: 2026-06-27 Questions are organized by theme. Each question has a stable OQ-ID for cross-referencing from spec documents. -Door type classifications follow ADR-009: -- **One-way door**: Reversal requires rewriting significant code or permanently closes a capability. Requires ADR before implementation. -- **Two-way door**: Reversal is cheap or additive. Can be decided during implementation. +Door type classifications follow ADR-009 — they describe **reversal cost** (how expensive it is to undo), not urgency: +- **One-way door**: Reversal requires rewriting significant code or permanently closes a capability. Getting it wrong is expensive — requires ADR before implementation. +- **Two-way door**: Reversal is cheap or additive. Getting it wrong is recoverable — decide, implement, revert if needed. + +Door type is separate from whether a decision is made. A two-way door is a decision you make now and can revert later, not a decision to defer. See ADR-009 §"What this framework is NOT." ## Theme: Core Types