Upstream connectors Beta

Intent is born where work is asked for. Upstream connectors put Triage’s diagnostic questions inside the tools requesters already live in (starting with Microsoft Teams) so the decision is made at the moment of need. composerID then carries that decision downstream into the systems of record.

The shape
One thin gateway between the chat surface and the decision core

Nothing about the diagnostic moves into the chat platform. The questions, the scoring, the routing and the audit spine all stay where they live today — the Intake Gateway only translates between chat cards and the same decision API the web intake uses.

The Teams app package

A manifest, icons and an Entra app registration — installed once per tenant from the org catalog, authorised with a single admin consent. Nothing is deployed inside the tenant; the package only points at the gateway.

The Intake Gateway

Receives bot activities, verifies the requester via Entra SSO, renders questions as Adaptive Cards and translates submissions back into answers. It holds the conversation position — and nothing else. Renderer‑agnostic by design: Slack is the same core with a Block Kit renderer.

The decision core, unchanged

The gateway calls the same evaluate contract as the web intake. Scoring, routing, anti‑gaming pattern detection and Compliance File generation are server‑side and identical regardless of where the questions were asked.

End to end
From first question to published record

The full journey. Steps 1–8 are the upstream connector; from step 9 the flow is standard composerID publishing — the same five stages documented in How integrations work.

StepWhat happensWhere it runs
1The requester opens the Triage bot in Teams — or is pointed at it the moment they ask for work in a channel.Teams
2Identity is verified silently via Entra ID SSO; no separate login. Contextual data is fetched in the background where the tenant tier allows.Gateway → Entra ID
3The first question arrives as an Adaptive Card: prompt, embedded guidance, choice answers.Gateway → Teams
4The answer is submitted; the card is replaced in place by its locked state — no inputs remain.Gateway
5The next question card arrives. One card per question, fixed order, however many questions the tenant’s diagnostic defines.Gateway → Teams
6On the final answer the gateway hands the complete answer set to the decision core; scoring and routing produce the channel decision.Triage decision core
7The Intent Record is minted — one traceable Intent ID. The Compliance File records the intake surface and the verified requester identity on the audit spine.Triage decision core
8The completion card shows the recommended channel, confidence, rationale and the intent:// chip.Gateway → Teams
9composerID preflights and publishes the intent into the destination system(s) of record, idempotently.composerID
10The publish receipt lands: the completion card gains a deep link to the created record. If a destination needs a missing field, the enrichment request returns to the same thread — as another card.composerID → Gateway → Teams
In the chat
The card lifecycle keeps the diagnostic honest

The intake has deliberate properties — they are what make the decision defensible. Each one maps to a card mechanic, so the chat surface enforces them by construction rather than by policy.

Intake propertyHow the cards enforce it
One question per screenOne card per message. The next question only arrives after the current one is answered.
Answers lock on submissionThe submission replaces the card with a version that has no input elements left. There is nothing to edit.
No back buttonEarlier cards are inert text, and the gateway rejects out-of-order or repeated answers.
Anti-gaming pattern detectionRuns server-side in the decision core — identical to the web intake, invisible to the surface.
Abandonment leaves no recordIf the thread goes quiet mid-flow, partial answers are not persisted: no Compliance File, no Intent Record.
Identity & tenancy
Installed once. Trusted per tenant.

Identity

Entra ID SSO verifies the requester silently — the person answering is the person signed into Teams. That verified identity rides the audit spine into the Compliance File, so “who asked for this?” is answered by the record, not by archaeology.

Tenancy

The app package is published to the tenant’s org catalog and authorised with one admin consent. Per-tenant configuration — the question set, tiers, contextual data sources — lives in Triage, not in the package, so updating the diagnostic never means reinstalling the app.

CaseBehaviour
SSO failsThe intake does not load; the error is shown by the surface, and nothing reaches the decision core.
Admin consent absentThe install blocks before any data flows — consent is the gate, once, for the whole tenant.
Requester abandons mid-flowNo partial answers persist. No Compliance File, no Intent Record.
Client drops mid-flowConversation state is server-side; the thread resumes at the current question on any device.
Downstream
Where composerID takes over

From the moment the Intent ID is minted, this is the standard composerID flow: preflight against the destination’s tenant requirements, idempotent publish keyed {intent_id}-{version}-{destination}, external IDs and a receipt on the timeline, webhooks and reconciliation keeping the record truthful after go-live. Two returns are specific to the chat surface:

The deep link

When the publish receipt lands, the completion card is updated with a link straight to the record composerID created — the requester watches their ask become a requisition, an SOW or an agreement without leaving the thread.

The enrichment loop

If preflight finds a gap the diagnostic didn’t cover — a cost centre, a location code — the enrichment_request comes back to the same thread as, naturally, another card.

Reference implementation
Run the gateway from this repository

The upstream/ package is the executable version of this page — pure stdlib, no network, same conventions as the adapter spine. The intake properties above are pinned by its contract tests.

Modules

questions.py the diagnostic set (indicative; any length) gateway.py renderer-agnostic state machine teams_cards.py Adaptive Card renderer (schema 1.4) slack_blocks.py Block Kit renderer — same contract demo.py full journey in one process test_…​.py 15 contract tests

Run it

python3 -m upstream.demo → cards → decision → intent minted on the spine → stamped into a mock tenant → deep link on the card python3 -m unittest discover -s upstream -t . → locked answers · fixed order · abandonment · card shapes