mirror of
https://github.com/Imbad0202/academic-research-skills.git
synced 2026-09-14 13:51:17 +08:00
f1a57bbcab
* fix: shared file-lock helper with msvcrt backend for the six fcntl sites (#845) scripts/file_lock.py owns the backend choice (fcntl.flock on POSIX, msvcrt.locking on byte 0 on Windows) and routes adjudication_activity, inquiry_branch_ledger, review_criteria_binding, and ars_mark_read through acquire()/release(). POSIX lock sequences are unchanged. Per-site Windows decisions: adjudication reads degrade to exclusive with a 5 s bounded wait; the review-criteria manifest lock is capped at 30 s on Windows only; the inquiry ledger alpha keeps refusing non-POSIX hosts. Two finally blocks that released an unacquired lock now release only what they acquired. SETUP docs state the best-effort Windows posture; no Windows CI job is added. Refs #845, #843, #844. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0131cZMWBPPeEFiqgEPFZ3X2 * fix(file_lock): interrupted attempts honour the deadline; pin adjudication wait policy (#845) Cross-model review round 1 (gpt-6-astra, xhigh): a persistent InterruptedError could retry past the bound; the Windows-shape test did not exercise adjudication's reader-waits / writer-does-not-wait policy; the adjudication contention message now names LockTimeout instead of BlockingIOError, recorded in the CHANGELOG rather than masked. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0131cZMWBPPeEFiqgEPFZ3X2 * refactor(file_lock): held() context manager, single BACKEND source, one fake msvcrt (#845) /simplify pass (four cleanup reviewers): the release-only-if-acquired invariant moves into file_lock.held() and review_criteria_binding / inquiry_branch_ledger use it; runtime branches key off BACKEND and SHARED_LOCKS_SUPPORTED is dropped; EINTR joins the retryable errno set and the unreachable EDEADLK entry goes; backend calls are deduplicated; all four consumers try the sibling import first so one module instance is shared; the Windows fake lives once in tests/fake_msvcrt.py; test scaffolding is folded into a lock_pair fixture and a parametrized wait test. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0131cZMWBPPeEFiqgEPFZ3X2 * fix(file_lock): keep lock acquisition and the guarded body in separate try blocks (#845) Cross-model review round 3 (gpt-6-astra, xhigh): wrapping the body in the same handler that translates LockTimeout meant a contended inner lock inside the body was reported as the outer manifest/passport lock failing. Both consumers now acquire in their own try block and release only after a successful acquire; held() is dropped from the helper. The subprocess test pins that a LockTimeout raised inside the binding body surfaces as itself. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0131cZMWBPPeEFiqgEPFZ3X2 * test(file_lock): let the body LockTimeout leave _locked() so the attribution check bites (#845) Cross-model review round 4: the inner LockTimeout was caught inside the binding body, so the erroneous outer translation would still have passed. Verified by mutation: restoring the outer translation fails this test. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0131cZMWBPPeEFiqgEPFZ3X2 * ci(673): whitelist scripts/test_file_lock.py as a non-consumer importer of the activity runtime (#845) The shared file-lock test imports adjudication_activity in a subprocess to exercise its lock backend under a fake msvcrt; it never reads or writes an activity store. The exact-owner whitelist is the lint's route for that. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0131cZMWBPPeEFiqgEPFZ3X2 --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
1519 lines
53 KiB
Python
1519 lines
53 KiB
Python
#!/usr/bin/env python3
|
|
"""Hermetic black-box and library tests for #673 adjudication activity."""
|
|
from __future__ import annotations
|
|
|
|
import copy
|
|
import hashlib
|
|
import json
|
|
from pathlib import Path
|
|
from collections.abc import Callable
|
|
from typing import Any
|
|
|
|
import jsonschema
|
|
import pytest
|
|
|
|
from scripts import adjudication_activity as activity
|
|
from scripts import file_lock
|
|
from scripts import check_re_review_synthesis as re_review
|
|
from scripts.test_check_re_review_synthesis import emit, scenario_g2d
|
|
|
|
|
|
REPO = Path(__file__).resolve().parents[1]
|
|
FIXTURES = REPO / "scripts/fixtures/adjudication_activity"
|
|
INPUT_SCHEMA = REPO / "shared/contracts/activity/adjudication_activity_input.schema.json"
|
|
STORE_SCHEMA = REPO / "shared/contracts/activity/adjudication_activity_store.schema.json"
|
|
STORE_ID = "ADJ-ACTIVITY-STORE-focused-tests"
|
|
LIMITATION = (
|
|
"This records explicit adjudication activity only. It cannot determine correctness, "
|
|
"attentiveness, engagement, or whether human ownership is real; genuine agreement and "
|
|
"non-review can produce the same history."
|
|
)
|
|
ADVISORY = "This series is advisory only; it never gates, blocks, scores, or changes any verdict."
|
|
COVERAGE = (
|
|
"Coverage: only successfully retained records in this explicitly selected store are "
|
|
"shown; runs without this store selection or whose append failed are not represented."
|
|
)
|
|
STAGES = (
|
|
"pipeline_stage_1",
|
|
"pipeline_stage_2",
|
|
"pipeline_stage_2_5",
|
|
"pipeline_stage_3",
|
|
"pipeline_stage_3_prime",
|
|
"pipeline_stage_4",
|
|
"pipeline_stage_4_prime",
|
|
"pipeline_stage_4_5",
|
|
"pipeline_stage_5",
|
|
"pipeline_stage_6",
|
|
)
|
|
|
|
|
|
def _load(path: Path) -> dict[str, Any]:
|
|
return json.loads(path.read_text(encoding="utf-8"))
|
|
|
|
|
|
def _write(path: Path, value: Any) -> None:
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
path.write_bytes(activity.canonical_bytes(value) + b"\n")
|
|
|
|
|
|
def _independent_digest(domain: bytes, value: Any) -> str:
|
|
canonical = json.dumps(
|
|
value, sort_keys=True, separators=(",", ":"), ensure_ascii=False
|
|
).encode("utf-8")
|
|
return hashlib.sha256(domain + canonical).hexdigest()
|
|
|
|
|
|
def _independent_interaction(run_id: str, interaction_id: str) -> str:
|
|
return _independent_digest(
|
|
b"ars.adjudication-activity.interaction/1.0\0",
|
|
{"run_id": run_id, "interaction_id": interaction_id},
|
|
)
|
|
|
|
|
|
def _copy_fixture(root: Path, name: str) -> str:
|
|
destination = root / "sources" / name
|
|
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
destination.write_bytes((FIXTURES / name).read_bytes())
|
|
return destination.relative_to(root).as_posix()
|
|
|
|
|
|
def _artifact(
|
|
artifact_id: str,
|
|
role: str,
|
|
group_id: str,
|
|
relative_path: str,
|
|
stage: str | None = None,
|
|
) -> dict[str, Any]:
|
|
return {
|
|
"artifact_id": artifact_id,
|
|
"artifact_role": role,
|
|
"artifact_group_id": group_id,
|
|
"artifact_group_stage": stage,
|
|
"relative_path": relative_path,
|
|
}
|
|
|
|
|
|
def _empty_rows(capture_state: str = "not_applicable") -> list[dict[str, Any]]:
|
|
reason = (
|
|
"not_applicable_for_run"
|
|
if capture_state == "not_applicable"
|
|
else "source_not_provided"
|
|
)
|
|
return [
|
|
{
|
|
"source_family": family,
|
|
"capture_state": capture_state,
|
|
"reason_code": reason,
|
|
"artifacts": [],
|
|
}
|
|
for family in activity.SOURCE_FAMILIES
|
|
]
|
|
|
|
|
|
def _terminal_state(
|
|
root: Path,
|
|
run_id: str,
|
|
*,
|
|
pipeline_state: str = "completed",
|
|
current_stage: str = "6",
|
|
status: str = "completed",
|
|
extra_completed: tuple[str, ...] = (),
|
|
) -> Path:
|
|
stages = {current_stage: {"status": status}}
|
|
stages.update({stage: {"status": "completed"} for stage in extra_completed})
|
|
state = {
|
|
"run_id": run_id,
|
|
"pipeline_state": pipeline_state,
|
|
"current_stage": current_stage,
|
|
"stages": stages,
|
|
}
|
|
path = root / "state" / f"{run_id}.json"
|
|
_write(path, state)
|
|
return path
|
|
|
|
|
|
def _call(capsys: pytest.CaptureFixture[str], *argv: str) -> tuple[int, str, str]:
|
|
code = activity.main(list(argv))
|
|
captured = capsys.readouterr()
|
|
return code, captured.out, captured.err
|
|
|
|
|
|
def _seal_and_build(
|
|
capsys: pytest.CaptureFixture[str],
|
|
root: Path,
|
|
state: Path,
|
|
rows: list[dict[str, Any]],
|
|
*,
|
|
output_name: str = "input.json",
|
|
) -> Path:
|
|
activity.seal_terminal_inventory(state, root, rows)
|
|
output = root / output_name
|
|
code, stdout, stderr = _call(
|
|
capsys,
|
|
"build-input",
|
|
"--state",
|
|
str(state),
|
|
"--artifact-root",
|
|
str(root),
|
|
"--store-id",
|
|
STORE_ID,
|
|
"--output",
|
|
str(output),
|
|
)
|
|
assert code == 0, stderr
|
|
assert stdout.startswith("[ARS-ADJUDICATION-ACTIVITY] built_input run_id=")
|
|
return output
|
|
|
|
|
|
def _append(
|
|
capsys: pytest.CaptureFixture[str], root: Path, store: Path, manifest: Path
|
|
) -> tuple[int, str, str]:
|
|
return _call(
|
|
capsys,
|
|
"append-run",
|
|
"--store",
|
|
str(store),
|
|
"--artifact-root",
|
|
str(root),
|
|
"--input",
|
|
str(manifest),
|
|
)
|
|
|
|
|
|
def _make_re_review_chain(root: Path) -> tuple[str, str, str, str]:
|
|
generated = root / "generated_re_review"
|
|
generated.mkdir()
|
|
emit(generated, scenario_g2d(False))
|
|
manifest = _load(generated / "manifest.json")
|
|
precommitment = _load(generated / "precommitment.json")
|
|
verdict = _load(generated / "verdict_record.json")
|
|
traceability = _load(generated / "traceability.json")
|
|
|
|
traceability["dissent_adjudications"][0]["adjudicator"] = "user"
|
|
reapplication = traceability["reapplications"][0]
|
|
reapplication["reapplied_verdict"] = "NOT_ADDRESSED"
|
|
reapplication.pop("cannot_verify_reason")
|
|
anchor = {
|
|
"anchor": 'text: §6 "procedure evidence"',
|
|
"anchor_artifact": "manuscript",
|
|
}
|
|
reapplication["evidence_anchor"] = [anchor]
|
|
traceability["adjustments"] = [
|
|
{
|
|
"adjustment_id": "ADJ-1",
|
|
"item_id": "REV-001",
|
|
"from_verdict": "FULLY_ADDRESSED",
|
|
"to_verdict": "NOT_ADDRESSED",
|
|
"basis": "cross_model_adjudication",
|
|
"evidence_anchor": [anchor],
|
|
"rationale": reapplication["rationale"],
|
|
"source_ref": "reapplication:RAP-1",
|
|
}
|
|
]
|
|
first_row = traceability["rows"][0]
|
|
first_row.update(
|
|
{
|
|
"verified": "NO",
|
|
"status": "NOT_ADDRESSED",
|
|
"final_verdict": "NOT_ADDRESSED",
|
|
"adjustment_id": "ADJ-1",
|
|
}
|
|
)
|
|
traceability["decision_inputs"]["per_item"][0]["final_verdict"] = "NOT_ADDRESSED"
|
|
|
|
precommitment["input_manifest_hash"] = re_review.canonical_hash(manifest)
|
|
verdict["precommitment_hash"] = re_review.canonical_hash(precommitment)
|
|
traceability["verdict_record_hash"] = re_review.canonical_hash(verdict)
|
|
_write(generated / "manifest.json", manifest)
|
|
_write(generated / "precommitment.json", precommitment)
|
|
_write(generated / "verdict_record.json", verdict)
|
|
_write(generated / "traceability.json", traceability)
|
|
|
|
for name in ("input_manifest", "precommitment", "verdict_record", "traceability"):
|
|
schema = REPO / "shared/contracts/re_review" / f"{name}.schema.json"
|
|
artifact_name = "manifest" if name == "input_manifest" else name
|
|
jsonschema.Draft202012Validator(_load(schema)).validate(
|
|
_load(generated / f"{artifact_name}.json")
|
|
)
|
|
return tuple(
|
|
(generated / name).relative_to(root).as_posix()
|
|
for name in (
|
|
"manifest.json",
|
|
"precommitment.json",
|
|
"verdict_record.json",
|
|
"traceability.json",
|
|
)
|
|
) # type: ignore[return-value]
|
|
|
|
|
|
def _all_event_rows(root: Path) -> list[dict[str, Any]]:
|
|
author_paths = [
|
|
_copy_fixture(root, "author_stage3_input.json"),
|
|
_copy_fixture(root, "author_stage3.json"),
|
|
_copy_fixture(root, "author_stage3_prime_input.json"),
|
|
_copy_fixture(root, "author_stage3_prime.json"),
|
|
]
|
|
override_report = _copy_fixture(root, "compliance_override.json")
|
|
override_action = _copy_fixture(root, "compliance_override_action.json")
|
|
pass_report = _copy_fixture(root, "compliance_pass.json")
|
|
explicit_log = _copy_fixture(root, "explicit_user_request_log.json")
|
|
mandatory_log = _copy_fixture(root, "mandatory_checkpoint_log.json")
|
|
manifest, precommitment, verdict, traceability = _make_re_review_chain(root)
|
|
return [
|
|
{
|
|
"source_family": "revision_author_adjudication",
|
|
"capture_state": "captured",
|
|
"reason_code": None,
|
|
"artifacts": [
|
|
_artifact("author-input-3", "author_adjudication_input", "SOURCE-GROUP-author-3", author_paths[0], "pipeline_stage_3"),
|
|
_artifact("author-output-3", "author_adjudication", "SOURCE-GROUP-author-3", author_paths[1], "pipeline_stage_3"),
|
|
_artifact("author-input-3p", "author_adjudication_input", "SOURCE-GROUP-author-3p", author_paths[2], "pipeline_stage_3_prime"),
|
|
_artifact("author-output-3p", "author_adjudication", "SOURCE-GROUP-author-3p", author_paths[3], "pipeline_stage_3_prime"),
|
|
],
|
|
},
|
|
{
|
|
"source_family": "compliance_report",
|
|
"capture_state": "captured",
|
|
"reason_code": None,
|
|
"artifacts": [
|
|
_artifact("compliance-override-report", "compliance_report", "SOURCE-GROUP-compliance-1", override_report),
|
|
_artifact("compliance-override-action", "compliance_override_action_receipt", "SOURCE-GROUP-compliance-1", override_action),
|
|
_artifact("compliance-pass-a", "compliance_report", "SOURCE-GROUP-compliance-2", pass_report),
|
|
_artifact("compliance-pass-b", "compliance_report", "SOURCE-GROUP-compliance-3", pass_report),
|
|
],
|
|
},
|
|
{
|
|
"source_family": "re_review_traceability",
|
|
"capture_state": "captured",
|
|
"reason_code": None,
|
|
"artifacts": [
|
|
_artifact("rereview-manifest", "input_manifest", "SOURCE-GROUP-rereview", manifest),
|
|
_artifact("rereview-precommitment", "precommitment", "SOURCE-GROUP-rereview", precommitment),
|
|
_artifact("rereview-verdict", "verdict_record", "SOURCE-GROUP-rereview", verdict),
|
|
_artifact("rereview-traceability", "traceability", "SOURCE-GROUP-rereview", traceability),
|
|
],
|
|
},
|
|
{
|
|
"source_family": "explicit_user_request",
|
|
"capture_state": "captured",
|
|
"reason_code": None,
|
|
"artifacts": [
|
|
_artifact("explicit-log", "explicit_user_request_log", "SOURCE-GROUP-explicit", explicit_log)
|
|
],
|
|
},
|
|
{
|
|
"source_family": "mandatory_checkpoint_response",
|
|
"capture_state": "captured",
|
|
"reason_code": None,
|
|
"artifacts": [
|
|
_artifact("mandatory-log", "mandatory_checkpoint_response_log", "SOURCE-GROUP-mandatory", mandatory_log)
|
|
],
|
|
},
|
|
]
|
|
|
|
|
|
def _compliance_rows(
|
|
root: Path,
|
|
run_id: str,
|
|
mutate_action: Callable[[dict[str, Any]], None] | None = None,
|
|
) -> list[dict[str, Any]]:
|
|
report_path = _copy_fixture(root, "compliance_override.json")
|
|
action = _load(FIXTURES / "compliance_override_action.json")
|
|
action["run_id"] = run_id
|
|
action["interaction_sha256"] = _independent_interaction(
|
|
run_id, action["interaction_id"]
|
|
)
|
|
action["report_sha256"] = hashlib.sha256((root / report_path).read_bytes()).hexdigest()
|
|
if mutate_action is not None:
|
|
mutate_action(action)
|
|
action_path = root / "sources" / "compliance-action-dynamic.json"
|
|
_write(action_path, action)
|
|
rows = _empty_rows()
|
|
rows[1] = {
|
|
"source_family": "compliance_report",
|
|
"capture_state": "captured",
|
|
"reason_code": None,
|
|
"artifacts": [
|
|
_artifact(
|
|
"compliance-report",
|
|
"compliance_report",
|
|
"SOURCE-GROUP-compliance",
|
|
report_path,
|
|
),
|
|
_artifact(
|
|
"compliance-action",
|
|
"compliance_override_action_receipt",
|
|
"SOURCE-GROUP-compliance",
|
|
action_path.relative_to(root).as_posix(),
|
|
),
|
|
],
|
|
}
|
|
return rows
|
|
|
|
|
|
def _single_log_rows(
|
|
root: Path,
|
|
run_id: str,
|
|
*,
|
|
mandatory: bool,
|
|
mutate_record: Callable[[dict[str, Any]], None] | None = None,
|
|
) -> list[dict[str, Any]]:
|
|
interaction_id = "USER-LOG-1"
|
|
common = {
|
|
"actor_role": "user",
|
|
"source": "explicit_session_user_action",
|
|
"stage": "pipeline_stage_3",
|
|
"interaction_id": interaction_id,
|
|
"interaction_sha256": _independent_interaction(run_id, interaction_id),
|
|
}
|
|
if mandatory:
|
|
record = {
|
|
**common,
|
|
"response_id": "RESPONSE-1",
|
|
"checkpoint_id": "checkpoint-1",
|
|
"checkpoint_type": "MANDATORY",
|
|
"disposition": "pause",
|
|
}
|
|
version = "adjudication-mandatory-checkpoint-log/1.0"
|
|
family_index = 4
|
|
family = "mandatory_checkpoint_response"
|
|
role = "mandatory_checkpoint_response_log"
|
|
else:
|
|
record = {
|
|
**common,
|
|
"request_id": "REQUEST-1",
|
|
"action": "justify_finding",
|
|
"finding_id": "REV-001",
|
|
}
|
|
version = "adjudication-explicit-user-request-log/1.0"
|
|
family_index = 3
|
|
family = "explicit_user_request"
|
|
role = "explicit_user_request_log"
|
|
if mutate_record is not None:
|
|
mutate_record(record)
|
|
log_path = root / "sources" / f"{family}-dynamic.json"
|
|
_write(
|
|
log_path,
|
|
{"schema_version": version, "run_id": run_id, "records": [record]},
|
|
)
|
|
rows = _empty_rows()
|
|
rows[family_index] = {
|
|
"source_family": family,
|
|
"capture_state": "captured",
|
|
"reason_code": None,
|
|
"artifacts": [
|
|
_artifact(
|
|
"action-log",
|
|
role,
|
|
f"SOURCE-GROUP-{'mandatory' if mandatory else 'explicit'}",
|
|
log_path.relative_to(root).as_posix(),
|
|
)
|
|
],
|
|
}
|
|
return rows
|
|
|
|
|
|
def _re_review_rows(
|
|
root: Path,
|
|
mutate: Callable[[dict[str, Any], dict[str, Any]], None],
|
|
) -> list[dict[str, Any]]:
|
|
paths = _make_re_review_chain(root)
|
|
verdict_path = root / paths[2]
|
|
trace_path = root / paths[3]
|
|
verdict = _load(verdict_path)
|
|
trace = _load(trace_path)
|
|
mutate(verdict, trace)
|
|
trace["verdict_record_hash"] = re_review.canonical_hash(verdict)
|
|
_write(verdict_path, verdict)
|
|
_write(trace_path, trace)
|
|
rows = _empty_rows()
|
|
rows[2] = {
|
|
"source_family": "re_review_traceability",
|
|
"capture_state": "captured",
|
|
"reason_code": None,
|
|
"artifacts": [
|
|
_artifact("rereview-manifest", "input_manifest", "SOURCE-GROUP-rereview", paths[0]),
|
|
_artifact("rereview-precommitment", "precommitment", "SOURCE-GROUP-rereview", paths[1]),
|
|
_artifact("rereview-verdict", "verdict_record", "SOURCE-GROUP-rereview", paths[2]),
|
|
_artifact("rereview-trace", "traceability", "SOURCE-GROUP-rereview", paths[3]),
|
|
],
|
|
}
|
|
return rows
|
|
|
|
|
|
def _recompute_record(run: dict[str, Any]) -> None:
|
|
preimage = {key: value for key, value in run.items() if key != "record_sha256"}
|
|
run["record_sha256"] = _independent_digest(
|
|
b"ars.adjudication-activity.run/1.0\0", preimage
|
|
)
|
|
|
|
|
|
def test_contract_schemas_and_closed_positive_negative_payloads() -> None:
|
|
input_schema = _load(INPUT_SCHEMA)
|
|
store_schema = _load(STORE_SCHEMA)
|
|
jsonschema.Draft202012Validator.check_schema(input_schema)
|
|
jsonschema.Draft202012Validator.check_schema(store_schema)
|
|
|
|
input_payload = {
|
|
"schema_version": "adjudication-activity-input/1.0",
|
|
"store_id": STORE_ID,
|
|
"run_id": "run-schema",
|
|
"terminal_state": "completed",
|
|
"terminal_stage": "pipeline_stage_6",
|
|
"terminal_receipt": {
|
|
"artifact_id": "pipeline-state-terminal-receipt",
|
|
"relative_path": "state/run-schema.json",
|
|
"sha256": "0" * 64,
|
|
"run_id": "run-schema",
|
|
"pipeline_state": "completed",
|
|
"current_stage": "pipeline_stage_6",
|
|
"current_stage_status": "completed",
|
|
},
|
|
"sources": _empty_rows(),
|
|
"data_minimization": copy.deepcopy(activity.DATA_MINIMIZATION),
|
|
}
|
|
jsonschema.Draft202012Validator(input_schema).validate(input_payload)
|
|
poisoned = copy.deepcopy(input_payload)
|
|
poisoned["events"] = []
|
|
assert list(jsonschema.Draft202012Validator(input_schema).iter_errors(poisoned))
|
|
|
|
empty_store = {
|
|
"schema_version": "adjudication-activity-store/1.0",
|
|
"store_id": STORE_ID,
|
|
"revision": 0,
|
|
"next_sequence": 1,
|
|
"runs": [],
|
|
"data_minimization": copy.deepcopy(activity.DATA_MINIMIZATION),
|
|
}
|
|
jsonschema.Draft202012Validator(store_schema).validate(empty_store)
|
|
poisoned_store = copy.deepcopy(empty_store)
|
|
poisoned_store["score"] = 100
|
|
assert list(jsonschema.Draft202012Validator(store_schema).iter_errors(poisoned_store))
|
|
|
|
|
|
def test_init_build_append_validate_render_and_exact_retry_no_write(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
root = tmp_path / "artifacts"
|
|
state = _terminal_state(root, "run-zero")
|
|
manifest = _seal_and_build(capsys, root, state, _empty_rows("unavailable"))
|
|
store = tmp_path / "activity.json"
|
|
|
|
code, stdout, stderr = _call(capsys, "init-store", "--store", str(store), "--store-id", STORE_ID)
|
|
assert (code, stderr) == (0, "")
|
|
assert stdout == f'[ARS-ADJUDICATION-ACTIVITY] initialized store_id="{STORE_ID}"; revision=0; next_sequence=1\n'
|
|
code, stdout, stderr = _append(capsys, root, store, manifest)
|
|
assert (code, stderr) == (0, "")
|
|
assert "append_sequence=1; revision=1" in stdout
|
|
before = store.read_bytes()
|
|
code, stdout, stderr = _append(capsys, root, store, manifest)
|
|
assert (code, stderr) == (0, "")
|
|
assert "already_appended" in stdout
|
|
assert store.read_bytes() == before
|
|
|
|
code, stdout, stderr = _call(capsys, "validate", "--store", str(store))
|
|
assert (code, stderr) == (0, "")
|
|
assert "retained_runs=1; revision=1; next_sequence=2" in stdout
|
|
code, stdout, stderr = _call(capsys, "render", "--store", str(store))
|
|
assert (code, stderr) == (0, "")
|
|
lines = stdout.splitlines()
|
|
assert lines[0] == (
|
|
"[ARS-ADJUDICATION-ACTIVITY INSUFFICIENT_HISTORY] "
|
|
"selected_retained_eligible_run_count=1; minimum_required=2; requested_window=10."
|
|
)
|
|
assert lines[-3:] == [COVERAGE, LIMITATION, ADVISORY]
|
|
assert "unavailable_source_count=5 (denominator: 5 source families)" in stdout
|
|
|
|
|
|
def test_all_seven_event_types_occurrence_digest_dedup_and_repeated_hashes(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
root = tmp_path / "artifacts"
|
|
state = _terminal_state(root, "run-all-events", extra_completed=("3", "3p"))
|
|
manifest = _seal_and_build(capsys, root, state, _all_event_rows(root))
|
|
store = tmp_path / "activity.json"
|
|
code, _stdout, stderr = _append(capsys, root, store, manifest)
|
|
assert code == 0, stderr
|
|
payload = _load(store)
|
|
run = payload["runs"][0]
|
|
events = [event for source in run["sources"] for event in source["events"]]
|
|
assert {event["event_type"] for event in events} == {
|
|
"author_triage_wont_address",
|
|
"author_triage_not_on_point",
|
|
"compliance_block_override",
|
|
"re_review_verdict_changed",
|
|
"finding_justification_requested",
|
|
"finding_redo_requested",
|
|
"mandatory_checkpoint_non_proceed",
|
|
}
|
|
author_events = run["sources"][0]["events"]
|
|
assert author_events[0]["interaction_sha256"] == _independent_interaction(
|
|
"run-all-events", "AUTHOR-EVENT-ONE"
|
|
)
|
|
assert author_events[1]["interaction_sha256"] == _independent_interaction(
|
|
"run-all-events", "AUTHOR-EVENT-TWO"
|
|
)
|
|
assert author_events[0]["interaction_sha256"] != author_events[1]["interaction_sha256"]
|
|
assert run["sources"][1]["artifact_sha256s"][2] == run["sources"][1]["artifact_sha256s"][3]
|
|
shared = _independent_interaction("run-all-events", "USER-REQUEST-SHARED")
|
|
assert sum(event["interaction_sha256"] == shared for event in events) == 1
|
|
assert any(
|
|
event["event_type"] == "finding_justification_requested"
|
|
and event["interaction_sha256"] == shared
|
|
for event in events
|
|
)
|
|
assert not any(
|
|
event["event_type"] == "mandatory_checkpoint_non_proceed"
|
|
and event["stage"] == "pipeline_stage_3"
|
|
for event in events
|
|
)
|
|
assert {event["stage"] for event in run["sources"][4]["events"]} == set(STAGES) - {
|
|
"pipeline_stage_1",
|
|
"pipeline_stage_3",
|
|
"pipeline_stage_4_5",
|
|
}
|
|
|
|
expected_input_digest = _independent_digest(
|
|
b"ars.adjudication-activity.input/1.0\0", _load(manifest)
|
|
)
|
|
assert run["input_receipt_sha256"] == expected_input_digest
|
|
record_without_digest = {
|
|
key: value for key, value in run.items() if key != "record_sha256"
|
|
}
|
|
assert run["record_sha256"] == _independent_digest(
|
|
b"ars.adjudication-activity.run/1.0\0", record_without_digest
|
|
)
|
|
first_author_source_record = {
|
|
"item_id": "REV-001",
|
|
"author_event_id": "AUTHOR-EVENT-ONE",
|
|
"author_triage": "wont_address",
|
|
"input_sha256": "a" * 64,
|
|
"interaction_sha256": author_events[0]["interaction_sha256"],
|
|
}
|
|
assert author_events[0]["source_event_sha256"] == _independent_digest(
|
|
b"ars.adjudication-activity.source-event/1.0\0",
|
|
{
|
|
"source_family": "revision_author_adjudication",
|
|
"source_record": first_author_source_record,
|
|
},
|
|
)
|
|
expected_event_digest = _independent_digest(
|
|
b"ars.adjudication-activity.event-id/1.0\0",
|
|
{
|
|
"run_id": "run-all-events",
|
|
"source_family": "revision_author_adjudication",
|
|
"event_type": author_events[0]["event_type"],
|
|
"stage": author_events[0]["stage"],
|
|
"disposition": author_events[0]["disposition"],
|
|
"interaction_sha256": author_events[0]["interaction_sha256"],
|
|
"source_event_sha256": author_events[0]["source_event_sha256"],
|
|
},
|
|
)
|
|
assert author_events[0]["event_id"] == f"ACTIVITY-EVENT-{expected_event_digest}"
|
|
|
|
|
|
def test_terminal_inventory_is_exact_authority_and_conflicting_retry_fails(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
root = tmp_path / "artifacts"
|
|
state = _terminal_state(root, "run-authority")
|
|
manifest = _seal_and_build(capsys, root, state, _empty_rows())
|
|
store = tmp_path / "activity.json"
|
|
assert _append(capsys, root, store, manifest)[0] == 0
|
|
|
|
forged_root = tmp_path / "forged-root"
|
|
forged_state = _terminal_state(forged_root, "run-forged-authority")
|
|
valid_forged_base = _seal_and_build(
|
|
capsys, forged_root, forged_state, _empty_rows()
|
|
)
|
|
forged = _load(valid_forged_base)
|
|
forged["sources"][0] = {
|
|
"source_family": "revision_author_adjudication",
|
|
"capture_state": "unavailable",
|
|
"reason_code": "source_not_provided",
|
|
"artifacts": [],
|
|
}
|
|
forged_path = forged_root / "forged-input.json"
|
|
_write(forged_path, forged)
|
|
before = store.read_bytes()
|
|
code, stdout, stderr = _append(capsys, forged_root, store, forged_path)
|
|
assert code == 3
|
|
assert stdout == ""
|
|
assert "ERROR:INPUT" in stderr
|
|
assert store.read_bytes() == before
|
|
|
|
second_root = tmp_path / "second-root"
|
|
second_state = _terminal_state(second_root, "run-authority")
|
|
conflicting = _seal_and_build(
|
|
capsys,
|
|
second_root,
|
|
second_state,
|
|
_empty_rows("unavailable"),
|
|
output_name="different-input.json",
|
|
)
|
|
code, stdout, stderr = _append(capsys, second_root, store, conflicting)
|
|
assert code == 5
|
|
assert stdout == ""
|
|
assert "ERROR:CONFLICT" in stderr
|
|
assert store.read_bytes() == before
|
|
|
|
|
|
def test_delete_gap_range_delete_and_delete_store_recovery(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
store = tmp_path / "activity.json"
|
|
roots: list[Path] = []
|
|
for ordinal in range(1, 4):
|
|
root = tmp_path / f"root-{ordinal}"
|
|
roots.append(root)
|
|
state = _terminal_state(
|
|
root,
|
|
f"run-{ordinal}",
|
|
pipeline_state="aborted" if ordinal == 2 else "completed",
|
|
current_stage="4p" if ordinal == 2 else "6",
|
|
status="blocked" if ordinal == 2 else "completed",
|
|
)
|
|
manifest = _seal_and_build(capsys, root, state, _empty_rows())
|
|
assert _append(capsys, root, store, manifest)[0] == 0
|
|
|
|
raw_hash = hashlib.sha256(store.read_bytes()).hexdigest()
|
|
before = store.read_bytes()
|
|
code, stdout, stderr = _call(
|
|
capsys,
|
|
"delete-runs",
|
|
"--store",
|
|
str(store),
|
|
"--store-id",
|
|
STORE_ID,
|
|
"--expect-store-sha256",
|
|
"0" * 64,
|
|
"--run-id",
|
|
"run-2",
|
|
)
|
|
assert code == 6
|
|
assert stdout == ""
|
|
assert "ERROR:DELETE_CONFIRMATION" in stderr
|
|
assert store.read_bytes() == before
|
|
code, stdout, stderr = _call(
|
|
capsys,
|
|
"delete-runs",
|
|
"--store",
|
|
str(store),
|
|
"--store-id",
|
|
STORE_ID,
|
|
"--expect-store-sha256",
|
|
raw_hash,
|
|
"--run-id",
|
|
"run-2",
|
|
)
|
|
assert (code, stderr) == (0, "")
|
|
assert "deleted_runs=1; revision=4; next_sequence=4" in stdout
|
|
assert [run["append_sequence"] for run in _load(store)["runs"]] == [1, 3]
|
|
|
|
raw_hash = hashlib.sha256(store.read_bytes()).hexdigest()
|
|
code, _stdout, stderr = _call(
|
|
capsys,
|
|
"delete-runs",
|
|
"--store",
|
|
str(store),
|
|
"--store-id",
|
|
STORE_ID,
|
|
"--expect-store-sha256",
|
|
raw_hash,
|
|
"--sequence-range",
|
|
"1:3",
|
|
)
|
|
assert code == 0, stderr
|
|
assert _load(store)["next_sequence"] == 4
|
|
store.write_bytes(b'{"corrupt":true}\n')
|
|
corrupt_hash = hashlib.sha256(store.read_bytes()).hexdigest()
|
|
code, stdout, stderr = _call(
|
|
capsys,
|
|
"delete-store",
|
|
"--store",
|
|
str(store),
|
|
"--store-id",
|
|
STORE_ID,
|
|
"--expect-store-sha256",
|
|
corrupt_hash,
|
|
"--confirm",
|
|
"WRONG-TOKEN",
|
|
)
|
|
assert code == 6
|
|
assert stdout == ""
|
|
assert "ERROR:DELETE_CONFIRMATION" in stderr
|
|
assert store.exists()
|
|
code, stdout, stderr = _call(
|
|
capsys,
|
|
"delete-store",
|
|
"--store",
|
|
str(store),
|
|
"--store-id",
|
|
STORE_ID,
|
|
"--expect-store-sha256",
|
|
corrupt_hash,
|
|
"--confirm",
|
|
"DELETE-ADJUDICATION-ACTIVITY-STORE",
|
|
)
|
|
assert (code, stderr) == (0, "")
|
|
assert stdout == "[ARS-ADJUDICATION-ACTIVITY] deleted_store=true\n"
|
|
assert not store.exists()
|
|
|
|
|
|
@pytest.mark.parametrize("window", ["1", "51"])
|
|
def test_renderer_rejects_out_of_range_window(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str], window: str
|
|
) -> None:
|
|
store = tmp_path / "activity.json"
|
|
code, _stdout, _stderr = _call(
|
|
capsys, "init-store", "--store", str(store), "--store-id", STORE_ID
|
|
)
|
|
assert code == 0
|
|
code, stdout, stderr = _call(
|
|
capsys, "render", "--store", str(store), "--window", window
|
|
)
|
|
assert code == 2
|
|
assert stdout == ""
|
|
assert "ERROR:USAGE" in stderr
|
|
|
|
|
|
def test_build_input_rejects_caller_sources_and_input_cap_is_fail_closed(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
root = tmp_path / "artifacts"
|
|
state = _terminal_state(root, "run-no-caller-authority")
|
|
output = root / "input.json"
|
|
code, stdout, stderr = _call(
|
|
capsys,
|
|
"build-input",
|
|
"--state",
|
|
str(state),
|
|
"--artifact-root",
|
|
str(root),
|
|
"--store-id",
|
|
STORE_ID,
|
|
"--output",
|
|
str(output),
|
|
"--source-sha256",
|
|
"0" * 64,
|
|
)
|
|
assert code == 2
|
|
assert stdout == ""
|
|
assert "ERROR:USAGE" in stderr
|
|
assert not output.exists()
|
|
|
|
oversized = root / "oversized-input.json"
|
|
oversized.write_bytes(b" " * ((1 << 20) + 1))
|
|
store = tmp_path / "activity.json"
|
|
code, stdout, stderr = _append(capsys, root, store, oversized)
|
|
assert code == 5
|
|
assert stdout == ""
|
|
assert "ERROR:CAP" in stderr
|
|
assert not store.exists()
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"corrupt",
|
|
[
|
|
b'{"schema_version":"adjudication-activity-store/1.0","schema_version":"duplicate"}\n',
|
|
b"\xef\xbb\xbf{}\n",
|
|
b"{} trailing\n",
|
|
b'{"float":1.5}\n',
|
|
],
|
|
)
|
|
def test_store_corruption_fails_closed(
|
|
tmp_path: Path,
|
|
capsys: pytest.CaptureFixture[str],
|
|
corrupt: bytes,
|
|
) -> None:
|
|
store = tmp_path / "activity.json"
|
|
store.write_bytes(corrupt)
|
|
code, stdout, stderr = _call(capsys, "validate", "--store", str(store))
|
|
assert code == 4
|
|
assert stdout == ""
|
|
assert "ERROR:STORE" in stderr
|
|
|
|
|
|
def test_symlink_artifact_and_lock_contention_fail_without_mutation(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
root = tmp_path / "artifacts"
|
|
target = root / "target.json"
|
|
_write(target, {"fixture": True})
|
|
link = root / "link.json"
|
|
link.symlink_to(target)
|
|
rows = _empty_rows()
|
|
rows[3] = {
|
|
"source_family": "explicit_user_request",
|
|
"capture_state": "captured",
|
|
"reason_code": None,
|
|
"artifacts": [
|
|
_artifact("explicit-log", "explicit_user_request_log", "SOURCE-GROUP-explicit", "link.json")
|
|
],
|
|
}
|
|
state = _terminal_state(root, "run-path")
|
|
state_before = state.read_bytes()
|
|
with pytest.raises(activity.ActivityError, match="symlink"):
|
|
activity.seal_terminal_inventory(state, root, rows)
|
|
assert state.read_bytes() == state_before
|
|
|
|
store = tmp_path / "activity.json"
|
|
assert _call(capsys, "init-store", "--store", str(store), "--store-id", STORE_ID)[0] == 0
|
|
before = store.read_bytes()
|
|
lock_path = store.with_name(store.name + ".lock")
|
|
with lock_path.open("r+b") as lock_file:
|
|
file_lock.acquire(lock_file.fileno(), exclusive=True, timeout=0)
|
|
try:
|
|
code, stdout, stderr = _call(capsys, "validate", "--store", str(store))
|
|
finally:
|
|
file_lock.release(lock_file.fileno())
|
|
assert code == 7
|
|
assert stdout == ""
|
|
assert "ERROR:LOCK" in stderr
|
|
assert store.read_bytes() == before
|
|
|
|
|
|
def test_captured_zero_compliance_report_only_is_valid(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
root = tmp_path / "artifacts"
|
|
pass_report = _copy_fixture(root, "compliance_pass.json")
|
|
rows = _empty_rows()
|
|
rows[1] = {
|
|
"source_family": "compliance_report",
|
|
"capture_state": "captured",
|
|
"reason_code": None,
|
|
"artifacts": [
|
|
_artifact("report-only", "compliance_report", "SOURCE-GROUP-pass", pass_report)
|
|
],
|
|
}
|
|
state = _terminal_state(root, "run-captured-zero")
|
|
manifest = _seal_and_build(capsys, root, state, rows)
|
|
store = tmp_path / "activity.json"
|
|
code, _stdout, stderr = _append(capsys, root, store, manifest)
|
|
assert code == 0, stderr
|
|
compliance = _load(store)["runs"][0]["sources"][1]
|
|
assert compliance["capture_state"] == "captured"
|
|
assert compliance["events"] == []
|
|
|
|
|
|
def test_nonqualifying_compliance_receipt_pair_is_rejected(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
root = tmp_path / "artifacts"
|
|
pass_report = _copy_fixture(root, "compliance_pass.json")
|
|
action = _load(FIXTURES / "compliance_override_action.json")
|
|
action["report_sha256"] = hashlib.sha256((root / pass_report).read_bytes()).hexdigest()
|
|
action_path = root / "sources" / "bad-paired-action.json"
|
|
_write(action_path, action)
|
|
rows = _empty_rows()
|
|
rows[1] = {
|
|
"source_family": "compliance_report",
|
|
"capture_state": "captured",
|
|
"reason_code": None,
|
|
"artifacts": [
|
|
_artifact("plain-report", "compliance_report", "SOURCE-GROUP-bad-pair", pass_report),
|
|
_artifact(
|
|
"forbidden-action",
|
|
"compliance_override_action_receipt",
|
|
"SOURCE-GROUP-bad-pair",
|
|
action_path.relative_to(root).as_posix(),
|
|
),
|
|
],
|
|
}
|
|
state = _terminal_state(root, "run-bad-pair")
|
|
activity.seal_terminal_inventory(state, root, rows)
|
|
manifest = root / "input.json"
|
|
store = tmp_path / "activity.json"
|
|
code, stdout, stderr = _call(
|
|
capsys,
|
|
"build-input",
|
|
"--state",
|
|
str(state),
|
|
"--artifact-root",
|
|
str(root),
|
|
"--store-id",
|
|
STORE_ID,
|
|
"--output",
|
|
str(manifest),
|
|
)
|
|
assert code == 3
|
|
assert stdout == ""
|
|
assert "ERROR:SOURCE" in stderr
|
|
assert not store.exists()
|
|
|
|
|
|
def test_exact_retry_ignores_deleted_source_and_terminal_bytes_without_write(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
root = tmp_path / "artifacts"
|
|
pass_report = _copy_fixture(root, "compliance_pass.json")
|
|
rows = _empty_rows()
|
|
rows[1] = {
|
|
"source_family": "compliance_report",
|
|
"capture_state": "captured",
|
|
"reason_code": None,
|
|
"artifacts": [
|
|
_artifact(
|
|
"report-only",
|
|
"compliance_report",
|
|
"SOURCE-GROUP-pass",
|
|
pass_report,
|
|
)
|
|
],
|
|
}
|
|
state = _terminal_state(root, "run-retry-deleted")
|
|
manifest = _seal_and_build(capsys, root, state, rows)
|
|
store = tmp_path / "activity.json"
|
|
assert _append(capsys, root, store, manifest)[0] == 0
|
|
before_bytes = store.read_bytes()
|
|
before_mtime = store.stat().st_mtime_ns
|
|
|
|
(root / pass_report).unlink()
|
|
state.unlink()
|
|
code, stdout, stderr = _append(capsys, root, store, manifest)
|
|
assert (code, stderr) == (0, "")
|
|
assert "already_appended" in stdout
|
|
assert store.read_bytes() == before_bytes
|
|
assert store.stat().st_mtime_ns == before_mtime
|
|
|
|
|
|
def test_short_write_is_completed_and_zero_write_fails_cleanly(
|
|
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
payload = b"short-write-fixture" * 64
|
|
short_path = tmp_path / "short.bin"
|
|
original_write = activity.os.write
|
|
|
|
def short_write(fd: int, data: bytes | memoryview) -> int:
|
|
return original_write(fd, data[: max(1, len(data) // 2)])
|
|
|
|
monkeypatch.setattr(activity.os, "write", short_write)
|
|
activity._atomic_create(short_path, payload)
|
|
assert short_path.read_bytes() == payload
|
|
|
|
zero_path = tmp_path / "zero.bin"
|
|
monkeypatch.setattr(activity.os, "write", lambda _fd, _data: 0)
|
|
with pytest.raises(activity.ActivityError) as caught:
|
|
activity._atomic_create(zero_path, payload)
|
|
assert caught.value.code == "WRITE"
|
|
assert not zero_path.exists()
|
|
|
|
|
|
def test_short_read_is_reassembled(
|
|
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
payload = b"short-read-fixture" * 64
|
|
path = tmp_path / "read.bin"
|
|
path.write_bytes(payload)
|
|
original_read = activity.os.read
|
|
|
|
def short_read(fd: int, count: int) -> bytes:
|
|
return original_read(fd, max(1, count // 2))
|
|
|
|
monkeypatch.setattr(activity.os, "read", short_read)
|
|
assert activity._read_limited(path, len(payload), code="INPUT") == payload
|
|
|
|
|
|
def test_noncanonical_valid_object_delete_store_recovery(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
store = tmp_path / "activity.json"
|
|
store.write_bytes(b'{ "z": 1, "a": 2 }\n')
|
|
raw_hash = hashlib.sha256(store.read_bytes()).hexdigest()
|
|
code, stdout, stderr = _call(
|
|
capsys,
|
|
"delete-store",
|
|
"--store",
|
|
str(store),
|
|
"--store-id",
|
|
STORE_ID,
|
|
"--expect-store-sha256",
|
|
raw_hash,
|
|
"--confirm",
|
|
"DELETE-ADJUDICATION-ACTIVITY-STORE",
|
|
)
|
|
assert (code, stderr) == (0, "")
|
|
assert stdout == "[ARS-ADJUDICATION-ACTIVITY] deleted_store=true\n"
|
|
assert not store.exists()
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"mutation",
|
|
[
|
|
lambda action: action.__setitem__("override_ordinal", True),
|
|
lambda action: action.__setitem__("scope", [["M4"]]),
|
|
],
|
|
ids=("boolean-ordinal", "unhashable-scope"),
|
|
)
|
|
def test_compliance_bad_ordinal_or_scope_is_bounded_source_error(
|
|
tmp_path: Path,
|
|
capsys: pytest.CaptureFixture[str],
|
|
mutation: Callable[[dict[str, Any]], None],
|
|
) -> None:
|
|
root = tmp_path / "artifacts"
|
|
run_id = "run-compliance-edge"
|
|
state = _terminal_state(root, run_id)
|
|
activity.seal_terminal_inventory(
|
|
state, root, _compliance_rows(root, run_id, mutation)
|
|
)
|
|
output = root / "input.json"
|
|
code, stdout, stderr = _call(
|
|
capsys,
|
|
"build-input",
|
|
"--state",
|
|
str(state),
|
|
"--artifact-root",
|
|
str(root),
|
|
"--store-id",
|
|
STORE_ID,
|
|
"--output",
|
|
str(output),
|
|
)
|
|
assert code == 3
|
|
assert stdout == ""
|
|
assert "ERROR:SOURCE" in stderr
|
|
assert "Traceback" not in stderr
|
|
assert len(stderr.rstrip("\n").splitlines()) == 1
|
|
assert len(stderr.rstrip("\n")) <= 560
|
|
assert not output.exists()
|
|
|
|
|
|
@pytest.mark.parametrize("mandatory", [False, True], ids=("finding-id", "checkpoint-id"))
|
|
def test_129_character_finding_or_checkpoint_id_is_rejected(
|
|
tmp_path: Path,
|
|
capsys: pytest.CaptureFixture[str],
|
|
mandatory: bool,
|
|
) -> None:
|
|
root = tmp_path / "artifacts"
|
|
run_id = f"run-long-{'checkpoint' if mandatory else 'finding'}"
|
|
|
|
def mutate(record: dict[str, Any]) -> None:
|
|
record["checkpoint_id" if mandatory else "finding_id"] = "X" * 129
|
|
|
|
state = _terminal_state(root, run_id)
|
|
activity.seal_terminal_inventory(
|
|
state,
|
|
root,
|
|
_single_log_rows(root, run_id, mandatory=mandatory, mutate_record=mutate),
|
|
)
|
|
output = root / "input.json"
|
|
code, stdout, stderr = _call(
|
|
capsys,
|
|
"build-input",
|
|
"--state",
|
|
str(state),
|
|
"--artifact-root",
|
|
str(root),
|
|
"--store-id",
|
|
STORE_ID,
|
|
"--output",
|
|
str(output),
|
|
)
|
|
assert code == 3
|
|
assert stdout == ""
|
|
assert "ERROR:SOURCE" in stderr
|
|
assert not output.exists()
|
|
|
|
|
|
def test_explicit_and_mandatory_raw_record_aggregate_4097_is_rejected(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
root = tmp_path / "artifacts"
|
|
run_id = "run-aggregate-4097"
|
|
explicit_id = "EXPLICIT-1"
|
|
explicit = {
|
|
"schema_version": "adjudication-explicit-user-request-log/1.0",
|
|
"run_id": run_id,
|
|
"records": [
|
|
{
|
|
"request_id": "REQUEST-1",
|
|
"actor_role": "user",
|
|
"source": "explicit_session_user_action",
|
|
"action": "justify_finding",
|
|
"stage": "pipeline_stage_3",
|
|
"finding_id": "REV-001",
|
|
"interaction_id": explicit_id,
|
|
"interaction_sha256": _independent_interaction(run_id, explicit_id),
|
|
}
|
|
],
|
|
}
|
|
mandatory_records = []
|
|
for ordinal in range(4096):
|
|
interaction_id = f"MANDATORY-{ordinal}"
|
|
mandatory_records.append(
|
|
{
|
|
"response_id": f"RESPONSE-{ordinal}",
|
|
"checkpoint_id": f"CHECKPOINT-{ordinal}",
|
|
"checkpoint_type": "MANDATORY",
|
|
"actor_role": "user",
|
|
"source": "explicit_session_user_action",
|
|
"stage": "pipeline_stage_4_5",
|
|
"disposition": "proceed",
|
|
"interaction_id": interaction_id,
|
|
"interaction_sha256": _independent_interaction(run_id, interaction_id),
|
|
}
|
|
)
|
|
mandatory = {
|
|
"schema_version": "adjudication-mandatory-checkpoint-log/1.0",
|
|
"run_id": run_id,
|
|
"records": mandatory_records,
|
|
}
|
|
explicit_path = root / "sources" / "explicit-4097.json"
|
|
mandatory_path = root / "sources" / "mandatory-4097.json"
|
|
_write(explicit_path, explicit)
|
|
_write(mandatory_path, mandatory)
|
|
rows = _empty_rows()
|
|
rows[3] = {
|
|
"source_family": "explicit_user_request",
|
|
"capture_state": "captured",
|
|
"reason_code": None,
|
|
"artifacts": [
|
|
_artifact(
|
|
"explicit-log",
|
|
"explicit_user_request_log",
|
|
"SOURCE-GROUP-explicit",
|
|
explicit_path.relative_to(root).as_posix(),
|
|
)
|
|
],
|
|
}
|
|
rows[4] = {
|
|
"source_family": "mandatory_checkpoint_response",
|
|
"capture_state": "captured",
|
|
"reason_code": None,
|
|
"artifacts": [
|
|
_artifact(
|
|
"mandatory-log",
|
|
"mandatory_checkpoint_response_log",
|
|
"SOURCE-GROUP-mandatory",
|
|
mandatory_path.relative_to(root).as_posix(),
|
|
)
|
|
],
|
|
}
|
|
state = _terminal_state(root, run_id)
|
|
activity.seal_terminal_inventory(state, root, rows)
|
|
output = root / "input.json"
|
|
code, stdout, stderr = _call(
|
|
capsys,
|
|
"build-input",
|
|
"--state",
|
|
str(state),
|
|
"--artifact-root",
|
|
str(root),
|
|
"--store-id",
|
|
STORE_ID,
|
|
"--output",
|
|
str(output),
|
|
)
|
|
assert code == 5
|
|
assert stdout == ""
|
|
assert "ERROR:CAP" in stderr
|
|
assert not output.exists()
|
|
|
|
|
|
def test_lone_surrogate_is_bounded_store_error(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
store = tmp_path / "activity.json"
|
|
store.write_bytes(b'{"surrogate":"\\ud800"}\n')
|
|
code, stdout, stderr = _call(capsys, "validate", "--store", str(store))
|
|
assert code == 4
|
|
assert stdout == ""
|
|
assert "ERROR:STORE" in stderr
|
|
assert "Traceback" not in stderr
|
|
assert len(stderr.rstrip("\n").splitlines()) == 1
|
|
assert len(stderr.rstrip("\n")) <= 560
|
|
|
|
|
|
def test_author_store_three_hashes_is_rejected(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
root = tmp_path / "artifacts"
|
|
paths = [
|
|
_copy_fixture(root, "author_stage3_input.json"),
|
|
_copy_fixture(root, "author_stage3.json"),
|
|
]
|
|
rows = _empty_rows()
|
|
rows[0] = {
|
|
"source_family": "revision_author_adjudication",
|
|
"capture_state": "captured",
|
|
"reason_code": None,
|
|
"artifacts": [
|
|
_artifact("author-input", "author_adjudication_input", "SOURCE-GROUP-author", paths[0], "pipeline_stage_3"),
|
|
_artifact("author-output", "author_adjudication", "SOURCE-GROUP-author", paths[1], "pipeline_stage_3"),
|
|
],
|
|
}
|
|
state = _terminal_state(root, "run-author-three-hashes", extra_completed=("3",))
|
|
manifest = _seal_and_build(capsys, root, state, rows)
|
|
store = tmp_path / "activity.json"
|
|
assert _append(capsys, root, store, manifest)[0] == 0
|
|
payload = _load(store)
|
|
hashes = payload["runs"][0]["sources"][0]["artifact_sha256s"]
|
|
hashes.append(hashes[-1])
|
|
_recompute_record(payload["runs"][0])
|
|
_write(store, payload)
|
|
code, stdout, stderr = _call(capsys, "validate", "--store", str(store))
|
|
assert code == 4
|
|
assert stdout == ""
|
|
assert "ERROR:STORE" in stderr
|
|
|
|
|
|
def test_store_next_sequence_cannot_exceed_revision_plus_one(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
root = tmp_path / "artifacts"
|
|
state = _terminal_state(root, "run-next-sequence")
|
|
manifest = _seal_and_build(capsys, root, state, _empty_rows())
|
|
store = tmp_path / "activity.json"
|
|
assert _append(capsys, root, store, manifest)[0] == 0
|
|
payload = _load(store)
|
|
assert payload["revision"] == 1
|
|
payload["next_sequence"] = 3
|
|
_write(store, payload)
|
|
code, stdout, stderr = _call(capsys, "validate", "--store", str(store))
|
|
assert code == 4
|
|
assert stdout == ""
|
|
assert "ERROR:STORE" in stderr
|
|
|
|
|
|
def _assert_re_review_mutation_rejected(
|
|
tmp_path: Path,
|
|
capsys: pytest.CaptureFixture[str],
|
|
mutation: Callable[[dict[str, Any], dict[str, Any]], None],
|
|
) -> None:
|
|
root = tmp_path / "artifacts"
|
|
state = _terminal_state(root, "run-rereview-negative")
|
|
rows = _re_review_rows(root, mutation)
|
|
activity.seal_terminal_inventory(state, root, rows)
|
|
output = root / "input.json"
|
|
code, stdout, stderr = _call(
|
|
capsys,
|
|
"build-input",
|
|
"--state",
|
|
str(state),
|
|
"--artifact-root",
|
|
str(root),
|
|
"--store-id",
|
|
STORE_ID,
|
|
"--output",
|
|
str(output),
|
|
)
|
|
assert code == 3
|
|
assert stdout == ""
|
|
assert "ERROR:SOURCE" in stderr
|
|
assert not output.exists()
|
|
|
|
|
|
def test_re_review_no_change_adjustment_is_rejected(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
def mutate(_verdict: dict[str, Any], trace: dict[str, Any]) -> None:
|
|
reapplication = trace["reapplications"][0]
|
|
reapplication["reapplied_verdict"] = "FULLY_ADDRESSED"
|
|
adjustment = trace["adjustments"][0]
|
|
adjustment["from_verdict"] = "FULLY_ADDRESSED"
|
|
adjustment["to_verdict"] = "FULLY_ADDRESSED"
|
|
trace["rows"][0].update(
|
|
{"verified": "YES", "status": "FULLY_ADDRESSED", "final_verdict": "FULLY_ADDRESSED"}
|
|
)
|
|
|
|
_assert_re_review_mutation_rejected(tmp_path, capsys, mutate)
|
|
|
|
|
|
def test_re_review_adjustment_endpoints_must_mirror_reapplication(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
def mutate(_verdict: dict[str, Any], trace: dict[str, Any]) -> None:
|
|
trace["adjustments"][0]["from_verdict"] = "PARTIALLY_ADDRESSED"
|
|
|
|
_assert_re_review_mutation_rejected(tmp_path, capsys, mutate)
|
|
|
|
|
|
def test_re_review_reapplication_and_adjustment_are_single_use(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
def mutate(verdict: dict[str, Any], trace: dict[str, Any]) -> None:
|
|
second_dissent = copy.deepcopy(verdict["dissents"][0])
|
|
second_dissent["dissent_id"] = "DIS-2"
|
|
verdict["dissents"].append(second_dissent)
|
|
second_adjudication = copy.deepcopy(trace["dissent_adjudications"][0])
|
|
second_adjudication["dissent_id"] = "DIS-2"
|
|
trace["dissent_adjudications"].append(second_adjudication)
|
|
trace["reapplications"][0]["answer_refs"].append("adjudication:DIS-2")
|
|
|
|
_assert_re_review_mutation_rejected(tmp_path, capsys, mutate)
|
|
|
|
|
|
def test_seal_rejects_invalid_artifact_id_without_state_write(tmp_path: Path) -> None:
|
|
root = tmp_path / "artifacts"
|
|
report = _copy_fixture(root, "compliance_pass.json")
|
|
rows = _empty_rows()
|
|
rows[1] = {
|
|
"source_family": "compliance_report",
|
|
"capture_state": "captured",
|
|
"reason_code": None,
|
|
"artifacts": [
|
|
_artifact(
|
|
"invalid artifact id",
|
|
"compliance_report",
|
|
"SOURCE-GROUP-invalid-id",
|
|
report,
|
|
)
|
|
],
|
|
}
|
|
state = _terminal_state(root, "run-invalid-artifact-id")
|
|
before = state.read_bytes()
|
|
with pytest.raises(activity.ActivityError) as caught:
|
|
activity.seal_terminal_inventory(state, root, rows)
|
|
assert caught.value.code == "SOURCE"
|
|
assert state.read_bytes() == before
|
|
|
|
|
|
def test_renderer_empty_one_two_full_golden_and_mixed_denominators(
|
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
store = tmp_path / "activity.json"
|
|
assert _call(
|
|
capsys, "init-store", "--store", str(store), "--store-id", STORE_ID
|
|
)[0] == 0
|
|
code, stdout, stderr = _call(capsys, "render", "--store", str(store))
|
|
assert (code, stderr) == (0, "")
|
|
assert stdout == "\n".join(
|
|
[
|
|
"[ARS-ADJUDICATION-ACTIVITY INSUFFICIENT_HISTORY] selected_retained_eligible_run_count=0; minimum_required=2; requested_window=10.",
|
|
"[ARS-ADJUDICATION-ACTIVITY COUNTS] adjudication_count=0 (denominator: 0 retained eligible terminal run records); overturn_count=0 (denominator: 0 recorded adjudications); unavailable_run_count=0 (denominator: 0 retained eligible terminal run records).",
|
|
COVERAGE,
|
|
LIMITATION,
|
|
ADVISORY,
|
|
"",
|
|
]
|
|
)
|
|
|
|
root_one = tmp_path / "root-one"
|
|
pass_report = _copy_fixture(root_one, "compliance_pass.json")
|
|
mixed_rows = _empty_rows()
|
|
mixed_rows[0] = {
|
|
"source_family": "revision_author_adjudication",
|
|
"capture_state": "unavailable",
|
|
"reason_code": "source_not_provided",
|
|
"artifacts": [],
|
|
}
|
|
mixed_rows[1] = {
|
|
"source_family": "compliance_report",
|
|
"capture_state": "captured",
|
|
"reason_code": None,
|
|
"artifacts": [
|
|
_artifact("report-only", "compliance_report", "SOURCE-GROUP-pass", pass_report)
|
|
],
|
|
}
|
|
state_one = _terminal_state(root_one, "run-mixed-zero")
|
|
manifest_one = _seal_and_build(capsys, root_one, state_one, mixed_rows)
|
|
assert _append(capsys, root_one, store, manifest_one)[0] == 0
|
|
code, stdout, stderr = _call(capsys, "render", "--store", str(store))
|
|
assert (code, stderr) == (0, "")
|
|
assert stdout == "\n".join(
|
|
[
|
|
"[ARS-ADJUDICATION-ACTIVITY INSUFFICIENT_HISTORY] selected_retained_eligible_run_count=1; minimum_required=2; requested_window=10.",
|
|
"[ARS-ADJUDICATION-ACTIVITY COUNTS] adjudication_count=0 (denominator: 1 retained eligible terminal run records); overturn_count=0 (denominator: 0 recorded adjudications); unavailable_run_count=1 (denominator: 1 retained eligible terminal run records).",
|
|
'sequence=1; run_id="run-mixed-zero"; terminal_state=completed; adjudication_count=0 (denominator: 1 retained eligible terminal run record); overturn_count=0 (denominator: 0 recorded adjudications); unavailable_source_count=1 (denominator: 5 source families).',
|
|
COVERAGE,
|
|
LIMITATION,
|
|
ADVISORY,
|
|
"",
|
|
]
|
|
)
|
|
|
|
root_two = tmp_path / "root-two"
|
|
state_two = _terminal_state(root_two, "run-not-applicable")
|
|
manifest_two = _seal_and_build(capsys, root_two, state_two, _empty_rows())
|
|
assert _append(capsys, root_two, store, manifest_two)[0] == 0
|
|
code, stdout, stderr = _call(capsys, "render", "--store", str(store))
|
|
assert (code, stderr) == (0, "")
|
|
assert stdout == "\n".join(
|
|
[
|
|
"[ARS-ADJUDICATION-ACTIVITY] selected_retained_eligible_run_count=2; requested_window=10; adjudication_count=0 (denominator: 2 retained eligible terminal run records); overturn_count=0 (denominator: 0 recorded adjudications); unavailable_run_count=1 (denominator: 2 retained eligible terminal run records).",
|
|
'sequence=1; run_id="run-mixed-zero"; terminal_state=completed; adjudication_count=0 (denominator: 1 retained eligible terminal run record); overturn_count=0 (denominator: 0 recorded adjudications); unavailable_source_count=1 (denominator: 5 source families).',
|
|
'sequence=2; run_id="run-not-applicable"; terminal_state=completed; adjudication_count=0 (denominator: 1 retained eligible terminal run record); overturn_count=0 (denominator: 0 recorded adjudications); unavailable_source_count=0 (denominator: 5 source families).',
|
|
COVERAGE,
|
|
LIMITATION,
|
|
ADVISORY,
|
|
"",
|
|
]
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("pipeline_state", "raw_stage", "status"),
|
|
[("completed", "6", "skipped")]
|
|
+ [("aborted", raw_stage, "blocked") for raw_stage in activity.RAW_TO_STAGE],
|
|
)
|
|
def test_completed_stage6_skipped_and_every_aborted_stage_replay(
|
|
tmp_path: Path,
|
|
capsys: pytest.CaptureFixture[str],
|
|
pipeline_state: str,
|
|
raw_stage: str,
|
|
status: str,
|
|
) -> None:
|
|
safe_stage = raw_stage.replace(".", "_")
|
|
root = tmp_path / "artifacts"
|
|
run_id = f"run-{pipeline_state}-{safe_stage}"
|
|
state = _terminal_state(
|
|
root,
|
|
run_id,
|
|
pipeline_state=pipeline_state,
|
|
current_stage=raw_stage,
|
|
status=status,
|
|
)
|
|
manifest = _seal_and_build(capsys, root, state, _empty_rows())
|
|
store = tmp_path / "activity.json"
|
|
code, _stdout, stderr = _append(capsys, root, store, manifest)
|
|
assert code == 0, stderr
|
|
run = _load(store)["runs"][0]
|
|
assert run["terminal_state"] == pipeline_state
|
|
assert run["terminal_stage"] == activity.RAW_TO_STAGE[raw_stage]
|
|
|
|
|
|
def test_delete_store_identity_swap_is_detected_before_unlink(
|
|
tmp_path: Path,
|
|
capsys: pytest.CaptureFixture[str],
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
store = tmp_path / "activity.json"
|
|
assert _call(
|
|
capsys, "init-store", "--store", str(store), "--store-id", STORE_ID
|
|
)[0] == 0
|
|
original_hash = hashlib.sha256(store.read_bytes()).hexdigest()
|
|
replacement = tmp_path / "replacement.json"
|
|
replacement_bytes = b'{"replacement":true}\n'
|
|
replacement.write_bytes(replacement_bytes)
|
|
displaced = tmp_path / "displaced-original.json"
|
|
original_assert = activity._assert_identity
|
|
swapped = False
|
|
|
|
def swap_then_assert(path: Path, expected: tuple[int, int, int]) -> None:
|
|
nonlocal swapped
|
|
if not swapped:
|
|
path.replace(displaced)
|
|
replacement.replace(path)
|
|
swapped = True
|
|
original_assert(path, expected)
|
|
|
|
monkeypatch.setattr(activity, "_assert_identity", swap_then_assert)
|
|
code, stdout, stderr = _call(
|
|
capsys,
|
|
"delete-store",
|
|
"--store",
|
|
str(store),
|
|
"--store-id",
|
|
STORE_ID,
|
|
"--expect-store-sha256",
|
|
original_hash,
|
|
"--confirm",
|
|
"DELETE-ADJUDICATION-ACTIVITY-STORE",
|
|
)
|
|
assert code == 5
|
|
assert stdout == ""
|
|
assert "ERROR:CONFLICT" in stderr
|
|
assert store.read_bytes() == replacement_bytes
|
|
assert displaced.exists()
|