727c87339b
---ci---
project: acdl
phase: 8
milestone: v1.1
status: plan-as-execute
persona: lead-developer
task: T-8.0
type: prerequisite-fix
---/ci---
The Phase 07 P1 ('platform/ package shadows stdlib platform module')
became a Phase 08 blocker: boto3 imports uuid -> platform.system(),
which fails when the repo's platform/ package is on sys.path[0]. Renamed
platform/ -> acdl_platform/ (the verifier's recommended v1.2 fix, pulled
forward because Phase 08 needs boto3).
- git mv platform/ acdl_platform/ (history preserved)
- verify_phase07.sh: updated paths; removed the /tmp workaround (no
longer needed; the shadow is gone)
- verify_phase06.sh: updated the new-dirs check for the rename
- README.md: layout table updated
Both verify_phase06.sh and verify_phase07.sh still pass; confidence_signal
now imports + runs correctly from the repo root. boto3 imports clean.
42 lines
1.8 KiB
Python
42 lines
1.8 KiB
Python
"""Check that qaApprover != prodApprover for a contract (ARCHITECTURE.md
|
|
§10.3, D-042). Reads `approver_qa` from the DynamoDB outbox for the
|
|
contractId, compares to the prod-dispatch `gitea.actor`. Blocks on
|
|
equality, emits `SEPARATION_OF_DUTIES_VIOLATION`, routes a halt artifact
|
|
to SRE on-call.
|
|
|
|
Spike scope (A-8.1): the spike is dev-only (REQ-27 contract has
|
|
environment: dev); HITL is not exercised. This module is authored to its
|
|
full v1.2 shape but the spike calls it with current_prod_approver=None
|
|
and a None outbox_client — the check returns (True, 'no QA approver
|
|
recorded (dev-only spike)').
|
|
"""
|
|
|
|
from typing import Optional, Tuple
|
|
|
|
|
|
def check(outbox_client, contract_id: str,
|
|
current_prod_approver: Optional[str]) -> Tuple[bool, str]:
|
|
"""Return (ok, reason). ok=False means block the prod promotion."""
|
|
if outbox_client is None:
|
|
return (True, "no outbox client (dev-only spike)")
|
|
item = outbox_client.get(contract_id)
|
|
if item is None:
|
|
return (True, "no prior approver (first promotion)")
|
|
qa_approver = item.get("approver_qa")
|
|
if not qa_approver:
|
|
return (True, "no QA approver recorded (dev-only spike)")
|
|
if current_prod_approver is None:
|
|
return (True, "no prod approver supplied (dev-only spike)")
|
|
if qa_approver == current_prod_approver:
|
|
return (False,
|
|
f"SEPARATION_OF_DUTIES_VIOLATION: "
|
|
f"qaApprover==prodApprover=={qa_approver}")
|
|
return (True, "distinct")
|
|
|
|
|
|
def route_halt_artifact(contract_id: str, violation_reason: str,
|
|
oncall_client) -> None:
|
|
"""Route a halt artifact to SRE on-call. Spike: stub that logs. v1.2
|
|
wires a real pager."""
|
|
print(f"[halt-artifact] contract={contract_id} reason={violation_reason} "
|
|
f"oncall={oncall_client}", flush=True) |