feat(fase2a): wire run_project(outbox_dir, run_id) → outbox-skriving, load-bearing (S2.1)
This commit is contained in:
parent
79c6e44f92
commit
a706184bdd
2 changed files with 137 additions and 3 deletions
|
|
@ -48,7 +48,7 @@ from portfolio_optimiser.ir import SavingsProposal
|
|||
from portfolio_optimiser.provenance import ProvenanceStamp
|
||||
from portfolio_optimiser.reference_domain import Project, load_reference_projects
|
||||
from portfolio_optimiser.validator import Rejection, ValidatedProposal
|
||||
from portfolio_optimiser import okf
|
||||
from portfolio_optimiser import okf, outbox
|
||||
from portfolio_optimiser.verdicts import (
|
||||
ExpeLContextProvider,
|
||||
ProposalFeatures,
|
||||
|
|
@ -221,6 +221,8 @@ async def run_project(
|
|||
dimension: Dimension | None = None,
|
||||
store: VerdictStore | None = None,
|
||||
verdict_dir: str | None = None,
|
||||
outbox_dir: str | None = None,
|
||||
run_id: str | None = None,
|
||||
client_factory: Callable[[str], BaseChatClient] | None = None,
|
||||
max_rounds: int = 3,
|
||||
max_tokens: int = 100_000,
|
||||
|
|
@ -238,8 +240,21 @@ async def run_project(
|
|||
files (plain JSON, R2 raw layer) MERGED into the store BEFORE the Step-1 fold, so a verdict
|
||||
dropped after an earlier run is consumed by this separate, later run — the long feedback loop,
|
||||
fully resumable across runs separated in time. The system READS this folder; it does not write
|
||||
to it (the expert/persona writes, målbilde §3). Raises ``pydantic.ValidationError`` on a bad
|
||||
contract and ``BudgetExceeded`` when the token/round cap is crossed."""
|
||||
to it (the expert/persona writes, målbilde §3). ``outbox_dir`` (Fase 2a, Steg 7 output layer,
|
||||
målbilde §3, R2) is the RAW OUTBOX: when set, the run's proposal + outcome artefacts are written
|
||||
there via ``outbox.write_outbox`` (``run_id`` is then REQUIRED — no wall-clock/uuid default, for
|
||||
byte-determinism). The outbox dir should be DISTINCT from any ``verdict_dir`` inbox: writing the
|
||||
outbox into a folder later read as an inbox would re-ingest raw agent output and bypass the
|
||||
Step-8 promotion gate (self-contamination) — documented here, not enforced. Raises
|
||||
``pydantic.ValidationError`` on a bad contract and ``BudgetExceeded`` when the token/round cap is
|
||||
crossed, and ``ValueError`` when ``outbox_dir`` is set without a ``run_id``."""
|
||||
# 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(
|
||||
"run_id is required when outbox_dir is set (no wall-clock/uuid default — the outbox "
|
||||
"artefacts are byte-deterministic and keyed on run_id)"
|
||||
)
|
||||
|
||||
# 1. Fail-fast: validate ALL contracts (incl. the verdict-feedback shape) before any client.
|
||||
load_contracts(
|
||||
{"docs_dir": docs_dir, "top_k": top_k},
|
||||
|
|
@ -382,6 +397,20 @@ async def run_project(
|
|||
if notify is not None:
|
||||
notify(verdict)
|
||||
|
||||
# S2.1 outbox (RAW output layer, målbilde §3): persist the run's proposal + outcome artefacts
|
||||
# when configured. Wired ONLY here — no new consumer (S5.1/S5.2 are Non-Goals this bolk). run_id
|
||||
# is guaranteed non-None by the fail-fast guard at the top.
|
||||
if outbox_dir is not None:
|
||||
assert run_id is not None # narrowed by the step-0 guard; keeps the type checker honest
|
||||
outbox.write_outbox(
|
||||
outbox_dir,
|
||||
run_id,
|
||||
outcome=outcome,
|
||||
provenance=stamp,
|
||||
checker_verdict=checker_decision,
|
||||
verdict_id=verdict.id,
|
||||
)
|
||||
|
||||
return RunResult(
|
||||
outcome=outcome,
|
||||
provenance=stamp,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue