Kaden runs several Claude chats against this codebase simultaneously. These rules exist so we don't overwrite each other. If you are an AI session: read this whole file before your first edit, and follow it.
Re-read before you write. Another chat may have changed a file since
you last saw it. Never edit from a stale copy; fetch the current content
first, especially main.tsx and fuel.ts.
BUILD bumps (main.tsx, const BUILD): read the CURRENT value and
bump by one. Never set it to a number you computed earlier in your chat —
it has probably moved. Every client-file change (fuel.ts, ui.ts,
transport.ts, repairs.ts, schedule.ts, ...) needs a bump or phones
never see it: /app.js?v=BUILD is cached immutable for a year.
Run check_floating.ts before shipping server changes. NOTHING may
outlive its request on Val Town — an unawaited promise dies with the
isolate and 500s a LATER, unrelated request ("resp.body?.cancel is not a
function"). Every push/notify/archive call must be awaited (keep the
.catch(() => {}) — fail quietly, but finish before the response).
Run _shipcheck2.ts (or equivalent) after client edits: fetch
/app.js, new Function(js) to prove it parses, confirm your markers are
in the served bundle. The client files are giant template literals — NO
backslashes, no backticks, no ${ in client code, ever. One slip ships a
bundle that throws on parse and the whole app goes dark on phones.
This includes COMMENTS: a backslash-n inside a // comment becomes a real
newline before the browser sees it, splitting the comment and leaving the
rest of the sentence as code. Both failure modes happened on 8/26 writing
one confirm() dialog. For newlines in client strings use
String.fromCharCode(10).
Databases and externals:
current_hours on a Tenna ASSET (registers as a manual meter
adjustment and corrupts utilization). No DELETE exists in Tenna.Product rules: never auto-alter a route (drafts push verbatim; a draft/auto push never overrides a manager's push); no personal names in fueler-facing UI ("the manager" is the approved wording); suspect paper meters are flagged, never corrected without Kaden's confirmation; don't fabricate GPS accuracy — planned route data is not GPS-verified data.
Scratch files start with _ (like this one's siblings). Don't delete
another chat's _ files mid-flight; there are ~100 and a cleanup pass
will happen on Kaden's go.
VIEWAS / realBoss() / isBoss() in fuel.ts: bosses get a
"View as crew" toggle; isBoss() reflects the toggle, realBoss() is the
truth. Gate UI on isBoss() so crew view stays honest.fuel_meterflag.ts — shared impossible-meter check used by BOTH the
review report and /api/fuel/histlog. Change it in one place only.OPEN_LOGIN = true in DEV (any PIN). Flip before prod.deadMeterSet() = fl_meter_trust ∪ fl_dark_seen ∪
fl_stuck_seen. fl_stuck_seen is AUTO-populated by stuckSweep() (a meter
that didn't move between two fills = stuck; self-clears when it moves) —
never hand-edit it. lastMovedMap() feeds m.h_moved, rendered by the
client's movedNote() next to every hours number.Kaden's go. The fuel module (fuel.ts + fuel_api.ts + the 12 fuel_* helpers) was COPIED to ndx-shop and every fl_* table was MIGRATED to that val's own sqlite (37 tables, 12,224 rows, counts verified). SQLite is per-val — this val's fl_* data is now the STALE copy.