feat(p21): the PROJECT carries the price, so a run against a road normal can be anchored
Four paid stress rounds ran entirely UN-ANCHORED, all of them, because the one file loader reads cost-baseline.json out of the BUNDLE and no vegnormal ships one: N100, N200, N500 and R761 are knowledge, and knowledge carries requirements, never amounts. The validator's stage 0 -- the one stage that tells an invented cost line from a line this project actually buys -- was skipped in every single run, so "validated" could not mean what it says. P20 G1/G2 measured real R761 process numbers (12.11 three times on Soraasen, 1.1.1 on Lindaas) validating with amounts nobody had anywhere. --cost-baseline FILE is PM decision (e), taken over the three alternatives P20 wrote down. A LOADED object, never a path (prepass_payload's rule): the CLI owns the file and loads it ONCE, so the notice, the stamp and every base of an --across-bundle pass all descend from one read. ONE parse, two doors -- load_cost_baseline delegates to load_cost_baseline_file -- while safe_resolve stays on the bundle door alone, because a project's own schedule is legitimately outside every base. No tolerant twin: this path exists only because an operator NAMED a file. DEL B: five anchored context sets, a1-a3 with their line and a4 with none, so stage 0 is what catches the falsification arm. THE ORDER'S OWN ARM (h) WAS FELLED BY MEASUREMENT: "no baseline code is a requirement number the base declares" is measured 0 of 4 on the project-coded sets and 5 of 5 on kontrakt-sorasen -- which is what R761 Prosesskoden IS, a bill of quantities priced BY process code. The complement keeps both, and the order's own mutation still bites. DEL B3: the judge reports anchored (off the run's own stamp), priced per row, and WHICH falsifier caught the falsification arm. Load-bearing MEASURED, five mutations all red against the WHOLE suite, green control 1850/5 (from 1809/5, superset, 0 removed), golden byte-unchanged: A3(i) the flag is read but the baseline is unused (3 red) . A3(ii) only the first base gets it (1) . A3(iii) report_forbidden drops it (1) . B2(i) a4 gets a line (1, arm (g) alone) . B2(ii) a code swapped to 12.11 (2, arms (f) and (h)). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
587480f050
commit
7b4f85d77c
20 changed files with 1259 additions and 15 deletions
|
|
@ -88,7 +88,7 @@ from portfolio_optimiser.generate import (
|
|||
generate_via_llm,
|
||||
grounding_offer,
|
||||
)
|
||||
from portfolio_optimiser.ir import SavingsProposal
|
||||
from portfolio_optimiser.ir import CostBaseline, SavingsProposal
|
||||
from portfolio_optimiser.mandate import (
|
||||
OWN_PROPOSAL_ID,
|
||||
Approach,
|
||||
|
|
@ -822,6 +822,36 @@ def cost_baseline_notice(anchored: bool) -> str | None:
|
|||
return None if anchored else _UNANCHORED_NOTICE
|
||||
|
||||
|
||||
def cost_baseline_source_notice(path: str | None, lines: int) -> str | None:
|
||||
"""Render where this run's cost baseline came from, or ``None`` when nobody named a file (P21).
|
||||
|
||||
A SECOND renderer beside ``cost_baseline_notice``, never a widening of it, because the two say
|
||||
DIFFERENT facts and cannot disagree: that one warns that stage 0 is SKIPPED, this one names the
|
||||
file an operator chose and how many lines it carries. Supplying ``--cost-baseline`` implies
|
||||
anchored, so exactly one of the two can ever render.
|
||||
|
||||
**A POSITIVE line, and that is a deliberate departure from the omission rule** its neighbours
|
||||
follow (``cost_baseline_notice``, ``skipped_links_notice``, ``unkeyed_verdicts_notice``) — the
|
||||
same departure ``proposal_review_notice`` makes, for the same reason. Silence here is
|
||||
AMBIGUOUS: an operator who passed a project price schedule cannot tell "your file anchored this
|
||||
run" from "the bundle happened to ship its own" or from "the flag was dropped somewhere", and
|
||||
the whole point of the flag is that stage 0 now judges. Without a file the renderer returns
|
||||
``None``, so the omission is kept exactly where it is unambiguous.
|
||||
|
||||
It takes the ALREADY-RESOLVED path and count rather than re-reading the file: a renderer that
|
||||
opened it again would be a second resolution of the same fact, free to drift from the baseline
|
||||
the run was actually given (``cost_baseline_notice``'s rule).
|
||||
|
||||
English, like every other line this CLI prints."""
|
||||
if path is None:
|
||||
return None
|
||||
plural = "" if lines == 1 else "s"
|
||||
return (
|
||||
f" Cost baseline: {lines} line{plural} from {path} — the validator's stage 0 reconciles "
|
||||
"every proposed cost line against this project's own schedule"
|
||||
)
|
||||
|
||||
|
||||
def grounding_offer_notice(offer: GroundingOffer | None) -> str | None:
|
||||
"""Render the one line that says what this run's delivered input can ground, or ``None`` when
|
||||
there is nothing to warn about (P8).
|
||||
|
|
@ -1018,6 +1048,13 @@ async def run_project(
|
|||
#: file loader, byte-identically.
|
||||
derive_cost_baseline: bool = False,
|
||||
require_cost_baseline: bool = False,
|
||||
#: P21: the PROJECT's own price schedule, supplied by the caller instead of read out of the
|
||||
#: knowledge base. A LOADED object, never a path — ``prepass_payload``'s rule, and
|
||||
#: ``mandate=``/``dimension=``' before it: the CLI owns the file, the library seam takes the
|
||||
#: validated artefact. ``None`` (the default) leaves every existing run on the bundle loader,
|
||||
#: byte-identically. Mutually exclusive with ``derive_cost_baseline``: two sources for one
|
||||
#: baseline would have to silently pick one, and the picked one would be a policy nobody wrote.
|
||||
cost_baseline: CostBaseline | None = None,
|
||||
dimension: Dimension | None = None,
|
||||
store: VerdictStore | None = None,
|
||||
verdict_dir: str | None = None,
|
||||
|
|
@ -1081,6 +1118,17 @@ async def run_project(
|
|||
semantics, so over a structural tie the resulting order is deterministic but arbitrary;
|
||||
retrieval *quality* arrives only with an embedder injected via ``embedder=`` or
|
||||
``--embedder-config``. Default false keeps the structural ranking exactly as before."""
|
||||
# 0. Fail-fast: TWO sources for ONE baseline, refused rather than merged (P21). A run holding
|
||||
# both would have to pick silently, and the picked one would be a policy nobody wrote down —
|
||||
# ``--prepass-payload``/``--prepass-seed``'s rule, and ``portfolio_meter``/``meter_factory``'s
|
||||
# before it. Checked HERE and not only at the CLI, because the library seam has the same two
|
||||
# arguments and a library caller must not be able to reach a state the CLI refuses by name.
|
||||
if cost_baseline is not None and derive_cost_baseline:
|
||||
raise ValueError(
|
||||
"cost_baseline and derive_cost_baseline are two sources for one baseline (a file the "
|
||||
"caller supplies, and a schedule derived from the knowledge base); pass exactly one"
|
||||
)
|
||||
|
||||
# 0. Fail-fast: an outbox write is byte-deterministic and keyed on run_id — no wall-clock default.
|
||||
if outbox_dir is not None and run_id is None:
|
||||
raise ValueError(
|
||||
|
|
@ -1173,8 +1221,15 @@ async def run_project(
|
|||
# silently downgraded order, which is what ``load_mandate`` fail-fasts against. This one
|
||||
# resolution serves BOTH the full run and the ``live_dry_run`` report below, so the dry-run
|
||||
# arm cannot drift away from what a real run would anchor on.
|
||||
# P21 takes precedence over BOTH bundle-side sources, and it is the only one whose input
|
||||
# is the PROJECT rather than the corpus: a vegnormal is knowledge and carries no prices, so
|
||||
# before this every paid run measured (P16/P18/P19/P17b/P20) was un-anchored and stage 0
|
||||
# never ran. Mutual exclusion with ``derive_cost_baseline`` is enforced at the top of this
|
||||
# function, so the ``if`` below is an ordering and not a silent pick.
|
||||
baseline = (
|
||||
okf.derive_cost_baseline(bundle, project_id=project_id)
|
||||
cost_baseline
|
||||
if cost_baseline is not None
|
||||
else okf.derive_cost_baseline(bundle, project_id=project_id)
|
||||
if derive_cost_baseline
|
||||
else okf.load_optional_cost_baseline(bundle_dir)
|
||||
)
|
||||
|
|
@ -2429,6 +2484,12 @@ async def run_mandate_across_bundles(
|
|||
#: silent drop on the paid path while the free drill honoured them, which is the F4 class.
|
||||
derive_cost_baseline: bool = False,
|
||||
require_cost_baseline: bool = False,
|
||||
#: P21, and threaded UNCHANGED into every base: ONE project has ONE price schedule, so the same
|
||||
#: baseline anchors each base's run. That is the one anchoring argument which is NOT a bundle
|
||||
#: concern — the two above are read out of the base being handed over, this one is the project's
|
||||
#: own, and giving base k a baseline and base k+1 none would anchor half a commission while the
|
||||
#: stamp reported anchoring for the half that happened to run first.
|
||||
cost_baseline: CostBaseline | None = None,
|
||||
) -> MultiBaseResult:
|
||||
"""Evaluate ONE commission across SEVERAL knowledge bases — the multi-base dispatch (§ C.7).
|
||||
|
||||
|
|
@ -2531,6 +2592,7 @@ async def run_mandate_across_bundles(
|
|||
run_id=base_run_id or None,
|
||||
derive_cost_baseline=derive_cost_baseline,
|
||||
require_cost_baseline=require_cost_baseline,
|
||||
cost_baseline=cost_baseline,
|
||||
notify=lambda verdict: minted_here.append(verdict.id),
|
||||
verdict_input=verdict_input,
|
||||
verdict_dir=verdict_dir,
|
||||
|
|
@ -2967,6 +3029,20 @@ def main(argv: list[str] | None = None) -> int:
|
|||
"guesses: an unpriced or ambiguous schedule stops the run"
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cost-baseline",
|
||||
default=None,
|
||||
metavar="FILE",
|
||||
help=(
|
||||
"anchor the validator's stage 0 to THIS PROJECT's own price schedule (P21): FILE is a "
|
||||
"cost-baseline.json (the same {project_id, items:{code:{quantity,unit_cost}}} shape a "
|
||||
"bundle may ship) and it is used INSTEAD of one inside --bundle-dir. The price belongs "
|
||||
"to the project, not to the knowledge base — a road normal carries requirements, never "
|
||||
"amounts — so without this a run against one is un-anchored and stage 0 is skipped. "
|
||||
"Applies to every base in --across-bundle mode: one project, one schedule. Mutually "
|
||||
"exclusive with --derive-cost-baseline; satisfies --require-cost-baseline"
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--require-cost-baseline",
|
||||
action="store_true",
|
||||
|
|
@ -3072,6 +3148,10 @@ def main(argv: list[str] | None = None) -> int:
|
|||
# Same reason, same rung: report mode returns above every run dispatch, so leaving it
|
||||
# out is a SILENT DROP of a guarantee the operator asked for by name.
|
||||
"--require-cost-baseline": args.require_cost_baseline,
|
||||
# P21, same rung and same reason: report mode returns ABOVE every dispatch that could
|
||||
# honour a project price schedule, so an omission here would accept the file, anchor
|
||||
# nothing, and exit 0 — a silent drop rather than a refusal (the F4 class).
|
||||
"--cost-baseline": args.cost_baseline is not None,
|
||||
# Same reason, one flag later: report mode returns above the S7b dispatch too.
|
||||
"--proposals-from-mandate": args.proposals_from_mandate,
|
||||
"PROJECT_ID": args.project_id is not None,
|
||||
|
|
@ -3183,6 +3263,11 @@ def main(argv: list[str] | None = None) -> int:
|
|||
# anchored by construction — so here the flag could only ever pass. BY NAME rather
|
||||
# than falling through to the --bundle-dir requirement, its neighbours' reason.
|
||||
"--require-cost-baseline": args.require_cost_baseline,
|
||||
# P21: ONE project's price schedule, and a portfolio pass keys on PROJECTS — each of
|
||||
# which already carries its own ``cost_items`` and is anchored by construction. A
|
||||
# single file could only ever be right for one row out of N. BY NAME rather than
|
||||
# falling through to the --bundle-dir requirement, its neighbours' reason.
|
||||
"--cost-baseline": args.cost_baseline,
|
||||
# It reads ONE base's schedule and settles ONE commission against it, so it sits on the
|
||||
# same side of the partition as the flag it requires. BY NAME rather than falling
|
||||
# through to "requires --derive-cost-baseline": an operator who wrote --portfolio
|
||||
|
|
@ -3364,6 +3449,37 @@ def main(argv: list[str] | None = None) -> int:
|
|||
)
|
||||
return 1
|
||||
|
||||
# P21, and its neighbours' reason exactly: on the road path the baseline IS the project's own
|
||||
# ``cost_items``, so a file here would be a SECOND source for one fact with nothing to break
|
||||
# the tie — and a flag that can only ever be shadowed is a claim the surface makes about
|
||||
# itself. Refused BY NAME rather than left to surface as a project lookup that ignored it.
|
||||
if (
|
||||
not args.portfolio
|
||||
and not args.across_bundle
|
||||
and args.cost_baseline is not None
|
||||
and args.bundle_dir is None
|
||||
):
|
||||
print(
|
||||
"run refused: --cost-baseline requires --bundle-dir or --across-bundle (the road path "
|
||||
"is already anchored by the reference project's own cost_items, so a second schedule "
|
||||
"there would have nothing to anchor that those do not)",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
|
||||
# TWO sources for ONE baseline, refused rather than merged — the same decision
|
||||
# ``run_project`` enforces at its own seam, said HERE by name so an operator who typed both
|
||||
# hears which two flags conflict instead of getting a library ValueError's traceback. Not
|
||||
# nested under either flag's branch, for the F4 reason its neighbours are not.
|
||||
if args.cost_baseline is not None and args.derive_cost_baseline:
|
||||
print(
|
||||
"run refused: --cost-baseline and --derive-cost-baseline are two sources for one "
|
||||
"baseline (a file you supply, and a schedule derived from a table in the knowledge "
|
||||
"base); pass exactly one",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
|
||||
# The SEEDING arm's three refusals, placed ABOVE the replacing arm's block on purpose: given
|
||||
# both flags, the block below would answer with "--prepass-payload and --explore cannot be
|
||||
# combined", which names neither of the two flags the operator actually put in conflict. At
|
||||
|
|
@ -3815,6 +3931,20 @@ def main(argv: list[str] | None = None) -> int:
|
|||
print(f"run refused: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# The PROJECT's price schedule, loaded fail-fast alongside the commission and for the same
|
||||
# reason: a baseline that cannot be read is not a run to start UN-anchored instead. Degrading
|
||||
# it to "no baseline" would answer an operator who asked for stage 0 by name with a run in
|
||||
# which stage 0 is skipped — ``load_mandate``'s rule, and the exact silence four paid rounds
|
||||
# were measured inside. Loaded ONCE and passed as an object, so the notice below, the stamp
|
||||
# and every base of an ``--across-bundle`` pass all descend from one read (kø-(p)).
|
||||
cost_baseline: CostBaseline | None = None
|
||||
if args.cost_baseline is not None:
|
||||
try:
|
||||
cost_baseline = okf.load_cost_baseline_file(args.cost_baseline)
|
||||
except (FileNotFoundError, ValidationError, ValueError) as exc:
|
||||
print(f"run refused: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# The declared cut, loaded fail-fast alongside the commission and for the same reason: a
|
||||
# payload that cannot be read is not a run to start with a navigating debate instead. Missing,
|
||||
# not JSON, or not the shape the models require — all three land on the refusal surface with
|
||||
|
|
@ -4191,6 +4321,15 @@ def main(argv: list[str] | None = None) -> int:
|
|||
print(f"run refused: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# P21, printed ONCE for the pass rather than per base, and that is the opposite placement
|
||||
# from its neighbours below FOR A REASON: they read each base's OWN stamp, whereas ONE
|
||||
# project has ONE price schedule and the same baseline anchors every base here. Per base it
|
||||
# would read as N schedules, which is the claim this flag exists to deny.
|
||||
source_notice = cost_baseline_source_notice(
|
||||
args.cost_baseline, 0 if cost_baseline is None else len(cost_baseline.items)
|
||||
)
|
||||
if source_notice is not None:
|
||||
print(source_notice)
|
||||
if args.live_dry_run:
|
||||
for bundle_id, bundle_dir, project_id in resolved:
|
||||
try:
|
||||
|
|
@ -4210,6 +4349,7 @@ def main(argv: list[str] | None = None) -> int:
|
|||
max_tokens=args.max_tokens,
|
||||
derive_cost_baseline=args.derive_cost_baseline,
|
||||
require_cost_baseline=args.require_cost_baseline,
|
||||
cost_baseline=cost_baseline,
|
||||
live_dry_run=True,
|
||||
)
|
||||
)
|
||||
|
|
@ -4269,6 +4409,7 @@ def main(argv: list[str] | None = None) -> int:
|
|||
),
|
||||
derive_cost_baseline=args.derive_cost_baseline,
|
||||
require_cost_baseline=args.require_cost_baseline,
|
||||
cost_baseline=cost_baseline,
|
||||
outbox_for=outbox_for,
|
||||
)
|
||||
)
|
||||
|
|
@ -4302,6 +4443,15 @@ def main(argv: list[str] | None = None) -> int:
|
|||
multi=multi,
|
||||
)
|
||||
|
||||
# P21, printed ONCE for the pass rather than per base, and that is the opposite placement
|
||||
# from its neighbours below FOR A REASON: they read each base's OWN stamp, whereas ONE
|
||||
# project has ONE price schedule and the same baseline anchors every base here. Per base it
|
||||
# would read as N schedules, which is the claim this flag exists to deny.
|
||||
source_notice = cost_baseline_source_notice(
|
||||
args.cost_baseline, 0 if cost_baseline is None else len(cost_baseline.items)
|
||||
)
|
||||
if source_notice is not None:
|
||||
print(source_notice)
|
||||
for bundle_run in multi.runs:
|
||||
print(f"--- {bundle_run.bundle_id} ({bundle_run.project_id}) ---")
|
||||
print(
|
||||
|
|
@ -4440,6 +4590,7 @@ def main(argv: list[str] | None = None) -> int:
|
|||
verdict_input=_verdict_input_from_args(args),
|
||||
derive_cost_baseline=args.derive_cost_baseline,
|
||||
require_cost_baseline=args.require_cost_baseline,
|
||||
cost_baseline=cost_baseline,
|
||||
mcp_servers=mcp_servers,
|
||||
live_dry_run=True,
|
||||
)
|
||||
|
|
@ -4470,6 +4621,14 @@ def main(argv: list[str] | None = None) -> int:
|
|||
notice = cost_baseline_notice(report.cost_baseline_anchored)
|
||||
if notice is not None:
|
||||
print(notice)
|
||||
# P21's positive half, on the FREE trip: the operator who named a project price schedule
|
||||
# learns on the drill that it was read and how many lines it carries, rather than paying
|
||||
# for a run to find out. Silence without the flag (omission, never an empty row).
|
||||
source_notice = cost_baseline_source_notice(
|
||||
args.cost_baseline, 0 if cost_baseline is None else len(cost_baseline.items)
|
||||
)
|
||||
if source_notice is not None:
|
||||
print(source_notice)
|
||||
# P8, printed next to the line it qualifies: "stage 0 is skipped" says the gate lost a
|
||||
# falsifier; this says what the input could have offered it instead. On the FREE trip, so
|
||||
# an operator learns a run cannot be grounded without paying three attempts to find out.
|
||||
|
|
@ -4519,6 +4678,7 @@ def main(argv: list[str] | None = None) -> int:
|
|||
semantic_retrieval=args.semantic_retrieval,
|
||||
derive_cost_baseline=args.derive_cost_baseline,
|
||||
require_cost_baseline=args.require_cost_baseline,
|
||||
cost_baseline=cost_baseline,
|
||||
client_factory=scripted_client_factory,
|
||||
mandate=mandate,
|
||||
mcp_servers=mcp_servers,
|
||||
|
|
@ -4567,6 +4727,12 @@ def main(argv: list[str] | None = None) -> int:
|
|||
notice = cost_baseline_notice(result.provenance.cost_baseline_anchored)
|
||||
if notice is not None:
|
||||
print(notice)
|
||||
# Same renderer on the paid run, so the drill and the run it rehearses say the same thing.
|
||||
source_notice = cost_baseline_source_notice(
|
||||
args.cost_baseline, 0 if cost_baseline is None else len(cost_baseline.items)
|
||||
)
|
||||
if source_notice is not None:
|
||||
print(source_notice)
|
||||
# Same renderer on the full run, read off the run's OWN measurement: a run that spent every
|
||||
# attempt being refused as ungrounded is exactly where the input-side fact costs the most.
|
||||
offer_notice = grounding_offer_notice(result.grounding_offer)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue