Three things. 1. CANON RESTATEMENT (info-tech-canon's ask after accepting our demand) data/capability/platform-audit-storage.json restates the backup case against ITC-CAP 0.2.0: requirement with profile, targets and the failure-domain constraint that decided the procurement; two provisions (data.object and data.backup); all four data.backup evidence hooks satisfied and measured; and consumption in native units — GB, hours, tokens — with unknown never zero. tools/capability.py reads their capabilities.yaml directly rather than copying it, so drift in either repo fails here. The requirement asks D5, the provision is D4, and the review reports below_requirement rather than inflating maturity. 2. EVIDENCE BASIS (tools/basis.py, docs/evidence-basis.md) Every value declares how it was obtained on an ordered scale: invoiced, measured, quoted, derived, projected, estimated, assumed, unknown. A derived value resolves to the weakest basis among its inputs, so precise arithmetic cannot launder weak assumptions. First application is a finding about our own biggest decision: the Scaleway vs Hetzner comparison, EUR 29.14/month stated to the cent, grades "indicative" — 1 of 4 load-bearing values evidenced, weakest "assumed". The direction is robust; the magnitude is a model output. The cheapest fix is recording real operator hours, not better arithmetic. 3. CONSUMPTION-MODE SIGNAL (railiance-platform RAILIANCE-WP-0017) settlement.py gains a consumption-mode command projecting statements into the signal they consume; make consumption-mode PERIOD=YYYY-MM publishes data/consumption-mode/current.json. Currently an empty list: no live charges for 2026-09, so no entity is restricted. Publishing the empty list makes that an assertion rather than an absence, which their contract distinguishes. The validator fails if the published signal is stale. 185 tests pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
163 lines
6.2 KiB
Python
163 lines
6.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Evidence basis: how a value was obtained, and how far it can be trusted.
|
|
|
|
Every quantity in this repository is one of a small number of epistemic kinds.
|
|
A counted object and an assumed hourly rate are both numbers; they are not both
|
|
knowledge. This module names the difference and propagates it.
|
|
|
|
The central rule is that a derived value is only as strong as its weakest
|
|
input. Without it, a precise-looking figure launders weak assumptions: EUR 30.00
|
|
of monthly labour reads like a measurement, when it is another repository's
|
|
estimate of hours multiplied by a rate we chose.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Ordered strongest to weakest. The order is the whole point: it is what makes
|
|
# "weakest input wins" computable.
|
|
BASIS_ORDER = (
|
|
"invoiced", # a booked financial fact, authoritative from fin-hub
|
|
"measured", # directly observed from the authoritative system
|
|
"quoted", # stated by a provider or counterparty in a citable source
|
|
"derived", # computed from other values by a stated rule
|
|
"projected", # interpolated between, or extrapolated beyond, observations
|
|
"estimated", # human judgement, neither observed nor computed
|
|
"assumed", # a modelling constant we chose
|
|
"unknown", # no value exists
|
|
)
|
|
BASES = frozenset(BASIS_ORDER)
|
|
_RANK = {name: index for index, name in enumerate(BASIS_ORDER)}
|
|
|
|
# Bases that assert an observed or contracted fact about the world.
|
|
EVIDENCED = frozenset({"invoiced", "measured", "quoted"})
|
|
|
|
|
|
def rank(basis: str) -> int:
|
|
if basis not in _RANK:
|
|
raise ValueError(f"unknown evidence basis {basis!r}")
|
|
return _RANK[basis]
|
|
|
|
|
|
def weakest(bases) -> str:
|
|
"""The weakest basis in a collection. Empty means nothing is known."""
|
|
bases = list(bases)
|
|
if not bases:
|
|
return "unknown"
|
|
return max(bases, key=rank)
|
|
|
|
|
|
def strongest(bases) -> str:
|
|
bases = list(bases)
|
|
if not bases:
|
|
return "unknown"
|
|
return min(bases, key=rank)
|
|
|
|
|
|
def is_evidenced(basis: str) -> bool:
|
|
"""True when the value asserts an observed or contracted fact."""
|
|
return basis in EVIDENCED
|
|
|
|
|
|
def resolve(value: dict) -> str:
|
|
"""Effective basis of a value, propagating through derivation.
|
|
|
|
A `derived` value resolves to the weakest basis among its inputs: deriving
|
|
GB from measured bytes stays measured, while deriving euros from estimated
|
|
hours and an assumed rate is no better than assumed.
|
|
"""
|
|
basis = value.get("basis", "unknown")
|
|
if basis not in BASES:
|
|
raise ValueError(f"unknown evidence basis {basis!r}")
|
|
if basis != "derived":
|
|
return basis
|
|
inputs = value.get("derived_from") or []
|
|
if not inputs:
|
|
raise ValueError("a derived value must record derived_from")
|
|
return weakest(resolve(item) for item in inputs)
|
|
|
|
|
|
def validate_value(value: dict) -> None:
|
|
basis = value.get("basis")
|
|
if basis not in BASES:
|
|
raise ValueError(f"unknown evidence basis {basis!r}")
|
|
if basis == "derived" and not value.get("derived_from"):
|
|
raise ValueError("a derived value must record derived_from")
|
|
if basis != "derived" and value.get("derived_from"):
|
|
raise ValueError("only a derived value may record derived_from")
|
|
if basis == "unknown":
|
|
if value.get("value") is not None:
|
|
raise ValueError("a value with basis unknown must not carry a quantity")
|
|
if not value.get("gap"):
|
|
raise ValueError("an unknown value must name the gap and its owner")
|
|
elif value.get("value") is None:
|
|
raise ValueError("a known basis must carry a quantity; use basis unknown instead")
|
|
# A proxy measures a different quantity than the one named. That does not
|
|
# weaken the measurement, but it does weaken the inference drawn from it.
|
|
proxy_for = value.get("proxy_for")
|
|
if proxy_for is not None and not str(proxy_for).strip():
|
|
raise ValueError("proxy_for must name the quantity actually wanted")
|
|
for item in value.get("derived_from") or []:
|
|
validate_value(item)
|
|
|
|
|
|
def profile(values) -> dict:
|
|
"""Summarize a set of values for decision review."""
|
|
resolved = []
|
|
proxies = []
|
|
for value in values:
|
|
validate_value(value)
|
|
effective = resolve(value)
|
|
resolved.append(effective)
|
|
if value.get("proxy_for"):
|
|
proxies.append({"name": value.get("name"), "proxy_for": value["proxy_for"]})
|
|
counts: dict[str, int] = {}
|
|
for basis in resolved:
|
|
counts[basis] = counts.get(basis, 0) + 1
|
|
evidenced = [b for b in resolved if is_evidenced(b)]
|
|
return {
|
|
"count": len(resolved),
|
|
"by_basis": {k: counts[k] for k in BASIS_ORDER if k in counts},
|
|
"weakest": weakest(resolved),
|
|
"evidenced": len(evidenced),
|
|
"evidenced_ratio": round(len(evidenced) / len(resolved), 4) if resolved else None,
|
|
"proxies": proxies,
|
|
}
|
|
|
|
|
|
def decision_grade(values) -> dict:
|
|
"""Grade a decision by the weakest evidence it actually rests on.
|
|
|
|
A conclusion is not stronger than its weakest load-bearing input, however
|
|
precise the arithmetic between them looks.
|
|
"""
|
|
summary = profile(values)
|
|
basis = summary["weakest"]
|
|
if basis == "unknown":
|
|
grade, note = "insufficient", "at least one load-bearing value is unknown"
|
|
elif is_evidenced(basis):
|
|
grade, note = "evidenced", "every load-bearing value is observed, invoiced, or quoted"
|
|
elif basis == "projected":
|
|
grade, note = "projected", "the conclusion rests on values projected from observations"
|
|
else:
|
|
grade, note = "indicative", f"the conclusion is no stronger than an {basis} value" if basis[0] in "aeiou" else f"the conclusion is no stronger than a {basis} value"
|
|
if summary["proxies"]:
|
|
note += f"; {len(summary['proxies'])} value(s) measure a proxy rather than the quantity named"
|
|
return {**summary, "grade": grade, "note": note}
|
|
|
|
|
|
def main() -> int:
|
|
if len(sys.argv) != 2:
|
|
print(f"usage: {sys.argv[0]} VALUES.json", file=sys.stderr)
|
|
return 2
|
|
payload = json.loads(Path(sys.argv[1]).read_text())
|
|
values = payload["values"] if isinstance(payload, dict) else payload
|
|
print(json.dumps(decision_grade(values), indent=2))
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|