feat(fase1): dimension in run_project — context scope + candidate constraint (F1)
This commit is contained in:
parent
525ff0dda1
commit
d2029964cc
2 changed files with 203 additions and 1 deletions
|
|
@ -40,6 +40,7 @@ from portfolio_optimiser.datasource import (
|
|||
make_retrieval_tool,
|
||||
retrieve_chunks,
|
||||
)
|
||||
from portfolio_optimiser.dimension import Dimension, admits
|
||||
from portfolio_optimiser.generate import generate_via_llm
|
||||
from portfolio_optimiser.ir import SavingsProposal
|
||||
from portfolio_optimiser.provenance import ProvenanceStamp
|
||||
|
|
@ -198,6 +199,7 @@ async def run_project(
|
|||
docs_dir: str,
|
||||
verdict_input: dict[str, str],
|
||||
bundle_dir: str | None = None,
|
||||
dimension: Dimension | None = None,
|
||||
store: VerdictStore | None = None,
|
||||
verdict_dir: str | None = None,
|
||||
client_factory: Callable[[str], BaseChatClient] | None = None,
|
||||
|
|
@ -243,7 +245,9 @@ async def run_project(
|
|||
if bundle_dir is not None:
|
||||
bundle = okf.navigate_bundle(bundle_dir)
|
||||
project = _project_from_bundle(bundle_dir, project_id, bundle=bundle)
|
||||
context = okf.bundle_context(bundle)
|
||||
# §4.1a context-scope: agents read ONLY dimension-scoped bundle knowledge (Step-3 filter);
|
||||
# dimension=None keeps the full context, byte-identical to before.
|
||||
context = okf.bundle_context(bundle, dimension=dimension.id if dimension else None)
|
||||
citations = bundle_citations(bundle)
|
||||
debate_tools: list[Any] = []
|
||||
else:
|
||||
|
|
@ -326,6 +330,21 @@ async def run_project(
|
|||
else:
|
||||
outcome = validator_outcome
|
||||
|
||||
# 6c. Step 2 dimension scope gate (§4.1b): a candidate whose measure_type/codes fall OUTSIDE the
|
||||
# run's dimension is rejected. A scope/type gate placed AFTER the checker override (preserves
|
||||
# test_checker_gate_loadbearing) — NOT a new numeric gate: validate_proposal stays the only
|
||||
# blocking numeric gate and provenance.validator_decision (the numbers) is untouched. Mirrors the
|
||||
# override form: only an otherwise-standing ValidatedProposal can be flipped to a Rejection.
|
||||
if dimension is not None and isinstance(outcome, ValidatedProposal):
|
||||
feats = _features_of(proposal)
|
||||
if not admits(
|
||||
measure_type=feats.measure_type, codes=feats.affected_codes, dimension=dimension
|
||||
):
|
||||
outcome = Rejection(
|
||||
proposal=proposal,
|
||||
reason=f"outside dimension {dimension.id!r}: measure_type={feats.measure_type!r}",
|
||||
)
|
||||
|
||||
# 7. ExpeL (regression guard + traceability): exercises the two-arg extend_instructions
|
||||
# injection on a REAL SessionContext (the Critical Fase-1 GA-signature guard), and surfaces
|
||||
# the proposal-keyed retrieval for RunResult.retrieved. On the bundle path the load-bearing
|
||||
|
|
@ -374,6 +393,7 @@ async def run_portfolio(
|
|||
project_ids: Sequence[str] | None = None,
|
||||
profile: Profile | str = Profile.LOCAL,
|
||||
*,
|
||||
dimension: Dimension | None = None,
|
||||
store: VerdictStore | None = None,
|
||||
client_factory: Callable[[str], BaseChatClient] | None = None,
|
||||
max_rounds: int = 3,
|
||||
|
|
@ -401,6 +421,7 @@ async def run_portfolio(
|
|||
profile,
|
||||
docs_dir=project.docs_dir,
|
||||
verdict_input=project.verdict_input,
|
||||
dimension=dimension,
|
||||
store=store,
|
||||
client_factory=client_factory,
|
||||
max_rounds=max_rounds,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue