feat: publish A1-A8 card viewer and FreeRTOS C generator
Check card layouts / check (push) Has been cancelled
Check card layouts / check (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,725 @@
|
||||
# A1–A8 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
|
||||
|
||||
A1–A8 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. A1–A8 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 A1–A8.
|
||||
- **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. A1–A8 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.
|
||||
|
||||
### A1–A8 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.
|
||||
Reference in New Issue
Block a user