Dock-to-stock eligibility determination tool — a Flask + SQLite web application that tracks part characteristics, collects subgroup measurements, renders SPC control charts, computes capability and performance indices, and applies a DTS eligibility gate against the sample-size-adjusted target tables published in the source handbooks.
Statistical methods implemented per:
- AIAG & VDA SPC Manual ("Yellow Volume"), 1st edition, February 2026
- Robert Bosch GmbH, Booklet No. 7 — Statistical Process Control, 11.2020
Not a validated quality system. Treat outputs as a calculation aid and verification tool — not as a substitute for validated SPC software (Q-DAS, Minitab, etc.) for formal production release decisions or customer-facing PPAP submissions.
- What it does
- Quick start
- Workflow overview
- Chart types
- Capability indices
- The DTS gate
- Process distribution panel
- CSV import
- Project layout
- Implementation notes
- What it deliberately does not do
- Comparison to commercial tools
Parts → Characteristics → Subgroups → Gate verdict.
Each part (drawing number, revision, supplier) carries one or more characteristics — any measurable dimension, form/position tolerance, or attribute pass/fail result that has a spec and a class. Each characteristic accumulates subgroups of measurements over time. From those subgroups, Gatekeeper computes:
- SPC control charts with live limits
- Stability assessment (violations, runs, trends, middle-third rule)
- Cp/Cpk, Pp/Ppk, General Geometric Method (Pg/Pgk), and z-Score/Bothe cross-check indices
- A rolling capability history trend
- A DTS gate verdict — eligible, not eligible, or insufficient data — with the specific reason(s) behind it
The gate result updates in real time as subgroups are added or deleted.
git clone <repo>
cd gatekeeper
pip install -r requirements.txt
python app.pyOpen http://127.0.0.1:5000. On first run the dashboard is empty; click Load demo data to populate it with a worked example (three characteristics on a fictional turbopump housing — one X̄/s, one X̄/R, one p-chart) so you can see the full workflow before entering real data.
The database is a single file: gatekeeper.db, created next to app.py on first run. Delete it to start over completely.
Requirements: Python 3.10+, pip (see requirements.txt — Flask, SQLAlchemy, SciPy, NumPy).
1. Create a part → Part number, name, drawing, revision, supplier
2. Add a characteristic → Name, class, study type, chart type, tolerance, n, α
3. Enter subgroups → Manual entry form OR bulk CSV import
4. Read the gate → Eligible / Not eligible / Insufficient data + reasons
5. Track history → Rolling Cpk/Ppk trend as subgroups accumulate
Characteristic class determines which target table row applies:
| Class | Process capability Cpk/Ppk target (n ≥ 125) | Machine performance Pmk target (n ≥ 50) |
|---|---|---|
| Critical | 1.67 | 2.00 |
| Major | 1.33 | 1.67 |
| Minor | 1.00 | 1.33 |
| Other | 1.00 | 1.00 |
Targets at lower sample sizes are linearly interpolated from VDA Table 8-1 / 9-3 breakpoints. If your n falls below the smallest breakpoint the handbook documents, the verdict is flagged as provisional.
Study type determines which target table applies (machine performance, preliminary process, process capability) and what sampling guidance is shown.
| Type | When to use | VDA ref |
|---|---|---|
| X̄/R | Subgroups n = 2–10, manual charting or simple software | 10.3.3 |
| X̄/s | Subgroups n = 3–10, software computing limits — statistically preferred | 10.3.3.2 |
| Median/R | Manual charting where median is easier than mean; n = 2–10 | 10.3.3.4 |
| I-MR | n = 1; destructive testing, low-rate processes, expensive parts | 10.3.3.5 |
| Type | When to use |
|---|---|
| p | Fraction nonconforming; lot size varies |
| np | Count nonconforming; lot size constant |
| c | Defect count per unit; constant area of opportunity |
| u | Defects per unit; area of opportunity varies |
All eight chart types compute limits dynamically via scipy.stats — the exact chi-square method for s-chart limits, normal quantiles for all location and range charts, and per-point limits for attribute charts with varying lot sizes.
Computed using within-subgroup sigma (σ̂ = R̄/d₂ or s̄/c₄) for Cp/Cpk, and overall (pooled) sigma for Pp/Ppk. Per VDA 7.4, Cp/Cpk are only reported once the control chart shows the process is stable.
Fits the selected distribution model (Normal, Lognormal, Weibull, or Folded-normal) to the pooled individual values using scipy.stats, then uses the 0.135%, 50%, and 99.865% quantiles of the fitted distribution to compute Pg/Pgk without assuming normality. This matters for naturally one-sided characteristics (flatness, roughness, runout) where a normal fit produces badly wrong PPM estimates.
Reads the actual tail probability from the fitted distribution's CDF/SF, converts it to an equivalent normal z-score, and reports Ppk.Z / Pp.Z — an independent cross-check against Pgk that should agree under the correct distribution model.
Configurable per characteristic: 0.27% (classic 3-sigma / AIAG convention) or 1% (VDA/Bosch convention). The multiplier u(1–α/2) is computed live with scipy.stats.norm.ppf — not hard-coded — so any α value works, not just those two presets.
For variable characteristics, the gate evaluates four conditions in order:
- k ≥ 25 subgroups collected — if not, verdict is Insufficient data regardless of the index value.
- Chart is stable — if not, Cp/Cpk are withheld and Ppk is reported instead (per VDA 7.4, Cp/Cpk require demonstrated stability).
- Target lookup — the appropriate index threshold for this characteristic's class, study type, and actual n, linearly interpolated between the handbook's documented breakpoints.
- Index vs. target — the gate passes only if the index meets or exceeds the threshold.
Attribute characteristics gate on stability and subgroup count only (Cp/Cpk are undefined for counted data), plus an optional acceptance-rate threshold entered in the characteristic's Nominal field.
Every verdict includes the specific reason(s) behind it: which target wasn't met, which stability rule fired, or how many more subgroups are needed.
Available for all variable characteristics. Displays between the control charts and the capability panel on the characteristic detail page.
Chart elements:
| Element | Color | What it shows |
|---|---|---|
| Step-polygon histogram | Blue filled | All individual measurements at their actual values |
| Fitted normal curve | Amber solid | Normal distribution using overall σ (Ppk sigma) |
| Second fitted curve | Blue dashed | Normal distribution using within-subgroup σ (Cpk sigma) — only when the two sigmas differ by > 8% |
| LSL / USL lines | Coral dashed | Specification limits with labeled callout boxes |
| Out-of-spec shading | Coral, low opacity | Regions beyond LSL and/or USL |
| ±3σ̂ lines | Blue dashed | Within-subgroup ±3 sigma boundaries (Cpk numerators) |
| ±3σ₀ lines | Amber dashed | Overall ±3 sigma boundaries (Ppk numerators), when sigmas differ |
| Mean line | Gray dashed | Grand mean x̄̄, labeled at the bottom of the chart |
When within-subgroup σ and overall σ differ by less than 8%, a single merged curve is shown — two nearly identical curves overlaid look like a rendering artefact and carry no additional information.
For naturally non-negative measurements (flatness, roughness, runout etc.) with no LSL set, the x-axis is clamped to start at zero.
Stats panel below the chart shows within-sg σ, overall σ, spec spread, and estimated PPM outside spec from the fitted normal — colour-coded teal (< 10 ppm), amber (10–1000 ppm), coral (> 1000 ppm).
Attribute characteristics (p/np/c/u): distribution panel hidden automatically.
Each characteristic's detail page has an Import CSV button next to the subgroup entry form, for backfilling historical data in bulk rather than typing it in one row at a time.
Variable:
timestamp, value_1, value_2, ..., value_n, notes
Attribute:
timestamp, sample_size, count_value, notes
timestamp and notes are optional. Column names are flexible:
sample_sizealso accepts:n,n_inspected,lot_sizecount_valuealso accepts:count,defects,nonconforming,rejects- For variable data, any column not recognized as timestamp/notes is treated as a measured value, left to right —
x1,x2,x3ortrial_1,trial_2,trial_3both work without configuration
Rows without a timestamp get synthetic ones, spaced one minute apart in row order. Import is all-or-nothing: if any row fails validation, nothing is written and every problem row is listed specifically so you can fix the file and re-upload once.
- Variable rows: values must be numeric
- p/np rows:
count_valuemust satisfy 0 ≤ count ≤ sample_size (a nonconforming count cannot exceed inspected count) - c/u rows:
count_valuemust be ≥ 0 only (defect counts are unbounded — one unit can have multiple defects) sample_sizemust be > 0 for attribute rows
Click Download a starter template inside the import dialog to get a CSV with the correct headers and one example row pre-filled for that specific characteristic's chart type and subgroup size.
gatekeeper/
├── app.py Flask routes — pages and the full JSON API
├── models.py SQLAlchemy models: Part → Characteristic → Subgroup → Measurement
├── constants.py Handbook lookup tables with inline citations
├── capability.py The statistics engine — every formula that produces a number
├── csv_io.py CSV parsing and template generation
├── analysis.py Orchestrates capability.py into API-ready payloads
├── seed_demo.py Demo data generator
├── requirements.txt
├── README.md
├── templates/
│ ├── base.html
│ ├── index.html Dashboard and part list
│ ├── part_detail.html Characteristic cards with live DTS badges
│ └── characteristic_detail.html All panels: gate, charts, distribution, capability, history
└── static/
├── css/style.css
├── js/app.js Shared modal/API/toast plumbing
├── js/charts.js Control chart and distribution chart renderers
└── js/vendor/
└── chart.umd.min.js Chart.js 4.x, vendored locally (no CDN)
| Route | Method | Returns |
|---|---|---|
/api/parts |
GET, POST | List / create parts |
/api/parts/<id> |
GET, PUT, DELETE | Read / edit / delete a part |
/api/parts/<id>/characteristics |
POST | Create a characteristic |
/api/characteristics/<id> |
GET, PUT, DELETE | Read / edit / delete a characteristic |
/api/characteristics/<id>/subgroups |
GET, POST | List subgroups / add one |
/api/characteristics/<id>/subgroups/import |
POST | Bulk CSV import |
/api/characteristics/<id>/csv-template |
GET | Download a starter CSV |
/api/subgroups/<id> |
PUT, DELETE | Edit / delete one subgroup |
/api/characteristics/<id>/chart-data |
GET | Control chart series + limits |
/api/characteristics/<id>/capability |
GET | Indices, stability, DTS verdict |
/api/characteristics/<id>/distribution |
GET | Histogram, fitted curve, reference markers |
/api/characteristics/<id>/history |
GET | Rolling Cpk/Ppk trend |
| Function | What it computes | Handbook ref |
|---|---|---|
get_constants(n) |
d₂, d₃, c₄, cₙ for n = 2–10 | VDA Table 10-3 |
u_quantile(α) |
Control-limit multiplier via norm.ppf |
VDA 10.3.3.2 |
grand_stats() |
x̄̄, R̄, s̄, σ̂_within, σ_overall | — |
xbar_limits() |
X̄ UCL/LCL | VDA 10.3.3.2 |
r_limits_approx() |
R chart UCL/LCL (normal-quantile method) | VDA 10.3.3.3 |
s_limits_exact() |
s chart UCL/LCL via χ² quantiles | VDA 10.3.3.2 |
i_mr_chart() |
I-MR limits | VDA 10.3.3.5 |
median_limits() |
Median chart limits (with cₙ correction) | VDA 10.3.3.4 |
attribute_limits() |
p/np/c/u per-point limits | VDA 10.3.3 |
stability_check() |
Violations, runs ≥ 7, trends ≥ 7, middle-third | VDA 7.5, BOSCH 4.3.1 |
_normal_indices() |
Cp/Cpk/Pp/Ppk | VDA 7.8.2 |
general_geometric_indices() |
Pg/Pgk via distribution fitting | VDA 7.8.2.1 |
zscore_bothe_indices() |
Ppk.Z/Pp.Z cross-check | VDA 7.8.2.3 |
lookup_target() |
Interpolated capability target for actual n | VDA Table 8-1, 9-3 |
dts_eligibility() |
Gate verdict | VDA 7.4, 8, 9 |
Exact chi-square s-limits rather than B3/B4 tables: scipy.stats.chi2.ppf(1–α/2, df=n–1) gives the exact quantile at any α and n, so no approximation table is needed and any α value works cleanly. This matches VDA 10.3.3.2's exact method rather than the older constant-table approximation most legacy SPC software still uses.
Capability target interpolation is linear between the handbook's documented n breakpoints. No extrapolation is performed past what the handbook actually specifies.
I-MR sigma path: the moving-range chart computes σ̂ = MR̄/d₂(n=2) inside i_mr_chart(), then the result is backfilled into the grand_stats dict that capability_summary() reads from. This is a distinct code path from the subgrouped chart types.
Float sanitisation (_sanitize_floats() in app.py): Python's json module emits non-standard NaN/Infinity tokens. Every API response passes through this before jsonify() to prevent silent browser parsing failures.
Frontend resilience: each of the seven render panels on the characteristic page runs in an independent try/catch (safeStep()). One panel failing leaves the other six working normally. Chart.js is vendored locally so a blocked CDN request can't silently break the entire page.
- PPAP / first-article documentation — this is a calculation tool; the formal submission package still needs a validated system with an audit trail.
- MSA / Gage R&R — measurement system analysis is a prerequisite to capability studies, not part of this tool.
- PFMEA or control plan content — link to those documents via a characteristic's Reference field.
- Real-time data acquisition — accepts manual entry and CSV uploads; no live gauge, CMM, or PLC feeds.
- Multi-user access control / audit trail — single SQLite file, no authentication. Suitable for personal or small-team use.
- DOE, regression, hypothesis testing — this is an SPC and DTS tool, not a general statistics platform.
- EWMA or CUSUM charts — only the eight chart types specified in the VDA handbook are implemented.
| Gatekeeper | Minitab | Q-DAS qs-STAT | |
|---|---|---|---|
| Primary job | DTS eligibility gate | General statistics platform | Enterprise automotive SPC |
| Handbook | AIAG-VDA Feb 2026 + Bosch 7 | ISO 22514, AIAG | ISO 22514-2 |
| Validated software | No | Depends on deployment | Yes |
| DTS gate logic | Native | Manual / macro | Manual |
| n-adjusted target interpolation | Built-in | Manual lookup | Manual |
| MSA / Gage R&R | None | Full | Full |
| Real-time data acquisition | None | Via Prolink (320+ devices) | Full |
| Distribution models | Normal/Lognormal/Weibull/Folded-normal | Many | Many |
| Formula transparency | Full source available | Closed | Closed |
| Cost | Free | ~$1.5–3k/seat/yr | Enterprise pricing |
Gatekeeper isn't competing with those tools — it's purpose-built for the specific DTS workflow: taking subgroup data, applying the exact AIAG-VDA handbook formulas, and emitting a documented, traceable eligibility verdict with all intermediate steps visible. Commercial tools compute Cpk; they don't natively compare it against a study-type- and class-specific target interpolated for the actual n and produce a structured verdict with reasons.
The practical position is as a calculation aid and pre-flight check alongside a validated system, or as the primary SPC tool for internal programmes where customer-facing validated-software requirements don't apply.
Both are freely available:
- AIAG & VDA SPC Manual — VDA QMC Yellow Volumes · AIAG catalog (SPCAV-1)
- Bosch Booklet No. 7 — Bosch supplier documentation
Every formula and constant in the codebase carries a comment citing the specific table or section number it came from.