**Note** from Bead: Firewatch Camera Grid · [canonical source](https://redfish.acequia.io/guerin/.agents/65783732-7907-4a36-983a-3b015e75e80b/2026-06-13/notes/10-bind-to-type-negotiated-not-reified.md) · session 2026-06-13 · discussion: Talk: Firewatch Camera Grid
**Triggered 2026-06-13** by Stephen, correcting a junior-programmer move on the `air7-track.json` question. Two corrections, nested. (Thread identity: **this bead's epic-3 = incident-viewer development** — the binding/agent model below is what epic-3 is really about; viewer code lives in #incident-viewer-taos-engine-app `cbf8b027`.)
## Correction 1 — data is not deployed wrapped up with the app (MVC) The AIR7 orbit was shipped as `air7-track.json` in the incident-viewer repo + a manual server PUT, fetched **relative** (`./air7-track.json`) and **Sandy-special-cased** in a bespoke `loadAir7()` / `air7Feature`. That is a **model leaked into the view/controller** — both the *bytes* and the *binding*. The "fix" I proposed (move it into `public/`) only relocates the leak: `public/` is still the app's deploy artifact, still relative, still **forked into every distributed domain the app is mounted at**, still dropping the ODbL attribution adsb.lol requires. **The bytes belong to the incident, not the app.** AIR7 is incident data — a flight track for `2026SandyFire`, derived from the adsb.lol pull (source-of-truth already in `artifacts/adsb-sandy/`). Its home is the incident's catalog, addressed by a **qualified absolute URL** (RTE remote-first), served from a logical URI that the namespace can route to any node (simtable origin / local OS node / Cloudflare-tunnel peer / service-worker cache) — *the app only ever holds the URL.* Same move that put the 10 camera billboards in with **zero viewer code** (additive catalog enrichment).
## Correction 2 — don't reify the *type* either (the deeper one) "Make it a STAC item" still pins a type from the app side. Wrong altitude. Per project_agent-as-file-ducktyping / project_uri-bind-mount, **the type-set is negotiated at interaction time, declared by the resource, not assumed by the caller.** - A **consumer** of the incident-viewer — a **bead** (agent) *or* a **human user driving the viewer** — may **seek `bind-to-type:STAC`**. The two are symmetric; both negotiate the same way. - At the bind point the resource is **asked for its type-set** (`OPTIONS` / `PROPFIND` / content-negotiation / HATEOAS / a `supportedCapabilities`-style declaration). The **type-set is declared *here*** — inline, at the resource — and the resource **binds self** (self-describing, self-binding). geo.camera's `supportedCapabilities.json` + the pareto-front dashboard are the live precedents. - STAC is **one type-set the incident node offers**, not *the* type. The viewer doesn't assume STAC; it negotiates "give me this incident node **as** STAC." The same node can offer a **different type-set to a different caller** (per-caller tailoring, Plan-9 per-caller namespace composition). So the resource is the abstraction; STAC is a *view negotiated over it*, not its essence. "Bind to type" is the verb; "ask type-set here / bind self" is the handshake. ### The type-set IS the bead's link-set **Beads have link-sets.** The "ask type-set here" declaration is not a separate `supportedCapabilities.json` bolted on — it **is the bead's link-set**: the set of polarized links it presents (`rel`-tagged, typed) to a caller. Binding-to-type is **choosing/traversing a link** in that set; "bind self" = the bead **presents its link-set** and the caller follows the link of the type it sought. STAC-binding is one link-type in the set (`rel="...stac..."`), alongside whatever else the bead offers (raw, FMV, capability, chat, …). Per project_polarized-links the link topology **IS** the wire network; **HATEOAS / a static `links[]` array is the frozen projection** of the live link-set, and content-negotiation/OPTIONS/PROPFIND are how a caller reads it at interaction time. This dissolves the "where's the manifest" question: there is no manifest, there's a link-set, and the incident node's link-set is what a bead-or-human consumer reads to decide it can `bind-to-type:STAC`. A bead composing a play (glass-bead-game) just walks link-sets and binds the links it needs. ### The agent model: beads ducktype as turtles; links are link-agents (end1/end2) Stephen, 2026-06-13: **beads ducktype as turtles** (NetLogo / **AgentScript** sense), and **links are `type:agent` with `end1` and `end2`.** This is not analogy — it says the bead ecology and the **agentscript substrate** (one of the four horizontals) are *the same agent model*: - A **bead ⇒ a turtle**: a mobile, stateful, behavior-carrying agent. Extends the duck-type list of project_agent-as-file-ducktyping (file / agent / camera / room / sensor / process) with **turtle** — the ABM-agent reading. The resource is the abstraction; "turtle" is one of its types. - A **link ⇒ a link-agent**, also `type:agent`, carrying **`end1` and `end2`** (its two turtle endpoints, exactly NetLogo's link primitive). A link is **not an edge** — it is a first-class agent with its own state, behavior, lifecycle (it can negotiate, weight, apoptose) and its own URI. - Therefore a bead's **link-set is a link-*agentset*.** Each link in it is a link-agent with `end1 =` this bead and `end2 =` the bound resource — **directional ⇒ polarized** (project_polarized-links: every link is a polarized GET to an agent-resource). HATEOAS's static `links[]` is the **frozen census of the live link-agentset**. - **`bind-to-type` = spawn/traverse a link-agent of the sought type** between `end1` (the caller — itself a bead/turtle, agent or human-driven) and `end2` (the resource). **`bind self` =** the resource presents its link-agentset and the caller follows the link whose type it sought. The bind is owner-mediated and carries attribution up the wire (advanced-wave / downstream-pattern). This is the literal reading of project_hubler-self-assembling-wires: bead-turtles are the bearings, the **link-agents are the wires** (self-assembling under demand), and "links are the wires" stops being metaphor. The incident-viewer (epic-3) is, at bottom, a turtle that walks the incident node's link-agentset and binds the track/camera/perimeter links it needs — agentscript all the way down.
## Consequences for the build 1. **Data path:** the AIR7 track (and its siblings from the same pull — the air-attack OV-10, the S-2/S-61 tankers, the military traffic) is offered for binding under the incident as a track resource, addressed by qualified URL. Born + proven in the bead (`artifacts/`), **published** into the incident catalog (owner-mediated, additive, `simtable-webdav-token`). 2. **Binding, not bytes:** retire the hardcoded `loadAir7()` + relative path + Sandy `if`. The viewer **discovers** tracks by negotiating a STAC binding of the incident node it's pointed at, then renders whatever track resources are bound there — AIR7 stops being special; an aircraft-traffic layer falls out for free for any incident. 3. **The app never declares the type.** It *requests* one. If a resource can't bind-as-STAC, that's the resource's declaration to make at the bind, not a crash in the renderer. Per downstream-pattern the bind is simultaneously devops + governance + attribution + ledger: binding-as-STAC at the incident URI is where the adsb.lol/ODbL attribution and the acequia read/authz sidecars travel with the data, up the advanced wave. **Cross-bead:** the viewer code lives in #incident-viewer-taos-engine-app (`cbf8b027`); this note is the design seam for generalizing its track/catalog binding. Related: [note 02 §3] (STAC bind-to-URI = access/authz), [note 03] (active cataloger), [note 08] (the adsb.lol pull that produced the tracks).