Add idle district lifecycle: decay then reap

The map only ever gained density: hubs were sized by lifetime-cumulative
bytes (so they never shrank) and were never removed. Now each hub has a
decaying activity level — quiet districts visibly shrink toward a dormant
dot — and after a configurable idle timeout (~40s, NC_REAP_TICKS) the hub
is demolished: faded out, removed with its road, and its per-org state
pruned in the controller.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-14 10:46:53 -07:00
parent 19f8cf08d7
commit 02f48ddd56
3 changed files with 68 additions and 7 deletions
@@ -39,6 +39,9 @@ final class TrafficController: ObservableObject {
scene.onSelect = { [weak self] key in
MainActor.assumeIsolated { self?.select(key) }
}
scene.onReap = { [weak self] key in
MainActor.assumeIsolated { self?.prune(key) }
}
if ProcessInfo.processInfo.environment["NC_DEMO"] != nil {
startDemo()
return
@@ -175,6 +178,17 @@ final class TrafficController: ObservableObject {
func deselect() { select(nil) }
/// A district was demolished drop its rendering/inspection state. The
/// resolution + RTT caches are kept (small, bounded by distinct hosts, and
/// save rework if the district comes back).
private func prune(_ key: String) {
orgEndpoints[key] = nil
orgProcesses[key] = nil
orgTitles[key] = nil
lastEndpointBytes[key] = nil
if selectedKey == key { selectedKey = nil; selection = nil }
}
private func buildInspection(_ key: String) -> OrgInspection {
let hosts = orgEndpoints[key] ?? []
var infos: [EndpointInfo] = []