▶ CONTINUE 6/22 (Outbound isochrone feature + security incident)
TL;DR
- OUTBOUND ISOCHRONE shipped (commits 7cb4b4c→7c03454, all live): direction=inbound|outbound flag (inbound=home-finder byte-stable; outbound='from here, how far can I go', access anchored at the click, _run_pass_outbound forward RAPTOR, kernel UNCHANGED). Fixes residential origins (Piscataway) where inbound 422'd.
- P&R/K&R/Drive+Transit/Uber+Transit/bike+transit = drive/uber/bike to a station CAPPED at the 'Max to stn' control, transit beyond (NOT the prior full-drive blend). Page controls: Max-to-stn, Max-time (→180), Timing (Fastest=best-departure default / Typical=median). P&R tuned to OTP (Penn 72m≈OTP71).
- Route/origin-aware drive+uber TOLLS + tiered PARKING (7c03454, raptor-design/fares.py): fares.side()=NJ|NY|SI, crossing_toll (Hudson/SI $16.79pk/$14.79off, Verrazzano $7.46, within-zone $0), dest_parking $35 CBD/$15 NYC/$8 SI/$0 NJ, engine._drive_extras per-cell + direction-aware. FIXED a real bug: outbound drive cost was $0 for every cell (priced the origin not each dest).
- SECURITY: React2Shell reinfection of geo2 remarketing-web (Jun-14 pre-patch window) + stale geo realestate dropper CONTAINED 2026-06-21 (vectors stopped, droppers purged, C2s blocked, fleet swept clean, creds rotated). Apps patched (15.5.19/15.3.9). Open: persist firewall blocks, remove krish from docker group, PasswordAuthentication no.
- GOTCHAS: engine restart is async (503 while GPU graphs load — poll a real outbound transit req); purge BOTH engine + adapter caches after a cost/logic change; GitHub push routes via geo (bundle→fetch→push temp ref); FE build needs node v18 + openssl-legacy.
CONTINUE — 2026-06-22 — Outbound isochrone feature + security incident
Host: geocoder (RTX 5080, 172.26.1.95) · GPU engine hexmap-api :8098 (systemd)
Live: https://multimodal.certihomes.com (geo2 .151; FE pm2 tlccommute :3000,
adapter pm2 multimodal-adapter :5055). Repo: tlcengine/gpu-pilot @ 7c03454 (pushed).
Read first: memory outbound-isochrone-direction.md, geo-security-and-pm2-state.md,
then this. Engine source = hexmap-api/{engine,app}.py + raptor-design/fares.py;
FE/adapter mirrors in multimodal/{fe-patches,adapter-src}/ (live copies on geo2).
DONE this session
A. SECURITY INCIDENT — React2Shell reinfection, contained. geo2 remarketing-web
(Next 15.x) was re-popped Jun-14 (pre-patch window) → credential exfil to C2
153.75.91.241; geo had a stale May-23 realestate dropper (C2 168.144.47.129).
Contained: vectors stopped, droppers purged (evidence → geo:~/incident-evidence-
20260621/), both C2s iptables-DROP'd on geocoder+geo2+geo. Apps were PATCHED Jun15-16
(remarketing 15.5.19, cma-ui/dossier 15.3.9 ≥ fix); 2026-06-21 fleet sweep = NO
post-patch compromise (macstudio clean per separate session); keys+secrets rotated
post-breach (owner-confirmed); remarketing-web/worker restarted online. See
geo:~/INCIDENT-react2shell-20260611.md + memory.
B. Adapter perf + FE hover (commit 55ea73e). adapter orjson + _RING_CACHE memo
(serialize 290ms→25ms; drive /click 12.7s→0.25s — also load recovery after the forex
runaway drained); Map.js onMapLoad monkey-patches queryRenderedFeatures to drop
missing layers → kills the maplibre@3×react-map-gl@6 hisochrone-fill throw.
C. OUTBOUND ISOCHRONE — the big feature (commits 7cb4b4c→7c03454, all live):
- direction=inbound|outbound flag. Inbound (default, byte-stable) = "who can reach
here" (home-finder). Outbound = "from here, how far can I go" — access anchored at
the click. Engine _run_pass_outbound (forward RAPTOR, 1 source, per-cell egress);
kernel UNCHANGED. Adapter sends outbound on all map clicks.
- P&R/K&R/Drive+Transit/Uber+Transit = drive/uber/bike to a station (CAPPED at the
"Max to stn" control), transit beyond. adapter maps drive+transit→pnr,
uber+transit→knr; engine paints the capped access shed (time>pnr_max_drive_s→UNREACH)
+ the transit reach. bike+transit caps the bike shed + bike-access seeds the same way.
- Page controls (FE TransitMethodsBar): Max to stn (5-120, shows for any access+transit),
Max time (30/45/60/90/120/150/All-180, client-side cap), Timing (Fastest=
best-departure / Typical=median). Display horizon raised 120→180 (adapter BUCKETS +2 bands).
- Best-departure (np.min over deps) default for outbound transit (OTP best-itinerary);
P&R tuned to OTP (pf 1.1/1.0, park 5min, 20 railheads) → Penn 72m ≈ OTP 71.
- Route/origin-aware drive+uber TOLLS + tiered PARKING (commit 7c03454, fares.py):
fares.side()=NJ|NY|SI; crossing_toll(zo,zd,peak) (Hudson/SI $16.79pk/$14.79off,
Verrazzano $7.46, within-zone $0); dest_parking $35 CBD/$15 NYC/$8 SI/$0 NJ;
engine._drive_extras(parking) per-cell + direction-aware. Fixed a real bug:
outbound drive cost was $0 for every cell (priced the origin, not each dest).
PENDING (precise, act-cold)
- Toll model refinements (offered, user may want): per-borough parking rates (now
flat $15 outer-NYC); distinguish tolled East-River TUNNELS ($7.46 Queens-Midtown/
Brooklyn-Battery) from the free bridges (now all $0 within NY); zones are bbox
approximations in
fares.side— Hudson(NJ/NY) split is solid, East-River Man/Bklyn coarse (doesn't affect cost since within-NY=$0). - Feed refresh (Phase D): feed 511 calendar expired 2026-05-16; engine pins
service_date=20260415. Refresh before production. Multi-region via the 961-feedpropsql.gs.feedsregistry (only NYC MTA loaded today). - Security follow-ups: persist the C2 iptables blocks (not reboot-persistent);
remove krish from docker group; set
PasswordAuthentication noon geo2/geo. - Drive on GPU: drive is the lone OSRM (CPU) holdout; cuGraph car graph = sub-second.
DECISIONS (what the user chose + why)
- P&R/K&R/Drive+Transit/bike+transit = capped access + transit (NOT full-drive blend, which was the prior a2a4b08 behavior — superseded). Cap = the "Max to stn" control so the USER tunes the extent. Drive+Transit ≡ P&R; Uber+Transit ≡ K&R (combining a drive/bike access WITH transit MEANS access-to-station). Drive ALONE = full drive shed.
- Timing: Fastest (best-departure) is the default, Typical (median) a toggle — best matches OTP and packs more reach per band; user wanted the choice on-page.
- Outbound for all map clicks; inbound reserved for the home-finder.
GOTCHAS (don't relearn)
- Engine restart is async — healthz 200 ≠ ready; a fresh transit request returns 503 while the GPU graphs load (~30-60s). Poll a real outbound transit request.
- Caches: after any engine cost/logic change, purge BOTH
hexmap-api/cache/*.jsonAND geo2multimodal-adapter/cache/*.json, or stale payloads shadow the new surface. - GitHub push routes via geo (geocoder has no GitHub key): bundle
<prev>..main→ scp to geo →git fetch bundle main:refs/temp/x; git push origin refs/temp/x:main; update-ref -d(leaves geo's dirty 152-file tree untouched). - ruff --fix strips an import added BEFORE its first use (F401) — add imports in the same edit as the code that uses them, or re-add after.
- FE build:
export PATH=…node/v18.18.0/bin:$PATH; npm run build(openssl-legacy);pm2 restart tlccommute. Hard-refresh to pick upindex-*.js. - sudo pw =
/home/krish/secert.txt(typo'd name); geo2 sudo too. - bike+transit is res-9 (objective:time); drive-family is res-8 — use the response's
out_resfor h3 lookups (res-8 lookup on a res-9 payload = false UNREACHED).