diff --git a/src/features/editScene/AGENTS.md b/src/features/editScene/AGENTS.md
index 732aff8..91ad6af 100644
--- a/src/features/editScene/AGENTS.md
+++ b/src/features/editScene/AGENTS.md
@@ -847,6 +847,25 @@ WeekScheduleRules, stats = {}, scoreHook = {}, warnings* )`:
only) for the stat-driven choices (6.8.10).
- Fallbacks warn once per distinct line per build.
+**Runtime store (6.8.4a — runtime motion/traffic NOT flipped yet):**
+`NpcPopulationSystem::generateAreaPopulation` runs the weekly build
+alongside the daily one (seed `effSeed ^ kWeekScheduleSeedXor
+0x27d4eb2f`, default rules) and stores it on the area —
+`weekScheduleOf(registryId)` returns the `WeekSchedule`,
+`weekUsageOf(areaIndex)` the build's pick tally. The scoring flows
+through an adapter onto `systems/ScheduleScoring::score`, so
+`ecs.schedule.set_score_hook` steers weekly picks too; stats
+snapshots stay empty until 6.8.10. **Migration:** the
+`npcWork`/`npcInterest` registry columns rebind to the weekly
+resolves (the first week's sticky `work:
` and the first
+`leisure:` pick; the old Interest placeholders remain only
+for tagless areas). Pure probes stay bit-identical; the runtime
+swap (motion `entryAt`/helpers + traffic legs) is 6.8.4b.
+`NpcScheduleDebugOverlay` (**F7**) gained a Week pane per selected
+NPC: Mon-Sun day selector (initial = the clock's day-of-week), a
+"today" line, From/To/Activity/**Query -> Location** rows and the
+usage tally (top-4).
+
Runtime is NOT wired yet (6.8.4): motion/traffic keep the daily
`generateSchedules()` product; the week verifier
`TownSchedule::weekEntryAt(week, day, hour)` exists for it.
diff --git a/src/features/editScene/demos/demo-taxi/PLAN.md b/src/features/editScene/demos/demo-taxi/PLAN.md
index 645782f..3a1ba5b 100644
--- a/src/features/editScene/demos/demo-taxi/PLAN.md
+++ b/src/features/editScene/demos/demo-taxi/PLAN.md
@@ -4538,8 +4538,9 @@ feet sliding.
### Phase 6.8 — DSL macros, symbolic schedules and POIs
**Status: IN PROGRESS — 6.8.9 stats foundation, 6.8.1 DSL macros,
-6.8.2 POI/tag model (a+b) and 6.8.3 weekly schedule generator DONE
-(2026-10-29); 6.8.4 runtime integration + migration next.** Rewritten
+6.8.2 POI/tag model (a+b), 6.8.3 weekly schedule generator and
+6.8.4a weekly store/F7/migration DONE (2026-10-29); 6.8.4b
+runtime day-tiling flip + week-rollover probe next.** Rewritten
2026-10-28: the original bullet list mixed four independent features
and contradicted the clock-pure motion core; it is now split into
workstreams with explicit design decisions, task-sized pieces and
@@ -4858,27 +4859,63 @@ symbolic schedule generator) next.**
**Task 6.8.4 — Runtime integration + migration (workstream B).**
+**Status: 6.8.4a DONE (2026-10-29) — the weekly store, the registry
+rebind migration and the F7 week pane are in (runtime motion/traffic
+NOT flipped yet); the day-tiling flip + rollover probe are 6.8.4b.**
+
- `NpcPopulationSystem` stores weekly schedules per area and the
resolved bindings; `NpcMotionSystem` reads the day-of-week tiling
through the same `entryAt()` path (clock-pure, no latch);
`NpcTrafficSystem` keeps deriving drive legs from the same
entries, so walking and driving never disagree.
-- Indoor scheduling follows the entry contract (6.8.12): interior
- destinations approach via the building's entry POI; the symbolic
- tier completes interior entries entity-less there, the live tier
- despawns/respawns at the door — no behavior change vs the current
- `isIndoorKind` rules.
+- **Implemented (6.8.4a):** every area population build
+ (`generateAreaPopulation`) now also runs the pure
+ `generateWeekSchedules` (seed `effSeed ^ kWeekScheduleSeedXor
+ 0x27d4eb2f`, default rules) and stores it on the area:
+ `weekSchedules` (registryId -> WeekSchedule) + `weekUsage` (the
+ build's pick tally); accessors `weekScheduleOf(registryId)` /
+ `weekUsageOf(areaIndex)`. The scoring flows through an adapter
+ onto `systems/ScheduleScoring::score` — the Lua override
+ (`ecs.schedule.set_score_hook`) steers weekly picks (exact hook
+ contract: only the candidate + snapshot). Stats snapshots stay
+ EMPTY this phase (6.8.10 samples them live at week start).
+ **Migration:** the `npcWork`/`npcInterest` registry columns
+ rebind to the weekly resolves — `npcWork` is now the first
+ week's sticky job location (a real `work:` when the
+ area has Work locations, else the old Interest fallback) and
+ `npcInterest` the week's first leisure pick (`leisure:`,
+ else curb/interest fallbacks) — the Interest placeholders are
+ gone for tagged towns; the taxi "Send by taxi to interest/work"
+ buttons and the F7 columns read the rebound values deterministically.
+- F7 overlay: **Week pane** (per selected NPC): Mon-Sun day
+ selector (initial selection = the clock's day-of-week), a
+ "today: (clock day N)" line, per-entry rows
+ From/To/Activity/**Query -> Location** (empty queries show the
+ raw location) and the build's usage tally (top-4 in the pane;
+ the full list lives in the location inspection).
+- Indoor scheduling follows the entry contract (6.8.12): unchanged
+ this phase — the weekly entries resolve to approach-anchored
+ LocationSet names like the daily ones do.
- Migration: existing `npcWork` Interest placeholders rebind to the
new Work locations once; schedules still recompute on load at this
stage (6.8.10 turns the weekly store into saved state).
-- F7 overlay: week view per NPC (day selector), resolved location
- names next to their tag queries, per-location usage counts.
+- **Remaining (6.8.4b):** flip `NpcMotionSystem`'s active-entry
+ evaluation and the shared `nextLocationChangeOf`/
+ `walkTravelHours` helpers (and through them
+ NpcTrafficSystem's drive-leg derivation + the claim replay) onto
+ the weekly day-tiling (day-of-week = `(absoluteDay % 7)`, the
+ daily schedule as the fallback), the week-rollover determinism
+ probe, and the full `--test-*` battery re-run.
- Done when: motion/traffic behave as before on a default town,
weekly variety is visible in the overlay, and scrubbing the clock
across a week boundary reproduces positions bit-exactly.
- Verification: `--test-motion`, `--test-determinism`,
- `--test-traffic-schedule`, `--test-taxi`, `--test-parking` all
- pass; new week-rollover determinism probe.
+ `--test-traffic-schedule`, `--test-taxi`, `--test-parking`,
+ `--test-detail`, `--test-population-switch` all PASS unchanged
+ (the runtime is untouched so far — weekly variety is visible in
+ the overlay; the swap comes with 6.8.4b); the week probe in
+ road_geometry_overlap_test grew the usage-tally identity check
+ (picks == members-with-a-job + leisure picks).
**Task 6.8.5 — Schedule realism rules (workstream B, content).**
diff --git a/src/features/editScene/roadlib/TownSchedule.cpp b/src/features/editScene/roadlib/TownSchedule.cpp
index e4ed24e..c57efcb 100644
--- a/src/features/editScene/roadlib/TownSchedule.cpp
+++ b/src/features/editScene/roadlib/TownSchedule.cpp
@@ -258,7 +258,8 @@ std::vector generateWeekSchedules(
const TownLocations::LocationSet &locations, uint32_t seed,
const WeekScheduleRules &rules,
const std::unordered_map &stats,
- const ScoreHook &hook, std::vector *warnings)
+ const ScoreHook &hook, std::vector *warnings,
+ std::map *usageOut)
{
const WeekIndex ix = buildWeekIndex(locations);
@@ -577,6 +578,11 @@ std::vector generateWeekSchedules(
out.push_back(std::move(ws));
}
+ if (usageOut) {
+ usageOut->clear();
+ for (const auto &kv : usage.counts)
+ (*usageOut)[kv.first] = kv.second;
+ }
return out;
}
diff --git a/src/features/editScene/roadlib/TownSchedule.hpp b/src/features/editScene/roadlib/TownSchedule.hpp
index 21e3ccb..74dc30a 100644
--- a/src/features/editScene/roadlib/TownSchedule.hpp
+++ b/src/features/editScene/roadlib/TownSchedule.hpp
@@ -2,6 +2,7 @@
#include
#include
+#include