Data AnalyticsReliable reporting automation

Design a human approval step for automated report distribution

PK
Pankit Kumar
Sr. Data Scientist at Parexel (a Goldman Sachs–backed company) · 20 September 2026 · 3 min read
Technically reviewed by Ishaan Sharma
In this article (6 sections)

Approval should apply to the exact report version and distribution scope a reviewer inspected. A general “looks good” flag attached to a mutable filename can remain true after the file changes, allowing an unreviewed artifact to be sent.

Separate report preparation, review and distribution. Automatic quality checks support the review; they do not create a human approval by themselves.

Define the states and the evidence

The original automation lab prepares a local bundle with status prepared_for_review and distribution not_sent. It has no email client or other external delivery integration.

A deployed review record should identify the artifact version, reviewer, decision, time and allowed recipient scope. The system must verify that the reviewer is authorized and that the record has not been forged or altered. Those authentication and storage controls are separate from a checksum comparison.

Test artifact binding with an explicitly fictional decision

This local example constructs a fictional training approval, not an approval from the user or any real reviewer. It tests only whether a decision is bound to the current manifest. It sends nothing.

python
import json
from pathlib import Path
from tempfile import TemporaryDirectory
from pipeline import run,verify_bundle,digest

def binding_matches(folder,review):
    manifest = verify_bundle(folder)
    return (review.get('decision')=='approved'
            and review.get('run_id')==manifest['run_id']
            and review.get('manifest_sha256')==digest((folder/'manifest.json').read_bytes())
            and review.get('recipient_scope')=='fictional-training-audience')

config = json.loads(Path('report-config.json').read_text())
with TemporaryDirectory(prefix='approval-binding-example-') as temporary:
    folder,created = run('events.csv','source-manifest.json',config,temporary)
    pending = {'decision':'pending'}
    assert not binding_matches(folder,pending)
    fictional_review = {'decision':'approved','reviewer':'fictional_training_reviewer',
                        'run_id':folder.name,
                        'manifest_sha256':digest((folder/'manifest.json').read_bytes()),
                        'recipient_scope':'fictional-training-audience'}
    assert binding_matches(folder,fictional_review)
    assert not binding_matches(folder,dict(fictional_review,run_id='different-run'))
    assert not binding_matches(folder,dict(fictional_review,recipient_scope='different-audience'))
    assert not binding_matches(folder,dict(fictional_review,manifest_sha256='changed'))
print({'artifact_binding_checks_passed':True,'messages_sent':0})

The function deliberately does not implement reviewer authentication, signatures or a delivery authorization service. A caller can construct its input dictionary, so it must not be used alone as a production security boundary.

Make the review surface concrete

Show the reporting period, source cutoff, key metrics, reconciliation status, known limitations and intended recipients. Provide access to the exact artifact and its supporting evidence.

If a report contains a corrected total or a changed audience, require a new decision for that changed scope. A review of one region's report should not automatically approve an all-region export that exposes additional information.

Likewise, a spreadsheet preview and its downloadable attachment should refer to the same version. A reviewer should not approve a preview generated from different data than the file that will be sent.

Keep distribution retries separate

After approval, delivery still needs an identity and reconciliation process. A timeout after the messaging service accepted a send can leave the client unsure whether delivery occurred. Blindly resending may duplicate the message.

Use the provider's supported idempotency or delivery-status mechanisms where available, and record the approved artifact, recipient scope and provider response. A report-preparation run ID alone does not solve every messaging failure mode.

The tutorial's code stops at a local binding check. It makes no claim that a real message was approved, transmitted or received.

Handle rejection and expiration explicitly

A rejected artifact should remain reviewable with the reason, while a corrected artifact receives a new version. Avoid editing the rejected file in place and retaining its old review history as if nothing changed.

Some reports may also become unsuitable after a freshness deadline. Evaluate freshness again before distribution if the decision contract requires it, even when the artifact was previously approved. A valid historical report can still be inappropriate for a current operational message.

Exercise: prepare a second report with a different region filter and verify that the first report's fictional review does not match it. Then list the authentication and delivery controls missing from this local demonstration.

NeuraPath's Data Analytics with Generative AI course connects automation with reviewable decisions. A meaningful approval step binds a real authorized decision to a concrete artifact and a defined audience.

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.

PK
Pankit Kumar
Lead Instructor, NeuraPath Academy

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
Counselling is free · no obligation

Not sure which programme fits?

Tell us your background and we will map it to the right entry point — including saying so when a cheaper programme is the better fit. A counsellor replies within one working day.