feat(verdicts): promoted verdicts carry a verified field with the actor verbatim
Co-Authored-By: Claude <claude-opus-5>
This commit is contained in:
parent
9e35cfefbf
commit
3d76a46d76
3 changed files with 170 additions and 1 deletions
|
|
@ -371,6 +371,43 @@ class SkippedLink:
|
||||||
reason: SkipReason
|
reason: SkipReason
|
||||||
|
|
||||||
|
|
||||||
|
#: Characters an actor may not contain, because each would RESTRUCTURE the flow mapping it is
|
||||||
|
#: written into. ``": "`` is in the set for a reason that is not decoration: ``decode_flow_value``
|
||||||
|
#: splits pairs on colon-SPACE, so an actor carrying it would be written out cleanly and then
|
||||||
|
#: mis-decoded on the way back. The writer and the reader must agree on this set, or the round trip
|
||||||
|
#: lies while every byte looks fine.
|
||||||
|
_VERIFIED_UNSAFE_TOKENS = (",", "{", "}", "[", "]", "\n", "\r", ": ")
|
||||||
|
|
||||||
|
|
||||||
|
def verified_field(actor: str, at: str) -> str:
|
||||||
|
"""Compose the SPEC §5.2 single-verifier flow shorthand ``{ by: <actor>, at: <at> }``.
|
||||||
|
|
||||||
|
The ENCODER half of this seam, and a separately named function on purpose: it gives the
|
||||||
|
round-trip property one site to be measured at, and ``render_frontmatter`` cannot serve —
|
||||||
|
it collapses every newline to a space and therefore cannot emit block form at all.
|
||||||
|
|
||||||
|
**The actor is written VERBATIM and is never prefixed with ``human:``.** A caller reaches the
|
||||||
|
human tier by saying so; minting the prefix on their behalf would fabricate a sign-off nobody
|
||||||
|
gave.
|
||||||
|
|
||||||
|
**Honesty limit, stated:** only ``actor`` is checked against the unsafe set. ``at`` is an ISO
|
||||||
|
timestamp in every caller today and is not validated here — a deliberate scope line, not an
|
||||||
|
oversight, and the place to revisit it is the invariant record rather than a silent widening.
|
||||||
|
|
||||||
|
Raises ``FlowDecodeError`` — the same named refusal the reader raises, which is what makes
|
||||||
|
"the writer refuses exactly what the reader cannot read" structural rather than a convention.
|
||||||
|
|
||||||
|
Gated by ``tests/test_provenance_decoder_loadbearing.py``."""
|
||||||
|
for token in _VERIFIED_UNSAFE_TOKENS:
|
||||||
|
if token in actor:
|
||||||
|
raise FlowDecodeError(
|
||||||
|
f"the actor {actor!r} contains {token!r}, which would restructure the `verified` "
|
||||||
|
"flow mapping — refusing to write a provenance record that parses cleanly into "
|
||||||
|
"something no one wrote"
|
||||||
|
)
|
||||||
|
return f"{{ by: {actor}, at: {at} }}"
|
||||||
|
|
||||||
|
|
||||||
#: A concept's trust level, derived from its ``verified`` actors (SPEC §5.3), lowest to highest.
|
#: A concept's trust level, derived from its ``verified`` actors (SPEC §5.3), lowest to highest.
|
||||||
#: Derived, never stored: OKF records objective signals and refuses to persist a subjective score,
|
#: Derived, never stored: OKF records objective signals and refuses to persist a subjective score,
|
||||||
#: so this is a reading of the actors and not a field any document carries.
|
#: so this is a reading of the actors and not a field any document carries.
|
||||||
|
|
@ -744,6 +781,14 @@ def write_concept_file(bundle_dir: str, name: str, frontmatter: dict[str, str],
|
||||||
a frontmatter carrying the complete ingest stamp raises ``IngestStampError`` and NOTHING is
|
a frontmatter carrying the complete ingest stamp raises ``IngestStampError`` and NOTHING is
|
||||||
written. A validation, never a repair — the caller is told, not silently corrected.
|
written. A validation, never a repair — the caller is told, not silently corrected.
|
||||||
Returns the written path."""
|
Returns the written path."""
|
||||||
|
verified = frontmatter.get("verified")
|
||||||
|
if verified is not None:
|
||||||
|
# Validation, never repair, and NOT a second copy of the rule: the check IS
|
||||||
|
# ``decode_flow_value``, so the writer refuses exactly what the reader cannot read. A
|
||||||
|
# duplicated rule here would be free to drift, and the drifted copy would decide what gets
|
||||||
|
# written. Scoped to ``verified`` BY NAME — ``render_frontmatter`` keeps collapsing
|
||||||
|
# newlines for every other key, which this step deliberately does not change.
|
||||||
|
decode_flow_value(verified, key="verified")
|
||||||
if _carries_complete_ingest_stamp(frontmatter):
|
if _carries_complete_ingest_stamp(frontmatter):
|
||||||
raise IngestStampError(
|
raise IngestStampError(
|
||||||
"refusing to write a curated concept file carrying the COMPLETE ingest ownership stamp "
|
"refusing to write a curated concept file carrying the COMPLETE ingest ownership stamp "
|
||||||
|
|
|
||||||
|
|
@ -697,6 +697,10 @@ def promote_verdict(
|
||||||
"verdict_id": verdict.id,
|
"verdict_id": verdict.id,
|
||||||
"provenance": f"godkjent av {approver}; eksperiment {experiment}; {timestamp}",
|
"provenance": f"godkjent av {approver}; eksperiment {experiment}; {timestamp}",
|
||||||
"timestamp": timestamp,
|
"timestamp": timestamp,
|
||||||
|
# SPEC §5.2 provenance, reusing the EXISTING required ``timestamp`` keyword so no
|
||||||
|
# wall-clock default sneaks in. The approver is written verbatim: a scripted stand-in lands
|
||||||
|
# in ``machine-confirmed``, which is true of it.
|
||||||
|
"verified": okf.verified_field(approver, timestamp),
|
||||||
"tags": "[verdict, promoted, HITL]",
|
"tags": "[verdict, promoted, HITL]",
|
||||||
}
|
}
|
||||||
codes = ", ".join(sorted(f.affected_codes))
|
codes = ", ".join(sorted(f.affected_codes))
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,13 @@ from __future__ import annotations
|
||||||
|
|
||||||
import ast
|
import ast
|
||||||
import itertools
|
import itertools
|
||||||
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from portfolio_optimiser import okf
|
from portfolio_optimiser import okf, verdicts
|
||||||
from portfolio_optimiser.okf import _read_body, parse_frontmatter
|
from portfolio_optimiser.okf import _read_body, parse_frontmatter
|
||||||
|
|
||||||
_OKF_SOURCE = Path(okf.__file__)
|
_OKF_SOURCE = Path(okf.__file__)
|
||||||
|
|
@ -509,3 +510,122 @@ def test_a_human_LAST_entry_still_resolves_to_human_reviewed() -> None:
|
||||||
)
|
)
|
||||||
== "machine-confirmed"
|
== "machine-confirmed"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# --- Step 6: the writers emit `verified`, with the actor verbatim ------------------------------
|
||||||
|
|
||||||
|
_ENERGI_BUNDLE = Path(__file__).resolve().parents[1] / "shared" / "examples" / "bygg-energi-mikro"
|
||||||
|
|
||||||
|
|
||||||
|
def _bundle_copy(tmp_path: Path) -> str:
|
||||||
|
"""Promotion WRITES into the bundle, so every arm works on a throwaway copy — the shared,
|
||||||
|
pull-only framework-neutral fixture is never mutated (the Step-8 discipline)."""
|
||||||
|
dst = tmp_path / "bundle"
|
||||||
|
shutil.copytree(_ENERGI_BUNDLE, dst)
|
||||||
|
return str(dst)
|
||||||
|
|
||||||
|
|
||||||
|
def _approved(bundle_dir: str) -> verdicts.Verdict:
|
||||||
|
return verdicts.Verdict(
|
||||||
|
id="PROVENANCE-ROUNDTRIP",
|
||||||
|
proposal_features=verdicts.bundle_candidate_features(bundle_dir),
|
||||||
|
decision="approved",
|
||||||
|
rationale="godkjent",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_verified_field_emits_the_spec_shorthand_exactly() -> None:
|
||||||
|
"""(a) The §5.2 single-verifier flow shorthand, byte for byte."""
|
||||||
|
assert (
|
||||||
|
okf.verified_field("persona", "2026-06-30T09:00:00Z")
|
||||||
|
== "{ by: persona, at: 2026-06-30T09:00:00Z }"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("actor", ["a,b", "a{b", "a}b", "a[b", "a]b", "a\nb", "a: b"])
|
||||||
|
def test_verified_field_refuses_an_actor_that_would_restructure_the_value(actor: str) -> None:
|
||||||
|
"""(d) The unsafe set, and ``": "`` is in it for a reason that is NOT decoration.
|
||||||
|
|
||||||
|
``decode_flow_value`` splits pairs on colon-SPACE. An actor containing it would be written out
|
||||||
|
cleanly and then MIS-DECODED on the way back — the writer and the reader must agree on the
|
||||||
|
unsafe set, or the round trip lies while every byte looks fine.
|
||||||
|
"""
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
okf.verified_field(actor, "2026-06-30T09:00:00Z")
|
||||||
|
|
||||||
|
|
||||||
|
def test_a_promoted_verdict_round_trips_to_machine_confirmed(tmp_path: Path) -> None:
|
||||||
|
"""(b) Write with ``promote_verdict``, read with ``read_provenance``, tier with ``trust_tier``.
|
||||||
|
|
||||||
|
A plain approver lands in ``machine-confirmed``, and that is TRUE of it: the demo passes
|
||||||
|
``"ekspert-persona (sim)"``, a scripted stand-in, and prefixing it with ``human:`` on the
|
||||||
|
caller's behalf would mint a human sign-off nobody gave — the fabricated-provenance defect one
|
||||||
|
layer up.
|
||||||
|
"""
|
||||||
|
bundle_dir = _bundle_copy(tmp_path)
|
||||||
|
path = verdicts.promote_verdict(
|
||||||
|
bundle_dir,
|
||||||
|
_approved(bundle_dir),
|
||||||
|
approver="ekspert-persona (sim)",
|
||||||
|
experiment="exp-B",
|
||||||
|
timestamp="2026-06-30T09:00:00Z",
|
||||||
|
)
|
||||||
|
raw = path.read_text(encoding="utf-8")
|
||||||
|
assert "verified: { by: ekspert-persona (sim), at: 2026-06-30T09:00:00Z }" in raw
|
||||||
|
|
||||||
|
entries = okf.read_provenance(path, "verified")
|
||||||
|
assert entries == ({"by": "ekspert-persona (sim)", "at": "2026-06-30T09:00:00Z"},)
|
||||||
|
assert okf.trust_tier(entries) == "machine-confirmed"
|
||||||
|
|
||||||
|
|
||||||
|
def test_a_human_prefixed_approver_reaches_the_human_tier(tmp_path: Path) -> None:
|
||||||
|
"""(b, second half) The ``human-reviewed`` tier is reached by a CALLER saying so."""
|
||||||
|
bundle_dir = _bundle_copy(tmp_path)
|
||||||
|
path = verdicts.promote_verdict(
|
||||||
|
bundle_dir,
|
||||||
|
_approved(bundle_dir),
|
||||||
|
approver="human:ktg",
|
||||||
|
experiment="exp-B",
|
||||||
|
timestamp="2026-06-30T09:00:00Z",
|
||||||
|
)
|
||||||
|
assert okf.trust_tier(okf.read_provenance(path, "verified")) == "human-reviewed"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("bad", "marker"),
|
||||||
|
[
|
||||||
|
("{ by: a, at: b }\n{ by: c, at: d }", "one line"),
|
||||||
|
("- { by: a, at: b }", "neither a flow sequence nor a flow mapping"),
|
||||||
|
("[ a.pdf ]", "bare scalar"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_write_concept_file_refuses_a_verified_value_outside_the_subset(
|
||||||
|
tmp_path: Path, bad: str, marker: str
|
||||||
|
) -> None:
|
||||||
|
"""(c) Validation, never repair — and NOTHING is written.
|
||||||
|
|
||||||
|
``render_frontmatter`` collapses newlines for every key, which for ``verified`` would turn a
|
||||||
|
block value into a single line that decodes to something nobody wrote. The refusal is scoped
|
||||||
|
to ``verified`` BY NAME; every other key keeps the old collapsing behaviour, and that is stated
|
||||||
|
rather than hidden by the control arm below.
|
||||||
|
"""
|
||||||
|
with pytest.raises(okf.FlowDecodeError) as excinfo:
|
||||||
|
okf.write_concept_file(str(tmp_path), "c.md", {"type": "concept", "verified": bad}, "b\n")
|
||||||
|
# The marker pins that the writer's refusal IS the reader's refusal, not a second rule beside
|
||||||
|
# it — a hand-rolled copy here would refuse with words of its own and be free to drift.
|
||||||
|
assert marker in str(excinfo.value)
|
||||||
|
assert not (tmp_path / "c.md").exists(), "the refusal wrote a file anyway"
|
||||||
|
|
||||||
|
|
||||||
|
def test_the_refusal_is_scoped_to_verified_and_other_keys_are_untouched(tmp_path: Path) -> None:
|
||||||
|
"""CONTROL — a refusal that fired on every key would break `render_frontmatter`'s contract for
|
||||||
|
the whole repo, and a refusal that fired on nothing would be worthless. Both are excluded."""
|
||||||
|
path = okf.write_concept_file(
|
||||||
|
str(tmp_path),
|
||||||
|
"c.md",
|
||||||
|
{"type": "concept", "provenance": "line one\nline two", "verified": "{ by: p, at: t }"},
|
||||||
|
"body\n",
|
||||||
|
)
|
||||||
|
written = path.read_text(encoding="utf-8")
|
||||||
|
assert "provenance: line one line two" in written, "an unrelated key stopped being collapsed"
|
||||||
|
assert "verified: { by: p, at: t }" in written
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue