# The Twelve-Layer Environmental Cognition Stack *Real Signal Research · 2026-06-06* ## Environment is not a data source Pick any consumer AI product that claims to understand a user's environment and look at how it treats the word. A weather API call. A location lookup. A calendar read. A "current activity" classifier. In most production systems environment is a single feature among many — a flat read from an external service, dropped into a prompt alongside whatever else is at hand. We argue this framing is the source of a long list of category errors in consumer AI. Environment is not a data source. It is a composable interpretation problem; the interesting properties live in how interpretations stack rather than in any single one. A weather reading on its own tells you nothing about whether someone will walk three minutes to a cafe. The weather reading composed with a transit-rhythm reading, a place-atmosphere reading, an intent reading, and an attention-saturation reading produces a probability — and the probability is what the system actually needs. This essay walks through the twelve interpretation layers that compose into what we call **environmental cognition** in Real Signal — the substrate observing Cluny Court (501 Bukit Timah Road) plus five adjacent activated pockets. The stack is the engineering companion to the silence-correctness essay [Real Signal Research 2026a] and to the preprint that defines the Attention Ethics layer [Real Signal Research 2026b]. The silence-correctness essay describes what restraint looks like as a measurable metric. This one describes what restraint operates over. ## The twelve layers, in order Each layer below has a single sentence answering *what question does it answer*, a list of feeding signals, and one concrete example drawn from a Cluny Court afternoon. ### Layer 1 — Geospatial substrate *Where do things exist, what is adjacent to what, what corridors of human movement connect them.* The floor of the stack; every other layer attaches to a pocket, an outlet, or a walking-distance bucket whose coordinates are settled here. Feeds: Google Places metadata (`google-places.js`), the pocket registry (`pockets.json`), outlet rows with lat/lng plus pocket assignment, and `walkability.js`. At Cluny Court, a user at the corner of Bukit Timah Road and Cluny Park Road resolves to `pocket_id = cluny`, with twenty-two outlets in a three-minute walk along two corridors. "Indoors near here" means about eight specific outlets, not a generic radius search. ### Layer 2 — Weather and comfort *What environmental resistance is the user feeling right now.* Rain hesitation, shelter-seeking, comfort-floor breaches. Feeds: NEA PSI and weather APIs [NEA 2024], pulled by `weather-geo.js` and `env-snapshot-loop` every fifteen minutes into `env_snapshots`. Layer-2 substrate composes into the Moment's `movement_friction` dimension. On a rainy Tuesday at Cluny Court at 14:42 SGT, the env snapshot reads 24 °C, light rain, humidity 88% — comfort floor ≈ 0.4, shelter-seeking prior ≈ 0.7. Outdoor-movement signals carry a headwind; stay-indoors signals carry a tailwind. ### Layer 3 — Transit and rhythm *What time-of-day rhythms are pulsing through this neighbourhood.* Commuter peaks, school release windows, lunch returns, transition gaps. Feeds: the LTA DataMall API [LTA 2024] via `lta-data.js` and `lta-poll-loop` into `lta_signals` — bus arrival cadences as foot-traffic proxies. Public-holiday and school-term feeds add context. Each pocket also carries an observed DNA fingerprint (`pocket_dna_runtime`) capturing rhythms that survive across days. On a Tuesday at 14:42 SGT at Cluny Court, the transit substrate reads as post-lunch lull; school release is forty minutes out; bus-arrival density sits at roughly 60% of peak — the rhythm layer marks this hour as a *transition gap*, which the cognition layer reads as an opportunity for calm-work framings rather than urgency. ### Layer 4 — Place atmosphere *What is the emotional texture of this pocket in the last fifteen minutes.* Atmosphere is a four-dimensional reading written every fifteen minutes per pocket. Feeds: `pocket_atmosphere` rows with calm, social_energy, productive, stress dimensions plus `primary_state` and `anomaly_flag`, composed by `pocket-atmosphere.js` from outlet hours, place categories, observed review tags, and recent traffic snapshots. On a rainy Tuesday at 14:42 SGT at Cluny Court, the latest reading carries calm 0.71, social_energy 0.32, productive 0.66, stress 0.18, primary_state `calm_productive`. Calm has been gently rising over the past hour as the rain intensified and indoor outlets absorbed circulating foot traffic. ### Layer 5 — Human intent *What does someone in this pocket plausibly want right now.* Intent is a first-class surface, not a guess: each entry in the `INTENTS` registry is a named shape (focus-seeking, decompression-seeking, comfort-seeking, family-time, working-quietly, sheltering, social-low-energy) with its own indexable page at `/intent/:pocket/:slug`. Feeds: `intents.js`, the watcher-event payload recording intent-slug clicks, and the user archetype profile when one exists. On a rainy Tuesday at 14:42 SGT at Cluny Court, intent shows elevated traffic to `/intent/cluny/work-quietly` and `/intent/cluny/shelter-from-rain` relative to the previous five Tuesdays. The user landing now is statistically more likely to want a calm productive surface than a social one. ### Layer 6 — Attention noise *Is the channel already saturated; should silence be preserved.* The anti-noise layer. The system reads its own recent emission history and asks: are we already speaking too much in this pocket, to this user, on this channel? Feeds: `signals` (the unified emit log), `notifications_log`, `notifications_dismissed`, and `user-fatigue.js`. Output: the Moment's `signal_saturation` dimension (rolling 60-minute window per pocket), plus Gate 0b and the saturation bump applied by Gate 4. On a rainy Tuesday at 14:42 SGT at Cluny Court, saturation reads 0.18 — well below the 0.5 bump threshold and the 0.7 silence threshold. Had the same reading been 0.72, Gate 0b would close and the cognition layer would emit silence even if every other layer agreed. ### Layer 7 — Merchant state *Which outlets have idle pressure, surplus risk, or recovery potential right now.* The supply side of the substrate — whether anything specific exists to surface, not just whether the moment is right. Feeds: `merchant_profiles` (nightly-refreshed), `merchant_alerts`, `merchant-energy.js`, `surplus-engine.js`, and `outlets.unit_number` plus hours for precise targeting. On a rainy Tuesday at 14:42 SGT at Cluny Court, three outlets show elevated idle pressure and one shows surplus risk with a closing window approaching. The cognition layer knows not only that the *moment* could support a calm-work signal, but which *specific outlets* would be appropriate destinations. ### Layer 8 — Offer intensity *What level of attraction energy is appropriate given the moment and the merchant state.* Five named tiers, classified by `classifyOfferIntensity` in `offer-intensity.js`: silent, atmosphere, pairing, rescue, urgency. Feeds: the Moment composite, merchant-state from Layer 7, `waste-anticipation.js`, the Moment Quality Score from `moment-quality.js`, and environmental priors from `environmental-priors.js`. On a rainy Tuesday at 14:42 SGT at Cluny Court, given MQS in the `forming` band, movement-friction at 0.66, surplus-risk on one outlet but not closing yet, the classifier returns `atmosphere` — a sentence describing the pocket's calm-productive state, with a soft-door hyperlinked outlet name in the line, and nothing more. ### Layer 9 — The Moment Engine *What is the present-moment composite, and should we be speaking at all.* The keystone. Layers 1–8 compose into a single `Moment` object per pocket, computed by `composeMomentFor` in `moment.js` and refreshed every fifteen minutes by `moment-quality-loop`. The Moment names dimensions previously scattered across primitives: `primary_state`, `attention_density`, `signal_saturation`, `movement_friction`, `calm_probability`, `fragility`, `half_life_minutes`, `expires_at`, `should_stay_silent`, `silence_reasons[]`, plus a `reasons[]` array carrying provenance per dimension. On a rainy Tuesday at 14:42 SGT at Cluny Court, the Moment composes as calm_probability 0.71, signal_saturation 0.18, movement_friction 0.66, fragility 0.34, half_life 38 minutes, `should_stay_silent` false, `primary_state` calm_productive — the reasons array points back at every contributing layer. ### Layer 10 — Explanation engine *Why did the agent speak, and why did it stay silent.* Every emission carries its own reason. Every silence carries its own reason. The resonance engine (`resonance-engine.js`) records the why; the observation router attaches a `reasonSummary` of ≤240 characters to every Observation; `/merchant/resonance` renders the explanation. Doctrine: *silence with no recorded reason is the bug, not the feature*. Suppose at 14:42 SGT on a rainy Tuesday at Cluny Court the cognition layer composes a candidate signal and Gate 0a closes it because resonance scored 0.42. The resonance engine writes a row with `decision = silent`, `reason = resonance_below_threshold`, score 0.42, substrate snapshot pointing back at the Moment. The merchant whose outlet would have received the proposal can view this on `/merchant/resonance` — an instrument readout, not a marketing claim. ### Layer 11 — Watcher memory *What have users actually done in this pocket, and what does that tell us about how to read the substrate next time.* The feedback loop. Feeds: `watcher_events`, `notifications_log.opened/clicked/converted`, `signal_feedback`, and `predictions_ledger` reveals. `user-archetype-learner.js` updates per-user confidence; aggregate patterns absorb into `pocket_dna_runtime`. On a rainy Tuesday at 14:42 SGT at Cluny Court, the watcher trace shows that on the previous three rainy Tuesdays at this hour, `atmosphere`-tier signals produced higher dwell and zero dismissals, while `pairing`-tier signals produced two dismissals out of three. The cognition layer feeds this back into Layer 8, which prefers atmosphere framings under matching signatures. ### Layer 12 — Distribution *How does interpretation reach the surfaces that need it, both human and machine.* Where the substrate becomes legible — to consumers via push and `/present`, to merchants via resonance and the autopilot inbox, to crawlers via 522 intent URLs and 13 server-rendered surfaces, to AI assistants via the MCP server. The artifacts: shadow profiles at `/observed/:id`, intent landings at `/intent/:pocketId/:slug`, the live pocket surface at `/pocket/:id/live`, the public visibility set (`/silence`, `/stream`, `/changelog`, `/sustainability`, `/api`, `/embed`, `/notebook`), the MCP server at `/api/mcp`, `llms.txt`, and JSON-LD embedded in every SSR pair. Doctrine: *a signal that nobody can see is the same as silence*. The calm-productive reading at Cluny Court at 14:42 SGT on a rainy Tuesday, composed into an Observation, surfaces as a push to opted-in users (through the voice lock), a soft-door line on `/intent/cluny/work-quietly` plus its SSR pair, a row in the `/stream` chronological feed, and a structured response to any AI assistant querying the MCP `get_pocket_moment` tool. All four reach the same conclusion at the same time because they all read from the same Moment object. ### The stack at a glance | # | Layer | Question answered | Keystone substrate | |---|---|---|---| | 1 | Geospatial | Where do things exist | `outlets`, `pockets.json` | | 2 | Weather + comfort | What resistance is present | `env_snapshots` | | 3 | Transit + rhythm | What time-of-day pulse | `lta_signals`, `pocket_dna_runtime` | | 4 | Place atmosphere | What is the emotional texture | `pocket_atmosphere` | | 5 | Human intent | What does someone plausibly want | `intents.js`, `watcher_events.payload.intent_slug` | | 6 | Attention noise | Is the channel saturated | `signals`, `notifications_log`, `user-fatigue.js` | | 7 | Merchant state | What outlets have idle pressure | `merchant_profiles`, `surplus-engine.js` | | 8 | Offer intensity | What attraction energy is appropriate | `offer-intensity.js`, `moment-quality.js` | | 9 | Moment Engine | Should we be speaking at all | `moment.js` (keystone) | | 10 | Explanation engine | Why speak / why silent | `resonance-engine.js` | | 11 | Watcher memory | What have users actually done | `watcher_events`, `predictions_ledger` | | 12 | Distribution | How does interpretation reach surfaces | `/api/mcp`, SSR routes, JSON-LD | ## The two architectural commitments The twelve layers are held together by two doctrinal anchors. They are not features of any one layer; they are the structural commitments that make the stack coherent. ### Lawful synthesis, not data ownership Every signal source in the stack is public, licensed, or first-party observational. We do not scrape, do not buy proprietary location traces, do not copy commercial datasets. The LTA DataMall feed is a public-API read; NEA weather and PSI are open government feeds; Google Places is consumed under its public licence; outlet review tags come from publicly-readable reviews with attribution in `src/lib/source-register.js`. Personal-data scrubbing runs unconditionally at the content-safety layer per the Singapore Personal Data Protection Act [PDPA 2012, as amended 2020]. The strategic posture is straightforward. Maps, weather, transit, place metadata — these are commodities. The companies that "own" the proprietary versions will outspend us a hundred to one on acquisition. We do not compete on data ownership. We compete on *interpretation quality*: how well twelve open signals compose into a usable read of the present moment. Interpretation compounds where data does not. ### Resonance over engagement The default for every emission in Real Signal is silence. The agent earns each emission through the seven sequential gates of the Attention Ethics layer plus a Moment-level silence check, measured and published as silence correctness [Real Signal Research 2026a]. A system that maximises emission frequency optimises for the wrong objective; a system that maximises *intervention legitimacy* — the fraction of moments where speaking was the right call given what the environment showed afterwards — optimises for what the user actually values. This is what makes the twelve-layer stack a cognition layer rather than a recommendation engine. Recommendation engines emit by default; their architectural question is *what* to recommend. Cognition layers stay silent by default; their architectural question is *whether* to speak. Twelve layers of interpretation are the prior work that has to happen before that question can be answered honestly. ## The composition pattern The interesting property of the stack is not any single layer but how they compose. Four claims worth naming directly. **Layer 9 is the keystone; layers 1–8 feed it.** The Moment is not a thirteenth layer — it is the composition object. Its constructor reads from atmosphere (4), env snapshots (2), recent emission history (6), DNA (3), attention density (6), and merchant state (7), with geospatial substrate (1) resolving the pocket. Layer 5 (intent) and Layer 8 (offer intensity) are read alongside the Moment by downstream decision-makers, because they are decision-time properties rather than environmental ones. New code should call `composeMomentFor(supabase, pocketId)` rather than re-querying feeds individually. **Layer 10 annotates Layer 9's outputs.** Every Moment produces a `reasons[]` array attached to its dimensions; every decision against a Moment is re-annotated by the resonance engine into a structured silence event or emit event. Every output, whether emission or silence, carries provenance back to the layer that contributed. This is what makes restraint inspectable. **Layer 11 feeds back into Layer 6.** Watcher memory closes the stack. The notifications-log, signal-feedback, and predictions-ledger feeds compose into the user-fatigue model and the pocket-DNA layer, which alter how Layer 6 reads attention noise on the next pass. A user who has dismissed three of the last four emissions lowers the system's saturation tolerance for that user. The stack is not a feedforward pipeline; it learns its own posture against the watcher trace. **Layer 12 is where Moment plus Explanation become surfaces.** Distribution is the single point where internal state becomes external — to humans through push and live surfaces, to merchants through resonance and proposals, to crawlers through SSR pairs and JSON-LD, to AI assistants through MCP. The Observation abstraction (`api/_lib/observation.js`) is the canonical shape: one Observation produces one resonance reason and one explanation, and every channel formatter consumes the same Observation. Channels cannot diverge because they read from the same source object. ### A worked trace: rainy Tuesday at 14:42 SGT A user lands on Real Signal at 14:42 SGT on a rainy Tuesday in Cluny Court and asks (via the intent surface or a search-engine landing) *where can I work quietly this afternoon?* The query traces through all twelve layers: | Layer | Reading | Substrate touched | |---|---|---| | 1 — Geospatial | resolved to `pocket_id = cluny`, 22 outlets in walking radius | `outlets`, `pockets.json` | | 2 — Weather | 24 °C, light rain, comfort floor 0.4, shelter-seeking prior 0.7 | `env_snapshots` row at 14:30 | | 3 — Transit | post-lunch lull; school release 40 minutes out; transition gap | `lta_signals` + `pocket_dna_runtime` | | 4 — Atmosphere | calm 0.71, productive 0.66, stress 0.18, `primary_state = calm_productive` | `pocket_atmosphere_latest` | | 5 — Intent | elevated `/intent/cluny/work-quietly` clicks vs same-hour-last-5-Tuesdays | `intents.js` + `watcher_events.payload` | | 6 — Noise | signal saturation 0.18; user fatigue low | `signals`, `user-fatigue.js` | | 7 — Merchant | three outlets idle-pressured; one with surplus risk but window open | `merchant_profiles`, `surplus-engine` | | 8 — Intensity | MQS forming-band; movement-friction 0.66 → softens to `atmosphere` | `offer-intensity.js`, `moment-quality.js` | | 9 — Moment | calm_probability 0.71, fragility 0.34, half_life 38min, `should_stay_silent` false | `moment.js` composed | | 10 — Explanation | reasonSummary: "calm window forming, rain supporting indoor stay, channel quiet" | `resonance-engine.js` writes a row | | 11 — Watcher memory | previous 3 rainy Tuesdays: atmosphere-tier produced higher dwell, zero dismissals | `watcher_events`, `predictions_ledger` | | 12 — Distribution | Observation surfaces to `/intent/cluny/work-quietly`, the live page, MCP `get_pocket_moment`, push channel; JSON-LD attached | `/api/mcp`, SSR routes, push | The user sees a single observational sentence describing the calm-productive state of the pocket with a soft-door reference to one of the three idle-pressured outlets, explainable back through the resonance row to every layer that contributed. The merchant whose outlet was named sees the same explanation on `/merchant/resonance`. The crawler indexing `/intent/cluny/work-quietly` reads it through the SSR pair plus JSON-LD. An AI assistant asking MCP `get_pocket_moment` for `cluny` reads the same Moment. Four surfaces, one composed object. ## What this enables that single-source AI cannot A single-source environmental AI — weather alone, transit alone, place atmosphere alone — produces *reactive* observations: it tells you what is true right now. Composition produces *anticipation*: what is likely to be true a short distance into the future, with what confidence. The twelve-layer stack is what makes anticipatory environmental intelligence possible. Five concrete predictions the composed stack produces today, each from substrate rather than a learned model trained over historic logs: | Prediction | Definition | Example reading | |---|---|---| | **Calm-seeking probability** | P(a user landing now wants a calm environment) — composed from atmosphere.calm minus signal-saturation minus movement-friction plus weather pressure | At Cluny Court 14:42 SGT, calm-seeking ≈ 0.71; the agent biases toward calm-work framings | | **Movement willingness** | P(a user is willing to walk three minutes) — composed as 1 minus Moment.movement_friction | Under light rain at Cluny Court, movement willingness ≈ 0.34; pairings biased toward already-here outlets | | **Offer-intensity threshold** | Which of five intensity tiers is appropriate — composed from MQS + merchant state + environmental priors | At Cluny Court at this moment, threshold = atmosphere; pairing and rescue available but rejected | | **Quiet-window decay** | When the current calm state is likely to collapse — composed from Moment.expires_at + fragility + half_life_minutes | Calm expected to hold through approximately 15:20 SGT, with rising fragility past 15:00 | | **Merchant receptivity** | P(a given merchant will receive a proposal positively right now) — composed from `surplus-engine` + `merchant-energy` + idle_pressure | Three outlets currently receptive; one at elevated surplus risk would prefer a rescue-tier proposal | The voice rule on every prediction is *probabilistic, not certain*. "Calm through approximately 15:20 SGT" is permitted; "calm until 15:20 SGT" is rejected by the voice lock. Every forecast is sealed into the `predictions_ledger` at composition time and scored against observed reality by the `predictions-reveal-loop` cron one or more hours later — a tamper-resistant track record [Real Signal Research 2026b]. The meta-claim: this is *anticipatory environmental intelligence*, not reactive environmental data. A single-source system can tell you it is raining. The composed stack can tell you that the rain plus the post-lunch lull plus elevated focus-seeking plus three idle outlets plus low saturation compose into a calm-work window with a 38-minute half-life and 0.34 fragility — and that the appropriate response is an atmosphere-tier signal rather than a pairing nudge or silence. ## Closing: the stack is what restraint operates over Without the twelve-layer stack, *silence correctness* is a slogan. With it, silence correctness is the runtime property the stack produces. A system that does not compose environment cannot meaningfully restrain itself — it has nothing to restrain against. A weather-only AI can only ask "is the weather notable" and emit when it is. There is no second question to ask, no Layer 6 attention-noise reading to check against, no Layer 9 Moment to fail Gate 0b on. The default is emission because there is no layer of interpretation that would justify silence on its own. Composition is the precondition for honest restraint. The companion silence-correctness essay describes how restraint is measured publicly [Real Signal Research 2026a]. This essay describes what restraint operates over: twelve layers of interpretation, two architectural commitments, one keystone composition object. Together they describe what the calm-AI category looks like as an engineering substrate, not a posture. The next interesting question for any AI product that reads "environment" is not how many feeds it consumes. It is what it composes those feeds into, whether the composition is inspectable, and whether anything stops the system from speaking when the composition says it should not. Companion essay: [real-signal.ai/research/silence-correctness.md](https://real-signal.ai/research/silence-correctness.md). Preprint: [real-signal.ai/research/attention-ethics-layer.md](https://real-signal.ai/research/attention-ethics-layer.md). Founder routine: [real-signal.ai/research/founder-morning-routine.md](https://real-signal.ai/research/founder-morning-routine.md). --- ## License + attribution © 2026 Real Signal Research. All rights reserved. This work is licensed under [Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)](https://creativecommons.org/licenses/by-nc-nd/4.0/). **Cite as:** > Real Signal Research (2026). *The Twelve-Layer Environmental Cognition Stack.* https://real-signal.ai/research/twelve-layer-cognition-stack.md **Companion essays:** [Why we built silence-correctness as a public metric](https://real-signal.ai/research/silence-correctness.md) · [What I check every morning on Real Signal](https://real-signal.ai/research/founder-morning-routine.md). **Preprint:** [The Attention Ethics Layer](https://real-signal.ai/research/attention-ethics-layer.md). Contact: `hello@real-signal.ai`