goatifi / docs /ROADMAP.md
KonoDioDaa's picture
Initial FlowTwin deployment
e7a9f02
|
Raw
History Blame Contribute Delete
8.3 kB
# FlowTwin — what to fix next
Written at the end of the build, from what actually broke. Ordered by value per
hour, not by size. Everything here is a known gap, not a wish list.
---
## P0 — before the final submission
### 1. The optimizer stops separating once the queue exists
**The bug.** Intervene at T+450 s and the winner is clearly better (peak density
2.45 → 1.74, queue 2,185 → 1,534). Intervene at T+900 s and *every* strategy
returns identical peak density and critical time; the winner is chosen only
because staggering reroutes nobody and so scores lowest on the reroute-cost term.
**Why.** Once a 4,000-person queue exists it drains at the gate rate (380/min)
no matter where new arrivals are sent. Peak density over the window is already
locked in, so `J` cannot distinguish the candidates. This is physically correct
and it only appeared after the queue-extent fix landed.
**Fix.** Add an end-of-window term to `J` — a strategy that leaves the queue
smaller at T+horizon is better even when the peak is identical. Concretely, in
`strategy/counterfactual.py` the metrics already carry `final_density` and
`final_queue`; add them to `OBJECTIVES` in `optimizer.py` with weights around
0.10–0.15 and re-run `scripts/run_benchmarks.py` to confirm the early case does
not regress. Also consider scoring the *integral* of density over the window
rather than its maximum.
**Test to add.** Assert separation at both an early and a late intervention
time, so this cannot silently return.
### 2. Verify the Hugging Face path against real weights
Nothing in the perception chain has ever run against downloaded weights — this
sandbox had no access to `huggingface.co`. On a networked machine:
```bash
pip install -r backend/requirements.txt
python scripts/fetch_hf_model.py
```
Expect the CSRNet candidate to be the risky one: the repo may ship a full module
rather than a `state_dict`, or use different layer names. `perception/huggingface.py`
already handles both shapes and falls through to YOLOv8n and then to YOLOS-tiny,
but **the fallthrough has not been exercised**. Budget an hour. If CSRNet
resists, take the detector path and say so in the pitch — the architecture is
the point, not which checkpoint won.
Then drop two or three crowd photographs into `data/perception/` with an
`index.json` giving each one a `zone_id` and `zone_area_m2`, so the Perception
panel has something to click rather than requiring an upload.
### 3. Commit and push
```bash
git init && git add -A && git commit -m "FlowTwin: AI crowd digital twin for F1 venues"
git branch -M main && git remote add origin <url> && git push -u origin main
```
`data/fallback/*.json` is gitignored (16 MB of generated frames). Anyone cloning
regenerates it with `python scripts/record_fallback.py`. The trained model *is*
committed (3.8 MB) so a fresh clone predicts properly without retraining. If the
repo must stay under a size limit, move the model to a release asset and have
`DensityPredictor` fall back to the analytic baseline — it already does that
cleanly.
---
## P1 — makes the submission materially stronger
### 4. Safety mode (compression risk) as a visible mode
The compression-risk proxy is **already implemented** — density growth, velocity
drop, queue growth and opposing flow all feed the risk score, and
`risk_contributions()` exposes the per-term breakdown. What is missing is the
proposal's in-event scenario and the framing.
Cheapest useful version: a third scenario on `circuit_alpha` where the crowd is
already inside and a large fraction converges on one zone (a fan-zone stage).
That is a new JSON in `data/scenarios/` plus demand groups pointing at
`CONC_NORTH` — no engine changes. Add a "SAFETY" toggle to the header that
switches the alert panel to rank by compression risk instead of flow risk.
Keep the Astroworld framing exactly as the proposal states it: a stress-test
reference for the *type* of scenario, never a claim of prevention.
### 5. Personnel dispatch
The largest genuinely-missing feature from the master proposal. Scope it small:
- A `resources` block in the venue JSON: id, type (security/medical), position, response speed.
- `DispatchScore = expected_risk_reduction − λ·response_time − µ·cost`, computed against the primary bottleneck.
- A map layer for unit positions and a dashed line to the recommended assignment.
- A `dispatch` intervention family so it appears in the strategy table alongside the flow levers.
Half a day. High pitch value because it answers "who should act", which no
crowd-monitoring product does.
### 6. Ablation study
The proposal asks for it and it is nearly free — the benchmark harness already
supports arms. Add: routing-only, prediction + routing, and the full
prediction + counterfactual loop. This is the cleanest possible answer to "which
part is actually doing the work", and right now that question has no data behind it.
### 7. Barcelona's static baseline is identical to shortest path
Both baselines produce byte-identical results because most origin–destination
pairs in the reconstructed topology have exactly one sensible route. That is a
legitimate finding and the README says so, but the benchmark column looks broken
at a glance. Either add a second rail approach so route choice exists, or
annotate the table in-place explaining why the two columns match.
---
## P2 — polish, if time remains
- **Pitch deck.** `docs/DEMO.md` has the narrative and every real number; it needs to become slides. Slide 7 (results) should be a screenshot of the strategy table, not retyped figures.
- **Deploy.** One box running `uvicorn` behind a reverse proxy is enough. Do not containerise for the sake of it; the demo runs from one command today.
- **Record a screen capture** of both demos as the true last-resort fallback, above the replay recordings.
- **Agent groups.** Families walk together and comply together; a `group_id` already exists in the schema but nothing uses it.
- **Uncertainty on predictions.** Quantile regression would give the alert a confidence band, which is honest and cheap with the existing training script.
- **Mobile/tablet layout.** Breakpoints exist down to 900 px but have not been exercised on a real device.
---
## Things not to change
Learned the hard way; each of these was a bug once.
1. **Do not average density over a whole corridor.** Per-cell evaluation is why a queue at a gate does not freeze people 200 m back. Reverting collapses throughput to about a tenth.
2. **Do not let a link accept people until it is physically full.** The backward-wave receiving function is what makes congestion spill back instead of a corridor silently absorbing an impossible crowd.
3. **Do not measure the queue only at the stop line.** Measuring it from everyone who has stopped is what lets a gate discharge at its real rate.
4. **Do not let routes transit grandstands.** They are seating bowls. Allowing it deadlocked Barcelona with 18,000 people stranded.
5. **Do not remove the U-turn guard or the penalty decay.** Without them, repeated interventions leave a residue bouncing between two nodes forever.
6. **Do not put a language model in the decision path.** It is the answer to "where is the AI" that judges respect, and the whole explainability story depends on the reasoning being the same arithmetic that produced the score.
7. **Do not let panels re-render every frame.** Frames arrive 5×/second; rebuilding a card restarts its entry animation and the panel goes invisible. This bug shipped once already.
8. **Do not unpin the thread limits** in `flowtwin/__init__.py`. A 66-row inference takes 1,000 ms on two threads and 9 ms on one.
---
## Pre-demo checklist
```bash
python scripts/build_venues.py # venues regenerate cleanly
cd backend && python -m pytest -q # 70 tests
cd .. && python scripts/ui_check.py # full acceptance path in a browser
python scripts/record_fallback.py # refresh replay insurance
```
Then, in the dashboard: run Simulation 1, wait for the prediction to read
"critical in N seconds" (roughly **T+07:30–T+10:00**), and press *Simulate
strategies* **then** — not after the alert has been red for minutes. See P0-1 for
why that timing matters until the optimizer is fixed.