From d35257edd6e873b158d9e1ee2d8b4367b8181aea Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Sat, 25 Jul 2026 09:21:24 +0300 Subject: [PATCH] =?UTF-8?q?docs(decision):=20D1/D4=20sub-2=20scores=20are?= =?UTF-8?q?=20derived=20=E2=80=94=20no=20independent=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit D1<2 is the D3-inherent manual root open; D4<2 is the decorator-free floor + inherent @inject (D5) + inherent lifecycle (D3). Corrects the audit's item-5 one-line-trim claim and records the post-rollout blessed-ready count of 4 (the ceiling under the inherent rulings). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../2026-07-22-blessed-ready-onramp-report.md | 27 +++++--- .../2026-07-25-d1-d4-derived-inherent.md | 69 +++++++++++++++++++ 2 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 planning/decisions/2026-07-25-d1-d4-derived-inherent.md diff --git a/planning/audits/2026-07-22-blessed-ready-onramp-report.md b/planning/audits/2026-07-22-blessed-ready-onramp-report.md index b7199e5..ccb2c00 100644 --- a/planning/audits/2026-07-22-blessed-ready-onramp-report.md +++ b/planning/audits/2026-07-22-blessed-ready-onramp-report.md @@ -220,14 +220,25 @@ Ranked by leverage (integrations touched / newcomer-facing weight) × cost (docs code vs new repo). The `not yet` integration with the fewest, cheapest sub-2 dims ranks first, since it is the cheapest path to a second blessed-ready row. -**Resolution (2026-07-25):** the **D3 / root-lifecycle** items below (1, 4, and the -lifecycle halves of 6, 7, 8, 9) are ruled **inherent by design** — no integration -code changes; see [decision: D3 root-lifecycle gaps are inherent](../decisions/2026-07-25-d3-root-lifecycle-inherent.md). -The **`@inject` item (3)** is likewise ruled **inherent** — `@inject` is required -only where the framework offers no per-parameter seam; see -[decision: the @inject asymmetry is inherent](../decisions/2026-07-25-inject-asymmetry-inherent.md). -The **canonical-example** items (2, 5, and the D2/D6 halves) shipped — every -integration now clears D2/D6. +**Resolution (2026-07-25):** every backlog item below is resolved. + +- **Canonical example** (item 2 + the D2/D6 halves of 5-9): **shipped** — all 12 + integrations now clear D2/D6. +- **D3 / root-lifecycle** (items 1, 4, and the lifecycle halves of 6-9): ruled + **inherent by design**; see [decision: D3 root-lifecycle gaps are inherent](../decisions/2026-07-25-d3-root-lifecycle-inherent.md). +- **`@inject`** (item 3): ruled **inherent** — `@inject` is required only where + the framework offers no per-parameter seam; see + [decision: the @inject asymmetry is inherent](../decisions/2026-07-25-inject-asymmetry-inherent.md). +- **D1 / D4** (item 5 + the D1/D4 halves of 7-9): **derived** from the inherent + D3/D5 above — no independent trim. Item 5's "one-line trim" does not hold: the + only line over the D4 bar is the inherent `@inject` line. See + [decision: D1/D4 sub-2 scores are derived](../decisions/2026-07-25-d1-d4-derived-inherent.md). + +**Blessed-ready is now 4** (litestar + aiogram, aiohttp, arq): the canonical-example +rollout flipped three, since D4=1 and D5=1 do not block the verdict. That is the +ceiling under the inherent rulings — the other eight are each gated by a +framework-inherent D3 (and, for flask/grpc/typer, D1), every one with a revisit +trigger. 1. **fastapi — close the D3 root-open caveat (Σ=11, only D3=1 blocks the verdict).** Leverage: flips one integration to blessed-ready — the single cheapest verdict diff --git a/planning/decisions/2026-07-25-d1-d4-derived-inherent.md b/planning/decisions/2026-07-25-d1-d4-derived-inherent.md new file mode 100644 index 0000000..cd6947c --- /dev/null +++ b/planning/decisions/2026-07-25-d1-d4-derived-inherent.md @@ -0,0 +1,69 @@ +--- +status: accepted +summary: D1 (one-call setup) and D4 (quickstart length) sub-2 scores are arithmetic consequences of the already-inherent @inject (D5) and caller-owned root lifecycle (D3) — no independent quickstart or setup fix; the audit's item-5 one-line trim does not hold. Post-rollout blessed-ready count is 4 (the ceiling under the inherent rulings). +supersedes: null +superseded_by: null +--- + +# D1/D4 sub-2 scores are derived — no independent fix + +**Decision:** The D1 and D4 scores below 2 in the +[blessed-ready on-ramp audit](../audits/2026-07-22-blessed-ready-onramp-report.md) +are arithmetic consequences of two facts already ruled inherent — the `@inject` +requirement ([D5](2026-07-25-inject-asymmetry-inherent.md)) and the caller-owned +root lifecycle ([D3](2026-07-25-d3-root-lifecycle-inherent.md)) — not independent +gaps. No quickstart or `setup_di` changes; the audit's §4 item-5 "trim one line" +does not hold. + +## Context + +D1 scores one-call setup (distinct wiring actions); D4 scores steps-to-first- +dependency (`L`, the DI-specific lines in a minimal single-dependency quickstart, +2 = `L` ≤ 7). The audit's §4 backlog carried D4 items (5, and the D4 halves of 8, +9) and D1 items (7, 8, 9) as candidate "quickstart trims." This checks whether any +is an independent fix once D3 and D5 are ruled inherent. + +## Decision & rationale + +**D1 < 2 is D3, restated.** Only flask, grpc, typer score D1=1, and in each the +second action is the manual root `open()` — the exact caller-owned-root fact ruled +inherent in the D3 decision. The audit itself notes flask's "D1=1 and D3=1 share +one root cause." No independent D1 fix exists. + +**D4 < 2 is D5 + D3, by line count.** The decorator-free floor is `L`=7 (two +imports, a `Group` + one provider + its dependency, `Container(...)`, `setup_di`). +Verified against the merged examples: + +- **aiogram, aiohttp, arq** — `L`=8 = the floor **+ the `@inject` line** (D5, + inherent). The audit's item 5 ("trim one line, D5 not part of it") is wrong: the + only line over 7 *is* `@inject`. +- **flask, typer** — `L`=9 = floor + `@inject` + the manual root `open()`/`with` + (D3, inherent). +- **grpc** — `L`=10 = floor + `@inject` + manual `open()` + `close_sync()` (D3, + inherent); the lone D4=0. + +Nothing is trimmable without deleting an inherent element. A minimal +single-dependency example needs both providers (a service *and* the thing it +depends on) to demonstrate DI at all, so the floor itself cannot drop. + +**The scores are also mostly moot.** The verdict rule is D1=D2=D3=2 and no `0`; +**D4=1 and D5=1 never block.** So once the canonical-example rollout fixed D2/D6, +the D4=1 rows are not held back by D4 at all — only grpc's D4=0 is a dimension- +zero, and grpc is already blocked by its inherent D1/D3. + +**Corrected blessed-ready count: 4.** Post-rollout, litestar plus **aiogram, +aiohttp, arq** clear the verdict (D1=D2=D3=2, no zero; their D4=1/D5=1 do not +block) — up from 1 at audit time. That is the **ceiling** under the inherent +rulings: the other eight are each gated by a framework-inherent **D3** lifecycle +score (or, for flask/grpc/typer, D1 too), every one with a revisit trigger in the +D3/D5 records. No integration reaches blessed-ready by a quickstart edit. + +**Consistency.** Same conclusion as the D3, D5, and +[exec](2026-07-19-exec-hot-path-declined.md) records: a sub-2 score reflecting a +framework limitation, not a modern-di gap, is documented, not engineered away. + +## Revisit trigger + +Whichever underlying record reopens: if `@inject` (D5) or the caller-owned root +lifecycle (D3) becomes avoidable for an integration, its D1/D4 improve for free. +No independent D1/D4 trigger.