5.7 KiB
Boundary Identifiers — In-Package Reference
If you're editing files in this package, you must know which identifier you're touching. This file is the in-package boundary contract for the SDK browser host. Provider overlays may maintain their own deployment-specific mapping docs, but boundary names exported by this package stay provider-neutral.
The Four Boundary Identifiers
| Boundary name | What it identifies | Example | Where it crosses boundaries |
|---|---|---|---|
| subjectScope | NATS subject prefix for this Host's actors | SPACE-HIVECAST |
data-subject-scope attr, bootstrap.subjectScope JSON field, IBrowserBootstrapResponse.subjectScope |
| authority | Who owns this surface (user/principal) | test-user-1 |
data-authority attr, bootstrap.authority JSON field, IBrowserBootstrapResponse.authority |
| appName | Which webapp this is | director |
data-app-name attr, bootstrap.appName JSON field, matrix.json:appName |
| tabRuntimeId | This browser tab's runtime identity | test-user-1.DIRECTOR.SESSION-A1B2C3D4 |
data-tab-runtime-id attr, computed client-side from authority + appName + session id |
The discipline: clear at the boundary, flexible inside
The names above are required at interface boundaries — anywhere code in this package talks to code outside it. That means:
- HTTP bootstrap response fields
- HTML attributes on
<matrix-dsl-host> - Exported TypeScript interfaces, types, and function signatures
- matrix.json fields
Inside private functions and private fields of this package, local variable names can use whatever feels natural for the surrounding code. The discipline is at the seams.
Rules
-
Boundary-crossing values use the canonical boundary name. When you read a value from a config file, HTML attribute, JSON field, or exported interface, you read the canonical name (
subjectScope,authority,appName,tabRuntimeId). You can rename it as a local variable inside your function if you want; just make sure the boundary read happened under the right name. -
One concept per boundary name. Never write
setAttribute('root', ...)in new code. Therootattribute is ambiguous — it has meant all four identifiers at different times in git history. Pick the specific one. -
No implicit substitution. If
appNameis missing from a bootstrap that needs it, throw. Do not silently degrade to usingsubjectScopein theappNameslot; that creates wire-crossing bugs. -
Forbidden boundary names (do not introduce in new code at boundaries):
root— meant all four at different timesrealm— alias ofroot, same problembaseRoot— got passed in as appName but is named after subjectScoperootAttr— generic, ambiguousdaemonRoot/daemonRealm— pre-Host-Service legacybusRoot/authorityRoot/runtimeRoot— these were in-flight rename drafts; superseded bysubjectScope/authority/tabRuntimeIdtransportRoot— classify each site; if the value has.SESSION-XXXX, the boundary name istabRuntimeId; otherwise it'ssubjectScopespaceRoot— useauthorityappRoot— useappNameortabRuntimeIddepending on which
-
Allowed legacy aliases (compat only at boundaries, one release):
bootstrap.root— still emitted for one release; readers must migratebootstrap.platformRoot— synonym ofsubjectScopeduring transitionbootstrap.addressRoot— synonym ofauthorityduring transitionbootstrap.busRoot/bootstrap.authorityRoot/bootstrap.runtimeRoot— in-flight rename names from earlier drafts; emit both old and new for one release so any consumer already coded against them keeps working
HTML attribute writes are intent-explicit
When you write attributes during browser bootstrap, write the specific canonical attribute name:
this.setAttribute('data-subject-scope', subjectScope); // not 'root', not 'realm'
this.setAttribute('data-authority', authority);
this.setAttribute('data-app-name', appName);
this.setAttribute('data-tab-runtime-id', tabRuntimeId);
The legacy root attribute is still written during the transition release
(transport readers in older code path still consume it as subjectScope in
hosted mode). New code reads data-subject-scope instead.
Why this exists
Through git history, "root" has meant all four of these identifiers at
different times. commit d73fc73ee (May 14, 2026) introduced busRoot
as a separate bootstrap field when Space-claimed users couldn't load the
platform shell. That fix worked for transport, but the HTML attribute
root is read by THREE consumers expecting THREE different meanings, so
writing busRoot into it broke tab identity downstream
(tab_realm.ts:generateIdentityTabRoot, whose appName parameter was being
fed busRoot until this workstream landed).
The lesson: at boundaries, names that say what they mean prevent the wire-crossing class of bug. Internal variable names can stay flexible; the boundary names cannot.
Where each identifier comes from
- subjectScope — server-side, derived from
status.transport.rootof whichever Host's gateway answered the HTTP request - authority — server-side, the signed-in principal's
primary_authority_root(or, on Device hosts, the Device's linked authority fromhost-auth.json) - appName — server-side, derived from the route's app context
(
/apps/director/→director); declared in the package'smatrix.json - tabRuntimeId — client-side, generated as
${authority}.${appName.toUpperCase()}.SESSION-${sessionId}, persisted in sessionStorage