Independent and not affiliated with the FDA, MHRA, ISPE, PDA, or any agency. Get the appgoutham@madhadi.com
madhadi.comData Integrity & GxP Quality
Browse all topics → Articles Templates & Procedures Learning paths GlossaryScenariosToolsRegulatory ReferencesLearning PathsTopics About Start here
Protocol Plug-and-play starting point AI & Automation

Protocol: Verification Testing of a GxP Script, Notebook, or Dashboard

A plug-and-play risk-scaled verification test protocol for homegrown GxP analytics: approval page, objective, tool and environment description, prerequisites, roles, acceptance criteria, and test cases covering known-answer verification against an independent reference, boundary and rounding-boundary cases, error handling on corrupt and missing input, reproducibility of the tagged version, and per-measure, join, filter, and row-level-security testing for dashboards, with deviation handling and a worked filled specimen.

Document type: Protocol

Read and copy the template below into your own quality system. It is a generic starting point for your own internal use, provided as is, with no warranty; see the Terms and License. Adopting it does not by itself create compliance.

This is a ready-to-use verification test protocol for one analytics tool. Approve it before execution, record actual results and evidence at the time of execution, and handle any failure as a documented deviation rather than a quiet correction. Replace every <<FILL: ...>> placeholder with your own specifics. A worked filled specimen with real arithmetic follows. This content is educational reference, not legal or regulatory advice; verify each cited regulation against the current source before you rely on it.

Approval page

Testing does not begin until this page is signed.

FieldEntry
Protocol titleVerification Testing, <<FILL: tool name>>
Protocol number<<FILL: VP-ID>>
Version<<FILL>>
Tool ID<<FILL>>
Risk class<<FILL: A / B / C>>
Specification reference and version<<FILL>>
Version under testTag <<FILL>> at commit <<FILL>>
Governing procedure<<FILL: SOP-ID>>

Pre-execution approvals

RoleNameSignatureDate
Author of protocol<<FILL>>
Tool owner<<FILL>>
Independent reviewer or SME<<FILL>>
Validation or CSV lead<<FILL>>
Quality Assurance<<FILL>>

Post-execution approvals

RoleNameSignatureDate
Executed by<<FILL>>
Reviewed by (independent of the executor)<<FILL>>
Validation or CSV lead<<FILL>>
Quality Assurance<<FILL>>

1. Objective

To verify that <<FILL: tool name>>, at the version identified on the approval page, performs as stated in <<FILL: specification reference>> when executed in the controlled environment, and to record documented evidence sufficient to support release for its intended GxP use.

Specifically, this protocol demonstrates that:

  1. The calculation agrees with an independently derived reference on representative inputs.
  2. The tool behaves correctly at boundaries, including the rounding boundary.
  3. The tool fails visibly and produces no result on corrupt, missing, or invalid input.
  4. The tool is reproducible: the same input produces the same output, and the tagged version reproduces an archived result.
  5. Where the tool is a dashboard, each measure agrees with an independent calculation on the same source data, and filters, joins, and row-level security neither drop nor duplicate rows.

2. Scope

In scope: <<FILL: the specific tool, version, and environment>>

Out of scope, with the control that covers each:

Out of scopeCovered by
Qualification of the compute platform, server, or analytics service<<FILL: infrastructure qualification reference>>
Validation of the source system supplying the input data<<FILL: source system validation reference>>
Correctness of the underlying scientific or statistical method as a method<<FILL: method validation or SOP reference>>. This protocol verifies the implementation of that method, not the choice of it.
Code correctness by inspection<<FILL: code review record reference>>. Code review and testing are complementary; neither replaces the other.

3. Description of the tool and its environment

FieldEntry
What the tool does<<FILL: two sentences>>
GxP decision supported<<FILL>>
Tool typeScript / Notebook / Dashboard / Query / Macro workbook / Pipeline job
Language, platform, or application and version<<FILL>>
Repository and tag under test<<FILL>>
Environment identifier<<FILL: manifest file, package snapshot, or image digest>>
Execution host or workspace<<FILL>>
Input source and extraction method<<FILL>>
Output destination<<FILL>>
Test environment relationship to production<<FILL: identical image and pinned versions / stated differences and their justification>>

Any difference between the test and production environments is stated here and assessed. Testing in an environment that differs from production in a way that could affect results invalidates the reproducibility conclusion.

4. Prerequisites

All of the following are confirmed before the first test case is executed. Record the evidence reference for each.

#PrerequisiteConfirmedEvidence reference
P1The specification is approved and current, and this protocol traces to its requirement IDs<<FILL>><<FILL>>
P2The version under test is tagged in version control and the tag points to the commit named on the approval page<<FILL>><<FILL>>
P3The independent code review for this exact version is complete with no open Critical or Major findings<<FILL>><<FILL>>
P4The environment is pinned, and the running environment matches the manifest, verified by listing installed versions<<FILL>><<FILL>>
P5Test data is controlled, documented, and its origin is recorded: production extract, anonymised extract, or constructed dataset<<FILL>><<FILL>>
P6Expected results were derived independently of the tool and were recorded before execution<<FILL>><<FILL>>
P7Testers are trained on this protocol and on the governing procedure<<FILL>><<FILL>>
P8The independent reference method or second tool used for known-answer verification is identified and is itself fit for that purpose<<FILL>><<FILL>>
P9Access to the source system for test execution is read-only<<FILL>><<FILL>>
P10The evidence capture method is defined: screenshots, output files, log extracts, or automated test run records<<FILL>><<FILL>>

Expected results must be written down before execution. An expected result derived from the tool’s own output is not a test; it is a description.

5. Roles

RoleResponsibility during execution
TesterExecutes each step exactly as written, records the actual result verbatim, attaches evidence, signs and dates each case. Does not modify the protocol or the tool during execution.
Independent verifier of expected resultsDerived and recorded the expected results before execution, by hand calculation, a validated system, or a second tool.
ReviewerReviews executed cases for completeness, evidence, and correct pass/fail determination. Independent of the tester.
Tool ownerAvailable during execution to answer questions about intended behaviour; does not determine pass or fail.
Validation or CSV leadAdjudicates deviations, approves the summary and conclusion.
Quality AssuranceApproves the protocol before execution and the summary after, and approves the disposition of every deviation.

6. Acceptance criteria

Testing is acceptable, and the tool may proceed to release, when all of the following are true.

#Criterion
AC1Every test case in section 8 has been executed against the version named on the approval page, with actual results and evidence recorded.
AC2Every requirement in the specification traces to at least one executed test case, and the traceability table in section 10 shows no untested requirement.
AC3Every known-answer test agrees with the independently derived expected value to the precision stated in the specification.
AC4Every boundary case, including the rounding boundary, returns the specified value.
AC5Every error case produces no usable output, a visible failure message, and the specified failure signal. No error case produces a plausible wrong result.
AC6Reproducibility is demonstrated: identical input produces identical output on repeat execution, and the tagged version reproduces the archived reference result.
AC7For dashboards, every specified measure agrees with an independent recomputation on the same frozen dataset, and the row-count reconciliation shows no dropped or duplicated rows.
AC8Every deviation is documented, assessed, and closed, and no open deviation affects a GxP-relevant result.
AC9Any test case that failed and was re-executed after a code change was re-executed against a new commit that has itself been code-reviewed.
AC10The executed protocol is reviewed and approved by a person independent of the tester.

A test case marked pass with no recorded actual result and no evidence does not satisfy AC1.

7. Test data

DatasetOriginContentsControlled locationWhy it is fit for this test
<<FILL: reference dataset>><<FILL>><<FILL>><<FILL>><<FILL>>
<<FILL: boundary dataset>><<FILL>><<FILL>><<FILL>><<FILL>>
<<FILL: corrupt dataset>>Constructed<<FILL: the specific corruption introduced>><<FILL>><<FILL>>
<<FILL: archived dataset for reproducibility>><<FILL: prior production run>><<FILL>><<FILL>><<FILL>>

Test data containing production GxP data is handled under <<FILL: SOP-ID for data handling>>. Constructed data is documented so that a reviewer can see what was constructed and why.

8. Test cases

Scale the case count to the risk class. Class A executes all applicable groups with pre-approved expected results. Class B executes groups 8.1, 8.2, 8.3, and 8.4 in reduced form. Class C may execute group 8.1 only, recorded as a verification note.

Record actual results verbatim. “As expected” is not an actual result.

8.1 Known-answer verification

Test IDRequirement tracedStepInputExpected resultActualPass/FailTesterDate
<<FILL>><<FILL>>Execute the tool against the reference dataset and record the primary result<<FILL>><<FILL: value derived independently, stated to the specified precision>>
<<FILL>><<FILL>>Compare the primary result to an independent recomputation in a second tool or by hand<<FILL>><<FILL>>
<<FILL>><<FILL>>Execute against a second, structurally different representative dataset<<FILL>><<FILL>>
<<FILL>><<FILL>>Confirm a controlled parameter is honoured rather than a constant, by executing with a different parameter value<<FILL>><<FILL>>

8.2 Boundary and edge cases

Test IDRequirement tracedStepInputExpected resultActualPass/FailTesterDate
<<FILL>><<FILL>>Execute at the rounding boundary, just above<<FILL: value at .xx5>><<FILL>>
<<FILL>><<FILL>>Execute at the rounding boundary, just below<<FILL>><<FILL>>
<<FILL>><<FILL>>Execute at the minimum permitted record count<<FILL>><<FILL>>
<<FILL>><<FILL>>Execute one record below the minimum permitted count<<FILL>><<FILL: rejection>>
<<FILL>><<FILL>>Execute with a value exactly at a specification limit<<FILL>><<FILL>>
<<FILL>><<FILL>>Execute with a value at each end of the allowed input range<<FILL>><<FILL>>
<<FILL>><<FILL>>Execute with empty inputEmpty file with headers<<FILL>>

8.3 Error handling and negative tests

Test IDRequirement tracedStepInputExpected resultActualPass/FailTesterDate
<<FILL>><<FILL>>Execute with a required column absent<<FILL>>No output written, visible message naming the missing column, failure signal raised
<<FILL>><<FILL>>Execute with non-numeric text in a numeric column<<FILL>>No output written, message naming the offending row, failure signal raised
<<FILL>><<FILL>>Execute with a value outside the allowed range<<FILL>><<FILL>>
<<FILL>><<FILL>>Execute with a truncated or corrupt file<<FILL>><<FILL>>
<<FILL>><<FILL>>Execute with a mathematically undefined condition, for example zero variance or division by zero<<FILL>><<FILL>>
<<FILL>><<FILL>>Execute with the output destination not writable<<FILL>><<FILL>>
<<FILL>><<FILL>>Attempt a write to the source system using the tool’s credentials<<FILL>>Write refused; source unchanged

8.4 Reproducibility

Test IDRequirement tracedStepInputExpected resultActualPass/FailTesterDate
<<FILL>><<FILL>>Execute twice on the same input in the same environment and compare outputs field by field<<FILL>>Identical in every field except the run timestamp
<<FILL>><<FILL>>Check out the tagged version into a clean environment built from the pinned manifest and execute against the archived input<<FILL>>Result identical to the archived output to the stated precision
<<FILL>><<FILL>>Confirm the provenance block on the output names the tag, commit, environment, timestamp, operator, and input identifier<<FILL>>All elements present and correct
<<FILL>><<FILL>>List the installed runtime and library versions in the execution environment and compare to the pinned manifest<<FILL>>Exact match on every pinned entry

8.5 Notebook-specific tests (execute where the tool is a notebook)

Test IDRequirement tracedStepInputExpected resultActualPass/FailTesterDate
<<FILL>><<FILL>>Restart the kernel and run all cells top to bottom; compare every displayed output to the saved output<<FILL>>Identical outputs; execution counts sequential from 1
<<FILL>><<FILL>>Execute the notebook non-interactively through the controlled runner and compare to the interactive run<<FILL>>Identical results
<<FILL>><<FILL>>Execute cells deliberately out of order and confirm the tool detects or prevents reliance on stale state<<FILL>><<FILL: expected safeguard behaviour>>

8.6 Dashboard-specific tests (execute where the tool is a dashboard or visual data-preparation flow)

Every specified measure gets its own row. Do not sample measures.

Test IDRequirement tracedStepInputExpected resultActualPass/FailTesterDate
<<FILL>>MEA-<<FILL>>Compare the measure value on the frozen dataset to an independent recomputation from source<<FILL: frozen dataset and filter state>><<FILL: independently computed value>>
<<FILL>><<FILL>>Reconcile the row count after every transformation step against the specified rows-in and rows-out<<FILL>><<FILL>>
<<FILL>><<FILL>>Reconcile the total record count in the model against the source system count for the same period<<FILL>>Counts equal; no dropped rows
<<FILL>><<FILL>>Confirm a one-to-many relationship does not duplicate the base measure, using a record deliberately having multiple child rows<<FILL>>Base measure unchanged; no double counting
<<FILL>><<FILL>>Apply each slicer and filter in turn and reconcile the filtered totals back to the unfiltered total<<FILL>>Filtered subsets sum to the unfiltered total
<<FILL>><<FILL>>Sign in as each row-level-security role and record the visible record count<<FILL>>Per-role counts sum to the full count, with no record visible to no role and none counted twice in a total
<<FILL>><<FILL>>Confirm the default filter state on page load matches the specification and is visible to the user<<FILL>><<FILL>>
<<FILL>><<FILL>>Trigger a refresh failure and observe what the user sees<<FILL>>Explicit stale-data indication; data not presented as current; notification raised
<<FILL>><<FILL>>Confirm the last successful refresh timestamp is displayed and correct<<FILL>><<FILL>>
<<FILL>><<FILL>>Export or print a page and compare every displayed value to the on-screen view<<FILL>>Identical values; filter state stated on the export

9. Deviation handling

  1. A test case whose actual result does not match the expected result is recorded as Fail. The tester does not adjust the input, the expected result, or the tool to obtain a pass.
  2. Every failure raises a test deviation under <<FILL: SOP-ID for validation deviations>>, recording: test ID, expected, actual, evidence, and the immediate assessment of whether other executed cases are affected.
  3. The validation lead classifies the deviation:
ClassDefinitionDisposition
Tool defectThe tool does not do what the specification requiresCorrect by a new commit, re-review the change, re-execute the affected cases and any case the change could have affected
Specification defectThe tool is correct and the specification is wrong, ambiguous, or incompleteRevise the specification through change control, re-approve, re-execute the affected cases
Protocol or expected-result defectThe test step or expected value was wrongCorrect the protocol through a documented amendment approved before re-execution, and record why the expected value was wrong
Environment or data defectThe failure came from the test environment or the test data, not the toolCorrect and re-execute; assess whether the environment difference affects the reproducibility conclusion
  1. A deviation is closed only when the corrective action is complete, the affected cases have been re-executed and passed, and the closure is approved by the validation lead and Quality Assurance.
  2. Where a code change is made, note that AC9 requires the new commit to have been code-reviewed before re-execution.
Deviation IDTest IDDescriptionClassificationCorrective actionCases re-executedClosed byDate
<<FILL>><<FILL>><<FILL>><<FILL>><<FILL>><<FILL>><<FILL>><<FILL>>

10. Traceability

Requirement IDTest case ID(s)ExecutedResult
<<FILL>><<FILL>><<FILL>><<FILL>>

Untested requirements: <<FILL: none, or ID and justification>>

11. Summary and conclusion

FieldEntry
Test cases planned<<FILL>>
Test cases executed<<FILL>>
Passed on first execution<<FILL>>
Failed and re-executed<<FILL>>
Deviations raised<<FILL>>
Deviations open at conclusion<<FILL: should be zero>>
Version at conclusion of testingTag <<FILL>> at commit <<FILL>>
Acceptance criteria metAC1 to AC10: <<FILL: met / not met, with detail on any not met>>
Limitations observed during testing<<FILL>>

Conclusion statement:

<<FILL: state whether the tool, at the identified version and in the identified environment, is verified against its specification and suitable for release for its intended use, and name any limitation that must appear on the release statement>>

12. Attachments

#AttachmentReference
AApproved specification<<FILL>>
BIndependent code review record<<FILL>>
CIndependently derived expected results, dated before execution<<FILL>>
DTest datasets and their control records<<FILL>>
EOutput files produced during execution<<FILL>>
FScreenshots and log extracts<<FILL>>
GEnvironment listing from the execution host<<FILL>>
HAutomated test run records, where used as evidence<<FILL>>
ITest deviation records<<FILL>>
JTraining records for testers<<FILL>>

Filled specimen

Executed test-case block for tool ANL-0007, the class A stability regression script, at tag v1.0-validated, commit a3f19c4, executed 05 May 2026 on analytics server ANSRV-01 in container image sha256:9c1d4b....

Reference dataset, lot <<FILL: lot ID>>, long-term condition, seven timepoints:

timepoint_monthspotency_pct
0100.2
399.4
698.7
997.9
1297.2
1895.8
2494.3

Expected values were derived on 30 April 2026 by hand calculation by the process statistician and confirmed in a second statistical package, and were signed and dated before the tool was run. The hand calculation gave: sum of t = 72, t_bar = 10.285714 months, sum of y = 683.5, y_bar = 97.642857%, Sxx = 429.428571, Sxy = -104.785714, slope = -0.2440% per month, intercept = 100.1527%, residual standard deviation = 0.040432%, one-sided t at 95% with 5 degrees of freedom = 2.0150.

Known-answer verification

Test IDReqStepInputExpectedActualPass/FailTesterDate
TC-05CALC-01Execute and record the fitted slopeReference dataset, T = 24Slope -0.2440 % per month-0.2440PassR. Duarte05 May 2026
TC-05bCALC-01Compare to independent recomputation in a second statistical packageSameAgreement to 4 decimal placesSecond package returned -0.2440120; script full-precision value -0.2440120PassR. Duarte05 May 2026
TC-06CALC-02Record predicted potency at the proposed shelf lifeReference dataset, T = 2494.3 % (full precision 94.2964)94.3 (94.29640719 in the full-precision log)PassR. Duarte05 May 2026
TC-06bCALC-02Re-execute with the shelf-life parameter changed, to prove the parameter is honoured rather than a constantReference dataset, T = 1895.8 % (full precision 95.7605)95.8 (95.76047904)PassR. Duarte05 May 2026
TC-07CALC-03Record the one-sided lower 95% confidence bound at the shelf lifeReference dataset, T = 2494.2 % (full precision 94.2343)94.2 (94.23431512)PassR. Duarte05 May 2026
TC-07bCALC-03Confirm the bound against independent recomputationSameMargin = 2.0150 x 0.040432 x sqrt(1/7 + 13.714286^2 / 429.428571) = 0.0621; 94.2964 minus 0.0621 = 94.234394.23431512PassM. Larsen05 May 2026
TC-10OUT-02Confirm the controlled result field is present and named as specifiedReference datasetField lcb_shelf_life_pct present and identified as the controlled resultPresent, correctly namedPassR. Duarte05 May 2026

Boundary and rounding-boundary cases

Test IDReqStepInputExpectedActualPass/FailTesterDate
TC-09aRND-02Rounding boundary, just at the halfReported potency full-precision value 99.95100.0 (half-up to one decimal place)100.0PassR. Duarte05 May 2026
TC-09bRND-02Rounding boundary, just below the halfReported potency full-precision value 99.9499.999.9PassR. Duarte05 May 2026
TC-09cRND-01Confirm rounding is applied only at reportingReference datasetFull-precision slope in the log carries at least 7 decimal places; reported slope carries 4Log -0.2440120, report -0.2440PassR. Duarte05 May 2026
TC-04aIN-04Minimum permitted timepoint countReference dataset reduced to 6 timepoints (0, 3, 6, 9, 12, 18)Result produced, no rejectionResult producedPassR. Duarte05 May 2026
TC-04bIN-04One below the minimumSame reduced to 5 timepointsNo output; message stating 5 timepoints found, 6 required; non-zero exitMessage “lot <<FILL>>: 5 timepoints found, minimum 6 required”; exit status 2PassR. Duarte05 May 2026
TC-08CALC-05Extrapolation guard against the supplied parameterReference dataset, T = 36, last observed timepoint 24, permitted extrapolation window 6 monthsNo output; message stating the requested shelf life exceeds the permitted extrapolation window; non-zero exitMessage raised, exit status 2PassR. Duarte05 May 2026

Error handling

Test IDReqStepInputExpectedActualPass/FailTesterDate
TC-02IN-02Required column absentReference dataset with potency_pct removedNo output; message naming the missing column; non-zero exitMessage “required column potency_pct not found”; exit status 2PassR. Duarte05 May 2026
TC-03IN-03Non-numeric value in a numeric columnReference dataset with “not tested” in the 12-month potency cellNo output; message naming the offending row; non-zero exitMessage named row 5; exit status 2PassR. Duarte05 May 2026
TC-11ERR-06Mathematically undefined conditionDataset with all seven timepoints set to 0 (zero variance in t)No output; message stating the regression is undefined; non-zero exitMessage raised; exit status 2PassR. Duarte05 May 2026
TC-11bERR-01, ERR-12Unreadable input fileInput file permissions removedNo output; message naming the file; non-zero exitMessage raised; exit status 2PassR. Duarte05 May 2026
TC-14SEC-01Attempt a write to the source using the tool’s accountInsert statement issued against the stability table on the replica with the tool’s credentialsRefused; source unchangedPermission denied; row count on the source unchanged before and afterPassR. Duarte05 May 2026

Reproducibility

Test IDReqStepInputExpectedActualPass/FailTesterDate
TC-15aReproducibilityExecute twice on the same input in the same environmentReference datasetOutputs identical in every field except the run timestampIdentical; only run_timestamp differedPassR. Duarte05 May 2026
TC-15bReproducibilityBuild a clean environment from the pinned manifest, check out tag v1.0-validated, execute against the archived inputArchived dataset from the March 2026 dry run, input hash on fileSlope, prediction and bound identical to the archived outputSlope -0.2440, prediction 94.3, bound 94.2, all identicalPassM. Larsen06 May 2026
TC-12IN-05, OUT-03Inspect the provenance blockReference datasetTag, commit, image digest, timestamp, operator, input SHA-256 all present and correctAll present; input hash matched the value recorded in the test data control recordPassR. Duarte05 May 2026
TC-13ENV-02Compare the running environment against the pinned manifestEnvironment listingExact match on python 3.11.8, numpy 1.26.4, pandas 2.2.1, scipy 1.12.0, statsmodels 0.14.1Exact match on all fivePassR. Duarte05 May 2026

One deviation raised during this execution

Deviation IDTest IDDescriptionClassificationCorrective actionRe-executedClosed
TD-2026-0033TC-09aFirst execution reported 99.9 for a full-precision value of 99.95, because the formatting call used the language’s default banker’s rounding rather than half-up as required by RND-02Tool defectExplicit half-up rounding applied at the formatter, committed at a3f19c4 and code-reviewed as finding F-05 before re-executionTC-09a, TC-09b, TC-09c, TC-06, TC-07Closed 06 May 2026, approved by QA

That deviation is the reason the rounding boundary is tested at all. The default rounding behaviour of several common numerical libraries is round-half-to-even, which disagrees with the half-up convention many validated laboratory systems use, and the disagreement only ever appears at the boundary. Without TC-09a the script would have gone into production quietly reporting a different value from the LIMS on one input in twenty.

Dashboard specimen extract, for contrast

Executed for tool ANL-0021, the class B release results dashboard, on a frozen dataset covering <<FILL: period>>.

Test IDReqStepInputExpectedActualPass/Fail
TC-D03MEA-03Compare “lots released within target” to independent recomputation from the source extractFrozen dataset: 52 lots disposed, of which 47 within 30 days47 / 52 = 90.4%90.4%Pass
TC-D07MEA-07Compare “out-of-specification result rate” to an independent query against the source replicaFrozen dataset: 1,240 reportable results, 18 flagged out of specification18 / 1,240 = 1.45%1.45%Pass
TC-D15MEA-<<FILL>>Reconcile total lot count in the model to the source count for the periodSame52 lots52Pass
TC-D16MEA-<<FILL>>Confirm the lot-to-result relationship does not duplicate the lot count. Three lots in the frozen set carry a repeat test recordSameLot count remains 52, not 5552Pass
TC-D17MEA-<<FILL>>Sum the site slicer subsets back to the unfiltered totalSameSite A 31 plus site B 21 equals 5231, 21, 52Pass
TC-D18MEA-<<FILL>>Sign in as each row-level-security role and record visible lot countsSameSite A role sees 31, site B role sees 21, no lot visible to both, sum equals 5231 and 21, no overlap, sum 52Pass
TC-D19MEA-<<FILL>>Suspend the gateway and open the reportRefresh deliberately failedStale-data banner shown with the last successful refresh timestamp; values not presented as current; notification sent to the data ownerBanner shown; notification received at 09:14Pass
TC-D20MEA-<<FILL>>Export the summary page and compare every value to the screenSameIdentical values; applied filter state printed on the exportIdentical; filter state printedPass

TC-D16 is the case worth keeping in every dashboard protocol. Three repeat test records in a set of 52 lots is exactly the sort of small, ordinary data condition that turns a correct measure into an inflated one, and it is invisible unless somebody counts.

Common inspection findings this protocol prevents

  • Testing was performed but the expected results were taken from the tool’s own output, so the test could not have failed.
  • The protocol was executed against a version that cannot be identified, so the evidence does not apply to the version in production.
  • Results were recorded as “OK” or “as expected” with no value and no evidence.
  • A test failed, the code was quietly changed, and the case was re-executed with no deviation record and no re-review of the change.
  • The rounding boundary was never tested, and the tool disagrees with the validated laboratory system on one value in twenty.
  • The tool returns a plausible number on corrupt input because no negative testing was performed.
  • Reproducibility was assumed rather than demonstrated, and the archived result cannot be regenerated.
  • Only some of a dashboard’s measures were tested, and the untested ones are the ones that are wrong.
  • A dashboard measure is correct on the full dataset but doubles when a filter is applied, because no row-count reconciliation was performed.
  • Row-level security was configured but never tested, so one site sees another site’s data, or a set of records is visible to nobody and silently absent from every total.
  • Testing was performed in an environment that differs from production, and the difference was never assessed.

How to adapt this protocol

  1. Scale by risk class before you scale by effort. Removing the negative tests to save time removes the tests most likely to find something, because a defect that produces a plausible wrong number is exactly what normal use will not reveal.
  2. Derive and sign the expected results before execution, on a separate dated page, and attach it as attachment C. This one practice is the difference between verification and demonstration.
  3. Where automated unit tests already encode the known-answer cases, reference the test run record as evidence for those cases rather than repeating them manually, provided the test code is under version control and was itself reviewed.
  4. Give every dashboard measure its own test row. Sampling measures is the most common shortcut and the one that most reliably leaves a wrong number in production.
  5. Add the row-count reconciliation at every transformation step for any tool that joins tables. It costs one row per step in the protocol and it catches the failure mode that produces confidently wrong charts.
  6. Keep group 8.4 even for class C tools if the output has any retention obligation. Reproducibility is the requirement that becomes impossible to retrofit once the environment has moved on.
  7. Set the extrapolation, minimum-count, and range limits in the specification first, then write the boundary tests against them. Boundary tests written without a specified boundary test nothing.
  8. Confirm the current status of every cited regulation and guidance in the governing SOP before issue.
Use madhadi.com as an app Full screen, works offline, one tap from your home screen.