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

5.3 KiB

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.