You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(adr-0114): record the degraded gauge and the missing-vs-unreadable split
Amends §4 and the acceptance criteria for the two follow-ups the 2026-07-30
amendment deliberately held out of the bug fix.
"Sets a degraded gauge" stops being aspirational: §4 now names the three surfaces
that publish it, and records the three shape decisions (absent rather than 0 when
the lever is not requested; no free-text reason label in the exposition; it does
not feed the console's engine-health heart) so they are not re-litigated.
AC-7 gains the unreadable-definition condition. New AC-7c requires the gauge to be
a surface an operator can READ, not merely an attribute — AC-7 as written required
a gauge and nothing required anyone to be able to see it, which is the same
one-directional gap the 2026-07-30 amendment found in the gate itself.
Also corrects the record on probe (a): the ADR always specified an OBJECT_ID
probe, and the implementation had folded it into the OBJECT_DEFINITION read.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/adr/0114-phase-4-claim-path-call-complexity-reduction-driver-interface-redesign-ingress-routed-reset-fold.md
+74-7Lines changed: 74 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -398,9 +398,9 @@ compat-120 database and under a DDL-denied principal.
398
398
`OBJECT_ID` of **both** procs; (b) a SHA-256 of each deployed body via `OBJECT_DEFINITION()` against the
399
399
**stored forms** of the shipped DDL text (normalized) — **existence alone cannot catch a hand-edited body**, and
400
400
the ADR 0064 marker covers only in-repo edits, while the proc *is* the claim logic; (c) `compatibility_level ≥
401
-
130`. Any failure → the store records `claim_proc_effective = False`, logs a **WARNING naming the reason** and
402
-
runs the shipped batch — never a lane outage; the hot path contains **no error-2812 handling**. Out-of-band
403
-
drift is caught at the next open.
401
+
130`. Any failure → the store records `claim_proc_effective = False`, logs a **WARNING naming the reason**,
402
+
publishes the degraded gauge (see the second amendment below), and runs the shipped batch — never a lane
403
+
outage; the hot path contains **no error-2812 handling**. Out-of-band drift is caught at the next open.
404
404
405
405
> **AMENDMENT (2026-07-30) — `OBJECT_DEFINITION()` does not return the submitted text, and this gate was
406
406
> inert until it was fixed.**
@@ -437,6 +437,65 @@ drift is caught at the next open.
437
437
> work** — the re-apply submits the same text, the engine rewrites it the same way, and the hash mismatches
438
438
> again — so the advice has been removed from the ADR and from the operator-facing degraded reason.
439
439
440
+
> **AMENDMENT (2026-07-31) — the degraded gauge now exists, and probe (a) is a real probe again.** Two
441
+
> follow-ups the amendment above deliberately held out of the bug fix.
442
+
>
443
+
> **1. The gauge was aspirational.** AC-7 requires "a WARNING naming the reason **+ degraded gauge**", and this
444
+
> section's compensating-control story assumes an operator can SEE the degraded state. Until this amendment
445
+
> nobody could: `claim_proc_effective` / `claim_proc_degraded_reason` were read by the store's own tests and
446
+
> **nothing else** — no `/stats`, no `/status`, no `/metrics`, no console. The entire operator signal was one
447
+
> WARNING line at `open()`. That is not a missing nicety, it is a load-bearing part of *why the amendment above
448
+
> was needed*: a fleet running the flag degraded on every open, forever, and the only thing that could have
449
+
> told anyone was a log line nobody was watching which named the wrong cause.
450
+
>
451
+
> The gauge is now a store accessor, `claim_proc_status()`, surfaced on three operator surfaces:
452
+
>
453
+
> | surface | carries |
454
+
> |---|---|
455
+
> |`GET /status` → `claim_proc`|`effective`, the human-readable `degraded_reason`, and the matched `head_forms`|
456
+
> |`GET /metrics`|`messagefoundry_store_claim_proc_effective` (0/1) and `messagefoundry_store_claim_proc_head_verbatim` (0/1) |
457
+
> | the console's store panel (`/ui/status`) | active-vs-degraded, plus the reason when degraded / the head forms when green |
458
+
>
459
+
> Three shape decisions, so they are not re-litigated. **`None` when the flag is off**, so "not requested" is a
460
+
> distinct state from "requested and degraded"; the Prometheus series are correspondingly **absent**, not a
461
+
> constant `0` that every SQLite fleet would publish unalertably. **No reason label in the exposition** — the
462
+
> reason is free text embedding a proc name and, on the probe-failure arm, an exception string, so a label
463
+
> would be unbounded cardinality *and* a breach of the exporter's strict `{connection, destination, status,
464
+
> version, le}` allowlist; the string lives on `/status` and the console instead. **It does not feed the
465
+
> console's engine-health heart**: a degrade is a performance lever not paying off, claims keep flowing, and
466
+
> making the nav cry wolf about it would devalue the signal that means the store is actually unwell.
467
+
>
468
+
> `head_forms` (proc name → `rewritten` | `verbatim`) is surfaced for the same reason it is logged: a fleet
469
+
> reporting `verbatim` is a live counterexample to `_CLAIM_PROC_STORED_HEADS`'s compatibility assumption — no
470
+
> engine measured to date stores the `CREATE OR ALTER` head unrewritten — and it was previously visible only
471
+
> at INFO. Observability only: the accept/degrade logic is untouched.
472
+
>
473
+
> **2. A missing `VIEW DEFINITION` grant was reported as a missing proc.** This section has always specified
474
+
> probe (a) as "`OBJECT_ID` of **both** procs", but the implementation folded (a) into (b) and inferred absence
475
+
> from a NULL `OBJECT_DEFINITION`. **MEASURED** (2026-07-31, on the lab SQL Server): a principal holding only
476
+
> `EXECUTE` on the proc gets a non-NULL `OBJECT_ID` and a **NULL**`OBJECT_DEFINITION`; the compat probe still
477
+
> passes. So a deployed, working, correct procedure was reported as *missing*, and the operator was sent to fix
478
+
> a `CREATE PROCEDURE` permission that was neither the cause nor the cure. `WITH ENCRYPTION` produces the
479
+
> identical NULL and the identical misdiagnosis — and because *that* half needs no security principal, it is
480
+
> now a live test leg (`test_a_deployed_proc_can_return_a_null_definition`), which pins on a real server the
481
+
> one thing an offline stub cannot show: that the two functions genuinely disagree. The permission half stays
482
+
> deferred with AC-10's other permission scenarios to a purpose-configured server.
483
+
>
484
+
> This is not a hypothetical posture here: §5's sub-lever B design explicitly serves "a fleet whose DB
485
+
> principal can never hold `CREATE PROCEDURE`" — DBA-provisioned procs plus a least-privilege app principal —
486
+
> which is exactly the deployment shape that hits it. The probe now returns `OBJECT_ID` beside the definition
487
+
> and the two conditions get separate reasons:
488
+
>
489
+
> | condition | reason |
490
+
> |---|---|
491
+
> |`OBJECT_ID` NULL | genuinely absent — guarded DDL skipped, `CREATE PROCEDURE`/ALTER-on-schema denied, or a pre-2016-SP1 engine |
492
+
> |`OBJECT_ID` non-NULL, `OBJECT_DEFINITION` NULL | deployed but unreadable — **`GRANT VIEW DEFINITION`**, or the module is `WITH ENCRYPTION`|
493
+
>
494
+
> Both still **degrade** — the gate hashes the body and cannot pass on one it cannot read — so no accept/reject
495
+
> behaviour changed; only the diagnosis did. The probe SQL is pinned by an exact-match assertion in the
496
+
> offline suite (a typo'd probe must fail loudly rather than silently match), so that pin moved with it and
0 commit comments