SUPPORT-FABRIC-01 — the support seam, specified and deliberately not built¶
Kind: specification. Filed 2026-09-09 at docs/docs/workspace/support-fabric.md; ratified in conversation with Tim, 2026-09-09. Supersedes nothing. Governed by WS-PRODUCT-01; where this conflicts with WS-PRODUCT-01, WS-PRODUCT-01 wins.
⛔ STATUS: RECORDED, NOT SCHEDULED. Nothing is built from this document today. It exists so that the interface being designed now leaves the slot open, and so that whoever builds support later builds the right thing rather than rediscovering these decisions. No window is assigned. No gate is owed. Ratified in conversation with Tim, 2026-09-09.
1 · THE GOVERNING RULE¶
The helpdesk is never a place the customer goes.
Whatever ticketing product is eventually adopted, RTOpacks uses its agent side and its API only. Its customer-facing half — portal, customer login, branded subdomain, "submit a request" form — is not used, not linked to, and not themed. The college never sees the vendor's name.
Support is a surface of RTOpacks, rendered by RTOpacks, on RTOpacks' domain, in the session the user already has.
This is one rule and it eliminates all four of the seams below at once. Every one of them exists in other products because the vendor's portal is free and building your own surface is not. That trade is refused here.
The four seams this rule prevents¶
- A different domain.
rtopacks.zendesk.comorsupport.rtopacks.com.auas a separate destination. - A second login. A user who is already authenticated is never asked to authenticate again.
- Re-entering what the app already knows. No form asks for the college, the user, the product area, the qualification, or the unit. The app knows all of it.
- Context loss. A request that arrives without the state that produced it turns one support interaction into three.
Truth before paperwork applies here too: the seam is the reality; the integration is downstream of it.
2 · THE SLOT — already reserved, and not to be repurposed¶
docs/docs/workspace/glossary.md:33 already reserves the shell element:
Interaction Layer (future — reserved slot) — context-aware co-pilot that speaks only when it has something worth saying; knows where the user is in the workflow. Not a chatbot. Code:
apps/workspace/components/shell/InteractionLayer/(stub only).
The Interaction Layer is the support entry point. It is a shell element in the same class as the Audit Folder — always visible, reachable from every app, never a per-page bolt-on.
Three constraints follow, and they bind work happening now:
- No surface ships its own separate "Help", "Support" or "Contact us" affordance. One door, in the shell. A second entry point is the seam arriving by the back stairs.
- The RAG companion and support are the same door, not two. The companion answers first; escalation to a human sits underneath it, in the same element. A user who has just failed to get an answer must not have to go and find a different button.
- The stub directory is not to be repurposed for anything else without a ruling. It is load-bearing precisely because it is empty.
3 · THE CONTEXT ENVELOPE — the one thing expensive to defer¶
Every support request carries a fixed envelope, assembled by the app, never typed by the user. The shape is decided here because retrofitting it means touching every call site that ever raises a request.
tenant org / client id (the canonical client key, per the Studio tenancy derivation)
user user id · display name · canonical tier (T3 / T4 / T4A — never L1–L4, ADR-020)
surface which module and which route the request was raised from
subject session id · qualification code · unit code — whichever apply, absent where they do not
state current version of the object in view; last write outcome
diagnostics recent client errors; app build; browser and platform
plane regulated | non_regulated (glossary v2.1 plane families)
raised_at timestamp
Absent is a value. A field that does not apply to a surface is omitted, never filled with a placeholder — a placeholder in a diagnostic payload is a wrong finding waiting to be read as fact.
No student personal information travels in the envelope. Support diagnoses the college's authoring work, not its learners. If a support case genuinely needs learner context, that is a separate, consented act and not this channel.
4 · THE REQUEST ID — minted here, never there¶
Every support request is identified by an id minted by RTOpacks and handed to the vendor as an external reference.
The reverse — adopting the vendor's ticket number as the identity — is what makes a vendor unswappable, because every link, every audit line and every customer-facing reference then belongs to them. Mint locally; let the vendor carry the id as a field.
5 · THE BOUNDARY — one function, vendor behind it¶
raiseSupportRequest(envelope) -> requestId
Application code calls this and nothing else. No vendor name appears anywhere upstream of the adapter — not in a type, not in an import, not in an environment variable read outside it.
The adapter behind it may, on the day, be a vendor API, an email to the operations inbox, or a row in a table. That choice is not an architectural decision as long as this boundary holds. With the boundary, changing vendor is a day. Without it, changing vendor is a migration.
The adapter is subject to the EXT-API RULE: any external API needs a reference doc in docs/ops/ before deploy.
6 · EXPLICITLY DEFERRED — not decisions, and not to be inferred from this document¶
None of the following is settled here, and nothing in §§1–5 depends on them:
- Which ticketing product, and whether hosted or self-hosted. Noted for whoever picks: the self-hosted options (osTicket, FreeScout, Zammad, Chatwoot, UVdesk) each introduce a stateful server — Postgres, Redis, Elasticsearch depending on the choice — into an estate that currently runs none. That is a new operational category for this operation, not a licence saving. Data residency is a hard question for Australian RTO customers and is asked before a vendor is chosen, not after.
- The customer-visible thread store — the table and the inbound webhook that let a college read replies inside RTOpacks. Required before support is usable; not required to keep the door open.
- Plan levels and entitlement tiers. Deferred entirely.
- Phone and interactive support, and what a support plan promises.
- Support presence in a live Studio room — see §7. A separate mechanism, separately specified.
One position recorded, because it is a design rule and not a plan level¶
Raising a request is never gated behind a paid plan. What is sold is response time and the interactive path. A customer who cannot report a defect in the product is a defect report you paid for twice — once in the fault you did not learn about, once in the customer who left without saying why. Separate "something in your product is broken" (always wanted, always free) from "help me do my job" (the service being sold).
7 · THE RULING THIS SETTLES — operator reach stays shut¶
This document answers the open question AUTH-ENV-LOCAL-02 was raised to hold, and the plain window's Gate 1 question at STUDIO-TENANCY-02.
Support reaches a college's work by being invited into a room, not by holding a tier that can see across tenants.
Consequences, ruled:
- T3 operators get no cross-tenant reach in Studio. The tenancy wall established by STUDIO-TENANCY-01 and -02 stays shut, on both the REST surface and the socket. No hole is opened in the tenancy model for support.
- Support access is a separate mechanism built on the collaboration room that already exists — a grant with an expiry, a read-only participant mode, and visible presence so the college can see who is in the room, recorded in the audit ledger.
AUTH-ENV-LOCAL-02is narrowed accordingly. It is no longer "how far should an operator see" — that is answered: not across tenants. What remains is the smaller question of what the local operator key should resolve to on the local estate so the case can be exercised at all.
Screen sharing is retained only for problems outside the application — a page that will not load, a device or network fault, an IT policy blocking something. Those are pixel problems and in-app presence is blind to them. They need no build.
8 · WHAT BINDS WORK HAPPENING NOW¶
Everything else in this document is for later. These three bind today:
- No surface ships its own help or contact affordance. The shell owns the door.
- The
InteractionLayer/stub is not repurposed without a ruling. - When any surface first needs to hand context to anything — support, the companion, diagnostics — it assembles §3's envelope, rather than inventing a local shape that will have to be reconciled later.
9 · LEAST SURE¶
- Whether read-only support presence is enough to be useful. If a supporter needs to take the pen on most calls, the grant flow becomes the friction and the design has reinvented screen sharing with extra steps. Test against one real support scenario before committing to the read-only default.
- Whether the companion can carry tier-zero help well enough to deflect meaningfully. The deflection assumption is doing real work in the support economics, and nobody has measured it. If it deflects little, the staffing cost is the whole cost and the plan levels need to say so.
- Whether "no student personal information in the envelope" survives contact with real support cases. It is the right default and it may prove too strict — a college describing a problem will paste what it likes into a free-text field. The envelope is structured and controllable; the free text beside it is not, and that gap is unaddressed here.
— Advisory seat, 2026-09-09. Recorded at Tim's direction; not scheduled.