resource-control/docs/evidence-basis.md
tegwick 7a196b6265 feat: adopt canon 0.4.0-0.6.0 — EvidenceBasis is canon, uses_provisions is canon
Both demands were accepted. Adopting what landed.

EVIDENCE BASIS IS NOW ITC-GOV CANON (0.4.0)
tools/basis.py reads infospace/models/governance/evidence-basis.yaml instead of
defining its own vocabulary — same discipline we already applied to the
capability catalog. Two semantic changes came back that we did not have:

- estimated and assumed are peers in tier "judgement". We had them separately
  ranked, which asserted a difference the canon does not.
- derived belongs to no tier at all; asking for its tier before resolving it is
  now an error rather than a silent rank.

Tier membership is read from tiers[].members, not bases[].tier: the latter
labels invoiced/measured/quoted all as "evidenced" while the tier list splits
them across "observed" and "quoted". tiers[] is authoritative; reported upstream.

USES_PROVISIONS IS NOW CANON (0.5.0, CAP-R11)
Dropped the proposed_extensions marker. Renamed relation "uses" to "may_use" per
their migration note. tools/capability.py now enforces CAP-R11: relation must be
depends_on or may_use, a provider must be named, and a depends_on entry MUST be
declared between those capabilities in the catalog. data.backup gained catalog
may_use: security.secrets from our restatement, so our entry now checks out.

Also in 0.4.0: §10.3 changed so a joinable consumer record counts as promotion
proof, met by our restatement; ITC-CAP is now 0.4.0 / canon 0.6.0, status draft.
Record and tests updated to those versions.

196 tests pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 19:57:46 +02:00

117 lines
5.3 KiB
Markdown

# Evidence basis — where we know, and where we guess
A counted object and an assumed hourly rate are both numbers. They are not both
knowledge. Every quantity in this repository declares **how it was obtained**,
so a decision can be graded by the weakest thing it actually rests on.
**The vocabulary is canon, owned by ITC-GOV.** resource-control originated the
concept, filed it as `demand/EvidenceBasis.md`, and info-tech-canon adopted it in
canon 0.4.0 as `infospace/models/governance/evidence-basis.yaml`. `tools/basis.py`
now *reads* that catalog rather than defining its own — the same discipline we
apply to the capability catalog. Drift in either repository fails our suite.
`CAP-R10` requires a basis on every `CapabilityConsumption` row.
## The scale
Strength is a **tier**, not a total order. Members of one tier are peers and do
not rank against each other — asserting an order between them would make the
propagation rule claim something it cannot know.
| Tier | Rank | Bases | Example here |
|---|---|---|---|
| `observed` | 0 | `invoiced`, `measured` | 8 objects, 6 604 031 B in the backup prefix |
| `quoted` | 1 | `quoted` | Scaleway €0.01606/GB-month |
| `projected` | 2 | `projected` | 457.968 GB stored at month 12 |
| `judgement` | 3 | `estimated`, `assumed` | apps-pg 6 operator-hours setup; €60/hour rate |
| `unknown` | 4 | `unknown` | railiance01 monthly price |
`derived` belongs to **no tier**: it resolves against its inputs, and asking for
its tier before resolution is an error.
`observed` and `quoted` are both **evidenced** — they assert an observed or
contracted fact. `quoted` sits below `observed` for propagation while still
counting as evidenced for a decision grade; the canon separates those two uses
deliberately, because a counterparty's stated price is a fact about a claim and
a measurement is a fact about the world.
An invoice is authoritative for a payment and a measurement is authoritative for
a quantity, so neither outranks the other — they are peers in `observed`. Our
first implementation used a strict list order and got this wrong; the canon
carries the corrected form as a normative rule.
## The propagation rule
> A derived value is only as strong as its weakest input.
Without this rule a precise-looking figure launders weak assumptions. The
monthly labour line for the backup store is €60.00, which reads like a
measurement. It is `derived` from an `assumed` operator-hour allowance and an
`assumed` hourly rate, so it resolves to **`assumed`** — the weakest class of
input we have.
Deriving in the other direction is not penalised: GB computed from measured
bytes resolves to `measured`, because both inputs are.
## Two orthogonal qualifiers
**`proxy_for`** — the value is a genuine measurement of a *different* quantity
than the one being reasoned about. It does not weaken the measurement; it
weakens the inference. The apps-pg allocation driver measures database bytes
accurately, and one of those databases has never recorded a transaction, so as
a driver for cost it is a proxy whose validity is separate from its precision.
**`observed_at`** — a measurement has an age. A single sample from a
four-hour-old resource is `measured` and still thin.
## Unknown is never zero
A value with basis `unknown` carries no quantity and must name the gap and its
owner. A value with any other basis must carry a quantity. Zero means "measured
and none"; unknown means "not measured". The validator enforces both directions.
## Decision grades
`decision_grade(values)` reports the distribution, the weakest basis, the
evidenced ratio, and a grade:
| Grade | Condition |
|---|---|
| `evidenced` | Every load-bearing value is invoiced, measured, or quoted |
| `projected` | The conclusion rests on values projected from observations |
| `indicative` | The conclusion is no stronger than an estimated or assumed value |
| `insufficient` | At least one load-bearing value is unknown |
### The first real application
The provider comparison that selected Scaleway over Hetzner — a €29.14/month
difference stated to the cent — grades **`indicative`**:
```
by_basis: {quoted: 1, projected: 1, assumed: 2}
weakest: assumed
evidenced_ratio: 0.25
```
One of four load-bearing values is evidenced. The two labour figures, which are
what actually inverted the ranking, are both `assumed` on top of `assumed`.
This does not overturn the decision. The direction is robust — Hetzner needs
more operator time under any plausible rate, and the alternative was five times
dearer. But it does say plainly that the *magnitude* is a model output, not a
measurement, and that the cheapest way to strengthen it is to record real
operator hours rather than to refine the arithmetic.
That is the whole purpose of the scale: to make the difference between a firm
conclusion and a confident-looking one visible before it is acted on.
## Where it applies today
- `data/capability/*.json` — every consumption row and evidence item.
- Provider comparisons carried in a capability restatement.
Not yet retrofitted: `data/actuals/`, `data/control-cycle/`, and the option
fields of `data/optimization/`. Those already distinguish known from unknown and
carry `measurement_gaps` and `uncertainty` notes, but they do not yet grade a
present value. That is the next step, and it is the one that would let
`make thresholds` report a breach alongside the strength of the evidence
producing it.