Check an evidence ledger before the auditor does
Your task
Audit season eats a quarter of your platform team's time. An agent gathers compliance evidence all year into an append-only ledger, and before each audit it checks the ledger the way an auditor would.
Write verify_evidence_chain(required_controls, ledger_records, current_day, max_age_days): the check the agent runs before an audit.
required_controls(list of str): the control ids the audit requires, such as"AC-2".ledger_records(list of str): one artifact each, writtencontrol_id,ledger_hash,recomputed_hash,collected_day. The ledger hash was written when the artifact was collected, and the recomputed hash is the artifact's hash today.current_day(int): today, as a day number.max_age_days(int): how old the newest artifact for a control may be.- Return a finding for each control an auditor would reject, written
"<control>:tampered","<control>:missing"or"<control>:stale", sorted in ascending order. A control listed twice is reported once.
Rules, for each required control:
- Use only the records that split on
,into exactly 4 fields, whose first field equals the control, and whose day is one or more digits (0 to 9 only). Skip every other record. - If any of those records has a ledger hash different from its recomputed hash, or a day after
current_day:"tampered". - If there are no such records:
"missing". - If the newest such record's day is before
current_day - max_age_days:"stale". - Otherwise the control has no finding.
Examples
verify_evidence_chain(required_controls: list[str], ledger_records: list[str], current_day: int, max_age_days: int) -> list[str]Example 1
Input
verify_evidence_chain(["AC-2", "CM-6"], ["AC-2,h1,h1,40", "CM-6,h2,h2,41"], 41, 1)Output
[]Example 2
Input
verify_evidence_chain(["AC-2", "CM-6", "IA-5"], ["AC-2,h1,h9,40", "IA-5,h3,h3,30"], 41, 1)Output
["AC-2:tampered", "CM-6:missing", "IA-5:stale"]Example 3
Input
verify_evidence_chain(["AC-2"], ["AC-2,h1,h1,41", "AC-2,h2,hX,41"], 41, 7)Output
["AC-2:tampered"]