aps-agent/tests/golden/test_drawing_links.py

133 lines
5.0 KiB
Python
Raw Normal View History

from __future__ import annotations
import time
import uuid
from copy import deepcopy
from pathlib import Path
from server.agent_core import harness
from server.agent_core.approval_store import utc_now
from server.aps_domain.drawing_understanding import build_drawing_link_evidence_records
from server.aps_domain.workflow import execute_confirmed
from server.auth.context import get_identity
from server.state.seed import seed_world
from server.state.store import WorldStore
def _selected_candidates() -> list[dict]:
return [
{"candidateType": "MATERIAL", "candidateId": "m-1", "code": "CTRL-A",
"name": "Controller A", "revision": "e", "confidence": 0.9},
{"candidateType": "BOM_REFERENCE", "candidateId": "b-1",
"componentReference": "PCB-001", "parentMaterialCode": "CTRL-A",
"confidence": 0.72, "revision": "e"},
{"candidateType": "ROUTING_OPERATION", "candidateId": "r-1",
"operationCode": "ASSEMBLY", "productCode": "CTRL-A",
"confidence": 0.63, "revision": "e"},
]
def _stage_drawing_confirmation(store: WorldStore, selected: list[dict]) -> str:
params = {
"drawingId": "drawing-1",
"sourceSha256": "0" * 64,
"selectedCandidates": selected,
"candidateIds": [row["candidateId"] for row in selected],
"executionSupported": True,
}
identity = get_identity()
confirm_id = f"drawing-link-{uuid.uuid4().hex[:12]}"
now = time.time()
record = {
"confirmId": confirm_id,
"sessionId": "drawing-test",
"action": "drawing.master.apply",
"power": "P2",
"params": deepcopy(params),
"paramsHash": harness._params_fingerprint(params),
"tenantUuid": store.tenant_uuid,
"ownerUserId": identity.user_id,
"delegateUserId": None,
"projectId": "default",
"worldKey": store.world_key,
"evidenceRefs": [],
"beforeSnapshot": None,
"beforeFingerprint": None,
"requester": {"userId": identity.user_id, "username": identity.username},
"approvals": [],
"approvalStep": 0,
"requiredApprovals": 1,
"createdAt": utc_now(now),
"createdAtEpoch": now,
"expiresAt": utc_now(now + 3600),
"expiresAtEpoch": now + 3600,
}
record["envelopeHash"] = harness._confirmation_envelope_fingerprint(record)
assert harness._approval_store.stage(record, now_epoch=now)
return confirm_id
def test_link_evidence_builder_adds_bom_routing_order_without_master_write():
world = seed_world()
before = deepcopy(world)
counter = {"n": 0}
def next_id(kind: str) -> int:
counter["n"] += 1
return counter["n"]
records = build_drawing_link_evidence_records(
world,
drawing_id="drawing-1",
source_sha256="0" * 64,
selected_candidates=_selected_candidates(),
actor="tester",
confirm_id="confirm-1",
next_id=next_id,
)
assert world == before
assert {row["linkType"] for row in records} == {"BOM", "ORDER", "ROUTING"}
bom = next(row for row in records if row["linkType"] == "BOM")
routing = next(row for row in records if row["linkType"] == "ROUTING")
orders = [row for row in records if row["linkType"] == "ORDER"]
assert bom["status"] == "PENDING_REVIEW"
assert bom["masterCommitted"] is False
assert bom["confidence"] == 0.72
assert bom["evidence"]["confirmId"] == "confirm-1"
assert routing["status"] == "PENDING_REVIEW"
assert routing["masterCommitted"] is False
assert orders
assert all(row["status"] == "CONFIRMED" for row in orders)
assert all(row["masterCommitted"] is True for row in orders)
def test_drawing_master_apply_persists_extended_drawing_link_evidence(tmp_path: Path):
store = WorldStore(path=tmp_path / "world.json")
selected = _selected_candidates()
before_master = {
key: deepcopy(store.data.get(key, []))
for key in ("boms", "bomItems", "routings", "routingSteps")
}
confirm_id = _stage_drawing_confirmation(store, selected)
message = execute_confirmed(store, confirm_id, True, actor="tester")
assert "Drawing review applied:" in message
assert "links=" in message
after_master = {
key: deepcopy(store.data.get(key, [])) for key in before_master
}
assert after_master == before_master
links = store.data.get("drawingLinks", [])
assert {"BOM", "MATERIAL", "ROUTING"} <= {row["linkType"] for row in links}
material = next(row for row in links if row["linkType"] == "MATERIAL")
bom = next(row for row in links if row["linkType"] == "BOM")
routing = next(row for row in links if row["linkType"] == "ROUTING")
assert material["masterCommitted"] is True
assert material["evidence"]["contractVersion"] == "drawing-link-evidence.v1"
assert bom["masterCommitted"] is False
assert bom["status"] == "PENDING_REVIEW"
assert routing["masterCommitted"] is False
assert routing["status"] == "PENDING_REVIEW"