System Internals · Confidential to the Yard

HANK TOOL IMS

Algorithms · Detection Math · Indexing Pathways
DOC HT-INT-01 SUBSTRATE single-file PWA RUNTIME vanilla js STORE local-first · OneDrive truth KEY NTI-NNNNNN

A laydown yard is just a promise about where things are. This is the machinery that keeps the promise — the math that moves a reel of fiber from a shelf to a tech's hands without ever losing the thread, and without letting a customer's catalog leave the building.

▢ stays on the machine

The Oracle catalog — oraclePN, descriptions, manufacturers. Customer data. Local disk & OneDrive only; never a third party.

M-00

Topology

Four storage tiers, one source of truth, zero servers in the customer-data path.

Every collection — items, products, requests, sos, assets, hankObjects, history — lives as an in-memory array backed by a single active adapter DB._a. The adapter is chosen at boot by descending preference, and once the operator runs the migration the whole rig drops to local and stays there.

adapter selectionboot · descending
// truth is local; the cloud copy is a shared file, not a database
tier := FileSystem    IndexedDB    localStorage
        (Supabase retired once ims_local_only := 1)

write(col, rec) ⟶ adapter.put | adapter.saveAll
              ⤷ FileSync.markDirty()     debounced push
delete(col, ids) ⟶ purge + FileSync.noteDelete()  tombstone
M-01

NTI Numbering

One key to rule the inventory — minted by exactly one authority, collision-free by construction.

The NTI number is the system's own product key. Oracle says one part number; the yard says one part number can mean several real things that satisfy the same spec. NTI gives each of those its own identity. Only the admin machine mints them; everyone else imports the map, so two numbers can never collide across devices.

monotonic counterO(1) amortized
counter₀ := max{ n : "NTI-"⟨n⟩ ∈ catalog } ∪ {0}

next()   counter  counter + 1
          emit "NTI-" ‖ pad₆(counter)        // NTI-017306

invariant  strictly increasing · single minter · never reused
cardinality  one Oracle PN ↦ {ν₁, ν₂, …}   substitutes get distinct ν
M-02

The Projection

A lossless one-way mirror: customer data goes in, only NTI comes out — and it reverses perfectly on the way back, but only if you hold the map.

This is the heart of it. Before any record touches the shared file it passes through the strip operator Π, a recursive walk that descends into nested line-items and variant lists alike. It resolves each product reference to an NTI and deletes the catalog fields — but only when an NTI exists to put them back. That single guard is what makes it safe: nothing is ever stripped that can't be restored, so a record is never left unreadable on the machine that owns it.

strip Π / rehydrate Π⁻¹depth-first · O(nodes)
C := { oraclePN, description, partNumber, manufacturer, model, mktPn }   // catalog data

Π(x)     = x                                   x scalar
Π([a…])  = [ Π(a) … ]
Π(obj)   = let ν = obj.nti ?? map⁻¹(obj.oraclePN)
           drop k∈C from obj  iff ν exists   ← the losslessness guard
           keep ν · recurse over the rest

Π⁻¹(obj) = re-attach C from map(ν)             needs the local map

invariant   f∈C removed  ⟺  ∃ ν : map(ν).f recovers f
privacy     image(Π) ∩ C = ∅            shared file holds no catalog field
identity    Π⁻¹ ∘ Π ≡ id   on mapped records
LOCAL RECORD nti: NTI-000412 oraclePN: ORA-1180 description: 288F… manufacturer: Corning qty: 342 shelf: A3-C NTI ⇄ Oracle map (local) SHARED FILE nti: NTI-000412 qty: 342 shelf: A3-C — no catalog — Π Π⁻¹
strip on push · rehydrate on pull · the map never leaves the machine
M-03

Convergence

Many hands, one file, no clobbering — last writer wins per record, deletes that stay dead, and a stale device can't raise the dead.

Several techs hit the same OneDrive file. There is no lock and no server, so the merge has to be order-independent. Each record carries an ISO-8601 stamp that sorts lexicographically as it ticks. Merging two versions of the same id keeps the later stamp. Deletions ride a separate tombstone set so a removed record stays gone — and a newer re-creation still wins over an old delete. Every push reads the file, merges its own changes over it, then writes; pulls only parse when the file's modified-time actually moved.

LWW register + tombstonescommutative · idempotent
merge(a, b) = argmaxₜ { a, b }            ties → incoming

admit(r)    ¬∃ T[r.id]  r.t           delete dominates older write
                                       newer write dominates old delete

push  = write ∘ merge ∘ read           read-before-write, never clobber
pull  = parse only if file.mtime ↑     cheap change-gate

theorem  ∀ replicas seeing the same op-set ⟹ identical state,
         independent of arrival order.
device A qty 300 · t=…:14:02 device B qty 280 · t=…:14:05 shared file OneDrive qty 280 later stamp wins
argmax over updatedAt · tombstones propagate deletes · stale re-adds rejected
M-04

Stock Engine

Material is consumed; equipment is loaned. The engine knows the difference, and it knows which shelf you meant.

When the same cable sits on two shelves, a sign-out has to pull from the right one. Source resolution gathers every candidate that matches the scanned token by id or barcode, then prefers the one at the named location. Consume decrements and logs a sign-out — material leaves the books because it got installed. Transfer is a move: consume at the source, merge into the destination, custody intact.

source resolution + consumeshelf-disambiguated
cand(σ)   = { i ∈ items : σ ∈ {i.id, i.barcode} ∪ i.allBarcodes }
src(σ, ℓ) = first{ i ∈ cand(σ) : i.shelf=ℓ ∨ i.loc=ℓ }  ?? cand(σ)₀

consume(σ, k, dest):
    t ← src.qty ;  k ← clamp(k, 1, t)
    if k ≥ t :  remove src · tombstone           line emptied
    else   :  src.qty ← t − k
    history ⊕ ⟨SIGNED-OUT, σ, k, dest, who⟩      never asks "due back"

transfer = consume(source) ⊕ merge(dest)              returnable / relocation
M-05

Indexing Pathways

One scan, six gates — the first that recognizes the token wins, every gate an O(1) probe.

A barcode off the gun is just a string. Resolving it is a cascade: the token falls through ordered hash indexes until one claims it. Oracle PN first, then the manufacturer part, then a known item barcode, its alternates, the marketing PN, and finally the part-group table that ties substitutes together. Miss everything and it's flagged unknown — an invitation to receive it, not an error.

lookup cascadelazy index · invalidated on mutation
σ  ⟶  idx_oracle  ⟶  idx_part  ⟶  idx_barcode
       ⟶  idx_allBarcodes  ⟶  idx_mkt  ⟶  idx_partGroup  ⟶  ∅

resolve(σ) = first non-∅ probe along the chain
each idxᵢ  hash map, built on demand, dropped when the catalog changes
∅ ⟹  "not in catalog" · offer Receive / Take to DM
scan σ ▾ idx_oracle idx_part idx_barcode idx_allBarcodes idx_mkt idx_partGroup product first hit wins ∅ unknown → Receive
ordered probes · O(1) each · miss is a doorway, not a dead end
M-06

Import Inference

Guess the columns, ask for help when unsure, and keep every single line.

A spreadsheet arrives shaped however the last person left it — sometimes the whole sheet crammed into one cell. The header mapper normalizes each column name and matches it to a field by keyword; gaps get handed to the model to sort out. And because one Oracle line can be several products, the master import runs in keep-every-row mode: each row becomes its own entry with its own NTI, duplicates and blank-key substitute lines preserved, only truly empty rows dropped.

column map + identity importheuristic ∪ model
autoMap(h) = field  where keyword-predicate(norm h) matches ; else ∅
fill ∅ with  Φ(headers, samples)        model assist, only the gaps

keep-every-row:  row ↦ entry            one NTI per line
    drop  ⟺  row is ⌀ (no PN ∧ no desc ∧ no part ∧ no mfr)
    keep  duplicate Oracle PNs · keep blank-PN substitutes
    |catalog| = |rows| − |⌀ rows|        the count finally matches the file
M-07

Anomaly Detection

The diagnostics surface what's wrong by set arithmetic — and they never act on it alone.

Integrity is checked, not assumed. Each scan over the data is a set operation: lines that group together but shouldn't, items pointing at catalog entries that don't exist, one barcode owned by two records, quantities that fell through zero. Everything found is flagged for a human. The audit flow moves shelf contents to a catch-bin instead of erasing them; normalization repairs records on load without deleting a thing. The machine notices. The operator decides.

integrity predicatesflag · never auto-delete
duplicates  = { g = group(items, ⟨oraclePN, loc, unit⟩) : |g| > 1 }
orphans     = { i : i.oraclePN ∉ catalog }
collisions  = { b : |{ owner(b) }| > 1 }
zero-lines  = { i : i.qty ≤ 0 }
custody-gaps= { a ∈ assets : status=out ∧ ¬∃ holder }

resolution  surface ⟶ one-tap fix ⟶ human confirm
audit       shelf ⟶ "Unlabeled" bin   move, don't delete
Colophon

Nothing is destroyed.
Only moved, flagged, or re-keyed.

That's the one rule underneath all seven modules. Data outlives the operation that touched it; the source of truth is singular; the human stays in the loop. Everything else is bookkeeping done carefully.

~12.5klines, one file 7collections 19,283rows, kept whole 0servers in the customer path
Vision & field Hank built it for the yard he runs. Marzel Greathouse was part of the vision — in on it before it had a name, and on the floor while it got built.
built by scanning real barcodes in a real yard  ·  compiled with care