| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075 |
- from __future__ import annotations
- import asyncio
- import re
- from collections.abc import Mapping, Sequence
- from datetime import UTC, datetime
- from pathlib import Path
- from types import SimpleNamespace
- from typing import Any, cast
- import pytest
- from agent import FileSystemArtifactStore, FileSystemTaskStore, FileSystemTraceStore
- from agent.orchestration import (
- AgentRole,
- ArtifactRef,
- AttemptSubmission,
- CriterionResult,
- DecisionAction,
- TaskCoordinator,
- TaskStatus,
- ValidationVerdict,
- )
- from agent.orchestration.protocols import ValidatorRunResult, WorkerRunResult
- from sqlalchemy import event, func, select
- from script_build_host.application.phase_two_boundary import ScriptPhaseTwoBoundaryVerifier
- from script_build_host.application.phase_two_candidates import PhaseTwoCandidateService
- from script_build_host.application.phase_two_inputs import (
- AcceptedInputResolver,
- ActiveFrontierResolver,
- StoredTaskContractReader,
- )
- from script_build_host.application.phase_two_planning import (
- PHASE_TWO_CANDIDATE_PORTFOLIO_READY,
- PhaseTwoPlanningService,
- )
- from script_build_host.domain.artifacts import (
- ArtifactKind,
- DirectionArtifact,
- DirectionGoal,
- EvidenceRecordV1,
- )
- from script_build_host.domain.errors import PhaseTwoBoundaryNotReady
- from script_build_host.domain.phase_two_artifacts import (
- CandidatePortfolioArtifactV1,
- StructuredScriptArtifactV1,
- )
- from script_build_host.domain.records import BuildStatus, MissionBinding
- from script_build_host.domain.task_contracts import ScriptTaskKind
- from script_build_host.infrastructure.legacy_tables import (
- script_build_element,
- script_build_paragraph,
- script_build_paragraph_element,
- script_build_record,
- )
- from script_build_host.infrastructure.tables import (
- artifact_version_table,
- publication_table,
- )
- from script_build_host.infrastructure.task_contract_store import FileScriptTaskContractStore
- from script_build_host.repositories.legacy_state import SqlAlchemyLegacyBuildStateRepository
- from script_build_host.repositories.sqlalchemy import (
- SqlAlchemyMissionBindingRepository,
- SqlAlchemyScriptBusinessArtifactRepository,
- )
- from script_build_host.repositories.workspace import SqlAlchemyCandidateWorkspaceRepository
- ROOT = "phase-two-sql-root"
- SNAPSHOT_ID = 11
- FULL_SCOPE = "script-build://scopes/full"
- FULL_WRITE = "script-build://writes/full"
- def _contract(
- kind: ScriptTaskKind,
- *,
- scope: str = FULL_SCOPE,
- write_scope: Sequence[str] = (FULL_WRITE,),
- input_refs: Sequence[dict[str, Any]] = (),
- base_ref: ArtifactRef | None = None,
- supersedes: Sequence[str] = (),
- closure: Sequence[dict[str, Any]] = (),
- adopted: Sequence[str] = (),
- held: Sequence[str] = (),
- order: Sequence[str] = (),
- comparison_refs: Sequence[dict[str, Any]] = (),
- execution_ready: bool = True,
- ) -> dict[str, Any]:
- output_schema = {
- ScriptTaskKind.DIRECTION: "script-direction/v1",
- ScriptTaskKind.DECODE_RETRIEVAL: "evidence-record/v1",
- ScriptTaskKind.STRUCTURE: "structure-artifact/v1",
- ScriptTaskKind.PARAGRAPH: "paragraph-patch/v1" if base_ref else "paragraph-artifact/v1",
- ScriptTaskKind.ELEMENT_SET: (
- "element-set-patch/v1" if base_ref else "element-set-artifact/v1"
- ),
- ScriptTaskKind.COMPARE: "comparison-artifact/v1",
- ScriptTaskKind.COMPOSE: "structured-script/v1",
- ScriptTaskKind.CANDIDATE_PORTFOLIO: "candidate-portfolio/v1",
- }[kind]
- if kind in {ScriptTaskKind.COMPOSE, ScriptTaskKind.CANDIDATE_PORTFOLIO}:
- intent = "compose" if kind is ScriptTaskKind.COMPOSE else "portfolio"
- elif supersedes:
- intent = "replace"
- else:
- intent = "explore"
- payload: dict[str, Any] = {
- "schema_version": "script-task-contract/v1",
- "task_kind": kind.value,
- "scope_ref": scope,
- "intent_class": intent,
- "objective": f"produce independently verifiable {kind.value} content",
- "input_decision_refs": list(input_refs),
- "base_artifact_ref": _ref_payload(base_ref) if base_ref else None,
- "write_scope": list(write_scope),
- "gap_ref": None,
- "output_schema": output_schema,
- "criteria": [
- {
- "criterion_id": "closed",
- "description": "the frozen increment is concrete and independently verifiable",
- "hard": True,
- }
- ],
- "budget": {
- "max_attempts": 4,
- "max_tokens": 32_000,
- "max_seconds": 900,
- "max_external_queries": 40,
- "max_no_improvement": 3,
- },
- "goal_ids": (
- []
- if kind in {ScriptTaskKind.DIRECTION, ScriptTaskKind.DECODE_RETRIEVAL}
- else ["goal-1"]
- ),
- "supersedes_decision_ids": list(supersedes),
- "candidate_closure_decision_refs": list(closure),
- "adopted_decision_ids": list(adopted),
- "held_or_rejected_decision_ids": list(held),
- "compose_order": list(order),
- "comparison_decision_refs": list(comparison_refs),
- }
- if not execution_ready and kind in {
- ScriptTaskKind.COMPOSE,
- ScriptTaskKind.CANDIDATE_PORTFOLIO,
- }:
- payload.update(
- candidate_closure_decision_refs=[],
- adopted_decision_ids=[],
- held_or_rejected_decision_ids=[],
- compose_order=[],
- )
- return payload
- def _decision_ref(
- decision_id: str,
- ref: ArtifactRef,
- *,
- scope: str,
- kind: ScriptTaskKind,
- ) -> dict[str, Any]:
- return {
- "decision_id": decision_id,
- "artifact_ref": _ref_payload(ref),
- "scope_ref": scope,
- "expected_task_kind": kind.value,
- }
- def _ref_payload(ref: ArtifactRef) -> dict[str, Any]:
- return {
- "uri": ref.uri,
- "kind": ref.kind,
- "version": ref.version,
- "digest": ref.digest,
- "summary": ref.summary,
- "metadata": ref.metadata,
- }
- def _task_kind(context: Mapping[str, Any]) -> ScriptTaskKind:
- refs = cast(dict[str, Any], context["task_spec"])["context_refs"]
- values = [value.rsplit("/", 1)[-1] for value in refs if "/task-kinds/" in value]
- assert len(values) == 1
- return ScriptTaskKind(values[0])
- class _ScriptedExecutor:
- """Drive real Coordinator stages through the same protected Host services."""
- def __init__(
- self,
- *,
- coordinator: TaskCoordinator,
- candidates: PhaseTwoCandidateService,
- artifacts: SqlAlchemyScriptBusinessArtifactRepository,
- script_build_id: int,
- ) -> None:
- self.coordinator = coordinator
- self.candidates = candidates
- self.artifacts = artifacts
- self.script_build_id = script_build_id
- async def run_worker(self, context: dict[str, Any]) -> WorkerRunResult:
- kind = _task_kind(context)
- candidate_context = {
- "root_trace_id": context["root_trace_id"],
- "task_id": context["task_id"],
- "attempt_id": context["attempt_id"],
- "spec_version": context["spec_version"],
- }
- if kind is ScriptTaskKind.DECODE_RETRIEVAL:
- await self.artifacts.freeze(
- script_build_id=self.script_build_id,
- task_id=context["task_id"],
- attempt_id=context["attempt_id"],
- spec_version=context["spec_version"],
- artifact=EvidenceRecordV1(
- evidence_id=f"evidence-{context['attempt_id']}",
- source_type="decode",
- tool_name="retrieve_decode",
- query={"query": "opening tension", "top_k": 3},
- source_refs=("decode-index://fixture/1",),
- raw_artifact_ref=None,
- summary="A concrete opening needs a visible tension and an observable detail.",
- supports=("direction",),
- confidence="high",
- limitations=(),
- content_sha256="",
- created_at=datetime.now(UTC),
- ),
- )
- elif kind is ScriptTaskKind.DIRECTION:
- child_results = cast(list[dict[str, Any]], context["accepted_child_results"])
- assert len(child_results) == 1
- evidence_refs = child_results[0]["submission"]["evidence_refs"]
- await self.artifacts.freeze(
- script_build_id=self.script_build_id,
- task_id=context["task_id"],
- attempt_id=context["attempt_id"],
- spec_version=context["spec_version"],
- artifact=DirectionArtifact(
- goals=(
- DirectionGoal(
- "goal-1",
- "Use a concrete reversal to reveal the topic",
- "A visible reversal makes the direction observable",
- success_criteria=("the opening reveals one concrete reversal",),
- ),
- ),
- evidence_refs=(str(evidence_refs[0]["uri"]),),
- ),
- )
- elif kind in {ScriptTaskKind.STRUCTURE, ScriptTaskKind.PARAGRAPH}:
- workspace = await self.candidates.read_attempt_workspace(context=candidate_context)
- if workspace["paragraphs"]:
- paragraph_id = workspace["paragraphs"][0]["paragraph_id"]
- else:
- created = await self.candidates.create_script_paragraph(
- payload={
- "paragraph_index": 1,
- "name": f"{kind.value} opening",
- "content_range": {"scope": "opening"},
- },
- context=candidate_context,
- )
- paragraph_id = created["paragraph_id"]
- await self.candidates.batch_update_script_paragraphs(
- updates=(
- {
- "paragraph_id": paragraph_id,
- "theme": "a specific reversal",
- "form": "contrast",
- "function": "hook",
- "feeling": "curiosity",
- "description": "The observable detail changes the initial interpretation.",
- "full_description": (
- "The opening states a familiar assumption, then overturns it with "
- "one visible and source-grounded detail."
- ),
- },
- ),
- context=candidate_context,
- )
- elif kind is ScriptTaskKind.ELEMENT_SET:
- created = await self.candidates.create_script_element(
- payload={
- "name": "observable reversal detail",
- "dimension_primary": "实质",
- "dimension_secondary": "narrative evidence",
- "topic_support": {"scope": "opening"},
- "weight_score": {"score": 0.9},
- },
- context=candidate_context,
- )
- workspace = await self.candidates.read_attempt_workspace(context=candidate_context)
- if workspace["paragraphs"]:
- await self.candidates.batch_link_paragraph_elements(
- links=(
- {
- "paragraph_id": workspace["paragraphs"][0]["paragraph_id"],
- "element_ids": [created["element_id"]],
- },
- ),
- context=candidate_context,
- )
- elif kind is ScriptTaskKind.COMPARE:
- pinned = await self.candidates.read_pinned_candidates(context=candidate_context)
- candidate_refs = [str(item["artifact_ref"]["uri"]) for item in pinned]
- await self.candidates.save_comparison_candidate(
- payload={
- "criterion_results": [
- {
- "criterion_id": "closed",
- "candidate_results": [
- {"artifact_ref": ref, "reason": "immutable candidate reviewed"}
- for ref in candidate_refs
- ],
- }
- ],
- "conflicts": ["the replacement has the more concrete opening"],
- "recommendation": candidate_refs[-1],
- },
- context=candidate_context,
- )
- elif kind is ScriptTaskKind.COMPOSE:
- await self.candidates.save_structured_script_candidate(
- acceptance_notes=("all adopted increments are pinned by ACCEPT decisions",),
- context=candidate_context,
- )
- elif kind is ScriptTaskKind.CANDIDATE_PORTFOLIO:
- await self.candidates.save_candidate_portfolio(
- payload={"unresolved_defects": []}, context=candidate_context
- )
- else: # pragma: no cover - this executor is intentionally phase-two bounded
- raise AssertionError(f"unexpected worker kind: {kind.value}")
- manifest = await self.candidates.resolve_attempt_manifest(context=candidate_context)
- safe_ref = ArtifactRef(
- manifest.artifact_ref.uri,
- manifest.artifact_ref.kind,
- manifest.artifact_ref.version,
- manifest.artifact_ref.digest,
- )
- await self.coordinator.submit_attempt(
- {
- "role": AgentRole.WORKER.value,
- "root_trace_id": context["root_trace_id"],
- "task_id": context["task_id"],
- "attempt_id": context["attempt_id"],
- "spec_version": context["spec_version"],
- "trace_id": context["worker_trace_id"],
- "tool_call_id": f"submit:{context['attempt_id']}",
- "operation_id": context["operation_id"],
- "execution_epoch": context["execution_epoch"],
- },
- AttemptSubmission(
- summary=f"kind={safe_ref.kind};status=frozen",
- artifact_refs=[] if safe_ref.kind == ArtifactKind.EVIDENCE.value else [safe_ref],
- evidence_refs=[safe_ref] if safe_ref.kind == ArtifactKind.EVIDENCE.value else [],
- ),
- )
- return WorkerRunResult(context["worker_trace_id"], "completed")
- async def run_validator(self, context: dict[str, Any]) -> ValidatorRunResult:
- criteria = cast(dict[str, Any], context["task_spec"])["acceptance_criteria"]
- results = [
- CriterionResult(
- criterion_id=item["criterion_id"],
- verdict=ValidationVerdict.PASSED,
- reason="the immutable SQL artifact is concrete and owner/digest closed",
- )
- for item in criteria
- ]
- await self.coordinator.submit_validation(
- {
- "role": AgentRole.VALIDATOR.value,
- "root_trace_id": context["root_trace_id"],
- "task_id": context["task_id"],
- "attempt_id": context["attempt_id"],
- "validation_id": context["validation_id"],
- "snapshot_id": context["snapshot_id"],
- "trace_id": context["validator_trace_id"],
- "tool_call_id": f"validate:{context['validation_id']}",
- "operation_id": context["operation_id"],
- "execution_epoch": context["execution_epoch"],
- },
- ValidationVerdict.PASSED,
- results,
- "all hard criteria passed against the immutable snapshot",
- (),
- (),
- (),
- "accept",
- )
- return ValidatorRunResult(context["validator_trace_id"], "completed")
- async def stop(self, trace_id: str) -> bool:
- del trace_id
- return True
- async def _plan_one(
- planning: PhaseTwoPlanningService,
- payload: Mapping[str, Any],
- *,
- parent_task_id: str | None,
- call_id: str,
- ) -> str:
- result = await planning.plan_script_tasks(
- contract_payloads=(payload,),
- parent_task_id=parent_task_id,
- context={"root_trace_id": ROOT, "tool_call_id": call_id},
- )
- return cast(str, result["task_ids"][0])
- async def _dispatch_accept(
- planning: PhaseTwoPlanningService, coordinator: TaskCoordinator, task_id: str
- ) -> tuple[str, ArtifactRef]:
- cycles = await planning.dispatch_script_tasks(
- task_ids=(task_id,),
- context={"root_trace_id": ROOT, "tool_call_id": f"dispatch:{task_id}"},
- )
- assert cycles[0]["error"] is None
- validation_id = cast(str, cycles[0]["validation_id"])
- accepted = await planning.decide_script_task(
- task_id=task_id,
- action=DecisionAction.ACCEPT.value,
- reason="independent validation passed",
- validation_id=validation_id,
- replacement_contract=None,
- child_contracts=(),
- context={"root_trace_id": ROOT, "tool_call_id": f"accept:{task_id}"},
- )
- decision_id = cast(str, accepted["decision_id"])
- ledger = await coordinator.task_store.load(ROOT)
- decision = ledger.decisions[decision_id]
- attempt = ledger.attempts[cast(str, decision.attempt_id)]
- assert attempt.submission is not None
- refs = [*attempt.submission.artifact_refs, *attempt.submission.evidence_refs]
- assert len(refs) == 1
- return decision_id, refs[0]
- @pytest.mark.asyncio
- async def test_sql_phase_two_dynamic_replacement_compose_portfolio_and_boundary(
- database: Any, tmp_path: Path
- ) -> None:
- engine, sessions = database
- mutation_statements: list[str] = []
- def observe_sql(
- _connection: Any,
- _cursor: Any,
- statement: str,
- _parameters: Any,
- _context: Any,
- _executemany: bool,
- ) -> None:
- if statement.lstrip().upper().startswith(("INSERT ", "UPDATE ", "DELETE ")):
- mutation_statements.append(statement)
- event.listen(engine.sync_engine, "before_cursor_execute", observe_sql)
- build_states = SqlAlchemyLegacyBuildStateRepository(sessions)
- script_build_id = await build_states.create(
- execution_id=101,
- topic_build_id=202,
- topic_id=303,
- agent_type="script-planner",
- agent_config={},
- data_source_url=None,
- strategies_config={},
- )
- bindings = SqlAlchemyMissionBindingRepository(sessions)
- await bindings.create(
- script_build_id=script_build_id,
- root_trace_id=ROOT,
- input_snapshot_id=SNAPSHOT_ID,
- engine_version="phase-two-test",
- schema_version="v1",
- )
- task_path = tmp_path / "task-ledger"
- artifact_path = tmp_path / "framework-artifacts"
- contract_path = tmp_path / "contract-data"
- task_store = FileSystemTaskStore(str(task_path))
- framework_artifacts = FileSystemArtifactStore(str(artifact_path))
- coordinator = TaskCoordinator(
- task_store,
- framework_artifacts,
- FileSystemTraceStore(str(tmp_path / "traces")),
- )
- await coordinator.ensure_ledger(
- ROOT,
- {
- "objective": "produce a governed phase-two candidate portfolio",
- "acceptance_criteria": [
- {"criterion_id": "portfolio", "description": "portfolio closed", "hard": True}
- ],
- "context_refs": [f"script-build://inputs/{SNAPSHOT_ID}"],
- },
- )
- contract_store = FileScriptTaskContractStore(contract_path)
- contract_reader = StoredTaskContractReader(contract_store)
- artifacts = SqlAlchemyScriptBusinessArtifactRepository(sessions)
- accepted_inputs = AcceptedInputResolver(
- task_store=task_store,
- artifact_store=framework_artifacts,
- artifacts=artifacts,
- contracts=contract_reader,
- )
- workspaces = SqlAlchemyCandidateWorkspaceRepository(sessions, artifacts)
- candidates = PhaseTwoCandidateService(
- bindings=bindings,
- task_store=task_store,
- framework_artifact_store=framework_artifacts,
- artifacts=artifacts,
- accepted_inputs=accepted_inputs,
- active_frontier=ActiveFrontierResolver(),
- workspaces=workspaces,
- )
- boundary = ScriptPhaseTwoBoundaryVerifier(
- task_store=task_store,
- artifact_store=framework_artifacts,
- artifacts=artifacts,
- bindings=bindings,
- accepted_inputs=accepted_inputs,
- )
- planning = PhaseTwoPlanningService(
- coordinator=coordinator,
- bindings=bindings,
- contracts=contract_store,
- artifacts=artifacts,
- closure_gate=boundary,
- )
- coordinator.set_executor(
- _ScriptedExecutor(
- coordinator=coordinator,
- candidates=candidates,
- artifacts=artifacts,
- script_build_id=script_build_id,
- )
- )
- direction = await _plan_one(
- planning, _contract(ScriptTaskKind.DIRECTION), parent_task_id=None, call_id="direction"
- )
- retrieval = await _plan_one(
- planning,
- _contract(ScriptTaskKind.DECODE_RETRIEVAL, write_scope=()),
- parent_task_id=direction,
- call_id="retrieval",
- )
- await _dispatch_accept(planning, coordinator, retrieval)
- direction_decision, direction_ref = await _dispatch_accept(planning, coordinator, direction)
- portfolio = await _plan_one(
- planning,
- _contract(
- ScriptTaskKind.CANDIDATE_PORTFOLIO,
- write_scope=("script-build://writes",),
- execution_ready=False,
- ),
- parent_task_id=None,
- call_id="portfolio",
- )
- compose = await _plan_one(
- planning,
- _contract(
- ScriptTaskKind.COMPOSE,
- write_scope=("script-build://writes",),
- execution_ready=False,
- ),
- parent_task_id=portfolio,
- call_id="compose",
- )
- # Exploration order is intentionally Element -> Paragraph -> Structure.
- old_element = await _plan_one(
- planning,
- _contract(
- ScriptTaskKind.ELEMENT_SET,
- scope="script-build://scopes/full/elements",
- write_scope=("script-build://writes/elements",),
- ),
- parent_task_id=compose,
- call_id="element-first",
- )
- old_element_decision, old_element_ref = await _dispatch_accept(
- planning, coordinator, old_element
- )
- old_paragraph = await _plan_one(
- planning,
- _contract(
- ScriptTaskKind.PARAGRAPH,
- scope="script-build://scopes/full/opening",
- write_scope=("script-build://writes/paragraphs/opening",),
- ),
- parent_task_id=compose,
- call_id="paragraph-second",
- )
- old_paragraph_decision, old_paragraph_ref = await _dispatch_accept(
- planning, coordinator, old_paragraph
- )
- structure = await _plan_one(
- planning,
- _contract(
- ScriptTaskKind.STRUCTURE,
- scope="script-build://scopes/full/opening",
- write_scope=("script-build://writes/paragraphs/opening",),
- input_refs=(
- _decision_ref(
- old_paragraph_decision,
- old_paragraph_ref,
- scope="script-build://scopes/full/opening",
- kind=ScriptTaskKind.PARAGRAPH,
- ),
- ),
- base_ref=old_paragraph_ref,
- ),
- parent_task_id=compose,
- call_id="structure-third",
- )
- structure_decision, structure_ref = await _dispatch_accept(planning, coordinator, structure)
- paragraph_replacement = await _plan_one(
- planning,
- _contract(
- ScriptTaskKind.PARAGRAPH,
- scope="script-build://scopes/full/opening",
- write_scope=("script-build://writes/paragraphs/opening",),
- input_refs=(
- _decision_ref(
- structure_decision,
- structure_ref,
- scope="script-build://scopes/full/opening",
- kind=ScriptTaskKind.STRUCTURE,
- ),
- _decision_ref(
- old_paragraph_decision,
- old_paragraph_ref,
- scope="script-build://scopes/full/opening",
- kind=ScriptTaskKind.PARAGRAPH,
- ),
- ),
- base_ref=structure_ref,
- supersedes=(old_paragraph_decision,),
- ),
- parent_task_id=compose,
- call_id="replace-paragraph",
- )
- paragraph_decision, paragraph_ref = await _dispatch_accept(
- planning, coordinator, paragraph_replacement
- )
- element_replacement = await _plan_one(
- planning,
- _contract(
- ScriptTaskKind.ELEMENT_SET,
- scope="script-build://scopes/full/elements",
- write_scope=("script-build://writes/elements",),
- input_refs=(
- _decision_ref(
- old_element_decision,
- old_element_ref,
- scope="script-build://scopes/full/elements",
- kind=ScriptTaskKind.ELEMENT_SET,
- ),
- _decision_ref(
- paragraph_decision,
- paragraph_ref,
- scope="script-build://scopes/full/opening",
- kind=ScriptTaskKind.PARAGRAPH,
- ),
- ),
- base_ref=paragraph_ref,
- supersedes=(old_element_decision,),
- ),
- parent_task_id=compose,
- call_id="replace-element",
- )
- element_decision, element_ref = await _dispatch_accept(
- planning, coordinator, element_replacement
- )
- comparison = await _plan_one(
- planning,
- _contract(
- ScriptTaskKind.COMPARE,
- scope="script-build://scopes/full/opening",
- write_scope=(),
- comparison_refs=(
- _decision_ref(
- old_paragraph_decision,
- old_paragraph_ref,
- scope="script-build://scopes/full/opening",
- kind=ScriptTaskKind.PARAGRAPH,
- ),
- _decision_ref(
- paragraph_decision,
- paragraph_ref,
- scope="script-build://scopes/full/opening",
- kind=ScriptTaskKind.PARAGRAPH,
- ),
- ),
- ),
- parent_task_id=compose,
- call_id="compare-opening-candidates",
- )
- comparison_decision, comparison_ref = await _dispatch_accept(planning, coordinator, comparison)
- with pytest.raises(PhaseTwoBoundaryNotReady, match="CandidatePortfolio"):
- await planning.decide_script_task(
- task_id=(await task_store.load(ROOT)).root_task_id,
- action=DecisionAction.BLOCK.value,
- reason=PHASE_TWO_CANDIDATE_PORTFOLIO_READY,
- validation_id=None,
- replacement_contract=None,
- child_contracts=(),
- context={"root_trace_id": ROOT, "tool_call_id": "early-boundary"},
- )
- local_refs = (
- _decision_ref(
- old_element_decision,
- old_element_ref,
- scope="script-build://scopes/full/elements",
- kind=ScriptTaskKind.ELEMENT_SET,
- ),
- _decision_ref(
- old_paragraph_decision,
- old_paragraph_ref,
- scope="script-build://scopes/full/opening",
- kind=ScriptTaskKind.PARAGRAPH,
- ),
- _decision_ref(
- structure_decision,
- structure_ref,
- scope="script-build://scopes/full/opening",
- kind=ScriptTaskKind.STRUCTURE,
- ),
- _decision_ref(
- paragraph_decision,
- paragraph_ref,
- scope="script-build://scopes/full/opening",
- kind=ScriptTaskKind.PARAGRAPH,
- ),
- _decision_ref(
- element_decision,
- element_ref,
- scope="script-build://scopes/full/elements",
- kind=ScriptTaskKind.ELEMENT_SET,
- ),
- )
- adopted = (structure_decision, paragraph_decision, element_decision)
- held = (old_element_decision, old_paragraph_decision)
- compose_contract = _contract(
- ScriptTaskKind.COMPOSE,
- write_scope=("script-build://writes",),
- input_refs=(
- _decision_ref(
- direction_decision,
- direction_ref,
- scope=FULL_SCOPE,
- kind=ScriptTaskKind.DIRECTION,
- ),
- ),
- closure=local_refs,
- adopted=adopted,
- held=held,
- order=adopted,
- comparison_refs=(
- _decision_ref(
- comparison_decision,
- comparison_ref,
- scope="script-build://scopes/full/opening",
- kind=ScriptTaskKind.COMPARE,
- ),
- ),
- )
- await planning.decide_script_task(
- task_id=compose,
- action=DecisionAction.REVISE.value,
- reason="freeze the selected active frontier and formal compose order",
- validation_id=None,
- replacement_contract=compose_contract,
- child_contracts=(),
- context={"root_trace_id": ROOT, "tool_call_id": "close-compose"},
- )
- compose_decision, compose_ref = await _dispatch_accept(planning, coordinator, compose)
- portfolio_contract = _contract(
- ScriptTaskKind.CANDIDATE_PORTFOLIO,
- write_scope=("script-build://writes",),
- closure=(
- _decision_ref(
- compose_decision,
- compose_ref,
- scope=FULL_SCOPE,
- kind=ScriptTaskKind.COMPOSE,
- ),
- ),
- adopted=(compose_decision,),
- order=(compose_decision,),
- )
- await planning.decide_script_task(
- task_id=portfolio,
- action=DecisionAction.REVISE.value,
- reason="freeze the uniquely adopted StructuredScript",
- validation_id=None,
- replacement_contract=portfolio_contract,
- child_contracts=(),
- context={"root_trace_id": ROOT, "tool_call_id": "close-portfolio"},
- )
- portfolio_decision, _ = await _dispatch_accept(planning, coordinator, portfolio)
- ledger = await task_store.load(ROOT)
- compose_attempt = ledger.attempts[cast(str, ledger.decisions[compose_decision].attempt_id)]
- frontier = await candidates.read_active_frontier(
- context={
- "root_trace_id": ROOT,
- "task_id": compose,
- "attempt_id": compose_attempt.attempt_id,
- "spec_version": compose_attempt.spec_version,
- }
- )
- assert [item["decision_id"] for item in frontier["inputs"]] == list(adopted)
- assert old_element_decision not in {item["decision_id"] for item in frontier["inputs"]}
- assert old_paragraph_decision not in {item["decision_id"] for item in frontier["inputs"]}
- await planning.decide_script_task(
- task_id=ledger.root_task_id,
- action=DecisionAction.BLOCK.value,
- reason=PHASE_TWO_CANDIDATE_PORTFOLIO_READY,
- validation_id=None,
- replacement_contract=None,
- child_contracts=(),
- context={"root_trace_id": ROOT, "tool_call_id": "phase-two-boundary"},
- )
- await build_states.set_checkpoint(
- script_build_id,
- checkpoint_code=PHASE_TWO_CANDIDATE_PORTFOLIO_READY,
- summary="one validated CandidatePortfolio is ready for phase three",
- root_trace_id=ROOT,
- )
- reloaded = await FileSystemTaskStore(str(task_path)).load(ROOT)
- assert reloaded.tasks[reloaded.root_task_id].status is TaskStatus.BLOCKED
- assert reloaded.tasks[reloaded.root_task_id].blocked_reason == (
- PHASE_TWO_CANDIDATE_PORTFOLIO_READY
- )
- compose_children = [reloaded.tasks[item] for item in reloaded.tasks[compose].child_task_ids]
- stored_reader = StoredTaskContractReader(FileScriptTaskContractStore(contract_path))
- assert [
- (
- await stored_reader.read_for_task(
- root_trace_id=ROOT,
- task=item,
- spec_version=item.current_spec_version,
- )
- ).task_kind
- for item in compose_children[:3]
- ] == [
- ScriptTaskKind.ELEMENT_SET,
- ScriptTaskKind.PARAGRAPH,
- ScriptTaskKind.STRUCTURE,
- ]
- compose_version = await artifacts.get_by_attempt(
- script_build_id=script_build_id,
- task_id=compose,
- attempt_id=compose_attempt.attempt_id,
- )
- assert isinstance(compose_version.artifact, StructuredScriptArtifactV1)
- assert len(compose_version.artifact.paragraphs) == 1
- assert compose_version.artifact.elements
- assert compose_version.artifact.paragraph_element_links
- portfolio_attempt = reloaded.attempts[
- cast(str, reloaded.decisions[portfolio_decision].attempt_id)
- ]
- portfolio_version = await artifacts.get_by_attempt(
- script_build_id=script_build_id,
- task_id=portfolio,
- attempt_id=portfolio_attempt.attempt_id,
- )
- assert isinstance(portfolio_version.artifact, CandidatePortfolioArtifactV1)
- assert portfolio_version.artifact.accepted_decision_ids == (compose_decision,)
- assert portfolio_version.artifact.adopted_structured_script_ref == compose_ref.uri
- async with sessions() as session:
- build = (
- (
- await session.execute(
- select(script_build_record).where(script_build_record.c.id == script_build_id)
- )
- )
- .mappings()
- .one()
- )
- branch_values = [
- *(
- await session.scalars(
- select(script_build_paragraph.c.branch_id).where(
- script_build_paragraph.c.script_build_id == script_build_id
- )
- )
- ),
- *(
- await session.scalars(
- select(script_build_element.c.branch_id).where(
- script_build_element.c.script_build_id == script_build_id
- )
- )
- ),
- *(
- await session.scalars(
- select(script_build_paragraph_element.c.branch_id).where(
- script_build_paragraph_element.c.script_build_id == script_build_id
- )
- )
- ),
- ]
- final_publications = await session.scalar(
- select(func.count())
- .select_from(publication_table)
- .where(
- publication_table.c.script_build_id == script_build_id,
- publication_table.c.publication_type == "final",
- )
- )
- phase_two_rows = (
- (
- await session.execute(
- select(artifact_version_table).where(
- artifact_version_table.c.script_build_id == script_build_id,
- artifact_version_table.c.artifact_type.in_(
- [
- ArtifactKind.STRUCTURE.value,
- ArtifactKind.PARAGRAPH.value,
- ArtifactKind.ELEMENT_SET.value,
- ArtifactKind.COMPARISON.value,
- ArtifactKind.STRUCTURED_SCRIPT.value,
- ArtifactKind.CANDIDATE_PORTFOLIO.value,
- ]
- ),
- )
- )
- )
- .mappings()
- .all()
- )
- mutation_targets = {
- match.group(1).strip('`"').lower()
- for statement in mutation_statements
- if (
- match := re.match(
- r"\s*(?:INSERT\s+INTO|UPDATE|DELETE\s+FROM)\s+([`\"\w]+)",
- statement,
- re.IGNORECASE,
- )
- )
- }
- assert mutation_targets <= {
- "script_build_record",
- "script_build_mission_binding",
- "script_build_artifact_version",
- "script_build_publication",
- "script_build_paragraph",
- "script_build_element",
- "script_build_paragraph_element",
- "script_build_task_plan_step",
- }
- assert not mutation_targets & {
- "script_build_branch",
- "script_build_round",
- "script_build_multipath",
- }
- assert BuildStatus(str(build["status"])) is BuildStatus.PARTIAL
- assert build["error_message"] == PHASE_TWO_CANDIDATE_PORTFOLIO_READY
- assert build["reson_trace_id"] == ROOT and build["end_time"] is not None
- assert branch_values and min(branch_values) > 0 and 0 not in branch_values
- assert final_publications == 0
- assert (
- sum(
- row["artifact_type"] == ArtifactKind.CANDIDATE_PORTFOLIO.value for row in phase_two_rows
- )
- == 1
- )
- for row in phase_two_rows:
- if row["artifact_type"] in {
- ArtifactKind.STRUCTURE.value,
- ArtifactKind.PARAGRAPH.value,
- ArtifactKind.ELEMENT_SET.value,
- ArtifactKind.STRUCTURED_SCRIPT.value,
- }:
- assert row["legacy_branch_id"] == row["id"] > 0
- else:
- assert row["legacy_branch_id"] is None
- class _SingleBinding:
- def __init__(self, root: str) -> None:
- now = datetime.now(UTC)
- self.value = MissionBinding(1, 1, root, 11, None, None, "test", "v1", now, now)
- async def get_by_root(self, root_trace_id: str) -> MissionBinding:
- assert root_trace_id == self.value.root_trace_id
- return self.value
- class _BlockingExecutor:
- def __init__(self) -> None:
- self.started = asyncio.Event()
- self.release = asyncio.Event()
- async def run_worker(self, context: dict[str, Any]) -> WorkerRunResult:
- self.started.set()
- await self.release.wait()
- return WorkerRunResult(context["worker_trace_id"], "failed", error="test release")
- async def run_validator(self, context: dict[str, Any]) -> ValidatorRunResult:
- raise AssertionError(f"unexpected validation: {context}")
- async def stop(self, trace_id: str) -> bool:
- del trace_id
- self.release.set()
- return True
- @pytest.mark.asyncio
- async def test_same_task_cannot_reserve_parallel_attempts(tmp_path: Path) -> None:
- root = "parallel-attempt-root"
- task_store = FileSystemTaskStore(str(tmp_path / "ledger"))
- executor = _BlockingExecutor()
- coordinator = TaskCoordinator(
- task_store,
- FileSystemArtifactStore(str(tmp_path / "artifacts")),
- FileSystemTraceStore(str(tmp_path / "traces")),
- executor=executor,
- )
- await coordinator.ensure_ledger(
- root,
- {
- "objective": "parallel attempt guard",
- "acceptance_criteria": [
- {"criterion_id": "guard", "description": "guard", "hard": True}
- ],
- "context_refs": ["script-build://inputs/11"],
- },
- )
- planning = PhaseTwoPlanningService(
- coordinator=coordinator,
- bindings=cast(Any, _SingleBinding(root)),
- contracts=FileScriptTaskContractStore(tmp_path / "contracts"),
- artifacts=cast(Any, SimpleNamespace()),
- )
- task = await planning.plan_script_tasks(
- contract_payloads=(_contract(ScriptTaskKind.DIRECTION),),
- parent_task_id=None,
- context={"root_trace_id": root},
- )
- task_id = task["task_ids"][0]
- first = asyncio.create_task(
- planning.dispatch_script_tasks(task_ids=(task_id,), context={"root_trace_id": root})
- )
- await asyncio.wait_for(executor.started.wait(), timeout=2)
- second = await planning.dispatch_script_tasks(
- task_ids=(task_id,), context={"root_trace_id": root}
- )
- assert "Dispatch conflict" in cast(str, second[0]["error"])
- executor.release.set()
- await first
- ledger = await task_store.load(root)
- assert len(ledger.tasks[task_id].attempt_ids) == 1
|