docs/perceptual-information-budget.md
Perceptual information budget — and two corrections
Measurement. Classifies every apparently-invisible fact by whether it is genuinely independent, then measures the remaining carrier bandwidth and the resulting deficit.
First: two errors in perceptual-state-space.md
Both are the same class — the sweep varied field values that cannot occur — and both inflated the deficit.
Error 1 — building.blocked is not a fact
Building has fourteen fields: id label shortLabel kind districtId position footprint height accent activity health capacity evidence detail. There is no
blocked. The fixture added one, the renderer ignored it, and it was recorded
as an invisible fact. It is not invisible; it does not exist.
(blocked exists on CityNode, the HQ view model consumed by CityMap — a
different type in a different layer.)
Error 2 — agent status was varied independently of its own inputs
Measured in build.ts:
status = unstaffed if placement.kind === "unstaffed"
| active if blocked > 0
| steady if queueDepth > 0
| idle otherwise
status is fully derived. Varying status = active while holding
blocked = 0 produced a state composeWorld can never emit, and the resulting
"active ≡ steady" collision measured nothing real.
Re-measured over reachable states only — 4 distinct of 6:
| Reachable state | Distinguishable |
|---|---|
idle (b0 q0) |
✓ |
steady (b0 q3) |
✓ |
steady (b0 q9) |
✗ collides with q3 |
active (b5 q9) |
✓ |
active (b1 q1) |
✗ collides with b5 |
unstaffed |
✓ |
The status vocabulary is fully distinguishable. All four categories render distinctly. The real remaining gap is magnitude within a category: a viewer sees blocked but not how blocked.
The lesson generalises: a state space must be enumerated over reachable states, not over the Cartesian product of field values. Half the deficit I reported was unreachable states colliding with each other.
Classification of the genuinely invisible
| Fact | Category | Evidence |
|---|---|---|
agent status |
Derived | computed from placement + blocked + queueDepth; all three are categorically visible, so it needs no carrier of its own |
agent load |
Redundant | a priority-weighted normalisation of the same queue that produces queueDepth. Two carriers would spend two channels on one underlying fact |
agent queueDepth magnitude |
Independent | q3 and q9 are byte-identical; nothing visible distinguishes them |
agent blocked magnitude |
Independent | b1 and b5 are byte-identical |
building health = warn |
Independent | read from incident facts; not reconstructible from height, activity, footprint or identity |
building capacity |
Independent | read from capacity facts; and three states collide — 8/10, 10/10 and unmeasured |
district health |
Independent | keyed separately on district id (index.health.get(d.id)), not aggregated from member buildings, so it cannot be inferred from them |
district revenue |
Independent | declared in the estate; nothing visible implies it |
focus, shortLabel |
Observer-dependent | text carried by Html overlays. Requires reading, not perceiving — and is outside this instrument |
A fifth category was forced by measurement: not a fact (building.blocked).
That is a correction to the map, not an ontology extension — the vocabulary
already distinguishes "a fact" from "a field I invented."
The carrier budget
Measured across the reachable sweep. Capacity is perceptual — how many states an observer can reliably separate — and is stated as an estimate where it cannot be measured without observers.
| Carrier | Est. capacity | Current use | Remaining | Collision risk |
|---|---|---|---|---|
position.y |
high (continuous) | building height; agent idle-vs-not | low — already dual | high: adding a third meaning makes elevation unreadable |
geometry params |
high | footprint; height | low | medium |
opacity |
~3 levels | lot (0.35); unknown (0.5); district activity |
~1 level | high — already carries two distinct meanings |
color |
high (hue space) | building kind; agent identity | low | high — identity must stay stable |
emissive |
high | identity only (cleaned) | none — reserved | would re-break identity |
emissiveIntensity |
~3 levels | activity; lot; agent status |
~0 | high |
wireframe |
2 states | unstaffed |
0 — binary, spent | n/a |
| object presence (beacon) | additive | health=fail; agent blocked |
medium — more marker types possible | medium: markers compete visually |
scale |
high | none | full | none |
labels (Html) |
high, low-salience | shortLabel, focus |
unknown | low, but requires reading |
| animation | ~2–3 rates | link flow |
unknown | unmeasured by this instrument |
One high-bandwidth carrier is entirely free: scale. Everything else is
either spent, binary, or reserved for identity.
The deficit
Independent facts requiring a carrier, and the states each needs:
| Fact | States needed | States rendered | Deficit |
|---|---|---|---|
building health |
4 (ok / warn / unknown / fail) | 3 | 1 |
building capacity |
3 (headroom / at-limit / unmeasured) | 1 | 2 |
district health |
4 | 1 | 3 |
district revenue |
≥2 (declared / none) | 1 | 1 |
agent queueDepth magnitude |
≥2 bands | 1 | 1 |
agent blocked magnitude |
≥2 bands | 1 | 1 |
Perceptual deficit = 9 distinguishable states missing.
Down from the impression left by the previous map, which counted eight invisible facts — of which one did not exist, one was derived, and one was redundant.
Decision importance — reasoned, not measured
This ranking is judgement, and is marked as such. No measurement here establishes what an executive needs; that requires the observer study. Ranked by the decision that becomes wrong if the fact is not perceived:
| Rank | Fact | Decision at risk if unperceived |
|---|---|---|
| 1 | building capacity at-limit vs unmeasured |
Capacity planning. Acting on "we have headroom" when the truth is "we never measured" is the failure mode with no recovery — it is the missing-vs-negative error, and it is currently a three-way collision. |
| 2 | building health = warn |
Preventive intervention. A warning is the only state that is actionable before failure; invisible warnings convert prevention into response. |
| 3 | district health |
Portfolio triage. A whole product line can be failing while every building in it looks ordinary. |
| 4 | agent blocked magnitude |
Escalation sizing. Blocked is visible; severely blocked is not, so triage between two blocked agents has no visual basis. |
| 5 | agent queueDepth magnitude |
Load balancing. Lower consequence — reassignment is reversible. |
| 6 | district revenue |
Investment. Important to the business, but slow-moving and available in text; the render is not where this decision is made. |
Note the inversion against implementation difficulty: the top-ranked item
(capacity) needs three states from a carrier that has roughly one level left,
while the lowest-ranked (revenue) could take scale tomorrow. Ranking by
consequence rather than convenience is what surfaces that.
Status
Do not propose a Legend amendment. The deficit is 9, one high-bandwidth
carrier remains, and two candidate carriers — labels and animation — are still
unmeasurable by this instrument. Extending it to Html and animation is the
prerequisite to any encoding decision, because two of the eleven carriers cannot
currently be budgeted at all.