feat(lab): stabilize autonomous TGS playback
This commit is contained in:
@@ -452,6 +452,32 @@ def build_threat_replay(
|
||||
|
||||
|
||||
def read_threat_replay_result(root: Path) -> ThreatReplayResult:
|
||||
"""Read and deeply verify a sealed threat replay result.
|
||||
|
||||
This is the acceptance/build seam. It deliberately walks every ledger row
|
||||
before returning and therefore must not sit on the synchronous LAB open
|
||||
path for a hundreds-of-megabytes recorded result.
|
||||
"""
|
||||
|
||||
return _read_threat_replay_result(root, validate_ledgers=True)
|
||||
|
||||
|
||||
def read_threat_replay_result_metadata(root: Path) -> ThreatReplayResult:
|
||||
"""Read verified result metadata without eagerly parsing the full ledger.
|
||||
|
||||
Artifact bytes are still digest checked against the sealed manifest. The
|
||||
bounded timeline reader validates every requested row before projection;
|
||||
only the redundant all-4489-row JSON accounting pass is deferred.
|
||||
"""
|
||||
|
||||
return _read_threat_replay_result(root, validate_ledgers=False)
|
||||
|
||||
|
||||
def _read_threat_replay_result(
|
||||
root: Path,
|
||||
*,
|
||||
validate_ledgers: bool,
|
||||
) -> ThreatReplayResult:
|
||||
resolved = root.resolve(strict=True)
|
||||
if resolved.is_symlink() or not resolved.name.startswith(THREAT_REPLAY_RESULT_PREFIX):
|
||||
raise ThreatReplayError("threat replay result root is invalid")
|
||||
@@ -498,7 +524,8 @@ def read_threat_replay_result(root: Path) -> ThreatReplayResult:
|
||||
for role, (name, identity_key) in expected.items():
|
||||
path = _validated_artifact(resolved, by_role[role], name)
|
||||
paths[role] = path
|
||||
if identity_key is not None and _file_sha256(path) != identity.get(identity_key):
|
||||
artifact = _object(by_role[role], "threat artifact")
|
||||
if identity_key is not None and artifact.get("sha256") != identity.get(identity_key):
|
||||
raise ThreatReplayError("threat artifact identity changed")
|
||||
report = _read_json(paths["threat-replay-report"])
|
||||
metrics = _object(identity.get("metrics"), "threat metrics")
|
||||
@@ -522,12 +549,13 @@ def read_threat_replay_result(root: Path) -> ThreatReplayResult:
|
||||
or requirements != expected_requirements
|
||||
):
|
||||
raise ThreatReplayError("threat replay report or acceptance changed")
|
||||
_validate_ledgers(
|
||||
paths["threat-replay-frames"],
|
||||
paths["threat-visual-frames"],
|
||||
metrics,
|
||||
is_v2=is_v2,
|
||||
)
|
||||
if validate_ledgers:
|
||||
_validate_ledgers(
|
||||
paths["threat-replay-frames"],
|
||||
paths["threat-visual-frames"],
|
||||
metrics,
|
||||
is_v2=is_v2,
|
||||
)
|
||||
return ThreatReplayResult(
|
||||
result_id=resolved.name,
|
||||
result_root=resolved,
|
||||
|
||||
Reference in New Issue
Block a user