Reading AFTEC Source — and Knowing What Actually Runs
Method notes for anyone doing AFTEC archaeology — ERP migration analysis, tracing a calculation, or answering “what does this screen actually do.” Verified 2026-08-07.
The one rule that matters: finding source in a directory tells you nothing about whether it runs. The UniData catalog decides, and the catalog can be older than the source on disk.
Where the source is
\\ad.ptihome.com\DFS\Data\LinuxShare\pro3prog\ (drive S: maps to \\ad.ptihome.com\DFS\Data). About 270
directories. Contents are current — items dated as recently as 2026-01.
| Directory | What it is |
|---|---|
PBSBASE | PSI’s PRO-III layer — the largest single source of running code |
VBBASE | PSI’s newer VB_* subroutine layer, called by the .NET/VB6 apps |
CABASE, IBASE, SFBASE, SYBASE, POBASE, APBASE, … | Base AFTEC modules — these run too |
PBSUTIL | Utilities and one-off fixes |
*PR (CAPR, IPR, MPR, …) | Driver PROCs — always plain text |
PBS.PARA | Batch paragraphs (DAILY.JOBS, WEEKLY.JOBS) |
AFTEC | Vendor source archive. Does not execute — see below |
MENUFILE | UniData hashed file; decodes to the whole green-screen menu tree |
*.1287 in a program or file name marks a PSI-specific extension to base AFTEC.
Encrypted vs readable
PBSBASE is roughly half plain text (~948 of 1,885 items); PBSUTIL similar; PBS.PARA and the *PR
PROC directories are entirely plain text. CABASE, PROBASE, UBASE and much of VBBASE are encrypted
with the AFTEC stream cipher.
Don’t try to decrypt. Read the compiled companion instead: every source item X has an object item _X in
the same directory, and the object keeps a null-separated literal table containing every OPEN’d file name,
the "<FILE> FILE (<FILE>)" open-error text, screen headings and prompts. That is enough to build a
program → table cross-reference for the whole system.
Two shortcuts worth trying first: an encrypted CABASE/X often has a plain-text twin at PBSBASE/X or
AFTEC/ACT.X, and the plain-text driver PROC in CAPR usually reveals the batch sequence.
The catalog decides what runs
Cataloging is a deliberate, per-program act — someone ran CATALOG <file> <item>. There is no
directory-precedence rule; no layer “supersedes” another.
A locally cataloged program leaves a type-C record in the account’s VOC, with the source file and item in
attribute 3:
C ⁞ /home/pro3/CTLG/CA1745.CA ⁞ PBSBASE CA1745.CA
Most programs are globally cataloged instead, with the objects in $UDTHOME/sys/CTLG and no VOC entry.
A copy of UniData home sits at S:\mrp1\DataBackup\ud.backup. Note the catalog directory is hashed into
single-letter subdirectories — CTLG/e/END.OF.SHIFT — so recurse when you look.
How PSI catalogs a program (John Tymes)
Most AFTEC programs are cataloged straight out of the editor with fibegf:
| Letter | Meaning |
|---|---|
fi | file — save |
b | compile binary |
c | catalogue |
g | global |
f | force |
fib saves and compiles only — no catalog, which is how source gets ahead of production. PROCAT
catalogs already-compiled code through a prompt sequence.
The prefix rule — get this wrong and nothing works
Many programs in AFTEC and PBSBASE are named as a letter-group, a period, then the name — I.1656,
I.0001, MRP.6810P, PO.0150. The cataloged name drops the prefix. PBSBASE/I.1656 is cataloged as
1656; IPR/I.0005P as 0005P.
Verified across the catalog — every one of these resolved by hash:
| Cataloged as | Source item |
|---|---|
1656 | PBSBASE/I.1656 |
0001 | PBSBASE/I.0001 |
0005P | IPR/I.0005P |
0007 | IBASE/I.0007 |
If someone compiles and catalogs one of these with the prefix, it will not work — not from the AFTEC menu, and not as a called program or subroutine, because every existing
CALLand menu entry references the unprefixed name.
This also matters when reasoning about the catalog: a name-based comparison must try the prefix-stripped form, or prefixed programs look like orphans. Four did in the first pass here.
Resolving provenance by hash
CATALOG copies the object. So you can identify what a program name resolves to by hashing the catalog
object against every _NAME object in pro3prog. Results as of 2026-08-07, over 3,318 catalog objects and
3,943 compiled source objects:
| Result | Count | Meaning |
|---|---|---|
| Exact byte match to a source object | 2,877 | Provenance proven |
| Same name, different bytes | 91 | Recompiled after cataloging — source on disk is not what runs |
No matching source item in pro3prog | 350 | Source lives elsewhere, or was deleted |
43 different source directories feed the catalog — PBSBASE 864, VBBASE 317, CABASE 193, SFBASE
115, IBASE 113, SYBASE 111, UBASE 94, APBASE 84, POBASE 83, and on down. The module directories all
run.
AFTEC is the sole exception — 0 of its 2,202 items source any cataloged object. It holds no compiled
objects at all, so there is nothing to catalog. Treat it as reference material only.
The drift hazard
Because CATALOG copies, recompiling without re-cataloging leaves the catalog copy running while the source
moves on. 91 programs are in that state. For those, reading pro3prog source tells you what someone
intended, not what production does.
The live example that proves it matters:
END.OF.SHIFT catalog copy (what runs) | 2024-09-11 |
PBSBASE/_END.OF.SHIFT object | 2025-02-24, 8 bytes larger, identical literal table |
An identical literal table with a small size delta means a pure control-flow change — and it is: a bare
STOP added early in the nightly, which would strand timesheets, WIP receipts, WIP close and the entire
evening financial block. It was written, compiled, and never re-cataloged, so it never went live. Confirmed
by behaviour: JOB.IP.1287 is written every night by a step that sits after the STOP.
If anyone recompiles and catalogs END.OF.SHIFT from current source, the nightly silently stops doing most
of its work. Same shape of risk applies to the other 90.
The 91
Four sit in the job-costing path — END.OF.SHIFT, PBS1803 (inventory valuation, writes the G/L side of
JOB.IP.1287), VB_W.7285 (WIP receipts), VB_JOB.COST.REV1 (the SO Manager Job Cost tab) — along with
GET.MAT, RPT.WIPLEDGER, TS.UPD and FIXJOBHRS.
The rest, by directory: PBSBASE 51, VBBASE 32, PBSUTIL 9, PROBASE 3, GLBASE / IBASE / UBASE /
WBASE 2 each, and one apiece in APBASE, ARBASE, PAYBASE, PCNBASE, POBASE, SYBASE, TESTBASE.
Notable names include MENU.PROCESSOR, MRP.DAILY, NOTIFY.REDBOOK, SEND.NOTIFICATIONS,
PROCESS.NOTIFY, WIPBMF.REV6, VB_PORECEIPT.REV2, VB_POMAINTWRITE.REV5 and most of the RPT.* Power BI
extract programs.
Two caveats before treating this as a to-do list. Drift means the bytes differ — not that the newer source is
correct; some of it is parked work-in-progress. And the 350 catalog objects with no source item in
pro3prog are a separate unknown: their source is either somewhere not searched or gone.
Reproducing the analysis
- Copy
$UDTHOME/sys/CTLG(3,318 objects, ~seconds over SMB withrobocopy /MT). - Copy every
_*item underpro3prog—robocopy S:\LinuxShare\pro3prog <dst> "_*" /S /MT:32. - SHA-256 both sides, recursing into the catalog’s letter subdirectories. Exact match proves provenance; same-name-different-bytes is drift; the catalog copy wins.
- For drifted or unmatched objects, extract the null-separated literal table and match on content.
A faster first pass, if you only need one program: sha256sum the catalog object on the host and grep the
source tree for a match, rather than copying anything.
Two gotchas that will skew the numbers if you miss them: recurse into the catalog’s letter subdirectories, and try the prefix-stripped name when matching by name — four programs were mis-filed as orphans in the first pass here for exactly that reason.
The original AFTEC documentation
S:\Dept\Computer\Documents\PTIS2\AFTEC\ holds the vendor’s own manuals — 71 files, mostly WordPerfect,
one per module, with screen layouts, field-by-field descriptions and per-program narratives. This is the
authority on what a program was designed to do, which is often not what PSI actually uses it for.
| File | Covers |
|---|---|
CABASE.wpd (710 KB) | Cost accounting — job/WIP ledgers, roll-ups, financial release/relief/close |
IBASE, WBASE, SFBASE, POBASE, GLBASE, APBASE, ARBASE, MRPBASE, OBASE, PAYBASE, SYBASE, EBASE, FSBASE, PMBASE, PBBASE, MBASE (.wpd) | The other modules; several have a …OVER.wpd overview companion |
AftecPro3Master1–3.pdf (12 MB) | The PRO-III master manuals |
GENERAL.WPD, PRO3PROG.WPD, aftecdoc.wpd, Timesheets.wpd, JOBHRS.WPD, WORKFLOW.WPD | Cross-cutting notes |
Convert with LibreOffice (installed locally, and on PS-PROXY):
& 'C:\Program Files\LibreOffice\program\soffice.exe' --headless --norestore `
-env:UserInstallation=file:///C:/Temp/lo_profile `
--convert-to txt:Text --outdir <out> <files>Batch roughly 80 files per invocation — passing them all on one command line exceeds the Windows command-length limit.
The parsed result is published as the AFTEC Module Reference — 799 programs across 19 modules.
Reading source and narrative together is what separates “this program writes that file” from “this is what
it was for, and PSI stopped using it.” The job-costing page has a worked example: the vendor narrative shows
CA1777/CA1778 are the standard-cost roll-up gated on financial release, which explains why PSI —
who never adopted financial release — posts actuals directly instead.
Related
- AFTEC Module Reference — what each module does, 799 programs from the vendor manuals
- AFTEC Job Costing & WIP — worked example of this method end to end
- AFTEC Subroutine Catalog — the
VB_*registry - Inventory & Work Orders