Files
card-layouts/docs/UML-VIEWPOINTS.md
T
mpabi 8bf8e22448
Check card layouts / check (push) Has been cancelled
feat: publish A1-A8 card viewer and FreeRTOS C generator
2026-07-19 16:43:35 +02:00

726 lines
29 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# A1A8 Interactive Architecture Viewpoints
Status: design contract, version 0.2, 2026-07-18.
This document defines how STEM cards describe architecture, code and runtime
evidence. It is a house convention, not a new UML standard. The convention is
organized in the spirit of ISO/IEC/IEEE 42010:2022, uses UML 2.5.1 notation,
adds selected MARTE 1.3 concepts for real-time systems, and uses PlantUML as
the textual source of rendered diagrams.
## Scope and rollout
A1A8 is runtime-independent. The fixed viewpoints are intended to support
embedded RTOS software, ordinary C++ object models, POSIX or standard threads,
and asynchronous Boost.Asio applications without changing the navigation
grammar.
The rollout is deliberately staged:
1. **current application:** FreeRTOS C++ cards on RV32I/Hazard3;
2. **later application:** `std::thread`/`std::jthread` and Boost.Asio;
3. **not yet scheduled:** concrete Asio/thread card repositories and lesson
numbering.
The later profile is specified below so current diagrams do not bake in RTOS-
only assumptions. It is a compatibility target, not a claim that the current
FreeRTOS card already implements or teaches Asio.
## Standards boundary
- **ISO/IEC/IEEE 42010:2022** supplies the concepts of architecture
descriptions, viewpoints, views and model kinds. A1A8 is our concrete set
of viewpoints. We do not claim full ISO conformance merely because a card
uses these labels.
- **UML 2.5.1** supplies the notation for classes, objects, components,
interactions, activities and state machines. It does not prescribe A1A8.
- **MARTE 1.3** may annotate schedulable resources, time, hardware and
allocation in RTOS cards. A MARTE property must come from configuration,
code or measurement; authors must not invent period, deadline or execution
time merely to fill a box.
- **arc42** is a useful wider documentation template. A1A8 is the smaller,
interactive teaching slice used inside a card, not a replacement for an
architecture description of the whole product.
- **PlantUML** is the text-first renderer. The `.puml` source, not a manually
edited SVG, is authoritative.
Primary references:
- <https://www.iso.org/standard/74393.html>
- <https://www.omg.org/spec/UML/2.5.1>
- <https://www.omg.org/spec/MARTE/1.3>
- <https://arc42.org/overview>
- <https://plantuml.com/class-diagram>
- <https://plantuml.com/sequence-diagram>
- <https://plantuml.com/ascii-art>
## The fixed navigation model
The tab names remain stable across cards. A subtitle identifies the actual
mechanism being taught.
```text
A1 CONTEXT
A2 STRUCTURE
A3 DISPATCH
A4 APPLICATION
A5 FLOW
A6 STATE
A7 RUNTIME
A8 PATTERNS
```
These eight tabs ask eight different questions:
| ID | Question | Typical model kind |
|---|---|---|
| A1 CONTEXT | Where is the subject and what lies outside its boundary? | component, package or deployment view |
| A2 STRUCTURE | What static elements and relationships construct it? | class, component or object structure |
| A3 DISPATCH | How is an abstract call bound to the actual implementation? | class plus sequence/call-path view |
| A4 APPLICATION | How does application code specialize or compose it? | application class/object view |
| A5 FLOW | What happens in what order? | sequence or activity view |
| A6 STATE | Which lifecycles and state transitions exist? | state machine, never an unlabeled flowchart |
| A7 RUNTIME | What actually exists in memory and in the debugger now? | object diagram plus evidence overlay |
| A8 PATTERNS | Which design roles and trade-offs explain the construction? | participant map plus decision record |
Not every card needs all eight views. The top-level navigation keeps all eight
positions stable; an omitted view is visibly unavailable and states why. A
small card should not create decorative diagrams to fill empty tabs.
## Viewpoint contracts
### A1 CONTEXT
**Purpose:** establish system boundary and dependency direction before class
details appear.
Required content:
- subject under study;
- upstream application actor or component;
- wrapped platform/API;
- runtime platform, hardware or simulator when relevant;
- one verb on every boundary-crossing relation.
For an RTOS wrapper this normally reads:
```text
Application task
│ specializes / uses
C++ wrapper
│ calls
FreeRTOS C API
│ schedules on
Hazard3 simulator
```
A1 must not list every method. It is a map, not a class reference.
### A2 STRUCTURE
**Purpose:** show the static construction that the compiler sees.
Required content:
- class/interface/component names;
- relevant fields and operations only;
- visibility where it is part of the lesson;
- precise relationship type: generalization, realization, composition,
aggregation or dependency;
- storage/ownership role when the structure owns a resource.
Class rows receive semantic anchors only when a card can connect them to a
source line or a compile-time proof. Inheritance, `friend`, templates and
visibility are CODE facts; they are never presented as runtime events.
### A3 DISPATCH
**Purpose:** explain the binding mechanism between the generic boundary and
the concrete implementation.
The title is fixed; the subtitle is mechanism-specific. Examples:
```text
A3 DISPATCH · CRTP static dispatch
A3 DISPATCH · virtual dispatch through vtable
A3 DISPATCH · C callback and function pointer
A3 DISPATCH · event to subscriber
A3 DISPATCH · executor and completion handler
```
The diagram must identify:
1. the call origin;
2. the erased or abstract boundary;
3. the cast, lookup or binding operation;
4. the concrete target;
5. whether the decision is compile-time or runtime;
6. the ABI proof that distinguishes the mechanism.
This viewpoint prevents a wrapper from being mislabeled. A CRTP wrapper must
show `static_cast<Derived*>` and the absence of virtual dispatch. A dynamic
wrapper must show object address, `vptr`, vtable entry and indirect call.
### A4 APPLICATION
**Purpose:** show one concrete use without repeating the complete library.
The generic mechanism is collapsed to its public contract. The view maps every
pattern or framework role to the names used in the exercise, for example
`Strategy -> PaymentStrategy` and `Context -> ShoppingCart`.
At least one application invariant is printed next to the model. Example:
"`ShoppingCart` depends on the strategy interface, not a payment variant."
### A5 FLOW
**Purpose:** show causal order for one named scenario.
Rules:
- state the precondition and observable postcondition;
- use sequence diagrams for collaborating participants and activity diagrams
for algorithmic branching;
- number messages in the same order as interactive steps;
- show returns only when they carry teaching information;
- split construction, scheduling and callback dispatch into phases when one
page would hide the boundary.
A5 is the primary home of RUN steps and deterministic checkpoints.
### A6 STATE
**Purpose:** separate lifecycle from execution flow.
When two state domains exist, draw two explicit lanes rather than merging them.
For a FreeRTOS C++ task these are commonly:
```text
C++ object lifetime: absent -> constructed -> alive -> destroyed
Kernel task state: Ready <-> Running <-> Blocked; Suspended; Deleted
```
Every transition has a trigger, guard or event. Values returned by platform
APIs are platform states, not invented wrapper states. A wrapper-specific state
machine is allowed only when the code really stores and enforces it.
### A7 RUNTIME
**Purpose:** connect the model to a reproducible observation.
A7 is deliberately a hybrid, not pure UML. It combines an object diagram with
selected debugger facts:
- object and subobject addresses;
- `this`, callback context and handles;
- fields, ownership pointers, TCB and stack interval;
- PC, SP and relevant argument registers;
- vptr/vtable target for dynamic dispatch;
- symbol/absence-of-symbol proof for static dispatch;
- timestamp, target, ELF revision and checkpoint identity.
Every value is either captured from a deterministic run or marked as a
symbolic example. A screenshot without target, source revision and timestamp is
illustration, not evidence.
### A8 PATTERNS
**Purpose:** explain why the design has its shape and what it costs.
Each claimed pattern records:
- intent and problem;
- forces/constraints;
- canonical participant roles;
- exact mapping from role to project class/function;
- collaboration that makes the pattern real;
- invariant or test;
- benefit and cost;
- rejected alternative;
- conditions in which the pattern should not be used.
Pattern names are not decorative stereotypes. `Facade` is valid only when a
simpler boundary to a subsystem can be identified. `RAII` is valid only when
acquisition and release are safely paired for every legal lifetime. A callback
bridge may be an Adapter without making the whole wrapper an Adapter.
## Authored viewpoint record
The future machine-readable form should preserve this conceptual record. This
is a design target, not yet a required `card_source.json` schema extension:
```json
{
"id": "a3-dispatch",
"number": "A3",
"label": "DISPATCH",
"subtitle": "Dynamic polymorphism through vtable",
"purpose": "Trace the C callback to the concrete C++ override.",
"stakeholders": ["student", "teacher", "embedded developer"],
"concerns": ["C-to-C++ bridge", "void* context", "vtable", "ABI"],
"model_kind": "uml-sequence",
"source": "doc/assets/a3-dispatch.puml",
"fallback_text": "doc/assets/a3-dispatch.txt",
"spread_group": "task-dispatch",
"steps": [
{
"id": "dispatch-vptr",
"number": 4,
"mode": "RUN",
"svg_target": "dispatch-vptr",
"code_ref": "include/FreeRTOS/Task.hpp:110",
"snapshot_ref": "task.dispatch.vptr",
"evidence": "a0, object address, vptr, vtable entry and jalr target"
}
]
}
```
Required semantics:
- `id`, `number` and `label` are stable teaching identity;
- `subtitle` names the actual mechanism and may differ between cards;
- `source` is the text source of the rendered asset;
- `fallback_text` is a compact readable map, not generated alt text;
- `code_ref` is repository-relative and validated;
- CODE steps may have no snapshot and never reset the program;
- RUN steps require a deterministic replay target;
- `evidence` says what proves the claim, not merely what should be visible;
- `spread_group` joins logical continuations without changing A4 print pages.
## Plain technical rendering profile
"Plain text UML" means two related things in this project:
1. diagrams are authored as reviewable text;
2. their rendered form resembles a restrained technical drawing rather than a
presentation slide.
The default profile therefore uses:
- white background, black/charcoal strokes and no shadows;
- square or nearly square corners;
- one monospaced family for identifiers, fields, methods and evidence;
- one sans-serif family only for explanatory prose;
- orthogonal relations where the renderer can keep labels legible;
- left-aligned members and short, explicit verbs on relations;
- no gradients, icons, ornamental colors or oversized titles;
- line weight and spacing, not color, as the primary print hierarchy;
- visible step anchors such as `01``08` that remain useful in SVG and print;
- two muted selectable tones in HTML and one subtle active outline;
- non-selectable content in neutral gray, never confused with a selectable
inactive element.
PlantUML can generate ASCII/Unicode text output for sequence diagrams. We may
ship that output as the fallback for sequences. Other diagram kinds receive a
small hand-maintained text map because PlantUML's ASCII renderer does not cover
all UML kinds. The fallback communicates topology and reading order; SVG and
TeX remain the visual outputs.
## Orientation, type scale and page visibility
The default reading direction is vertical. A horizontal layout is reserved for
a genuine sequence or timeline whose primary fact is execution order over
time. A binding chain is vertical unless time or participant lifelines are
being modelled explicitly.
| Viewpoint | Default orientation | Reason |
|---|---|---|
| A1 CONTEXT | vertical | responsibility descends from application to platform |
| A2 STRUCTURE | vertical | base types, specializations and dependencies form tiers |
| A3 DISPATCH | vertical | binding stages form a top-to-bottom chain; use horizontal only for a genuine sequence |
| A4 APPLICATION | vertical | application objects lead to observers and invariants |
| A5 FLOW | horizontal | messages and time advance in reading order |
| A6 STATE | vertical | lifecycle transitions form explicit top-to-bottom paths |
| A7 RUNTIME | geometry-dependent | use vertical for an ownership descent, horizontal for a memory/CPU evidence pipeline |
| A8 PATTERNS | geometry-dependent | use vertical for tiers and horizontal for a short chain of roles and consequences |
Use `top to bottom direction` unless the diagram is a genuine sequence or
timeline (normally A5). A diagram must not be made horizontal merely to fill
page width.
Physical page orientation follows the rendered model rather than the viewpoint
name: use one portrait page, one landscape page, or an explicit semantic page
composition. Prefer a single page after a deliberate layout change; introduce
tiles only when readable labels and complete semantic blocks still cannot fit.
The default PlantUML type scale is `14` for ordinary labels, `15` for class
names and `13` for class attributes. A smaller value is allowed only when the
diagram remains readable at the normal A4 viewer scale. Prefer fewer words,
shorter relation labels and a second logical page over shrinking text.
All diagrams belonging to one card use one shared PlantUML style include. The
style is print-first and keeps the following invariants:
- one monospaced family for nodes, relations and sequence messages;
- a `190 px` minimum class width, while content may make a node wider;
- `1.5 px` node borders and `1.3 px` arrows;
- a near-white node fill, blue-grey borders and dark text with sufficient
monochrome-print contrast;
- the same base styling for class, state and sequence diagrams;
- no shadows, decorative gradients or per-diagram colour inventions.
Interactive selection is an overlay owned by the viewer. The source diagram
must remain fully legible with no selection, while selectable nodes receive a
clearer idle treatment than non-interactive context nodes. Selection changes
emphasis, not geometry: it must not resize a node, move a label or alter the
diagram layout.
At `content scale = 100%`, the HTML viewer preserves the intrinsic PlantUML
scale. A diagram that exceeds the declared A4-safe viewport is split into
semantic tiles; it is not silently compressed to `width: 100%`. The joined
HTML spread reconstructs the logical page in a CSS grid, while ordinary view
and print retain separate physical A4 sheets. Canvas zoom remains an explicit
viewer action and may be used to inspect the joined overview.
Every diagram starts on a new A4 page in HTML and TeX. Its SVG must fit within
the page-safe margins with all labels, arrowheads and numbered anchors visible.
Long diagrams continue on a new page with stable global step numbers and may be
joined by the HTML spread view. Every physical tile remains legible on its own,
but its `part`, row and column identify its exact position in the logical model.
## Large diagrams and page continuity
A viewpoint is one logical model even when it needs several A4 pages.
- `page_grid` declares columns, rows and explicit semantic `cuts_x`/`cuts_y`;
- a cut may cross whitespace or a connector, but never a class, object, state,
participant, note, numbered anchor or other closed semantic block;
- the generator validates the rendered SVG geometry and rejects a colliding
seam instead of shrinking the diagram or accepting a broken print;
- every interactive step belongs to exactly one tile through `step_tiles`;
- all tiles use one logical figure number and one global navigation cursor;
- each page carries `A<n>`, the same viewpoint title, `part x/y`, and a shared
`spread_group`;
- duplicated participants at a page boundary are marked `continued`, not
treated as new objects;
- step numbers remain global across parts;
- connectors leaving a page use a named continuation token, for example
`D3 -> A5.2`;
- HTML can join the parts side by side; print keeps independent A4 pages;
- the joined HTML view fits the complete logical row into the viewport, keeps
page tops aligned and centers the semantic join rather than either sheet;
- a screen-only continuation cue in every part header indicates available
neighbours to the left, right, above and below;
- selecting a step scrolls to the correct part and preserves one cursor;
- no information is encoded only in the physical proximity of two pages.
The source diagram may use a modest, explicit PlantUML `scale` when that is
necessary to place a semantic seam inside the A4-safe viewport. This is a
design decision, not automatic fit-to-width. The resulting normal print must
still meet the shared type-scale readability gate; HTML hover/canvas zoom is a
convenience and never a substitute for readable print.
## Interaction and correspondence rules
The diagram, source tree and debugger share one navigation identity:
```text
SERIES -> CARD -> TASK -> BLOCK -> VIEWPOINT/PHASE -> STEP -> SNAPSHOT
```
For every selectable anchor:
- its visible step number occurs exactly once inside that diagram;
- click and keyboard navigation select the same step;
- CODE opens the exact code or binary proof and does not mutate runtime;
- RUN opens code and may replay only after explicit activation;
- compile-time relations use code, `nm`, `readelf` or disassembly evidence;
- runtime messages use checkpoint evidence;
- focus is a subtle overlay; unselected selectable targets stay visible;
- a missing `snapshot_ref` is valid for CODE and invalid for RUN;
- the authored SVG target is validated after PlantUML rendering.
## Diagram-first teaching contract
The diagram is the primary entry point into an example. A printed card must
teach the algorithm, responsibility boundary, state transition or dispatch
mechanism before it exposes implementation syntax. Complete source listings
do not belong on the card. The card carries the repository URL/QR code, while
an interactive CODE anchor opens only the relevant symbol or source range in
Neovim.
The intended learning path is:
```text
goal and scope
-> relevant A1-A8 viewpoint
-> numbered diagram element
-> CODE source anchor or RUN checkpoint
-> Neovim / Termdebug / Hazard3 evidence
-> timestamped snapshot
```
Consequently:
- a card uses only the A1-A8 viewpoints which materially explain the subject;
- the diagram explains the mechanism, source confirms its implementation and
the debugger supplies evidence;
- CODE navigation does not restart or mutate the program;
- RUN navigation may replay only to a declared deterministic checkpoint;
- source excerpts may appear temporarily in the interactive Neovim view, but
are not duplicated as full static listings in HTML, TeX or print;
- every source jump is attached to a concrete diagram element, relation,
message or state rather than to an unrelated code catalogue;
- the repository link remains the canonical route to the complete source.
This order is deliberate: students first reason about algorithms, states and
responsibilities, then inspect the C or C++ syntax that implements them.
## Editable UML layout and JSON persistence
Interactive UML views may expose an explicit `EDIT` mode. It applies only to
UML/model assets; it must not turn the whole card page into a free-form editor
or interfere with normal CODE/RUN navigation.
PlantUML remains the authoritative semantic source for participants,
relationships and diagram kind. Manual visual decisions are stored in a
sidecar JSON document named after the source, for example:
```text
doc/assets/a2-structure.puml
doc/assets/a2-structure.layout.json
```
Saving a layout persists the complete authored presentation state, not only a
temporary browser transform. At minimum the sidecar records:
- diagram identity, source revision and layout schema version;
- canvas size, page orientation, scale and optional page-grid metadata;
- stable element identity (`id`/`svg_target`), position and stacking order;
- width, height, local scale and rotation when the model kind allows it;
- displayed name, stereotype, short description and member text overrides;
- font family, font size, weight, style, line height and text alignment;
- fill, stroke, border width, corner treatment and semantic style role;
- group membership, collapsed state and explicit grouping/ungrouping;
- relation endpoints, labels and manually placed routing points;
- numbered CODE/RUN anchor placement without changing its teaching identity;
- editor metadata such as update timestamp and optional author.
A representative record is:
```json
{
"schema": "stem.uml-layout/v1",
"diagram_id": "task01.a2-structure",
"source": "a2-structure.puml",
"source_digest": "sha256:...",
"canvas": {
"width": 1120,
"height": 760,
"orientation": "landscape",
"scale": 1
},
"elements": {
"task-base": {
"x": 310,
"y": 72,
"width": 360,
"height": 290,
"z": 2,
"text": {
"title": "Task<Derived>",
"description": "Static task wrapper",
"font_family": "IBM Plex Mono",
"font_size": 14,
"font_weight": 500,
"align": "left"
},
"style": {
"role": "wrapper",
"fill": "#eef5f8",
"stroke": "#397c99",
"stroke_width": 1.5
}
}
},
"relations": {
"task-to-api": {
"from": "task-base",
"to": "freertos-api",
"label": "calls",
"points": [[490, 362], [490, 430], [690, 430]]
}
},
"updated_at": "2026-07-19T12:00:00+02:00"
}
```
Editor requirements:
- dragging, resizing, text editing, grouping and relation routing update an
in-memory draft first;
- `Save layout` validates stable IDs and writes the sidecar atomically;
- `Cancel` restores the last saved sidecar without changing PlantUML;
- `Reset layout` removes visual overrides and returns to the generated
PlantUML geometry only after explicit confirmation;
- rerendering PlantUML reapplies compatible overrides by stable ID and reports
orphaned overrides instead of silently discarding them;
- a source digest mismatch is visible to the editor but does not destroy the
saved layout;
- normal view and print consume the same saved JSON, so the authored geometry
is reproducible outside the editing session;
- CODE/RUN step IDs, source references and snapshot identities cannot be
renamed accidentally by a visual edit.
Exact manual coordinates cannot be represented reliably through PlantUML
layout hints alone. The sidecar is therefore the canonical manual presentation
layer, while `.puml` remains the canonical semantic layer.
## Two valid A3 profiles for FreeRTOS wrappers
The viewpoint set intentionally supports both of these designs.
### Current teaching wrapper in K02
```text
A2 STRUCTURE Task<Derived>, SumTask, SupervisorTask
A3 DISPATCH CRTP static dispatch
void* -> Task<Derived>* -> Derived* -> run()
A7 RUNTIME same object address; direct/inlined target; no vtable symbol
```
This matches the current K02 acceptance gate: no virtual dispatch, vtable,
RTTI or hosted runtime.
### `jonenz/FreeRTOS-Cpp` reference design
```text
A2 STRUCTURE TaskBase <- Task / StaticTask<N> <- application task
A3 DISPATCH dynamic dispatch
void* -> TaskBase* -> taskEntry() -> virtual taskFunction()
A7 RUNTIME object address, vptr, vtable entry and indirect target
```
The upstream `Task.hpp` creates dynamic/static kernel tasks in constructors,
passes `this` to `callTaskFunction(void*)`, and uses a virtual
`taskFunction()`. Its `TaskBase` destructor may call `vTaskDelete(handle)` when
configured. These are reference facts, not automatic design choices for our
teaching wrapper. Adopting that design would require changing K02's lifecycle,
ABI and no-vtable acceptance contracts explicitly.
Reference:
<https://github.com/jonenz/FreeRTOS-Cpp/blob/develop/FreeRTOS-Cpp/include/FreeRTOS/Task.hpp>
## Target profile: Boost.Asio and standard threads
This is the required future compatibility profile. It does not rename the
fixed tabs. Mechanism-specific wording belongs in subtitles:
```text
A1 CONTEXT · application, Asio, io_context, worker threads, OS
A2 STRUCTURE · Server, Session, socket, strand and ThreadPool
A3 DISPATCH · executor and completion-handler dispatch
A4 APPLICATION · one concrete Session or Client
A5 FLOW · asynchronous initiation and completion
A6 STATE · operation, session and thread lifecycles
A7 RUNTIME · threads, executors, handlers and owned buffers
A8 PATTERNS · Proactor and verified collaboration roles
```
The fixed label remains `A5 FLOW`, not `A5 ASYNC FLOW`; the UI subtitle may be
`Async completion flow`. Likewise the fixed label remains `A7 RUNTIME`, with
`Threads / executors` as a subtitle. This keeps cards comparable while still
naming the actual mechanism.
### A1A8 mapping
**A1 CONTEXT** shows this dependency/execution stack:
```text
Application Session / Server
│ initiates
Boost.Asio async operations, executors and strands
│ queue completions in
io_context
│ run() is called by
std::thread / std::jthread workers
│ use
operating-system sockets and scheduling
```
**A2 STRUCTURE** shows the static ownership and dependency graph: `Server`,
`Session`, `tcp::socket`, executor/strand, buffers, `io_context` and the worker
collection. It must make lifetime ownership explicit, especially when a
session uses `shared_from_this()` to outlive an initiating call.
**A3 DISPATCH** traces an initiating function through the outstanding
operation, associated executor, completion queue and selected handler. It must
not draw `async_read` as if it created a user thread. Completion handlers are
invoked only by threads currently running `io_context::run()`; several such
threads form a pool from which `io_context` may choose. A strand adds strictly
sequential handler invocation, not physical affinity to one thread.
**A4 APPLICATION** collapses Asio infrastructure and shows one concrete
protocol/session contract, for example `EchoSession::start/read/onRead/write`.
**A5 FLOW** uses the explicit sequence:
```text
initiate -> outstanding -> operation completes -> handler queued
-> one run() thread invokes handler -> next operation or completion
```
**A6 STATE** separates at least three domains when present:
```text
jthread object: absent -> joinable -> stop requested -> joined
async operation: initiated -> outstanding -> queued -> running -> done
application Session: Created -> Reading -> Processing -> Writing -> Closed
```
The `std::jthread` destructor requests stop and joins when the object is still
joinable. A session state is application data; it must not be inferred merely
from a handler being present in a queue.
**A7 RUNTIME** records `io_context`, worker IDs, current handler and thread,
executor/strand identity, socket descriptor, operation kind, session address,
buffer lifetime and relevant smart-pointer ownership. The evidence view uses
`info threads`, backtraces and object inspection rather than RTOS TCB fields.
**A8 PATTERNS** may identify Proactor, callback/continuation, serialized
execution through a strand, thread pool, RAII thread ownership and lifetime
management. These are classified carefully: `std::jthread` ownership is a C++
idiom, a thread pool is a concurrency architecture, and not every completion
handler constitutes a GoF Command. Boost.Asio documents its asynchronous model
as Proactor; the card must still map each claimed role to project code.
The central invariant for every future Asio card is:
```text
asynchronous operation != thread
operation completion -> associated executor -> io_context
-> one thread currently executing run()
```
Primary references for this profile:
- <https://www.boost.org/doc/libs/latest/doc/html/boost_asio/overview/core/threads.html>
- <https://www.boost.org/doc/libs/latest/doc/html/boost_asio/overview/core/strands.html>
- <https://www.boost.org/doc/libs/latest/doc/html/boost_asio/overview/core/async.html>
- <https://eel.is/c++draft/thread.thread.class>
- <https://eel.is/c++draft/thread.jthread.class>
## Definition of done for a card view
A viewpoint is ready when:
1. its purpose and question are stated;
2. the chosen UML/model kind fits that question;
3. every relation has one unambiguous meaning;
4. every selectable item has a stable anchor and code reference;
5. runtime claims have reproducible evidence;
6. compile-time claims use compiler/binary evidence rather than fake runtime;
7. the text fallback remains understandable without SVG;
8. the view prints in monochrome and works as an interactive HTML asset;
9. continuation across pages preserves identity and step order;
10. A8 names costs and rejected alternatives, not only benefits.