Operational ↔ tactical — user flows¶
Status: Design (proposed) — 2026-07-04. Screen-level flows for the operational ↔ tactical information flow design, agreed via mockup review. Seven journeys: planning at the edge, building an operation on web, the report cycle, provisional teams, HQ oversight, content readiness, and the plan timeline on COP/Replay.
Amended 2026-07-04 (web UX consolidation): the existing web comms
node-graph and synchronisation matrix are folded into these flows rather
than kept alongside — see Journey 2 (comms matrix, net carriage), the orders
editor's timeline lens, and Journey 7. HTML mocks for the amended surfaces
live in architecture/mocks/.
Journey 1 — team leader plans with the 7 Questions (Android)¶
flowchart LR
MAP[Map — order banner] -->|View order| PV[Plan viewer<br/>task-first]
PV -->|Start my estimate| HUB[7Q hub<br/>non-linear tiles]
HUB --> Q5[Q5 roster-first tasking]
HUB --> Q7[Q7 plan draw mode]
HUB -->|complete or not| REV[Review — warn, never block]
REV -->|Publish| OUT[Bubble acks + uplink<br/>one act, two audiences]
OUT --> TRP[Troop device —<br/>same viewer, Acknowledge]
Entry — an order arrives. A map banner fires only when the order tasks the reader's unit. View order opens the plan viewer:
- Task-first layout: the reader's unit's task is extracted into a highlighted card at the top; the full order (situation, mission, all tasks, control measures, attachments) sits below as collapsible sections. The same viewer serves every echelon — a troop member later sees their callsign's task in the same place.
- Attachments show their blob-plane pull state inline (cached ✓ / downloading); the classification label is pinned in the header.
- Show on map renders the order's control measures; Start my estimate opens the hub.
Standalone create. Plan (estimate) is an entry in the existing create picker and in the Plans panel — visible to everyone. A commander goes straight to the hub. A principal with no command appointment is routed into the provisional-team flow ("Plan for whom?" → pick nearby callsigns → self-appoint provisionally → team gossips as provisional ORBAT) and then gets the hub scoped to that team. Authority never comes from the button — receivers verify the (possibly provisional) appointment. Whether commanders also get a dedicated top-level button (like chat) is an Android implementation decision.
The estimate hub. The 7 Questions are a grid of seven tiles, answerable in any order, revisable anytime — estimates run interrupted and partial, so the hub is a resumable draft, not a wizard. Q1 (situation) and Q2 (mission) pre-seed from the parent order. Spatial questions open map modes; text questions open full-screen cards. Save draft persists locally; nothing publishes until the publish act.
Q5 — resources → tasks, roster-first. The screen lists the commander's ORBAT subtree (attachments included); tasks nest under each callsign. An untasked callsign is flagged red — the classic planning omission is made impossible to miss. Effects captured in Q3 are offered as suggestions when adding a task. Timings are H-hour-relative (the order sets H). Request attachment records an ask that travels up inside the published plan.
Q7 — control measures, plan draw mode. Q7 flips the map into a mode: a banner names the estimate being drawn into, the palette biases to control-measure types (boundary, report line, FUP, axis, target ref), and every shape drawn auto-binds to the plan. Long-press binds an existing shape. Bound shapes stay draft-local to the author — the troop cannot see them until the plan publishes, and the publish is atomic (record + shapes together).
Review and publish — warn, never block. The review screen is a checklist of what the record carries (mission, tasks, timings, control measures, requests, parent link). Gaps — an untasked callsign, an empty question — show as warnings but never prevent publishing: a 60% plan now beats a 100% plan after H-hour, and the gaps travel visibly in the record (HQ sees them too). Distribution is shown, not chosen: down the tasked subtree, up the chain of command and web, automatically. After publish the device shows live per-device acknowledgements from the bubble and, when HQ is unreachable, the queued uplink state explicitly — never silently.
Troop receive. A troop member gets the same task-first viewer with their callsign's task on top; control measures render on the map on receipt with no action needed. Acknowledge feeds the publisher's ack count.
Journey 2 — build an operation (web)¶
flowchart LR
OP[New operation<br/>name, ceiling, dates] --> ORBAT[ORBAT builder<br/>tree + drag-in pool]
ORBAT --> MX[Comms matrix<br/>suggested from ORBAT]
MX -->|signaller confirms| REG[comms-plan registry]
ORBAT --> ORD[Order authoring<br/>orders-format editor]
ORD -->|Publish| DIST[Records + manifests<br/>to tasked units]
New operation is a plain form: name, classification ceiling, dates.
ORBAT builder — manual tree + drag-in pool. Left pane: the unit tree — add sub-units, star (★) a commander on any unit. Right pane: operation members sourced from the Directory, not yet in a unit, dragged onto units. Dragging a member onto a unit assigns their tactical callsign in the same step, edited inline on the member row (uppercased, max 32 chars, unique case-insensitive per operation among planned memberships) — this is the only place a callsign is set; it is never self-declared on-device, and every tactical label a device shows is resolved from it (see callsign resolution). No doctrinal template assumptions in v1 — a "save unit as template" accelerator can come later. Unassigned members still receive operation-level content; they just have no unit tasking or rollup. Field-formed provisional teams surface in this screen for bless / merge / retire, mirroring the comms-plan registry's field-entry handling; a colliding callsign on merge drops to null (first-merged-wins) rather than blocking the merge.
Comms matrix — a real matrix, replacing the comms graph. (Amended 2026-07-04 — web UX consolidation; mock: mocks/comms-matrix.html.) The comms surface is a full-screen step in operation setup (Operation → ORBAT → Comms → Orders; each step later re-enterable for edits) and a true table: rows are the ORBAT in tree order (unit rows, callsign rows indented, an unassigned-members pool at the bottom), columns are nets, cells carry membership + role (★ owner / ● talk / ◌ listen — click to toggle, unit-row cell toggles the whole unit). This replaces web's existing comms-network node-graph and its COP overlay outright — comms planning leaves the COP; the live voice/chat panel is unaffected.
Every net declares its carriage:
petra(in-band) — materialises as live voice/chat channels. Confirm/save is the provisioning act: channel create/edit publishes through the existing provisioning path, and the result is surfaced per net (provisioned / pending / failed + retry) — never fire-and-forget. Classification stays immutable post-provision, but with a guided recreate-at-new-classification affordance instead of a dead control.radio(out-of-band) — plan-of-record only: bearer detail (HF/VHF/UHF/SATCOM; frequency/crypto fill later), a PLAN ONLY marker, no channels ever provisioned. Still fully present in the matrix so the signaller assigns who holds which radio net.
Net classification uses the operation's classification lattice — the
same {policy, level} vocabulary as every other ceiling/clearance check,
never a net-specific enum (a bespoke enum can't participate in the
net ≤ operation-ceiling, author-clearance, banner-union, or replay-export
comparisons, and hardcoding a marking set forks the open, deployment-
specific policy vocabulary — e.g. it excludes a UK GSC deployment's
OFFICIAL floor). New and suggested nets default to the operation
ceiling; the signaller lowers deliberately — under-marking is the wrong
fail direction, and the same lattice keeps radio→petra recreation lossless
at exactly the boundary where mislabeling matters.
The matrix pre-populates from the ORBAT: a command net (HQ + all unit
commanders), one net per unit, and an all-hands informal chat — all
suggested as petra drafts. Suggestions are drafts: nothing gossips or
provisions until a signaller (author_comms_plan) confirms each entry (or
confirms all) — ORBAT churn during setup never spams devices with
short-lived channels, and comms stays a deliberate act owned by the signals
role. Suggestions re-derive when the ORBAT changes, with membership diffs
flagged. Field-created channels appear provisional, exactly as the
comms-plan registry specifies. Net detail edits
live in a side drawer beside the matrix, not a modal.
Order authoring — orders-format editor over the shared record. Staff
write in the format they know — situation / mission / execution / control
measures / attachments — and each section is a field of the same plan
record the edge estimate produces (situation, mission, tasks[],
controlMeasures[], attachments[]). No free-text-then-extract step. The
execution section is a task table whose unit column picks from the ORBAT;
attachments upload to the artifact store. One record, two lenses: web
renders it order-shaped, Android renders it task-first. The publish panel
shows the automatic distribution, live device acknowledgement counts (from
the plan-ack plane; offline devices served by outbox + latest-version
catch-up), and the version history (edits publish seq+1, latest wins on
devices, all versions kept for replay).
The Orders page — stepper step 4, and the only plan surface.
(Amended 2026-07-04 — orders consolidation.) The editor lives at the
operation-setup stepper's Orders step, full-screen and re-enterable like
ORBAT and Comms. Left pane: the plan tree (Journey 5) — selecting a plan
opens it in the editor on the right. This page absorbs and retires web's
PLAN page and its estimate form outright: web authors orders, not
estimates (the 7 Questions is the edge process; field estimates arrive as
plan records up the record plane), and web keeps no separate map-overlay
authoring stack — heavy overlays are blob-plane artifacts produced in real
GIS tools and attached to plans or the operation; drawn operational graphics
are draw-plane shapes. Edits are web-SQL drafts per plan id — draft-local
until publish, matching the edge; publish validates (warn-never-block),
stamps seq+1, signs, and publishes to the record plane.
Control measures — draw on the COP, bound to the plan. The control measures section opens the COP draw tools in a bind-to-plan mode — the web twin of Android's Q7 plan draw mode: a banner names the plan being drawn into, shapes auto-bind, stay draft-local to the author, and publish atomically with the record.
Plan-bound graphics get their own map layer. On both the COP and the Android map, shapes bound to a published plan render under a per-plan layer toggle named for the plan ("2 Tp order v3" switches on and off as a set), distinct from the existing free-drawings toggle. Binding is the formal/informal split made visible: order graphics arrive verified and appointment-gated with the plan; loose drawings stay the ad-hoc "look over there" plane.
Execution has two lenses — table and timeline. (Amended 2026-07-04;
mock: mocks/orders-timeline.html.) The
execution section toggles between the task table and a timeline:
ORBAT-ordered lanes on an H-hour-relative axis, drag a bar to retime, drag
its edge for duration, untasked callsigns flagged as empty red lanes. Both
lenses edit the same tasks[] — task timing carries an H-hour offset and
a duration. This absorbs and retires web's existing synchronisation
matrix and its separate task store (rows are dropped, not migrated — task
execution state is derived from reports per Journey 7, never hand-set).
Journey 3 — the report cycle¶
flowchart LR
REQ[Commander tasks report<br/>kind, subtree, cadence] --> DUE[Device due prompt]
DUE --> FORM["<10s form: RAG + narrative<br/>auto DTG/location"]
FORM -->|Send| UP[Bubble SA + web log]
UP --> CM[Compliance matrix<br/>commander device + web]
Tasking. A commander (web or Android, same form) publishes a report
requirement down the subtree: kind (sitrep at v1), target units, and a
cadence ("every 4h from 0600Z") or a one-shot due DTG. The requirement is a
signed record on the record plane like any order.
Submitting. When a report falls due the unit commander's device prompts. The form is deliberately a sub-10-second act: tap GREEN / AMBER / RED, speak or type a short narrative, optionally attach a photo (blob plane); DTG and location auto-stamp. Offline, the outbox holds and forwards.
Who answers: the unit commander, and only the unit commander. A unit-targeted requirement is answered by one consolidated unit report — matching voice procedure, where one callsign answers for the unit. The command appointment is the gate: only the appointed commander of a unit (a provisional field team's forming lead counts as its appointment) is prompted, and a report authored by anyone else is dropped at ingest on both web and Android. A unit with nobody appointed is never asked and never counts SILENT — but it is never hidden either: it rides beside the matrix as an explicit no commander appointed gap (an ORBAT authority hole is exactly what the ORBAT exists to state), counted separately from "expected" so the triage numbers stay actionable. Members of such a unit see the same gap passively on their device — awareness, not permission to answer. When a commander is down, the fix is appointing their successor in the ORBAT (or forming a team, which self-appoints a lead), never widening the gate; the unit's red SILENT run is itself the signal that drives that appointment. A commander can also send an ad-hoc (unscheduled) report at any time for a unit they command; ad-hoc reports appear in the feed but not the compliance matrix. "Ad-hoc" relaxes the schedule, never the appointment. Per-callsign polling (e.g. a LOGSTAT sweep) is deferred as a later requirement kind.
Rollup. The commander's device and web render the same compliance matrix
per battle-rhythm round: unit / RAG / reported-at, with a silent unit
rendered as a red signal, never a blank row. Each past round is judged
against the ORBAT as it stood when that round opened — web folds the
orbat_change timeline forward to t_k — so re-appointing or vacating a
command today cannot rewrite what a past round asserted. A unit that owed
nothing in a given round (no commander yet, not in the scope yet, already
retired) renders as an explicit UNEXPECTED cell rather than a false SILENT,
and columns are the union across rendered rounds so a unit never appears and
vanishes mid-table. Where the timeline does not reach back to a round (an
operation older than change-recording), that round falls back to the current
ORBAT rather than blanking. The commander's Android device stays
current-ORBAT by design — it holds latest-version-only state; the durable
accountability record is Web's. Tapping a row opens the report;
previous rounds stack beneath. The full feed and every round land in the
replay export.
Journey 4 — provisional team formation (Android)¶
flowchart LR
IN["Entry: 'Plan for whom?'<br/>or Team panel"] --> PICK[Form team —<br/>name + pick callsigns]
PICK --> SUM[Team summary —<br/>overlay, ★ lead, team net offer]
SUM -->|gossips provisional| MEM[Members notified —<br/>standing Leave]
SUM -->|Plan for this team| HUB[7Q hub scoped to team]
MEM -.-> WEB[Web ORBAT builder —<br/>bless / merge / retire]
Forming. The picker lists bubble-present callsigns first (live presence shown), with the full operation roster searchable beneath. The former is ★ lead by default (changeable). Form team publishes a provisional ORBAT record — signed by the former, verified by receivers, visible up to HQ.
The team is an overlay. Members keep their parent unit; the provisional team adds a tasking/report scope on top until web blesses it into the ORBAT proper (or merges/retires it). The summary screen offers a team net (a field channel, provisional in the comms matrix as the registry already specifies) and a one-tap path into the 7 Questions hub scoped to the team.
Consent — declare + notify, standing leave. Picked members are notified, not asked: "you two, with me" is not a negotiation, and an accept-gate stalls exactly when teams form under pressure or a device is in a pouch. Every member's screen carries a standing one-tap Leave team, which publishes a signed ORBAT record of its own — a dispute is visible to the lead and HQ, never silent. HQ bless is the human backstop for error or abuse.
Journey 5 — HQ oversight: plan tree and reconcile (web)¶
The plan tree is the COP of planning state. The plan tree is the Orders page's left pane (Journey 2) — the ORBAT tree with a detail pane (a map view is a toggle, not the primary). Every unit line answers the staff-officer question at a glance:
- Planned — plan title, author, version, DTG, ack coverage (e.g. "6/9 ack").
- No plan yet — flagged with how long since the unit was tasked ("no plan — tasked 0500Z ⚠").
- Provisional — field-formed teams and their plans carry the provisional badge.
- Leaf units with no subordinate plan simply show "task direct" — not every echelon plans.
The detail pane for a selected plan surfaces the record's travelled gaps (untasked callsigns), its up-flowing asks as actionable items (an attachment request renders approve / deny), versions, ack coverage, that unit's latest report status, and a link to its control measures on the operation map.
Reconcile — inline, in context. Provisional items queue where they'd live: teams in the ORBAT builder, field plans in the plan tree, field nets in the comms matrix — each purple-flagged, with one badge count in the operation header. Clicking opens the reconcile dialog:
| Action | Effect |
|---|---|
| Bless as unit | Team becomes a real unit under a chosen parent; the lead's appointment is confirmed; its plan and net re-parent and lose the provisional flag |
| Merge into unit | Members fold into the chosen existing unit; the team dissolves; its plan re-parents (authorship unchanged); its net retires or transfers |
| Retire | Tombstone, audit kept; members revert to parent units; the plan stays readable but flagged orphaned; the net retires via the registry tombstone path |
Every action is a signed record down the record plane — devices see the outcome like any ORBAT change. A central triage inbox is deferred; if volume demands it, it is a filter view over the same inline state.
Journey 6 — content readiness (Android)¶
The blob plane is pull-only, so nothing guarantees a device pulled before losing reach. A chrome status pill (sibling of the transport pill) is the pre-mission confidence check: green = everything the manifest lists is cached, amber = pending, red = an active order references missing content. It opens the operation-content panel: items grouped ready / pending / verification (manifest refresh time, sha256 state), with a "get everything now" action before stepping off. A plan that references an un-pulled blob renders with an explicit gap marker — never silently without it.
Auto-download is per-kind. Records always ride gossip regardless. Small blobs (overlays, order annexes) auto-pull on any link as soon as the manifest lists them; large blobs (map packs, imagery) auto-pull only on wi-fi/unmetered and are on-demand on tactical bearers ("tap to force") — a multi-gigabyte map pack must never starve the record plane or voice. Defaults become MDM-tunable later.
Journey 7 — plan timeline on COP and Replay (web)¶
(Added 2026-07-04; mock: mocks/plan-timeline-cop-replay.html.)
The orders editor's timeline lens is one shared read-only component driven by a time cursor, hosted on three surfaces: the orders editor (editable), the COP, and Replay. On COP and Replay it renders as a collapsible bottom panel — the same slot family as the comms panel, never a map overlay, never a view toggle. Collapsed, it is a one-line strip: plan name, version, cursor position, past-due count.
COP — the live now-line. Tasks come from the operation's current plan
tree (latest seq per plan id); a now-line ticks across the H-hour axis.
Task state derives from reports: complete (report received covering the
task window), in window, and past due + unreported rendered red —
the visual sibling of the compliance matrix's silent-unit rule. Clicking a
bar opens the task and the unit's latest report. Unit lanes by default;
a unit expands to callsign lanes.
Replay — the plan as it existed at T. The same panel driven by the
replay cursor: the plan folds forward from the plan export layer (highest
seq ≤ T per plan id — the orbat_change / target_transition pattern),
so scrubbing shows what HQ actually believed at that moment, with the
version chip naming the active seq and when it was superseded. Task states
are computed from reports at or before T only — later knowledge never leaks
backwards. Plan-publish moments render as marks on the replay scrubber, and
lanes use the ORBAT as at T, so a mid-operation provisional team appears
only after its formation.
No compatibility window. The web synchronisation-matrix's sync_task
export layer is removed in the same change set that lands the plan
layer — single storm, no dual-export period.
Cross-cutting decisions this pass locked¶
| Decision | Choice |
|---|---|
| 7Q container | Non-linear hub of tiles, resumable draft |
| Plan viewer | Task-first card + collapsible full order, all echelons |
| Create-plan entry | Create picker + Plans panel, visible to everyone; non-commanders route via provisional team |
| Q5 layout | Roster-first; untasked callsigns flagged |
| Q7 binding | Plan draw mode; draft-local shapes; atomic publish |
| Publish gating | Warn, never block; distribution automatic |
| ORBAT builder | Manual tree + drag-in pool; templates later |
| Matrix materialisation | Suggest → signaller confirms; never auto-create |
| Web plan editor | Orders-format sections mapped 1:1 onto the shared record |
| Report answering | Unit commander consolidates; the command appointment is the gate — a commanderless unit is never asked but is shown as an explicit gap; ad-hoc relaxes the schedule, not the appointment |
| Team formation consent | Declare + notify; standing signed Leave; HQ bless as backstop |
| Web plans surface | ORBAT tree + detail pane; map as toggle; no-plan-yet is a first-class state |
| Reconcile queue | Inline in context (ORBAT / tree / matrix), header badge; central inbox deferred |
| Blob auto-download | Per-kind: small auto anywhere, large wi-fi-auto / on-demand on tactical bearers |
| Comms matrix form (2026-07-04) | True table (ORBAT rows × net columns, role cells), full-screen operation-setup step; replaces the COP comms node-graph outright |
| Net carriage (2026-07-04) | Explicit petra | radio per net; only petra provisions channels; radio is plan-of-record with bearer detail |
| Provisioning act (2026-07-04) | Signaller confirm/save on a petra net provisions; result surfaced per net (ok/pending/failed + retry), never fire-and-forget |
| Execution editing (2026-07-04) | Table + timeline lenses over tasks[] (H-hour offset + duration); web sync matrix retires into the orders editor |
| Plan timeline hosts (2026-07-04) | Shared read-only component: COP bottom panel with live now-line, Replay with plan-as-at-T fold; sync_task export layer replaced with no compat window |
| Orders page (2026-07-04) | Stepper step 4 hosts plan tree + editor; absorbs and retires the PLAN page, the web estimate form, and the section/layer/annotation overlay stack — overlays are blob-plane artifacts, drawn graphics are draw-plane shapes |
| Web control measures (2026-07-04) | COP draw tools in bind-to-plan mode (web twin of Q7): draft-local, atomic with publish |
| Web plan drafts (2026-07-04) | Web-SQL draft per plan id until publish; publish stamps seq+1 and signs to the record plane |
| Sync-task data (2026-07-04) | Dropped, no migration; execution state derives from reports, never hand-set |
| Plan geometry export (2026-07-04) | /api/plan/export (GeoJSON/KML) survives re-sourced from draw-plane shapes: published = control measures of current published plans, all = all current drawings |
| Plan-bound map layer (2026-07-04) | Published-plan shapes render under a per-plan layer toggle (named for the plan), distinct from the free-drawings toggle — COP and Android both |