Both from info-tech-canon's review of the restatement. STRAIN 1 — credential custody was recorded as one unit of class P consumption. P is purchased platform capacity, and using security.secrets buys none. Removed the row; the relationship now sits in provisions[].uses_provisions alongside the object-store dependency, marked explicitly as a proposed extension because ITC-CAP declares no provision-to-provision relation. Filed as info-tech-canon/demand/ProvisionRelationships.md (their commit ce17dc4). BASIS TIERS — their point about invoiced being a fin-hub fact we name rather than originate exposed a real bug: a strict list order made weakest(["invoiced", "measured"]) return "measured", implying an invoice outranks a measurement. It does not outside its own domain. Strength is now a tier — invoiced and measured are peers, quoted below both — with ties broken deterministically by catalog order without implying a difference that does not exist. Also filed info-tech-canon/demand/EvidenceBasis.md at their request, proposing ITC-GOV as owner rather than ITC-CAP. 187 tests pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
183 lines
7 KiB
Python
183 lines
7 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)
|
|
|
|
# Strength is a tier, not a total order. `invoiced` and `measured` are peers:
|
|
# an invoice is the authoritative record of a payment, a measurement is the
|
|
# authoritative record of a quantity, and neither outranks the other outside
|
|
# its own domain. Asserting an order between them would make the weakest-input
|
|
# rule claim something it cannot know.
|
|
_TIER = {
|
|
"invoiced": 0, "measured": 0,
|
|
"quoted": 1,
|
|
"derived": 2,
|
|
"projected": 3,
|
|
"estimated": 4,
|
|
"assumed": 5,
|
|
"unknown": 6,
|
|
}
|
|
_ORDER = {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:
|
|
"""Strength tier; lower is stronger. Peers share a tier."""
|
|
if basis not in _TIER:
|
|
raise ValueError(f"unknown evidence basis {basis!r}")
|
|
return _TIER[basis]
|
|
|
|
|
|
def weakest(bases) -> str:
|
|
"""The weakest basis in a collection. Empty means nothing is known.
|
|
|
|
Ties within a tier resolve by catalog order so the result is deterministic
|
|
without implying a strength difference that does not exist.
|
|
"""
|
|
bases = list(bases)
|
|
if not bases:
|
|
return "unknown"
|
|
return min(bases, key=lambda b: (-rank(b), _ORDER[b]))
|
|
|
|
|
|
def strongest(bases) -> str:
|
|
bases = list(bases)
|
|
if not bases:
|
|
return "unknown"
|
|
return min(bases, key=lambda b: (rank(b), _ORDER[b]))
|
|
|
|
|
|
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())
|