Notes-Based Obsolescence Scan — Surfacing Hidden Obsolete Parts
Alex Walker flagged a recurring problem: AFTEC’s
OBSOLETEflag is an incomplete signal. Many parts are de facto discontinued, but engineers only discover this when they read the free-text notes attached to the part. These notes — “use 053804 instead”, “AB obsoleted DC coil”, “no longer available” — are the real source of truth. This scan surfaces them at fleet scale.
The Problem
In PRODUCT records, AFTEC has an OBS flag (attribute 8, values O/I). That flag is supposed to signal obsolescence. In practice:
- Engineers record obsolescence context in free-text notes on the PRODUCT.NOTES record, not by setting the OBS flag
- The flag is set inconsistently — some truly obsolete parts have never been flagged
- The notes are rich: they often name the replacement part, cite the vendor’s announcement, and explain the substitution reasoning
- A BOM exploder looking only at the flag misses most of the real obsolescence
Concrete demonstration: of 530 (job, part) hits with unambiguous replacement language in the notes across the GKN El Cajon fleet, 368 had no OBS flag set. 69 % of the obsolescence is invisible to anything that only reads the flag.
The Scan
Method
For each job:
- Fetch BOM via
GET /api/bom/dev/job/{job}— recursive explode, unique parts - Batch read PRODUCT.NOTES for all unique parts via
POST /api/data/dev/PRODUCT.NOTES/batch - Regex-scan the concatenated notes text for replacement language (discontinued, no longer available, use {part#}, replaced by, superseded, substitute, etc.)
- For parts that matched, batch read PRODUCT to check the OBS flag
- Enrich hits with manufacturer code and design category via
/api/manufacturer/dev/by-part/{pn} - Produce Excel report: one sheet for hidden obsolescence (no OBS flag), one sheet for all hits
Source: PSI.UniData.API/pipeline/notes_obsolescence_scan_batch.py
The batch endpoint
The per-part version of this scan (sequentially calling GET /api/data/dev/PRODUCT.NOTES/1!{pn} for each of ~7,000 parts across 8 machines) ran for 4+ hours before UniData session pool exhaustion jammed the API server. Full details in the deployment/ops lessons section below.
The batch endpoint (POST /api/data/dev/{table}/batch, added in commit cd2e08f) opens one UniData session and reuses the file handle for up to 5,000 key reads per call. The same scan with the batch endpoint:
| Phase | Per-part scan | Batch scan |
|---|---|---|
| BOM fetches (8 jobs) | ~3 min | ~3 s |
| PRODUCT.NOTES reads (5,447 keys) | ~2 h (est.) | 8.1 s (3 batches × 2-3s) |
| PRODUCT OBS-flag reads (264 keys) | ~15 s | 0.2 s |
| Manufacturer enrichment (264 hits) | ~15 s | ~15 s (still per-part) |
| Total wall clock | Never completed | 91.9 s |
Batch is ~150× faster on the UniData-heavy phases. The remaining bottleneck is manufacturer enrichment — an obvious candidate for a batch MFG endpoint next.
Scope — GKN Aerospace El Cajon Fleet
Eight active machines at GKN’s El Cajon facility:
| Job | Description | Unique parts |
|---|---|---|
| 1382 | Fan Blade Peener (roots & foils) | 924 |
| 1383 | Glass Bead Suction Foil Peen | 1,019 |
| 1384 | Robotic Shot Peen for Roots and Discs | 1,634 |
| 1795 | CITS Monitor JetKote III | 175 |
| 1836 | Std Robot Peen | 1,939 |
| 1962 | Suction Fan Blade Peen | 1,200 |
| 2096 | Robotic Shot Peen System | 2,175 |
| 2280 | IBR Shot Peen | 1,954 |
| Total | 5,447 unique |
Data quality gotcha — Jobs 1795, 1836, and 1962 have empty
CUSTOMER.NOin PROJECT.1287 but are linked to GKN El Cajon viaACCOUNT.NO=0397. Any customer search using only CUSTOMER.NO misses them. See AFTEC Customer Fields.
Top-Line Results
| Metric | Value |
|---|---|
| Unique parts scanned | 5,447 |
| Parts with any PRODUCT.NOTES text | 987 |
| Parts where notes contained replacement language | 264 |
| Total (job, part) hits (deduped appearances) | 530 |
| Already correctly OBS-flagged | 162 |
| Hidden obsolete — notes say replaced, NO OBS flag | 368 |
The 368 hidden-obsolete (job, part) pairs represent ~160 unique parts repeated across the eight machines. Several are used in six or more of the eight machines.
Findings by Category
1. Allen Bradley 100-C Contactor “DC coil renaming” (systemic)
A cluster of identically-worded notes dated 2012-11-06 by JDP:
AB obsoleted DC coil. "EJ" was "ZJ". Same footprint [...]
Affected parts:
| Part | Description |
|---|---|
| 037903 | 100-C23EJ10 24VDC 15HP contactor |
| 037944 | 700-CF310EJ 24VDC relay 3 N.O. / 1 N.C. |
| 037894 | 100-C09EJ10 24VDC 5HP contactor |
| 038878 | 100-C23EJ400 24VDC 15HP 4-pole |
| 045412 | 100-C43EJ10 24VDC 30HP |
| 039315 | 100-C16EJ10 24VDC 10HP |
| 037945 | 700-CF400EJ 24VDC relay 4 N.O. |
Significance: These are the everyday motor contactors on GKN’s robotic peeners. The old “ZJ” coils are gone; the “EJ” replacement is a direct drop-in but the renaming was never reflected with an OBS flag on the old part numbers. Engineers ordering from legacy prints may still specify “ZJ” variants.
2. Allen Bradley 193-1E Overload Relays (E1 Plus line discontinued)
Cluster dated 2021-02-02 by JDP:
"-1EFBB" was "-EEBB" (AB discontinued old E1 Plus line)
Affected parts:
| Part | Description |
|---|---|
| 051839 | 193-1EFBB overload, 0.2-1.0 A |
| 048766 | 193-1EFCB overload, 1.0-5.0 A |
| 048767 | 193-1EFDB overload, 3.2-16 A |
| 048768 | 193-1EFEB overload, 5.4-27 A |
| 050245 | 193-1EPB DIN rail adapter |
Significance: Every AB overload relay on GKN machines is affected. The replacements are in stock under the new part numbers but the old numbers are still cited on drawings.
3. Allen Bradley 2098 Drive / F-4030 & F-4050 Servo System (retrofit-required)
Available from Elwood, but AB has discontinued 2098 drive.
We should now be [using Kinetix]
| Part | Description |
|---|---|
| 026942 | F-4030-Q-H00AA 4000 RPM servo motor |
| 026481 | F-4050-Q-H00AN 4000 RPM servo motor with 56C face |
| 050616 | Y-1003-1-H00AA 115V servo motor |
| 046973 | 2090-U3BB2-DM44 drive-mounted breakout board (non-SERCOS) |
| 051346 | 2090-XXNPY-16S25 25 m power cable (no replacement) |
Significance: This is not a cosmetic relabel — the 2098 platform is end-of-life. Any GKN machine still running 2098 servo drives is on borrowed time. Cable part 051346 has no replacement per Rockwell — machines with long power runs may be stranded. Retrofit to Kinetix is the recommended path; this may warrant its own engineering proposal.
4. Grove Gear Reducers — “Gold and Enviroseal no longer available”
Cluster dated 2015-07-28 by SA:
GOLD AND ENVIROSEAL ARE NO LONGER AVAILABLE.
ORDER ALL GROVE GEAR [standard finish]
| Part | Description |
|---|---|
| 039703 | DHMQ-220-75-1.4375-56C-PV reducer |
| 040624 | GR-JMQ-826-60-L-56-PV reducer |
| 018741 | HMQ-220-80-1-1.4375-56C-PV reducer 1-7/16” bore |
| 062554 | GR-FHMQ818-7.5-HL-56-16 reducer 1” bore |
Significance: Not a functional obsolescence; the Gold and Enviroseal surface treatments are discontinued but the underlying reducers remain available. Spares ordering just needs to drop the finish code.
5. Lumberg → Remeke Connector/Cable Equivalents
At least a dozen Lumberg proximity-cable part numbers with identical notes:
Use 0xxxxx for Remeke equivalent.
Examples: 042618, 043931, 045410, 040161, 041026, 043930, 047891, 056820, 056821, 037333, 037894
Significance: PSI has a dual-source strategy — Lumberg is preferred but Remeke is the drop-in. Neither the Lumberg nor the Remeke part is OBS-flagged, so this shows up only in notes. Knowing the equivalence pair is valuable for spares cost optimization (Remeke is often cheaper).
6. FANUC A98L-0031-0025 Battery — fully obsolete
GEF said parts is now obsolete. New battery and new style case [required]
Single part: 038481 — A98L-0031-0025 lithium 6V battery.
Significance: Every FANUC-controlled GKN machine that uses this battery for CMOS/memory backup is at risk. The replacement is a different form factor — replacing it is not drop-in, requires the new case. This is worth a proactive customer-advisory communication.
7. PTI Physical-Level Parts (internal supersessions)
Many PTI-manufactured physical parts (part numbers 7xxxxx, 8xxxxx, 9xxxxx) carry “use [newer PTI part] instead” notes:
| Old | → New | Reason |
|---|---|---|
| 713501 SWECO (30”, 3D4”, POLY) | 910249 with stiff boots | high-vacuum applications |
| 785155 Suction feeder tube | 102412 | not recommended for grit |
| 816453 Rubber lining (std robotic) | 884069 | cabinets 80”×53” without grating |
| 884069 Rubber lining (80×53 std robotic) | 909465 | cabinets with grating |
| 903071 Rotary lance drive (RLD500) | 931681 | latest motor version |
| 865946 Z-axis carriage subassy | (replacement noted) | junction box (786235) obsoleted |
| 883288 BNS-819 switch/conn L.H. | 221197 for R.H. | connector handedness |
| 805104 Media hopper weldment | 277314 | updated weldment |
| 805103 Virgin hopper side | 271026 + bars | internal revision |
Significance: These are engineering internal supersessions, not vendor obsolescence. They don’t impact customer spares orders (both old and new numbers remain valid), but they matter for new-build BOMs — using the old part number pulls an outdated subassembly into the build.
8. Long Tail — One-Off Vendor Substitutions
The remaining ~250 hidden-obsolete hits are one-offs:
- Schmersal safety switch 031814 — plastic adapter replaced by 045682
- Hoffman barrier kit F-44BK60 (005130) — use 057766
- Phoenix receptacle 047482 — obsoleted 2019
- Hilti KBTZ2 anchor (054689) — discontinued, use KBTZ2
- Ashcroft gauge 010406 — use 047734 instead
- Parker 95U-6-062 polyurethane tubing (033735) — obsolete per Parker’s website
- Marsh gauge 011681 — use 047733
- Clemco blast hose coupling 046359 — use 055273 for Plicord
- Enidine shock 002983 — OEM-1.0 obsoleted by vendor
- McMaster hardware — many small items where supplier changed
Each alone is modest impact. Collectively they represent hundreds of lines of uncoded institutional knowledge.
Implications
For engineering
- Treat PRODUCT.NOTES as load-bearing. The OBS flag is advisory at best; the real obsolescence status lives in notes. Any tooling that reads AFTEC for component selection must read notes.
- Update the OBS flag for the 368 (job, part) hidden-obsolete hits so the flag becomes reliable over time. This is a one-shot data cleanup — the spreadsheet has the list.
- New PTI supersessions (section 7) should be propagated to active BOMs where the old part is still referenced. Roll-forward policy TBD.
For spares / customer service
- GKN El Cajon spares orders should default to the replacement part unless the customer explicitly requests the original. The spreadsheet is a quote-time cheat sheet.
- FANUC A98L battery needs a proactive customer advisory — the replacement is not drop-in.
- AB 2098 servo drives need retrofit planning for affected machines (026942 / 026481 / 050616 are the signal parts).
For tooling (MCP/API)
- Add a field to the obsolete-parts search response that includes the first replacement-language phrase from the notes, so tool users see the context without another API call.
- Consider a batch manufacturer-lookup endpoint to close out the remaining ~15s enrichment phase.
- The regex approach is fast and effective. An AI-augmented pass (Azure OpenAI over regex hits) could additionally extract the replacement part number as structured data — a GPT 5.4 Mini trial on three GKN jobs identified explicit replacement parts for 208 of 256 AI-identified hits. That’s the natural next step.
Operational Lessons
This run surfaced two ops issues worth recording.
UniData session-pool exhaustion
The per-part version of this scan leaked UniData sessions at scale. The first attempt made ~7,000 sequential GET /api/data/dev/PRODUCT.NOTES/{id} calls across six machines over ~4 hours. Eventually every UniData endpoint began returning HTTP 000 (connection timeout). Cause: DataQueryService opens a session per call, and under sustained sequential load, session cleanup was not keeping up. A Restart-Service PSI.UniData.API on PS-PROXY cleared the condition.
Fix: The batch endpoint (one session per batch of up to 5,000 reads) is both much faster and exerts far less pressure on the session pool. Going forward, any “read many records” workload should use batch, not iterate.
Follow-ups:
- Audit
DataQueryServicesession lifecycle under exception paths - Add a semaphore on concurrent UniData operations
- Add a deep health check (
/api/health/deep) that reads a real record with a short timeout, and an external watchdog on PS-PROXY that restarts the service if deep-health fails twice consecutively
GitHub Actions self-hosted runner required interactive session
Deploying the batch endpoint sat queued for over an hour until someone logged into PS-PROXY. The GitHub Actions runner service should run unattended. Likely mis-configured as a console app or service without the required “Log on as a service” rights. Runner needs to be reinstalled with --unattended or have its service account rights fixed.
Next Steps
- Populate OBS flags for the 368 identified hidden-obsolete (job, part) hits — one-time data update via AFTEC.
- Apply the same scan to other high-value fleets (e.g., AB 9/Series CNC machines from the CNC obsolescence analysis).
- Build a batch manufacturer-lookup endpoint — closes the 15 s enrichment gap.
- AI-augmented pass — run Azure OpenAI over the regex hits to extract structured replacement-part mappings.
- Automate it — nightly scan of recently-edited BOMs, flag new hidden-obsolete hits in a Redbook-style queue.
Related Pages
- PSI.UniData.API — REST API including the new batch endpoint (
POST /api/data/dev/{table}/batch) - AB CNC Obsolescence Analysis — related fleet-wide obsolescence study
- AFTEC Customer Fields — why CUSTOMER.NO alone misses 3 of the 8 GKN El Cajon machines
- Spare Parts Data Model — AFTEC spare-parts tables and manual flags