This is a ready-to-use specification for one analytics tool. It exists so that testing has a pass criterion: without a written statement of what the tool must do, “we tested it” means “we ran it and the output looked reasonable”. Replace every <<FILL: ...>> placeholder with your own specifics, set your document numbers and dates, and route it through your normal document control, review, and approval before testing begins. A worked filled specimen follows. This content is educational reference, not legal or regulatory advice; verify each cited regulation against the current source before you rely on it.
Document control header
| Field | Entry |
|---|---|
| Document title | Specification, <<FILL: tool name>> |
| Document number | <<FILL: SPEC-ID>> |
| Version | <<FILL>> |
| Effective date | <<FILL>> |
| Tool ID | <<FILL: from the analytics tool inventory register>> |
| Risk class | <<FILL: A / B / C, from the risk classification record>> |
| Risk classification reference | <<FILL: RC-YYYY-nnnn>> |
| Governing procedure | <<FILL: SOP-ID>> |
| Author | <<FILL>> |
| Supersedes | <<FILL: prior version or "New">> |
How to write requirements in this document
Every requirement carries a unique ID, is written so that a tester can observe pass or fail without interpretation, and states one thing. Use the prefixes below so that a traceability table sorts sensibly and a reader can see at a glance what a failing test threatens.
| Prefix | Requirement category |
|---|---|
| IN | Input contract: source, format, columns, types, units, ranges, missing and out-of-range handling |
| CALC | Processing logic and calculations |
| RND | Rounding, precision, and significant figures |
| OUT | Outputs, format, destination, and which field is the controlled result |
| ERR | Error handling and failure behaviour |
| ENV | Environment and dependency requirements |
| SEC | Access, security, and read-only behaviour toward the source |
| MEA | Per-measure requirements for low-code dashboards |
| LIM | Stated limits of validity |
Wording that is not testable: “the tool shall handle errors appropriately”, “performance shall be acceptable”, “results shall be accurate”. Wording that is testable: “on encountering a non-numeric value in the timepoint column, the tool shall write no output file and shall exit with a non-zero status and a message naming the offending row”.
1. Purpose and intended use
| Field | Entry |
|---|---|
| One-sentence statement of what the tool produces | <<FILL>> |
| The GxP decision the output supports | <<FILL: name the decision and the record where it is taken>> |
| Who uses the output and in what role | <<FILL>> |
| Frequency of use | <<FILL>> |
| Is the output the record of origin or a view | <<FILL>> |
| Source method, SOP, compendial procedure, or statistical method implemented | <<FILL: name and version>> |
| What this tool explicitly does not do | <<FILL>> |
2. Inputs
2.1 Input sources
| Input | Source system and validation status | Extraction method | Format | Refresh or extraction timing |
|---|---|---|---|---|
<<FILL>> | <<FILL>> | <<FILL: named export, read-only view, API, direct query>> | <<FILL>> | <<FILL>> |
2.2 Input contract
State the expected schema exactly. A tool that accepts whatever it is given cannot be tested.
| Column or field | Data type | Units | Required | Allowed range or values | Handling of missing | Handling of out of range |
|---|---|---|---|---|---|---|
<<FILL>> | <<FILL>> | <<FILL>> | Yes / No | <<FILL>> | <<FILL: reject / impute with stated rule / exclude with logged reason>> | <<FILL>> |
2.3 Input requirements
| ID | Requirement |
|---|---|
| IN-01 | The tool shall read only from <<FILL: named source>> and shall not accept a manually edited copy of that extract. |
| IN-02 | The tool shall verify that all columns listed in section 2.2 are present, and shall reject the input naming any missing column. |
| IN-03 | The tool shall verify the data type of each column against section 2.2 and shall reject the input naming the first offending row and column. |
| IN-04 | The tool shall reject input containing fewer than <<FILL: minimum record count>> records. |
| IN-05 | The tool shall record, in the output provenance block, an identifier or hash of the input dataset used. |
| IN-06 | <<FILL: additional input requirement>> |
3. Processing logic and calculation
3.1 Narrative description
<<FILL: describe the processing in ordered steps, in plain language, so a reviewer who does not read code can follow what happens to the data from input to output>>
3.2 The calculation
State the equation where a calculation is performed. Where the method comes from a compendial procedure, a pharmacopoeial chapter, an SOP, or a statistical reference, name it and describe the method in your own words rather than reproducing the source text.
<<FILL: the equation, with every term defined and its units stated>>
Terms:
| Symbol | Meaning | Units |
|---|---|---|
<<FILL>> | <<FILL>> | <<FILL>> |
Source method implemented: <<FILL: name, version, and clause>>
3.3 Exclusion, filtering, and grouping rules
Any rule that removes or partitions data is a calculation and must be specified, because it is where results most often silently diverge from expectation.
| Rule | Definition | Justification | Requirement ID |
|---|---|---|---|
<<FILL: e.g. outlier exclusion>> | <<FILL: the exact test and threshold>> | <<FILL>> | <<FILL>> |
<<FILL: e.g. date window>> | <<FILL: inclusive or exclusive at each end, and the time zone>> | <<FILL>> | <<FILL>> |
3.4 Calculation requirements
| ID | Requirement |
|---|---|
| CALC-01 | <<FILL: the primary calculation, stated so it can be verified against an independent computation>> |
| CALC-02 | <<FILL>> |
| CALC-03 | The tool shall apply the exclusion rules in section 3.3 in the stated order and shall record in the output which records were excluded and under which rule. |
| CALC-04 | <<FILL: any conditional or branching logic, with the condition stated>> |
4. Rounding and significant figures
Rounding is stated explicitly because it is a common source of silent disagreement between a homegrown tool and a validated source system, and because “the two systems round differently” is a finding that is trivially avoidable and frequently found.
| Value | Reported precision | Rounding rule | Stage at which rounding is applied |
|---|---|---|---|
<<FILL>> | <<FILL: decimal places or significant figures>> | <<FILL: half-up, half-even, truncate>> | <<FILL: final reporting only, or intermediate>> |
| ID | Requirement |
|---|---|
| RND-01 | Rounding shall be applied only at final reporting. All intermediate computation shall be carried at full available precision. |
| RND-02 | <<FILL: the reported value>> shall be reported to <<FILL: n>> decimal places using <<FILL: rounding rule>>. |
| RND-03 | The rounding rule shall match that used by <<FILL: named source or downstream system>>, and any difference shall be documented and justified here. |
5. Outputs
5.1 Output definition
| Output | Format | Destination | Is this the controlled result | Consumer |
|---|---|---|---|---|
<<FILL>> | <<FILL>> | <<FILL>> | Yes / No | <<FILL>> |
5.2 Output schema
| Field | Type | Units | Precision | Description |
|---|---|---|---|---|
<<FILL>> | <<FILL>> | <<FILL>> | <<FILL>> | <<FILL>> |
5.3 Provenance block
Every GxP output carries a provenance block so that the result can be traced back to the exact logic and data that produced it.
| Element | Content |
|---|---|
| Tool ID and name | <<FILL>> |
| Version tag and commit identifier | <<FILL>> |
| Environment identifier | <<FILL: manifest reference or image digest>> |
| Run timestamp and time zone | <<FILL>> |
| Operator or service account | <<FILL>> |
| Input dataset identifier or hash | <<FILL>> |
| Specification document and version | <<FILL>> |
5.4 Output requirements
| ID | Requirement |
|---|---|
| OUT-01 | The tool shall write the output to <<FILL: destination>> with the schema in section 5.2 and no additional or missing fields. |
| OUT-02 | The field <<FILL: name>> is the controlled result. All other fields are supporting. |
| OUT-03 | Every output shall carry the complete provenance block in section 5.3. |
| OUT-04 | The tool shall not overwrite a previous output. Outputs shall be written with a unique name or to a versioned location. |
| OUT-05 | <<FILL>> |
6. Error handling
The governing rule is fail loudly. A GxP tool that cannot compute a correct answer must produce no answer, visibly, rather than a plausible wrong one.
| Condition | Required behaviour | Requirement ID |
|---|---|---|
| Missing or unreadable input file | <<FILL>> | ERR-01 |
| Missing required column | <<FILL>> | ERR-02 |
| Wrong data type in a required column | <<FILL>> | ERR-03 |
| Value outside the allowed range in section 2.2 | <<FILL>> | ERR-04 |
| Fewer records than the stated minimum | <<FILL>> | ERR-05 |
| Division by zero or an undefined mathematical result | <<FILL>> | ERR-06 |
| Loss of connection to the source during execution | <<FILL>> | ERR-07 |
| Output destination not writable | <<FILL>> | ERR-08 |
| ID | Requirement |
|---|---|
| ERR-09 | In every failure condition the tool shall write no output file, or shall write an output clearly marked as failed that cannot be mistaken for a result. |
| ERR-10 | Every failure shall produce a message that names the condition and, where applicable, the offending record, and shall be recorded in the run log at <<FILL: log location>>. |
| ERR-11 | The tool shall not silently substitute a default value for a missing or invalid input. |
| ERR-12 | The tool shall exit with a non-zero status on failure so that a scheduling or orchestration layer detects the failure. |
7. Environment and dependencies
| ID | Requirement |
|---|---|
| ENV-01 | The tool shall run on <<FILL: language and runtime version>>, pinned exactly. |
| ENV-02 | Every library dependency shall be pinned to an exact version in <<FILL: manifest filename>>, stored in version control with the code. |
| ENV-03 | The tool shall run in an isolated environment (<<FILL: virtual environment, package snapshot, or container image>>) on <<FILL: qualified infrastructure reference>>. |
| ENV-04 | The tool shall not require internet access at run time, or where it does, the accessed endpoint shall be named here and its availability treated as an input dependency. |
| ENV-05 | A change to any pinned version is a change requiring assessment and, where results could be affected, re-execution of the calculation test cases. |
Pinned manifest:
<<FILL: exact runtime and library versions, one per line>>
8. Access and source protection
| ID | Requirement |
|---|---|
| SEC-01 | The tool shall connect to the source system with a read-only account and shall not write, update, or delete any record in the source. |
| SEC-02 | Permission to modify the tool shall be restricted to <<FILL: named group>> and shall be separate from permission to run it. |
| SEC-03 | Credentials shall be retrieved at run time from <<FILL: secrets solution>> and shall not appear in the code, the manifest, the output, or the logs. |
| SEC-04 | <<FILL: row-level or record-level access requirements, if any>> |
9. For low-code dashboards: per-measure specification
Complete this section instead of, or in addition to, sections 3 to 5 where the tool is a dashboard or a visual data-preparation flow. Each calculated measure, each transformation step, each calculated column, and each relationship gets its own row and its own requirement ID, because each one is independently capable of producing a wrong number.
9.1 Data model
| Table | Source | Grain (what one row represents) | Row count expectation | Key |
|---|---|---|---|---|
<<FILL>> | <<FILL>> | <<FILL>> | <<FILL>> | <<FILL>> |
| Relationship | From table | To table | Cardinality | Filter direction | Risk if wrong |
|---|---|---|---|---|---|
<<FILL>> | <<FILL>> | <<FILL>> | <<FILL: one to many / many to many>> | <<FILL>> | <<FILL: drops rows / duplicates rows>> |
9.2 Calculated measures
| ID | Measure name | Definition in words | Source fields | Filter context applied | Expected precision | Independent check method |
|---|---|---|---|---|---|---|
| MEA-01 | <<FILL>> | <<FILL>> | <<FILL>> | <<FILL>> | <<FILL>> | <<FILL: how a tester recomputes this from source>> |
| MEA-02 | <<FILL>> | <<FILL>> | <<FILL>> | <<FILL>> | <<FILL>> | <<FILL>> |
9.3 Query and transformation steps
| ID | Step | What it does | Rows in | Rows out | Why the row count changes |
|---|---|---|---|---|---|
MEA-<<FILL>> | <<FILL>> | <<FILL>> | <<FILL>> | <<FILL>> | <<FILL>> |
9.4 Calculated columns
| ID | Column | Table | Definition | Why a column rather than a measure |
|---|---|---|---|---|
MEA-<<FILL>> | <<FILL>> | <<FILL>> | <<FILL>> | <<FILL>> |
9.5 Refresh and stale data
| ID | Requirement |
|---|---|
MEA-<<FILL>> | The dataset shall refresh on the schedule <<FILL>> from <<FILL: source>>. |
MEA-<<FILL>> | Every page shall display the timestamp of the last successful refresh, in <<FILL: time zone>>. |
MEA-<<FILL>> | On refresh failure the user shall see <<FILL: explicit stale-data banner or blocked view>>. The dashboard shall not present stale data as current. |
MEA-<<FILL>> | Refresh failure shall notify <<FILL: role>> within <<FILL: time>>. |
9.6 Row-level security and filters
| ID | Requirement |
|---|---|
MEA-<<FILL>> | Role <<FILL>> shall see only <<FILL: scope>>. |
MEA-<<FILL>> | The sum of the records visible across all roles shall equal the total record count with no role filter applied, with no record visible to no role and none double-counted in a total. |
MEA-<<FILL>> | Default filter and slicer states on page load shall be <<FILL>>, and shall be visible to the user rather than implicit. |
10. Limits of validity
State what the tool is not valid for. This is the section that stops a tool being reused in a context nobody assessed.
| ID | Limitation |
|---|---|
| LIM-01 | Valid only for <<FILL: product, process, study, or data type>>. |
| LIM-02 | Valid only for input ranges stated in section 2.2. Outside those ranges the tool shall reject the input rather than extrapolate. |
| LIM-03 | Not valid for <<FILL: named excluded use>>. |
| LIM-04 | The method assumes <<FILL: stated assumption>>. Where that assumption does not hold, the output is not valid and the assumption shall be checked before use. |
11. Requirement-to-test traceability
Every requirement traces to at least one test case, and every test case traces back to at least one requirement. A requirement with no test is unverified. A test with no requirement is testing something nobody specified.
| Requirement ID | Requirement summary | Test case ID | Verification method |
|---|---|---|---|
<<FILL>> | <<FILL>> | <<FILL>> | Known-answer test / boundary test / negative test / inspection / reproducibility test |
Coverage statement: <<FILL: number>> requirements, <<FILL: number>> test cases, <<FILL: number>> requirements with no test case (must be zero, or each justified below).
Justified exceptions: <<FILL: none, or requirement ID and reason>>
12. Approvals
| Role | Name | Signature | Date |
|---|---|---|---|
| Author | <<FILL>> | ||
| Independent technical reviewer | <<FILL>> | ||
| Method or statistical reviewer (where applicable) | <<FILL>> | ||
| Tool owner | <<FILL>> | ||
| Quality Assurance | <<FILL>> |
Filled specimen
Specification extract for tool ANL-0007, a class A Python script that fits a stability regression for drug product potency and produces the values reported in the annual product review. Identifiers, products, and dates are illustrative.
Purpose and intended use
Produces, for one lot, the ordinary least squares slope of potency against time, the predicted potency at the proposed shelf life, and the one-sided lower 95% confidence bound on that prediction. The output populates the stability trend table in the annual product review and supports the conclusion that the lot remains within the potency specification through the proposed shelf life. Used by the stability lead, once per lot per annual review cycle. Output is the record of origin: no other system computes these values. Implements the linear regression approach described in the stability data evaluation section of <<FILL: internal SOP-ID>>, which is written against the ICH stability guidance series. This tool does not perform poolability testing across lots and does not set the shelf life; it produces the per-lot inputs to that assessment.
Input contract
| Column | Type | Units | Required | Allowed range | Missing | Out of range |
|---|---|---|---|---|---|---|
| lot_id | text | none | Yes | Matches <<FILL: lot format>> | Reject | Reject |
| timepoint_months | numeric | months | Yes | 0 to 60, non-negative, ascending, no duplicates | Reject | Reject |
| potency_pct | numeric | % label claim | Yes | 50.0 to 150.0 | Reject | Reject |
| storage_condition | text | none | Yes | One of the controlled condition codes | Reject | Reject |
| ID | Requirement |
|---|---|
| IN-01 | Reads only the validated LIMS stability export from the read-only reporting replica. Manually edited copies are rejected by checksum comparison against the export manifest. |
| IN-02 | Rejects input if any of the four columns above is absent, naming the missing column. |
| IN-03 | Rejects input if any value in timepoint_months or potency_pct is non-numeric, naming the first offending row. |
| IN-04 | Rejects input containing fewer than six timepoints for a lot. |
| IN-05 | Records the SHA-256 hash of the input file in the provenance block. |
Calculation
Ordinary least squares regression of potency on time, fitted per lot per storage condition.
Slope:
b = sum_i (t_i - t_bar) * (y_i - y_bar) / sum_i (t_i - t_bar)^2
Intercept:
a = y_bar - b * t_bar
Predicted potency at the proposed shelf life T:
y_hat(T) = a + b * T
One-sided lower 95% confidence bound on the mean response at T:
LCB(T) = y_hat(T) - t_(0.95, n-2) * s * sqrt( 1/n + (T - t_bar)^2 / Sxx )
| Symbol | Meaning | Units |
|---|---|---|
| t_i | timepoint of observation i | months |
| y_i | potency of observation i | % label claim |
| n | number of timepoints for the lot and condition | count |
| s | residual standard deviation, square root of the residual sum of squares divided by n minus 2 | % label claim |
| Sxx | sum of squared deviations of t from its mean | months squared |
| T | proposed shelf life | months |
| ID | Requirement |
|---|---|
| CALC-01 | Computes b and a by ordinary least squares as stated above, per lot per storage condition. |
| CALC-02 | Computes y_hat(T) at the proposed shelf life supplied as a controlled parameter, not hard-coded. |
| CALC-03 | Computes LCB(T) as stated, using the one-sided t quantile at 95% with n minus 2 degrees of freedom. |
| CALC-04 | Applies no outlier exclusion. Any suspected outlier is handled by the out-of-trend procedure outside this tool, and the tool records the full input set used. |
| CALC-05 | Fails rather than extrapolating if T exceeds the last observed timepoint by more than <<FILL: months>>. |
Rounding
| Value | Precision | Rule | Stage |
|---|---|---|---|
| slope | 4 decimal places | half-up | final reporting only |
| predicted potency | 1 decimal place | half-up | final reporting only |
| lower confidence bound | 1 decimal place | half-up | final reporting only |
| ID | Requirement |
|---|---|
| RND-01 | All intermediate computation at full double precision. Rounding applied only when writing the output. |
| RND-02 | Potency values reported to one decimal place, half-up, matching the reporting convention of the validated LIMS so that the two never disagree on a boundary value. |
Reference dataset and expected values agreed before testing
Lot <<FILL: lot ID>>, long-term condition, seven timepoints.
| timepoint_months | potency_pct |
|---|---|
| 0 | 100.2 |
| 3 | 99.4 |
| 6 | 98.7 |
| 9 | 97.9 |
| 12 | 97.2 |
| 18 | 95.8 |
| 24 | 94.3 |
Hand-computed intermediate values, verified independently by the statistician before the tool was run:
| Quantity | Value |
|---|---|
| n | 7 |
| 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 b | -0.2440 % per month |
| intercept a | 100.1527 % |
| residual standard deviation s | 0.040432 % |
| y_hat at T = 24 months | 94.2964, reported 94.3 % |
| one-sided t at 95%, 5 degrees of freedom | 2.0150 |
| LCB at T = 24 months | 94.2343, reported 94.2 % |
| Lower specification limit | 90.0 % |
| Conclusion | Pass, lower bound above the specification limit |
Error handling extract
| Condition | Required behaviour | ID |
|---|---|---|
Non-numeric value in potency_pct | No output written, non-zero exit, message naming lot and row number | ERR-03 |
| Fewer than six timepoints for a lot | No output written for that lot, non-zero exit, message naming the lot and the count found | ERR-05 |
| Zero variance in timepoints (all timepoints identical) | No output written, non-zero exit, message stating the regression is undefined | ERR-06 |
| Input file hash does not match the export manifest | No output written, non-zero exit, message stating the input was not the validated export | ERR-01 |
Environment
python==3.11.8
numpy==1.26.4
pandas==2.2.1
scipy==1.12.0
statsmodels==0.14.1
Built into container image digest sha256:9c1d4b..., executed on analytics server ANSRV-01.
Traceability extract
| Requirement ID | Summary | Test case ID | Verification method |
|---|---|---|---|
| IN-02 | Rejects missing column | TC-02 | Negative test |
| IN-03 | Rejects non-numeric timepoint or potency | TC-03 | Negative test |
| IN-04 | Rejects fewer than six timepoints | TC-04 | Boundary and negative test |
| IN-05 | Records input hash in provenance | TC-12 | Inspection of output |
| CALC-01 | Slope by ordinary least squares | TC-05 | Known-answer test against hand calculation and an independent statistical package |
| CALC-02 | Predicted potency at shelf life | TC-06 | Known-answer test |
| CALC-03 | One-sided lower 95% confidence bound | TC-07 | Known-answer test against independent recomputation |
| CALC-05 | Fails on extrapolation beyond the allowed window | TC-08 | Negative test |
| RND-02 | One decimal place, half-up | TC-09a, TC-09b | Boundary test at 99.95 and 99.94 |
| OUT-02 | Controlled result field identified | TC-10 | Inspection of output schema |
| OUT-03 | Provenance block complete | TC-12 | Inspection of output |
| ERR-06 | Undefined regression fails loudly | TC-11 | Negative test |
| ENV-02 | Dependencies pinned | TC-13 | Inspection of manifest against the running environment |
| SEC-01 | Read-only toward source | TC-14 | Negative test, attempt to write to the source with the tool’s account |
Coverage: 14 requirements in this extract, verified by 14 distinct test cases, with 0 requirements left without a test case. The counts match rather than the test cases outnumbering the requirements, because TC-12 verifies two requirements at once, IN-05 and OUT-03, in a single inspection of the output provenance block.
Dashboard specimen extract, for contrast
For tool ANL-0021, the class B release results dashboard, the equivalent section 9 rows read as follows for two of the fourteen measures.
| ID | Measure | Definition in words | Source fields | Filter context | Precision | Independent check |
|---|---|---|---|---|---|---|
| MEA-03 | Lots released within target | Count of lots whose disposition date minus manufacture completion date is 30 days or fewer, divided by the count of lots disposed in the selected period, expressed as a percentage | lot.disposition_date, lot.mfg_complete_date, lot.status | Period slicer, site slicer | 1 decimal place | Recompute from the LIMS export in a separate spreadsheet on a frozen dataset |
| MEA-07 | Out-of-specification result rate | Count of results flagged out of specification divided by the count of reportable results in the selected period, expressed as a percentage | result.oos_flag, result.reportable_flag | Period slicer, test-method slicer | 2 decimal places | Recompute by direct query against the source replica |
Frozen verification dataset agreed before testing: 52 lots disposed in the period, of which 47 were disposed within 30 days. Expected MEA-03 = 47 / 52 = 90.4%. In the same period, 1,240 reportable results with 18 flagged out of specification. Expected MEA-07 = 18 / 1,240 = 1.45%.
Row-level security requirement for the same dashboard: the site A role sees 31 of the 52 lots and the site B role sees 21, and the two together account for all 52 with no lot visible to both.
Common inspection findings this specification prevents
- Testing was performed but no document states what the tool was supposed to do, so no result could have failed.
- The tool and the validated source system disagree on a value at a rounding boundary, and neither rounding rule was ever specified.
- A filter or date-window rule quietly changes the population the calculation runs on, and nobody can say what the intended population was.
- A specification limit, a shelf-life value, or a conversion constant is hard-coded in the tool, and it silently became wrong when the product changed.
- The tool substitutes a default when a value is missing, and the substitution is invisible in the output.
- A dashboard has fourteen calculated measures and one paragraph of documentation, so only the measures someone happened to think of were tested.
- Nobody can state what the tool is not valid for, so it was reused for a second product with different assumptions.
- Requirements exist but half of them have no corresponding test, and the gap was not visible because no traceability table was maintained.
- A refresh failed and the dashboard kept showing last week’s data with no indication, so a reviewer looked at stale results believing they were current.
How to adapt this specification
- Scale the depth to the risk class. A class C tool may need only sections 1, 3.2, 4, 6, and 10, and one page is a legitimate specification for it. Class A tools get everything.
- Delete sections 3 to 5 for a pure dashboard and complete section 9 instead, or complete both where a dashboard sits on top of a script.
- Write the calculation section before writing any code. Specifications written after the code are descriptions of what the code happens to do, and they never catch the error you were trying to catch.
- Agree the reference dataset and the hand-computed expected values with the independent reviewer before the tool is run against them. Expected values derived from the tool’s own output are not a test.
- State the rounding rule of the downstream system you must agree with, by name, in RND-03. This one line prevents a recurring class of discrepancy investigation.
- Keep the traceability table in this document rather than in a separate matrix for small tools. A separate matrix is worth maintaining only when the requirement count runs to the dozens.
- Treat section 10 as the most reused part of the document. When someone asks whether the tool can also be used for a different product or a different condition, the answer is either already there or the tool needs reclassification.
- Confirm the current status of every cited regulation and guidance in the governing SOP before issue.