Create a report manifest with timestamps and row counts
In this article (6 sections)
A report manifest is a compact record of what produced a report and which files belong to it. It should let a reviewer identify the source snapshot, configuration, code, runtime, quality counts and output artifacts without reverse-engineering a spreadsheet filename.
Keep analytical facts separate from operational timestamps. “Generated today” does not mean the report contains today's data.
Record the evidence needed to reproduce the result
The original automation lab produces a bundle with three files: selected event rows, a metrics JSON and a manifest JSON.
The manifest records the run ID, source-data hash, source-manifest hash, configuration hash, pipeline-code hash, Python version, output hashes, creation time and preparation status. The metrics file records the reporting period, event watermark, extraction time, raw and unique counts, replay count and selected totals.
Those responsibilities are intentionally linked: the manifest's checksum identifies the exact metrics file containing the counts. A useful manifest need not duplicate every metric if it reliably references the artifact that contains it.
Inspect and verify a generated bundle
import json
from pathlib import Path
from tempfile import TemporaryDirectory
from pipeline import run,verify_bundle,digest
config = json.loads(Path('report-config.json').read_text())
with TemporaryDirectory(prefix='report-manifest-example-') as temporary:
folder,created = run('events.csv','source-manifest.json',config,temporary)
manifest = verify_bundle(folder)
metrics = json.loads((folder/'metrics.json').read_text())
assert manifest['run_id']==folder.name
assert manifest['status']=='prepared_for_review'
assert manifest['distribution']=='not_sent'
assert manifest['outputs']['metrics.json']==digest((folder/'metrics.json').read_bytes())
assert (metrics['raw_rows'],metrics['unique_events'],metrics['identical_replays'],metrics['selected_events'])==(7,6,1,3)
assert metrics['amount_paise']==3500 and metrics['amount_unit']=='paise'
assert metrics['period_end']=='2026-01-12T00:00:00Z'
assert metrics['extracted_at']=='2026-01-12T01:00:00Z'
print({'run_id':manifest['run_id'],'counts':{key:metrics[key] for key in (
'raw_rows','unique_events','identical_replays','selected_events')},
'status':manifest['status'],'distribution':manifest['distribution']})Seven raw rows become six unique events after one identical replay is removed. Three paid events fall inside the configured period. These counts explain the transformation; a single final row count would not.
Name timestamps by the event they describe
The reporting period ends at January 12 midnight. The source is extracted at 01:00. The bundle is generated whenever this example runs. Those times can legitimately differ by months when reproducing a historical report.
Do not update the historical period or source extraction time to the current time simply to make a freshness indicator look recent. Use creation time to describe the artifact, and source-related times to describe the evidence.
The source watermark has a different meaning again: it is the source's declared event-time coverage. Its reliability depends on the upstream contract, not on the manifest field merely existing.
Treat hashes as integrity evidence with limits
Python's hashlib documentation provides the digest primitives. The lab uses SHA-256 to identify exact bytes and detect changes against recorded expectations.
A hash is not a human approval, an authenticity signature or proof of source completeness. Someone with write access to both data and manifest can replace both. Protect the storage and use stronger provenance or signing when the deployment requires it.
Likewise, the recorded Python version is useful but does not capture every environmental dependency in a more complex application. This lab uses the standard library. A package-based pipeline should record its relevant dependency lock or environment evidence too.
Make status describe an actual completed step
The bundle is prepared for review and not sent. It is not labeled approved merely because all automatic checks pass. If a later human approval exists, record it as separate evidence bound to the exact artifact version.
Avoid mutable filenames such as final_latest_really_final.xlsx as the only history. A readable title can coexist with a stable run identity and an explicit pointer to the currently selected version.
Exercise: edit the selected-events CSV after generation and verify that bundle validation fails. Then explain how an approved manifest would need to bind the reviewer decision to the original bytes rather than to a reusable filename.
NeuraPath's Data Analytics with Generative AI course connects reproducible scripting with audit-friendly reporting. A useful manifest makes the report's evidence and status inspectable without claiming more assurance than the checks provide.
Continue learning
This article is part of the Reliable reporting automation sequence. Use the neighbouring tasks when you need the prerequisite or the next application.
- Review the prerequisite or neighbouring task in Schedule a Python report with observable failures.
- Continue with Data freshness checks: stop a stale dashboard release.
Pankit Kumar has 10 years in Data Science & AI, building and shipping production systems in regulated pharma and clinical environments. He is a freelance trainer at Boston Institute of Analytics, AnalytixLabs and Scaler, and has taught this material to thousands of working professionals.
This article is part of our Data Analytics with Generative AI programme — 3–4 months. The full analyst stack — Excel, SQL, Power BI and Python pipelines — then a generative-AI layer you can prove is right.
Explore Data Analytics with Generative AI