From af44b3506a75a6ab70d6572834df99c6be7916e2 Mon Sep 17 00:00:00 2001 From: Nikita Belenkiy Date: Tue, 1 Sep 2026 13:36:06 +0200 Subject: [PATCH 1/2] message_passing: seooc preparations --- .../actualize-message-passing-seooc.prompt.md | 80 ++++++ .github/skills/rules-score-actualize/SKILL.md | 270 ++++++++++++++++++ .github/skills/rules-score/SKILL.md | 217 ++++++++++++++ score/message_passing/research/backlog.md | 41 +++ .../message_passing/research/nice_to_haves.md | 16 ++ .../research/problem_statement.md | 185 ++++++++++++ score/message_passing/research/references.md | 30 ++ score/message_passing/research/work_log.md | 34 +++ 8 files changed, 873 insertions(+) create mode 100644 .github/prompts/actualize-message-passing-seooc.prompt.md create mode 100644 .github/skills/rules-score-actualize/SKILL.md create mode 100644 .github/skills/rules-score/SKILL.md create mode 100644 score/message_passing/research/backlog.md create mode 100644 score/message_passing/research/nice_to_haves.md create mode 100644 score/message_passing/research/problem_statement.md create mode 100644 score/message_passing/research/references.md create mode 100644 score/message_passing/research/work_log.md diff --git a/.github/prompts/actualize-message-passing-seooc.prompt.md b/.github/prompts/actualize-message-passing-seooc.prompt.md new file mode 100644 index 0000000000..2235cb3c36 --- /dev/null +++ b/.github/prompts/actualize-message-passing-seooc.prompt.md @@ -0,0 +1,80 @@ +--- +description: "Start using the rules-score-actualize lifecycle on score/message_passing/: create its research/ scratchpad with a reverse-documented baseline snapshot of the existing (trusted) dependability artifacts, then stop and ask the human what the first concrete actualization cycle should be about." +agent: "agent" +argument-hint: "Bootstrap the message_passing actualization scratchpad; the concrete change comes later" +--- + +# Bootstrap: Message Passing Actualization Scratchpad (Cycle 0 — Baseline Snapshot) + +You are starting to use the **`rules-score-actualize`** skill +(`.github/skills/rules-score-actualize/SKILL.md`) on `score/message_passing/`. Read that skill +first — it defines the impact-analysis-first update process, the `research/` scratchpad layout for +repeated cycles, and the checkpoint discipline you must follow. This prompt only supplies the +component-specific starting facts; do not rely on any other session or host-specific memory. + +## Why this component, and why `rules-score-actualize` and not `rules-score` + +`score/message_passing/` already has a real `dependable_element` at +`score/message_passing/dependability/` (`integrity_level = "B"`, `maturity = "development"`) with +frozen `assumed_system/`, `requirements/`, `software_architectural_design/`, and +`safety_analysis/` content that passes verification today. This is **not** a discardable PoC — +treat it as the trusted baseline. Any future change to it must go through +`rules-score-actualize`'s impact-analysis-and-cascade process, never through `rules-score`'s +"re-derive fresh, discard old names" rework path. + +## What you are doing in this prompt + +Only the **first bullet of `rules-score-actualize`'s "If `research/` does not exist yet for this +component"** section — nothing else. Concretely: + +1. Confirm `score/message_passing/research/` does not already exist. If it does, stop and ask the + human how to proceed instead of overwriting it. +2. Read, read-only, the existing frozen artifacts under `score/message_passing/dependability/`: + `assumed_system/` (`aous.trlc`, `assumed_system_requirements.trlc`), `requirements/` + (`feature_requirements.trlc`, `component_requirements.trlc`, `external_component_requirements.trlc`), + `software_architectural_design/` (`static_design.puml`, `public_api.puml`, `private_api.puml`, + `client_connection_activity_diagram.puml`, `server_client_sequence.puml`, `client-server.md`), + and `safety_analysis/` (`failure_modes.trlc`, `control_measures.trlc`, `fta_*.puml`). Also skim + the public headers in `score/message_passing/` itself (`i_client_connection.h`, + `i_client_factory.h`, `i_server.h`, `i_server_factory.h`, `i_server_connection.h`, + `i_connection_handler.h`, `service_protocol_config.h`) for the current public API surface these + artifacts describe. +3. Write `score/message_passing/research/problem_statement.md` as a **reverse-documented baseline + snapshot** — per the skill's template guidance: terminology already in use (e.g. what this + component calls a "protocol", a "session", a client vs. server connection), the system slice + (same-host IPC abstraction, Linux Unix-domain-socket and QNX native-dispatch backends behind one + API), an index of the existing `AssumedSystemReq`/`FeatReq`/`CompReq`/`FailureMode`/ + `ControlMeasure` records (names + one-line gist each, not full text), and the current + `integrity_level`/`maturity`. State explicitly, near the top of the file, that this is + orientation material reverse-documented from a trusted baseline, not a fresh Step-0-style + derivation, and that the frozen TRLC/PlantUML remain the authoritative source of truth. +4. Note **`score/mw/com/impl/bindings/lola/messaging/`** in `research/references.md` as one known, + concrete, non-exclusive consumer of `score/message_passing/` — it uses the client/server + connection API for LoLa method calls (see `message_passing_service.{h,cpp}`, + `message_passing_client_cache.{h,cpp}`). Record this only as orientation evidence for future + impact analyses ("does a change affect this consumer's usage pattern?") — `message_passing`'s + public API and architecture must stay consumer-agnostic; do not let this one consumer's needs + drive the baseline snapshot's content, and do not go looking for or assume any other specific + consumer beyond what already exists in the repository today. +5. Seed `research/backlog.md` and `research/nice_to_haves.md` with anything you noticed while + reading (e.g. inconsistencies between the code and the frozen diagrams/requirements, TODOs in + the design docs) — capture only, do not fix anything yet. +6. Write a first dated entry in a top-level `research/work_log.md` describing this bootstrap (there + is no `changes//` directory yet — that only gets created once a concrete change is + defined, per the skill). + +## What NOT to do in this prompt + +- Do not modify anything under `score/message_passing/dependability/` or + `score/message_passing/*.{h,cpp}` — this is a read-only reconnaissance pass. +- Do not invent a concrete change, defect, or new requirement to act on. There is no specific + trigger yet — do not manufacture one just to have something to do. +- Do not create a `research/changes//` directory yet. + +## Stop condition + +After writing `problem_statement.md` and the shared scratchpad files, stop. Summarize the baseline +snapshot for the human and explicitly ask what the first real actualization cycle should be about +(a new need, a known defect, an assumption that no longer holds, or something else) — per +`rules-score-actualize` Step 0, that answer becomes `research/changes// +change_request.md` in a follow-up run, not in this one. diff --git a/.github/skills/rules-score-actualize/SKILL.md b/.github/skills/rules-score-actualize/SKILL.md new file mode 100644 index 0000000000..521b1addbc --- /dev/null +++ b/.github/skills/rules-score-actualize/SKILL.md @@ -0,0 +1,270 @@ +--- +name: rules-score-actualize +description: "Incremental, traceable actualization/update lifecycle for an EXISTING S-CORE Safety Element out of Context (SEooC) built with the rules_score Bazel rules, whose requirements/architecture/safety/test artifacts are the trusted baseline (not a discardable PoC) but may themselves be incorrect, obsolete, or out of date with a new need. USE FOR: adding a new requirement to an already-authored dependable_element; fixing a defect where code/tests contradict a frozen requirement or diagram; retiring an obsolete requirement/behaviour; extending the design for a new or changed consumer; deciding the minimal set of existing artifacts a change must touch; keeping version numbers, derived_from links, FTA aliases, and lobster-tracing ids consistent across a small, reviewable diff. Component-agnostic — do not hardcode any component's domain content here. NOT FOR: bootstrapping a brand-new dependable_element or discarding a low-maturity/PoC baseline wholesale — use rules-score for that." +argument-hint: "component/SEooC name and the change being made (new need, defect, or drift)" +--- + + + +# S-CORE SEooC Actualization Lifecycle — Orchestrating Skill + +This skill is the router and process backbone for **updating an already-authored S-CORE Safety +Element out of Context (SEooC)** built with the `rules_score` Bazel rules, when its existing +requirements/architecture/safety-analysis/test artifacts are the **trusted baseline** for the +project — not evidence to discard — but the world has moved: a new need appeared, a defect was +found, an assumption stopped holding, or the design silently drifted from the code. It sequences +the same four mechanical skills as `rules-score` (`score-requirements`, `score-architecture`, +`score-safety-analysis`, `score-testing`), but drives them through **impact analysis and +minimal-diff cascade** instead of top-down fresh derivation. + +**This skill is intentionally component-agnostic.** It must never be edited to bake in the domain +content of one particular component. Component-specific knowledge belongs in that component's +`research/` scratchpad and its frozen/updated TRLC/PlantUML artifacts. + +## Which lifecycle skill do I need? + +| Situation | Use | +|---|---| +| No `dependable_element` exists yet for this component | **rules-score**, fresh Step 0 | +| Existing artifacts are low-maturity/PoC-quality and explicitly discardable (no external consumer relies on their names/wording) | **rules-score**, "Handling a rework" | +| Existing artifacts are the project's trusted baseline (released or actively relied upon), and something changed, was found wrong, or needs extending | **rules-score-actualize** (this skill) | + +If you are unsure which bucket a component is in, ask the human — do not guess whether an existing +baseline is discardable. + +## When to use + +- A new informal need lands on top of an **already-existing** dependable_element (not a blank + slate) — e.g. a new consumer needs a capability the current contract doesn't promise. +- A defect is found: the code, a test, or an architecture-consistency/coverage-lock check + contradicts a frozen requirement, diagram, or safety record. +- An `AssumedSystemReq`/`AoU` no longer holds because the environment changed. +- A requirement or behaviour is obsolete and should be retired without breaking traceability. +- Deciding the **smallest correct set** of existing artifacts a change must touch, and in what + order, without re-deriving the whole component from scratch. + +## Not for + +- Bootstrapping a `dependable_element` that doesn't exist yet, or wholesale-discarding a + low-maturity/PoC baseline → **rules-score** +- The mechanics of writing a `.trlc` record once you know what it should say → **score-requirements** +- PlantUML diagrams and the Bazel hierarchy once the target decomposition is agreed → + **score-architecture** +- FMEA/FTA/`FailureMode`/`ControlMeasure` mechanics once the failure reasoning is done → + **score-safety-analysis** +- Test annotation and `test_case_coverage.lock.yaml` mechanics once coverage intent is decided → + **score-testing** + +--- + +## Core principles + +1. **Additive and minimal by default.** Express a change as either (a) an in-place edit **and** + version bump of exactly the record(s)/diagram(s) whose content actually changed, or (b) a + genuinely new record for genuinely new content. Never rewrite, rename, or reshuffle an + unaffected artifact just to "clean it up" while you're in the area — log opportunistic findings + in `backlog.md` instead of acting on them. +2. **Freeze what the change doesn't touch.** If a layer, record, or diagram falls outside the + impact analysis (see Step 1 below), it does not appear in the diff at all. A large, sprawling + diff for a small stated change is a sign the impact analysis was wrong, not a sign of + thoroughness. +3. **Impact analysis runs both directions before any edit.** For the artifact that appears to be + directly affected, walk **upward** first — what does it derive from, and is the *real* defect + actually one layer higher (a wrong `FeatReq` masquerading as a `CompReq` bug, a wrong diagram + masquerading as a wrong safety record)? Never patch a downstream symptom while the upstream + defect stays in place. Then walk **downward** — every `derived_from` reference, every FTA + `$BasicEvent`/`$TransferInGate` alias, every `lobster-tracing` id, every + `test_case_coverage.lock.yaml` entry that points at what you are about to change — to build the + full ripple set that must be re-pinned or re-verified. +4. **Version bump + re-pin discipline is not optional.** Every content change bumps `version` + (per `score-requirements`); every downstream reference to that record is updated to the new + version in the same cycle. A change that "forgot" a ripple reference is incomplete, not done. +5. **Distinguish "wrong today" from "was right, world changed".** A record can be factually wrong + right now (defect) or can have been a correct, deliberate decision that a new fact (new + consumer, new assumption) now invalidates. The write-up in `change_request.md` (Step 0) must say + which one it is — it changes where the fix belongs and whether the original author's intent + needs revisiting. +6. **Retire, don't silently delete.** An obsolete requirement/record is marked superseded/deprecated + (e.g. a `note` explaining why, and what replaces it) and only physically removed once the + downward ripple confirms nothing still references it. Removing a record that something else + still `derived_from`s or traces a test to breaks the build loudly — treat that as the safety net + it is, not an obstacle to route around. +7. **Human-in-the-loop scoped to what changed.** Unlike a full fresh lifecycle, you do not need a + checkpoint on every layer of the model — only on the layers the impact analysis says are + touched. But every touched layer still gets an explicit human go-ahead before its version bump + is treated as final. +8. **Everything is a file, nothing is memory.** The change's rationale, its impact analysis, and + its evidence bundle live in git-tracked files under the component's `research/` directory (see + below), not in agent/session memory, so the next actualization cycle — possibly months later, + by a different person — can reconstruct why a version was bumped. +9. **Maturity raises the stakes, it doesn't change the process.** If the component's + `dependable_element.maturity` is `"development"`, drift/coverage/GWT violations are warnings + during the work; if it is `"release"`, the same violations fail the build. Either way, run the + same impact-analysis-first process — `"release"` maturity is a reason for a more careful human + review before merging, not a reason to skip steps. + +--- + +## The `research/` directory (adapted for repeated, ongoing cycles) + +A component actualized through this skill is expected to go through **many** cycles over its +lifetime — unlike `rules-score`'s one-shot bootstrap, this scratchpad convention must not let +successive cycles clobber each other's history. + +``` +/research/ +├── problem_statement.md # OPTIONAL, amended in place across cycles (see below) — a living +│ # orientation snapshot, never itself the source of truth once the +│ # component has frozen TRLC/PlantUML artifacts +├── changes/ +│ └── -/ # one directory per actualization cycle, never reused or overwritten +│ ├── change_request.md # Step 0 output: the trigger, in the vocabulary of Core Principle 5 +│ ├── impact_analysis.md # Step 1 output: upward root-cause + downward ripple set +│ ├── work_log.md # append-only, dated entries for this cycle only +│ ├── next_steps.md # current step within this cycle +│ └── evidence_bundle.md # Step 6 output: final change list, version-bump table, ripple +│ # map, residual risk / deferred items +├── references.md # long-lived, shared across all cycles +├── backlog.md # long-lived, shared across all cycles — opportunistic findings land +│ # here (Core Principle 1), not in the current cycle's diff +└── nice_to_haves.md # long-lived, shared across all cycles +``` + +### If `research/` does not exist yet for this component + +Components actualized with this skill may predate the `research/` convention entirely (they may +never have gone through a `rules-score` bootstrap). Before the first real change cycle, do a +one-time, read-only **baseline snapshot**: + +- Read the component's existing frozen artifacts (`assumed_system/`, `requirements/`, + `software_architectural_design/`, `safety_analysis/`, tests/coverage lock) and summarize them in + `research/problem_statement.md` — terminology, system slice, current requirement/architecture + index, current maturity and ASIL. This is **reverse documentation of a trusted baseline**, not + the fresh, discardable-evidence derivation `rules-score` Step 0 performs against a PoC. Say so + explicitly in the file so a later reader does not mistake it for authoritative source-of-truth — + the frozen TRLC/PlantUML remain authoritative; this file exists only to orient future cycles + quickly without re-reading the whole tree. +- Seed `references.md`, `backlog.md`, `nice_to_haves.md`, even if only with what the baseline + read-through surfaced. +- Do **not** invent a change in this step. If there is no concrete trigger yet, stop here and ask + the human what the first actualization cycle should be about. + +### Keeping it current + +- **`work_log.md`** (per cycle): append a dated entry every time a step starts or finishes inside + that cycle. Never rewrite history. +- **`next_steps.md`** (per cycle): always reflects the *current* step in this cycle's table below; + stale entries are removed, not accumulated. +- **`problem_statement.md`** (component-wide): amended, never silently rewritten — when a cycle's + change affects the terminology/system-slice/informal-requirements narrative, append a short + dated note under a `## Changelog` section at the bottom pointing at the cycle directory that + caused the update, then edit the body. Do not delete the changelog trail. +- **`backlog.md`** / **`nice_to_haves.md`**: capture out-of-scope or opportunistic findings from + every cycle; do not fold them into the current cycle's diff (Core Principle 1). + +### `change_request.md` template + +```markdown +# — Change Request: + +## Trigger + + +## Classification +<"wrong today" (defect in an existing record) vs. "was right, world changed" (Core Principle 5) — +state which, and why.> + +## Stated scope + + +## Open Questions + +``` + +### `impact_analysis.md` template + +```markdown +# — Impact Analysis: + +## Upward trace (root-cause localization) +.@", not just "somewhere near X".> + +## Downward trace (ripple set) + + +## Artifacts to touch + + +## Artifacts explicitly NOT touched (and why) + +``` + +--- + +## Lifecycle steps & checkpoints (per change cycle) + +| # | Step | Artifact skill | Checkpoint | +|---|------|-----------------|-------------| +| 0 | Capture the trigger in `changes//change_request.md` | — | Human confirms the trigger, its classification (Core Principle 5), and its stated scope are correctly understood | +| 1 | Impact analysis in `changes//impact_analysis.md`: upward root-cause trace + downward ripple trace | score-requirements / score-architecture / score-safety-analysis / score-testing (read-only) | Human confirms the impact set is complete, closed, and rooted at the correct layer | +| 2 | Amend the root-layer artifact(s): edit content, bump `version` | matching skill for that layer | Human confirms the new wording/diagram/measure is correct | +| 3 | Cascade: re-pin every downstream reference identified in Step 1 to the new version — a re-pin only, no new content smuggled in | matching skill(s) | Lightweight — verify each cascade edit is purely a version-pin update | +| 4 | Add genuinely new records the change requires (new `CompReq`, `FailureMode`, test, `AoU`, …) | matching skill(s) | Human confirms new records are correctly leveled/allocated, not disguised edits of unrelated existing ones | +| 5 | Retire superseded/obsolete content: mark it (note + rationale), confirm via the downward trace that nothing else still references it, then remove | score-requirements (mostly) | Human confirms removal is safe before it happens | +| 6 | Validation gates over the whole component: `bazel test //...`, `trlc --verify`, architecture-consistency, coverage-drift, AI quality checks (`tags = ["manual"]`) | all four | Human reviews any warnings, especially ones surfaced only because `maturity = "development"` | +| 7 | Evidence bundle in `changes//evidence_bundle.md`: final change list, version-bump table, ripple map, residual risk / anything deferred to `backlog.md` | — | Human accepts the cycle | + +Steps 2–4 may interleave in either order once Step 1's impact set is agreed (e.g. a new `CompReq` +in Step 4 might need its own new test before Step 6 validation, while an unrelated ripple re-pin +from Step 3 proceeds independently) — but nothing in Steps 2–5 starts before Step 1's checkpoint, +and Step 6 does not start until every artifact in Step 1's closed set has been addressed by 2–5. + +--- + +## Worked shape of a cycle (illustrative, component-agnostic) + +```mermaid +flowchart TD + A["Step 0\nchange_request.md"] --> B["Step 1\nimpact_analysis.md\n(upward + downward trace)"] + B --> C["Step 2\nAmend root-layer artifact\n(version bump)"] + C --> D["Step 3\nCascade re-pin\n(derived_from / FTA alias / lobster-tracing)"] + D --> E["Step 4\nAdd genuinely new records"] + E --> F["Step 5\nRetire superseded content\n(mark, confirm, remove)"] + F --> G["Step 6\nValidation gates\n(bazel test, trlc --verify, coverage)"] + G --> H["Step 7\nevidence_bundle.md"] +``` + +--- + +## References + +- `.github/skills/rules-score/SKILL.md` — the fresh/rework lifecycle this skill is the companion + to; read it for the four mechanical skills' full mechanics and the `research/` convention this + one adapts. +- `.github/skills/score-requirements/SKILL.md`, `.github/skills/score-architecture/SKILL.md`, + `.github/skills/score-safety-analysis/SKILL.md`, `.github/skills/score-testing/SKILL.md` — the + four mechanical skills this one sequences, in delta mode. +- [Dependable Element Concept & Automatic Validations](https://eclipse-score.github.io/tooling/latest/user_guide/general.html) + — canonical description of what `rules_score` enforces (architecture consistency, certified + scope, integrity level, coverage-lock drift) — the same checks this skill's Step 6 relies on to + catch an incomplete cascade. diff --git a/.github/skills/rules-score/SKILL.md b/.github/skills/rules-score/SKILL.md new file mode 100644 index 0000000000..d07dc3bba7 --- /dev/null +++ b/.github/skills/rules-score/SKILL.md @@ -0,0 +1,217 @@ + + +--- +name: rules-score +description: "Top-down, human-gated lifecycle for building or reworking an S-CORE Safety Element out of Context (SEooC) with the rules_score Bazel rules — from an informal problem statement to a passing TRLC/architecture/safety/test verification. USE FOR: kicking off a new dependable_element from scratch; re-authoring an existing/PoC dependable_element whose process artifacts are wrong or disorganized; deciding which of score-requirements / score-architecture / score-safety-analysis / score-testing to use next; setting up or maintaining a component's research/ scratchpad directory; sequencing work so each layer is frozen before the next is authored. Component-agnostic — do not hardcode any component's domain content here." +argument-hint: "component/SEooC name and current lifecycle step" +--- + +# S-CORE SEooC Lifecycle — Orchestrating Skill + +This skill is the router and process backbone for building an S-CORE **Safety Element out of +Context (SEooC)** with the `rules_score` Bazel rules. It does not duplicate the mechanics already +covered by the four artifact skills — it sequences them, defines the human checkpoints between +them, and defines the on-disk scratchpad (`research/`) that keeps in-progress work reproducible +across developers and workstations instead of living in agent/session memory. + +**This skill is intentionally component-agnostic.** It must never be edited to bake in the domain +content of one particular component (e.g. a specific service's API). Component-specific knowledge +belongs in that component's `research/problem_statement.md` and its frozen TRLC/PlantUML artifacts. + +## When to use + +- Starting a brand-new `dependable_element` from an informal, human-provided problem description. +- Reworking an existing/PoC `dependable_element` whose requirements/architecture/safety/test + artifacts are semantically wrong, disorganized, or were produced without traceability discipline + (e.g. one-shot "vibe coded" TRLC that verifies but doesn't reflect real layering). +- Deciding what to do next / which skill applies at the current point in the lifecycle. +- Setting up or maintaining a component's `research/` directory. + +## Not for + +- The mechanics of writing `.trlc` records → **score-requirements** +- PlantUML diagrams and the `dependable_element`/`component`/`unit` Bazel hierarchy → **score-architecture** +- FMEA/FTA/`FailureMode`/`ControlMeasure` records → **score-safety-analysis** +- Test annotation, `lobster-tracing`, and `test_case_coverage.lock.yaml` → **score-testing** +- Incremental, traceable updates to an already-trusted `dependable_element` baseline (new need, + defect, drift, deprecation) → **rules-score-actualize** + +## Scope & limits + +This skill currently covers two related starting points: a **brand-new** `dependable_element`, and +a **low-maturity/PoC rework** where prior requirements/architecture/safety artifacts exist but are +not trustworthy and are treated as discardable evidence (see **Handling a rework** below — names, +IDs, and versions of the old artifacts carry no weight and do not need to be preserved). + +It does **not** cover **amending an already-mature or otherwise trusted `dependable_element`** +(e.g. adding a feature to, or fixing a defect in, a component whose requirements/architecture/ +safety artifacts are the trusted baseline rather than discardable evidence). That case needs a +different, minimal-delta workflow — preserve existing requirement IDs/versions where unaffected, +bump versions only where content actually changes, and re-run only the lifecycle steps whose +inputs changed, so the diff stays small and traceable over the project's lifetime. Use +**rules-score-actualize** for that case instead — do not apply this skill's "re-derive fresh, +discard old names freely" guidance to a trusted baseline. + +--- + +## Core principles + +1. **Top-down, one layer at a time.** Author content in this order: problem statement → + assumed-system requirements & AoUs → feature requirements → architecture (static design) → + component requirements → architecture (Bazel wiring + unit design) → safety analysis → + implementation delta → tests & coverage → validation. Do not jump ahead: a lower layer is + *derived from* the frozen layer above it, never the other way round. +2. **Freeze after agreement.** Once a layer has passed its human checkpoint (see below), treat it + as read-only. A bug found later is fixed by **re-opening the layer where it originates** — + bump its `version`, update it, then walk back down re-deriving/re-pinning every downstream + reference (`derived_from`, FTA `$BasicEvent` aliases, `lobster-tracing` ids). Never silently + patch a symptom in a downstream artifact to route around an upstream defect. +3. **Evidence, not specification.** An existing PoC/prior implementation may be used as *evidence* + of feasible behaviour (it shows something can work), but it is never treated as the source of + truth for requirements wording, structure, or layering. Requirements are re-derived from the + informal problem statement and the assumed system, not reverse-engineered from PoC code/TRLC. +4. **Everything is a file, nothing is memory.** Decisions, open questions, and progress live in + git-tracked files (the component's `research/` directory, plus the frozen artifacts themselves) + so any developer/agent, on any workstation, can resume from a clean checkout with no session or + host-specific memory. +5. **Human-in-the-loop at every layer transition.** The agent proposes; a human confirms before the + layer freezes. See **Checkpoints** below for what "confirm" means at each step — it does not + always require a long review, but it always requires an explicit go-ahead. +6. **Maturity stays `"development"` until the human decides otherwise.** `development` downgrades + architecture-consistency/coverage-lock/GWT-annotation violations to warnings so partial work can + still build; `release` is a separate, later decision, not a default to flip casually. + +--- + +## The `research/` directory + +Every SEooC component being brought through this lifecycle owns one `research/` directory at its +top level — a sibling of the component's `dependability/` directory (which itself holds +`requirements/`, `software_architectural_design/`, etc.) and of the implementation sources, not +nested under any of them. It is git-tracked like any other source. Its purpose is to make +in-progress reasoning, +inputs, and planning **durable and shared** — never keep this information only in an agent's +running context. + +``` +/research/ +├── problem_statement.md # informal → semi-formal problem description (see template below) +├── inputs/ # verbatim user-provided source material (docs, transcripts, emails...) +│ └── ... # keep originals; add a plain-text/markdown rendering alongside +│ # binary formats (e.g. .docx) so content is greppable/diffable +├── work_log.md # append-only, dated entries: what was done, in which step, by whom/when +├── next_steps.md # living TODO — current lifecycle step and what remains in it +├── references.md # links/snippets discovered while researching (code, docs, prior art) +├── backlog.md # known technical debt / deferred issues found along the way +└── nice_to_haves.md # requests toward *other* components/teams that are out of scope here +``` + +Guidance for keeping it current: + +- **`work_log.md`**: append a dated entry every time a lifecycle step starts or finishes. Never + rewrite history — corrections get a new entry, not an edit of an old one. +- **`next_steps.md`**: always reflects the *current* step from the plan below plus its immediate + remaining actions; stale entries are removed, not accumulated. +- **`references.md`**: anything worth not re-discovering next session — file paths, external doc + links, useful grep patterns, code snippets that clarify intent. +- **`backlog.md`** / **`nice_to_haves.md`**: capture but do not act on out-of-scope findings; they + are inputs to a future cycle, not silently folded into the current one. +- **`problem_statement.md`** is the one file in `research/` that graduates: once agreed with the + human (Checkpoint 0), it is effectively frozen like the TRLC layers, even though it is prose, not + TRLC. Changing it after later layers exist means re-running Checkpoint 0 and cascading down. + +### `problem_statement.md` template + +```markdown +# — Problem Statement + +## Terminology +- : + +## System Slice + + +## Informal Functional Requirements + + +## Expectations Toward the Environment + + +## Open Questions + +``` + +--- + +## Lifecycle steps & checkpoints + +Each step names its artifact skill in parentheses. **Checkpoint** = what must be explicitly +confirmed by a human before freezing and moving on. + +| # | Step | Artifact skill | Checkpoint | +|---|------|-----------------|-------------| +| 0 | Author `research/problem_statement.md` from informal input | — | Human confirms terminology, system slice, and informal requirements are correct and complete enough to proceed | +| 1 | `AssumedSystemReq` + `AoU` (assumed_system/) | score-requirements | Human confirms assumptions are precise, verifiable, and correctly ASIL-classified | +| 2 | `FeatReq` (requirements/feature_requirements.trlc) | score-requirements | Human confirms each feature requirement is atomic/verifiable and correctly derived | +| 3 | Static architecture design (PlantUML, collaborative) | score-architecture | Human agrees the component/unit decomposition — this **is** the design decision | +| 4 | `CompReq` per component (requirements/component_requirements.trlc) | score-requirements | Human confirms allocation to exactly one component and testability | +| 5 | Bazel wiring: `dependable_element`/`component`/`unit`/`unit_design` (mechanical transcription of step 3) | score-architecture | Lightweight — verify architecture-consistency check passes; flag any forced deviation from the agreed diagram | +| 6 | Safety analysis: FMEA → `FailureMode` → FTA → `ControlMeasure`/`AoU` | score-safety-analysis | Human confirms severity/plausibility judgements and that root causes bottom out in actionable measures | +| 7 | Implementation delta — change code/tests only where the now-frozen artifacts require it | — | Human reviews the diff against the frozen requirements/architecture, not against the old PoC | +| 8 | Test annotation + coverage lock (`lobster-tracing`, GWT, `test_case_coverage.lock.yaml`) | score-testing | Human confirms every `CompReq` has ≥1 covering test case | +| 9 | Validation gates: `bazel test //...`, `trlc --verify`, AI requirement/safety quality checks (`tags = ["manual"]`), architecture consistency, coverage drift | all four | Human reviews any warnings surfaced under `maturity = "development"` | +| 10 | Evidence bundle: change list + requirement→test map + failure-mode→control-measure map + residual risks | — | Human accepts the package for this cycle / defers remaining items to `backlog.md` | + +Steps 4 and 5 may run in parallel once step 3 is agreed; step 6 needs step 4 (and, for interface +naming, step 5). Nothing downstream of a step starts before that step's checkpoint is passed. + +### Handling a rework (existing/PoC dependable_element) + +When the starting point is a low-maturity or PoC implementation rather than a blank slate — the +case this skill currently targets (see **Scope & limits**): + +1. Do **Step 0** anyway — write the problem statement from the original informal intent (customer + requests, docs, prior discussions), not from the PoC's TRLC wording. +2. Treat the PoC's requirements/architecture/safety/test artifacts, and any comparable artifacts + from a component it was extracted from, as read-only reference material under + `research/references.md` — useful for spotting behaviour that must be preserved, never copied + verbatim into the new layer. If the PoC has never been reviewed/released outside its own + development, its requirement/record **names and version numbers carry no traceability weight** + and are fully discardable — there is no external consumer to keep them stable for. +3. Re-run Steps 1–6 fresh. Requirement/record names are expected to change freely; do not force new + content into old names to minimize diff noise, and do not port over old `version` numbers — a + freshly-authored record starts at `version = 1` regardless of what the PoC called it. A rename + map is only needed if some *other*, already-trusted artifact (not the PoC itself) depends on the + old names. +4. Only after the new artifacts are frozen, do Step 7 (implementation delta) against them — not + against a desire to keep the PoC's structure or code. + +If instead the existing artifacts are an already-mature, trusted baseline (not a discardable PoC), +stop and see **Scope & limits** — this workflow does not apply as-is. + +--- + +## References + +- `.github/skills/score-requirements/SKILL.md`, `.github/skills/score-architecture/SKILL.md`, + `.github/skills/score-safety-analysis/SKILL.md`, `.github/skills/score-testing/SKILL.md` — the + four mechanical skills this one sequences. +- [Dependable Element Concept & Automatic Validations](https://eclipse-score.github.io/tooling/latest/user_guide/general.html) + — canonical description of what a `dependable_element` is composed of and what Bazel enforces + (architecture consistency, certified scope, integrity level). diff --git a/score/message_passing/research/backlog.md b/score/message_passing/research/backlog.md new file mode 100644 index 0000000000..7c98348bac --- /dev/null +++ b/score/message_passing/research/backlog.md @@ -0,0 +1,41 @@ +# Message Passing — Backlog + +Long-lived, shared across all actualization cycles. Opportunistic findings noticed while reading +or working land here (Core Principle 1 of `rules-score-actualize`) — they are not acted upon until +a future cycle deliberately picks them up as its own change request. + +## From the 2026-08-31 baseline snapshot (read-only reconnaissance) + +- `dependability/assumed_system/aous.trlc` contains no real Assumptions of Use — only a `TODO` + comment and a single placeholder `ExampleAoU` record (`mitigates = "FailureModeName"`, which + does not match any real `FailureMode` name in `safety_analysis/failure_modes.trlc`). A future + cycle should author real AoUs for this SEooC (e.g. host OS guarantees around UID spoofing + resistance, IPC buffer limits, thread scheduling) and retire the placeholder. +- `dependability/safety_analysis/control_measures.trlc` only defines `ControlMeasure` records for + one of the eight failure modes/FTAs (`MessageNotDeliveredCorrectly` — `OsIpcFaultHandling`, + `SendBufferArgumentValidation`, `BE_MessageTooBig`, `BE_SendQueueExhausted`). The remaining seven + failure modes (`IpcChannelUnavailable`, `NotificationNotDelivered`, + `ServerMessageHandlingFailure`, `MessageTimingViolated`, `IpcApiMisuseOrLifecycleViolation`, + `ConnectionContextDataWrong`, `StateMachineError`) each have an `fta_*.puml` diagram but no + matching control measures in the `.trlc` file yet. Worth a dedicated future cycle. +- `dependability/software_unit_design/` exists (with a `BUILD` file) but is otherwise empty — no + unit-design content has been authored there yet, despite `component_requirements.trlc` having a + "Client Unit Requirements (client_connection)" and "Server Unit Requirements" section that would + naturally feed unit design. +- `client-server.md` explicitly defers several things as "not in scope of the first release": + passing shared-memory handles over the connection, a paired watchdog-arm/disarm callback + mechanism for notification timing, and larger shared thread pools for concurrent message + processing. None of these have corresponding placeholder requirements yet — if any are picked up + in a future cycle, they will likely need new `FeatReq`/`CompReq` records, not edits of existing + ones. +- `client-server.md` marks two implementation questions as still-`TODO`: the exact shape of the + server-side "User Data" object (`void*` vs. `std::uintptr_t` vs. + `score::cpp::pmr::unique_ptr`) and the semantics/audience of + `GetClientIdentity()` for access control ("TODO: TBD"). Worth checking whether the current code + (`server_types.h`, `i_server_connection.h`) has since resolved these; if so, `client-server.md` + is stale on this point. + +## Nice to have vs backlog + +Anything that is a *possible future improvement* rather than an *observed inconsistency* goes in +`nice_to_haves.md` instead of here. diff --git a/score/message_passing/research/nice_to_haves.md b/score/message_passing/research/nice_to_haves.md new file mode 100644 index 0000000000..7c7f9f3e16 --- /dev/null +++ b/score/message_passing/research/nice_to_haves.md @@ -0,0 +1,16 @@ +# Message Passing — Nice to Haves + +Long-lived, shared across all actualization cycles. Possible future improvements noticed in +passing, not (yet) inconsistencies or defects — see `backlog.md` for those. + +## From the 2026-08-31 baseline snapshot + +- `client-server.md` calls out passing shared-memory region handles between processes (native in + Unix Domain Socket messaging; `shm_create_handle()` on QNX) as a possible future extension, out + of scope for the first release. +- `client-server.md` calls out a watchdog-friendly notification interface (paired client-side + arm / server-side disarm callbacks around `Notify`) as a possible future extension to give + timing guarantees for notification messages, which today have none. +- `client-server.md` calls out larger shared thread pools serving multiple `Server`/ + `ClientConnection` instances concurrently as a possible future extension beyond the current + single-thread-or-single-pair-of-threads model. diff --git a/score/message_passing/research/problem_statement.md b/score/message_passing/research/problem_statement.md new file mode 100644 index 0000000000..b646716337 --- /dev/null +++ b/score/message_passing/research/problem_statement.md @@ -0,0 +1,185 @@ +# Message Passing — Baseline Snapshot (orientation, not source of truth) + +> **This file is reverse-documented orientation material**, written per the `rules-score-actualize` +> skill's "if `research/` does not exist yet" step. It is a read-only summary of an already-existing, +> trusted `dependable_element` (`score/message_passing/dependability/`), not a fresh Step-0-style +> derivation against a discardable PoC. The frozen TRLC records and PlantUML diagrams under +> `dependability/` remain the authoritative source of truth; this file exists only so a future +> actualization cycle can orient itself quickly without re-reading the whole tree. If this file and +> the frozen artifacts ever disagree, the frozen artifacts win — treat the disagreement as a finding +> for `backlog.md`, not as license to trust this file instead. + +## Current maturity / integrity level + +From `dependability/BUILD`, `dependable_element_message_passing`: +- `integrity_level = "B"` (ASIL B) +- `maturity = "development"` (drift/coverage/GWT violations are warnings, not hard build failures, + today) + +## Terminology already in use + +- **Service Identifier** — the name a `Server` is addressable by in the service-address namespace + (`ServiceProtocolConfig::identifier`). +- **Service Protocol** — the application-level contract (max message/reply/notify sizes) that both + a `Server` and the `ClientConnection`s that talk to it must agree on; carried by + `ServiceProtocolConfig`. +- **Server** (`IServer`) — a named entity that accepts inter-process traffic addressed to one + Service Identifier; produced by `IServerFactory::Create`. +- **Server Connection** (`IServerConnection`) — the server-side endpoint object for one + successfully-established client connection; not created directly by the user, lifetime managed + by the library. Provides `GetClientIdentity()`, `GetUserData()`, `Reply()`, `Notify()`, + `RequestDisconnect()`. +- **Client Connection** (`IClientConnection`) — the client-side endpoint object toward one Server; + produced by `IClientFactory::Create`. Owns a state machine (`Starting`, `Ready`, `Stopping`, + `Stopped`) with an associated `StopReason` (`kNone`, `kInit`, `kUserRequested`, `kPermission`, + `kClosedByPeer`, `kIoError`, `kShutdown`). +- **Client Factory** / **Server Factory** (`IClientFactory` / `IServerFactory`) — encapsulate the + OS-dependent transport implementation, configuration, and shared resources (background thread, + command queue, memory resource); outlive every connection/server object they produce. +- **Connection Handler** (`IConnectionHandler`) — optional per-connection user object + (`OnMessageSent`, `OnMessageSentWithReply`, `OnDisconnect`) that, when present as `UserData`, + replaces the server-wide callbacks for that one connection. +- Packet types in the abstracted wire protocol: `SEND` (fire-and-forget), `REQUEST` + (send-and-wait/send-with-callback), `REPLY`, `NOTIFY`. +- "Point-to-point" — the design explicitly limits connections to 1:1 (client connection ↔ server + connection); N:M is out of scope. + +## System slice + +A same-host, OS-independent, point-to-point client-server IPC abstraction over two backends behind +one API: +- **Linux**: Unix Domain Sockets (`unix_domain/`), used for host testing and as the Linux transport. +- **QNX**: native QNX message passing / `dispatch` with `pulse_attach()` (`qnx_dispatch/`), the + ASIL-B-safety-certified transport on target. + +Both backends implement the same `IClientConnection` / `IServer` / `IServerConnection` / +`IClientFactory` / `IServerFactory` interfaces so callers are transport-agnostic. The design is +singleton-free, supports bounded monotonic memory allocation (pre-allocated connection objects, +ring-buffer send queues sized at construction time), and allows resource-mock injection via +`ISharedResourceEngine` for unit testing. + +## Existing requirement index (name + one-line gist) + +### Assumed System Requirements (`assumed_system/assumed_system_requirements.trlc`) +- `SystemMessagingProtocol` (AssumedSystemReq, ASIL B) — system needs a client-server IPC + messaging mechanism across process boundaries respecting ISO 26262 failure modes. +- `SafeState` (Mitigation, ASIL B) — the safe state of the system is *safe-silent*. + +### Assumptions of Use (`assumed_system/aous.trlc`) +- **Placeholder only** — contains a single `TODO` comment and one literal `ExampleAoU` record with + placeholder description/note text (`mitigates = "FailureModeName"`, which is not a real failure + mode name in this component). No real AoUs have been authored yet. Flagged in `backlog.md`. + +### Feature Requirements (`requirements/feature_requirements.trlc`), all `derived_from +SystemMessagingProtocol@1` +- `ServerInterface` (B) — server registers connection handlers and processes incoming requests. +- `OSIndependentAPI` (B) — OS-independent API over OS-native IPC mechanisms. +- `SafetyCertifiedTransportMechanism` (B) — QNX implementation uses a safety-certified transport. +- `PointToPointConnections` (B) — only 1:1 connections; N:M explicitly excluded. +- `SmallDataLowLatencyCommunication` (QM) — low-latency small-data communication. +- `SynchronousUnidirectionalCommunication` (B) — blocking fire-and-forget send. +- `SynchronousBidirectionalCommunication` (B) — blocking send-and-wait-for-reply (`SendWaitReply`). +- `AsynchronousUnidirectionalCommunication` (B) — non-blocking send, no delivery guarantee. +- `SingletonFreeImplementation` (B) — no singletons in the design. +- `AllowsBoundedMonotonicMemoryAllocation` (B) — bounded monotonic allocation. +- `AllowsResourceMockInjectionForTesting` (B) — resource mock injection for tests. + +### Component Requirements (`requirements/component_requirements.trlc`), grouped by section +- *Behaviour Requirements*: `ServerCallbacksAreSequential`, `ServerProcessesSinglePendingRequest`, + `ClientConnectionMaintainsStateMachine`, `SynchronousSendBlocksUntilServerReceives`, + `AsynchronousSendReturnsAfterLocalAcceptance`, `SendWaitReplyBlocksUntilServerReply`, + `MessageOrderPreservationPerConnection`, `SingleServerInstancePerServiceIdentifier`. +- *API Requirements*: `IServerStartListeningAPI`, `IServerStopListeningAPI`, + `IClientConnectionSendAPI`, `IClientConnectionSendWaitReplyAPI`, + `IClientConnectionSendWithCallbackAPI`, `IServerConnectionReplyAPI`, + `IServerConnectionNotifyAPI`, `ClientFactoryCreateAPI`, `ServerFactoryCreateAPI`, + `IClientConnectionGetStateAPI`. +- *Server Unit Requirements*: `ServerPreallocatesConnectionObjects`, + `ServerRingBufferQueueSizeConfigurable`, `ServerConnectionRefusal`, + `ServerIConnectionHandlerDispatch`. +- *Client Unit Requirements (client_connection)*: `ClientConnectionSendQueuePreallocation`, + `ClientConnectionSharedResourceEngineInjection`, `ClientConnectionMockInjectionForTesting`, + `ClientConnectionSendFailsWhenStopped`, `ClientConnectionSendWaitReplyFailsWhenStopped`, + `ClientConnectionSendWithCallbackFailsWhenStopped`, `ClientConnectionStateCallbackInvocation`. +- All entries above are ASIL B, `version = 1`. + +### External Component Requirements (`requirements/external_component_requirements.trlc`) +(requirements towards the system / environment) +- `SafetyCertifiedTransportMechanismUnderQNX` (B) — QNX uses QNX-message-passing. +- `TransportMechanismOnLinux` (B) — Linux uses Unix Domain Sockets. +- `OSProvidedSenderIdentity` (B) — server identifies sender by OS-provided UID. +- `UnforgableSenderIdentity` (B) — UID used for identification cannot be forged by the client. + +### Failure Modes (`safety_analysis/failure_modes.trlc`), all ASIL B, `version = 1` +- `IpcChannelUnavailable` — channel cannot be established/maintained. +- `MessageNotDeliveredCorrectly` — message lost/partial/corrupted, or routed to wrong instance. +- `NotificationNotDelivered` — server→client notification lost/partial/late/corrupted/spurious. +- `ServerMessageHandlingFailure` — server handler fails to process/reply. +- `MessageTimingViolated` — message/reply delivered outside timing bounds (FTTI risk). +- `IpcApiMisuseOrLifecycleViolation` — API called at wrong lifecycle stage/context. +- `ConnectionContextDataWrong` — identity/context data for a connection absent/incorrect. +- `StateMachineError` — `GetState`/`GetStopReason` returns a state inconsistent with reality. + +Each failure mode has a matching `fta_*.puml` diagram (`fta_ipc_channel_unavailable.puml`, +`fta_message_not_delivered_correctly.puml`, `fta_notification_not_delivered.puml`, +`fta_server_message_handling_failure.puml`, `fta_message_timing_violated.puml`, +`fta_ipc_api_misuse_or_lifecycle_violation.puml`, `fta_connection_context_data_wrong.puml`, +`fta_state_machine_error.puml`). + +### Control Measures (`safety_analysis/control_measures.trlc`) +Only **one** FTA's control measures are authored so far — all three mitigate +`MessagePassing.MessageNotDeliveredCorrectly`: +- `OsIpcFaultHandling` (B) — check the return value of every OS call. +- `SendBufferArgumentValidation` (B) — validate Send/SendWaitReply/SendWithCallback arguments + before any IPC operation. +- `BE_MessageTooBig` (B) — enforce `max_send_size`/`max_reply_size`/`max_notify_size` limits. +- `BE_SendQueueExhausted` (B) — bounded pre-allocated send-queue pool, error (not block/drop) when + exhausted. + +The other seven failure modes/FTAs (`IpcChannelUnavailable`, `NotificationNotDelivered`, +`ServerMessageHandlingFailure`, `MessageTimingViolated`, `IpcApiMisuseOrLifecycleViolation`, +`ConnectionContextDataWrong`, `StateMachineError`) currently have **no** corresponding +`ControlMeasure` records. Flagged in `backlog.md`. + +## Software architectural design overview + +- `static_design.puml` — top-level `dependable_element_message_passing` SEooC box containing + `component_message_passing` (units: `client_connection`, `server_connection`, and a `dispatch` + sub-component with units `qnx_dispatch` and `unix_domain`), exposing a single public API port + (`score::message_passing`) and consuming an `os` port. +- `public_api.puml` / `private_api.puml` — public vs. private interface surfaces. +- `client_connection_activity_diagram.puml`, `server_client_sequence.puml` — client connection + lifecycle and client/server message-exchange sequencing. +- `client-server.md` — the prose design rationale (see below); by far the most detailed artifact + in this component and the natural first read for any future actualization cycle. Covers: why the + design moved away from POSIX mqueue and the old short/medium message split, the + Server/ServerConnection/ClientConnection/ClientFactory/ServerFactory abstractions, the client + and server state machines, the abstracted `SEND`/`REQUEST`/`REPLY`/`NOTIFY` wire protocol, + client- and server-side implementation notes (thread models, QNX resource-manager questions, + ring-buffer sizing), safety concerns for the four safe/QM client/server combinations, timing + guarantees (explicitly *not* provided in general), and two concrete usage examples (DataRouter + logging/tracing source, DataRouter subscriber). + +## Current public API surface (headers in `score/message_passing/`) + +- `i_client_connection.h` — `IClientConnection`: `Send`, `SendWaitReply`, `SendWithCallback`, + `GetState`, `GetStopReason`, `Start`, `Stop`, `Restart`; `State` and `StopReason` enums; + `ReplyCallback`, `NotifyCallback`, `StateCallback` typedefs. +- `i_client_factory.h` — `IClientFactory::Create(ServiceProtocolConfig, ClientConfig)`; + `ClientConfig` (`max_async_replies`, `max_queued_sends`, `fully_ordered`, `truly_async`, + `sync_first_connect`). +- `i_server.h` — `IServer::StartListening(ConnectCallback, DisconnectCallback, MessageCallback, + MessageCallback)`, `StopListening()`. +- `i_server_factory.h` — `IServerFactory::Create(ServiceProtocolConfig, ServerConfig)`; + `ServerConfig` (`max_queued_sends`, `pre_alloc_connections`, `max_queued_notifies`). +- `i_server_connection.h` — `IServerConnection`: `GetClientIdentity`, `GetUserData`, `Reply`, + `Notify`, `RequestDisconnect`. +- `i_connection_handler.h` — `IConnectionHandler`: `OnMessageSent`, `OnMessageSentWithReply`, + `OnDisconnect`. +- `service_protocol_config.h` — `ServiceProtocolConfig` (`identifier`, `max_send_size`, + `max_reply_size`, `max_notify_size`), shared by both client and server factories. + +## Changelog + +(none yet — this section is appended to, never rewritten, per cycle that touches the narrative +above; see `rules-score-actualize` SKILL.md "Keeping it current".) diff --git a/score/message_passing/research/references.md b/score/message_passing/research/references.md new file mode 100644 index 0000000000..e73ed74c81 --- /dev/null +++ b/score/message_passing/research/references.md @@ -0,0 +1,30 @@ +# Message Passing — References + +Long-lived, shared across all actualization cycles. Capture pointers to external code, docs, or +artifacts that inform impact analysis; do not fold cycle-specific detail in here (that belongs in +`changes//`). + +## Known consumers (orientation evidence only, not exhaustive) + +- **`score/mw/com/impl/bindings/lola/messaging/`** (LoLa binding of `mw::com`) is one known, + concrete consumer of `score/message_passing/`'s client/server connection API, used for LoLa + method calls: + - [message_passing_service.h](../../mw/com/impl/bindings/lola/messaging/message_passing_service.h) / + [message_passing_service.cpp](../../mw/com/impl/bindings/lola/messaging/message_passing_service.cpp) + - [message_passing_client_cache.h](../../mw/com/impl/bindings/lola/messaging/message_passing_client_cache.h) / + [message_passing_client_cache.cpp](../../mw/com/impl/bindings/lola/messaging/message_passing_client_cache.cpp) + + This is recorded purely as orientation evidence for future impact analyses ("does a change + affect this consumer's usage pattern?"). `message_passing`'s public API and architecture must + stay consumer-agnostic — this one consumer's needs must never drive the baseline snapshot's + content or be assumed to be the only consumer. Do not go looking for additional specific + consumers beyond what already exists in the repository today. + +## Related lifecycle skills + +- `.github/skills/rules-score-actualize/SKILL.md` — the process this `research/` directory + belongs to. +- `.github/skills/rules-score/SKILL.md`, `.github/skills/score-requirements/SKILL.md`, + `.github/skills/score-architecture/SKILL.md`, `.github/skills/score-safety-analysis/SKILL.md`, + `.github/skills/score-testing/SKILL.md` — the mechanical skills `rules-score-actualize` + sequences per cycle. diff --git a/score/message_passing/research/work_log.md b/score/message_passing/research/work_log.md new file mode 100644 index 0000000000..6868545690 --- /dev/null +++ b/score/message_passing/research/work_log.md @@ -0,0 +1,34 @@ +# Message Passing — Work Log + +Append-only. Top-level log for shared scratchpad activity (before any `changes//` exists). +Never rewrite history — add new dated entries only. + +## 2026-08-31 — Bootstrap: baseline snapshot (Cycle 0) + +- Confirmed `score/message_passing/research/` did not exist yet. +- Read, read-only, the existing frozen artifacts under `score/message_passing/dependability/`: + `assumed_system/` (`aous.trlc`, `assumed_system_requirements.trlc`), `requirements/` + (`feature_requirements.trlc`, `component_requirements.trlc`, + `external_component_requirements.trlc`), `software_architectural_design/` (`static_design.puml`, + `client-server.md`, and the other diagrams by name), `safety_analysis/` (`failure_modes.trlc`, + `control_measures.trlc`, and the eight `fta_*.puml` diagrams by name), and confirmed + `software_unit_design/` currently has no content beyond its `BUILD` file. Also read the current + public headers (`i_client_connection.h`, `i_client_factory.h`, `i_server.h`, + `i_server_factory.h`, `i_server_connection.h`, `i_connection_handler.h`, + `service_protocol_config.h`) and confirmed `integrity_level = "B"` / `maturity = "development"` + from `dependability/BUILD`. +- Wrote `research/problem_statement.md` as a reverse-documented baseline snapshot (terminology, + system slice, requirement/failure-mode/control-measure index, current maturity/ASIL), explicitly + marked as orientation material, not source of truth. +- Confirmed `score/mw/com/impl/bindings/lola/messaging/` exists as a known consumer of the + client/server connection API and recorded it in `research/references.md` as orientation-only + evidence, per the bootstrap prompt's instruction not to let it drive the baseline content. +- Seeded `research/backlog.md` (placeholder AoUs, incomplete control measures for 7 of 8 failure + modes, empty `software_unit_design/`, stale/unresolved TODOs in `client-server.md`) and + `research/nice_to_haves.md` (shared-memory handle passing, watchdog-friendly notification + callbacks, shared thread pools) from things noticed during the read-through. +- Did not modify anything under `dependability/` or the public headers — read-only reconnaissance + only. Did not create a `changes//` directory — no concrete change was defined in this + pass. +- Stopped per the prompt's stop condition to ask the human what the first real actualization cycle + should be about. From e47faa06d626e68e65b2ea51aeda114cb7d95dd7 Mon Sep 17 00:00:00 2001 From: Nikita Belenkiy Date: Mon, 7 Sep 2026 10:42:34 +0200 Subject: [PATCH 2/2] MP2 SEooC: first iteration in fixing requirements --- .../requirements/component_requirements.trlc | 15 +++ .../external_component_requirements.trlc | 17 +-- .../requirements/feature_requirements.trlc | 7 ++ .../client-server.md | 4 +- score/message_passing/research/backlog.md | 23 ++++ .../change_request.md | 100 ++++++++++++++++++ .../evidence_bundle.md | 65 ++++++++++++ .../impact_analysis.md | 95 +++++++++++++++++ .../next_steps.md | 14 +++ .../work_log.md | 56 ++++++++++ .../research/problem_statement.md | 30 ++++-- 11 files changed, 411 insertions(+), 15 deletions(-) create mode 100644 score/message_passing/research/changes/2026-09-01-client-identity-and-userdata-docs/change_request.md create mode 100644 score/message_passing/research/changes/2026-09-01-client-identity-and-userdata-docs/evidence_bundle.md create mode 100644 score/message_passing/research/changes/2026-09-01-client-identity-and-userdata-docs/impact_analysis.md create mode 100644 score/message_passing/research/changes/2026-09-01-client-identity-and-userdata-docs/next_steps.md create mode 100644 score/message_passing/research/changes/2026-09-01-client-identity-and-userdata-docs/work_log.md diff --git a/score/message_passing/dependability/requirements/component_requirements.trlc b/score/message_passing/dependability/requirements/component_requirements.trlc index 2630613660..94169b4c98 100644 --- a/score/message_passing/dependability/requirements/component_requirements.trlc +++ b/score/message_passing/dependability/requirements/component_requirements.trlc @@ -146,6 +146,21 @@ ScoreReq.CompReq IClientConnectionGetStateAPI { version = 1 } +ScoreReq.CompReq IServerConnectionGetClientIdentityAPI { + description = "`IServerConnection` shall provide a `GetClientIdentity` method that returns the client's OS-provided process ID (PID), user ID (UID), and primary group ID (GID), established once when the connection was accepted." + note = "A PID identifies a client process uniquely only among processes running simultaneously; the OS may reuse a PID for a different process afterwards, so it shall not be used by itself as a persistent, long-term client identity. A UID identifies a client process uniquely only if the integrating system dedicates a UID to that client process. The UID and/or the primary GID may be used by the server-side application for access control decisions. On QNX, this data is only meaningful when the connection uses the QNX-native-messaging transport (see SafetyCertifiedTransportMechanismUnderQNX); the Unix Domain Sockets backend on QNX, used there for internal testing purposes only, cannot retrieve real peer credentials and reports pid=uid=gid=0 instead." + safety = ScoreReq.Asil.B + derived_from = [MessagePassing.ClientIdentificationForAccessControl@1] + version = 1 +} + +ScoreReq.CompReq IServerConnectionGetUserDataAPI { + description = "`IServerConnection` shall provide a `GetUserData` method that returns the `UserData` object associated with the connection, as returned by the connection callback when the connection was accepted." + safety = ScoreReq.Asil.B + derived_from = [MessagePassing.ServerInterface@1] + version = 1 +} + } section "Server Unit Requirements" { diff --git a/score/message_passing/dependability/requirements/external_component_requirements.trlc b/score/message_passing/dependability/requirements/external_component_requirements.trlc index f0515f50f3..edda345682 100644 --- a/score/message_passing/dependability/requirements/external_component_requirements.trlc +++ b/score/message_passing/dependability/requirements/external_component_requirements.trlc @@ -25,21 +25,24 @@ ScoreReq.CompReq SafetyCertifiedTransportMechanismUnderQNX { ScoreReq.CompReq TransportMechanismOnLinux { description = "On the Linux operating system, the message passing component shall use unix domain-sockets as the underlying IPC mechanism." - safety = ScoreReq.Asil.B - derived_from = [MessagePassing.SafetyCertifiedTransportMechanism@1, MessagePassing.OSIndependentAPI@1] - version = 1 + note = "Lowered from ASIL B to QM: ASIL compliance is not currently pursued on Linux, which is used for host development and testing. The safety-certified transport for ASIL B is QNX-native messaging on QNX (see SafetyCertifiedTransportMechanismUnderQNX); this record therefore no longer derives from SafetyCertifiedTransportMechanism." + safety = ScoreReq.Asil.QM + derived_from = [MessagePassing.OSIndependentAPI@1] + version = 2 } -ScoreReq.CompReq OSProvidedSenderIdentity { - description = "The message passing server shall be able to identify the sender of each received message by the sender's OS-provided user ID (UID)." +ScoreReq.CompReq OSProvidedClientIdentityPerConnection { + description = "The message passing server shall identify the client of a Server Connection once, when the connection is accepted, by the client's OS-provided process ID (PID), user ID (UID), and primary group ID (GID)." + note = "Replaces the retired OSProvidedSenderIdentity record: identification is established once per Server Connection, not re-derived per message, and now names all three OS-provided identifiers instead of only the UID." safety = ScoreReq.Asil.B derived_from = [MessagePassing.ServerInterface@1] version = 1 } -ScoreReq.CompReq UnforgableSenderIdentity { - description = "The transport mechanism shall ensure that the UID used to identify a message, cannot be forged by the client." +ScoreReq.CompReq ConnectionIdentityIntegrityGuaranteed { + description = "The transport mechanism shall ensure that the client identity established for a Server Connection cannot be forged by the client and remains valid for the entire lifetime of that Server Connection." + note = "Replaces the retired UnforgableSenderIdentity record: the integrity guarantee covers the whole Server Connection lifetime, not just the message that established it." safety = ScoreReq.Asil.B derived_from = [MessagePassing.ServerInterface@1] version = 1 diff --git a/score/message_passing/dependability/requirements/feature_requirements.trlc b/score/message_passing/dependability/requirements/feature_requirements.trlc index 2e24e0e1e9..bfaa457f17 100644 --- a/score/message_passing/dependability/requirements/feature_requirements.trlc +++ b/score/message_passing/dependability/requirements/feature_requirements.trlc @@ -96,3 +96,10 @@ ScoreReq.FeatReq AllowsResourceMockInjectionForTesting { derived_from = [MessagePassing.SystemMessagingProtocol@1] version = 1 } + +ScoreReq.FeatReq ClientIdentificationForAccessControl { + description = "The message passing component shall provide the server-side application with the OS-provided identity of the client of each Server Connection, to support server-side client identification and access control decisions." + safety = ScoreReq.Asil.B + derived_from = [MessagePassing.SystemMessagingProtocol@1] + version = 1 +} diff --git a/score/message_passing/dependability/software_architectural_design/client-server.md b/score/message_passing/dependability/software_architectural_design/client-server.md index 370aa38ae9..6143e84db3 100644 --- a/score/message_passing/dependability/software_architectural_design/client-server.md +++ b/score/message_passing/dependability/software_architectural_design/client-server.md @@ -80,13 +80,13 @@ The *Server* object is supposed to handle multiple connections at the same time. The user of the *Server* interface communicates with the *Clients* using *Server Connection* objects. There is one such object per every established connection, plus one provisional object for a connection being established. The object's lifetime is managed by the Message Passing library itself. For the library user, it is allowed to keep a pointer/reference to a *Server Connection* object until return from the disconnection callback with this object's reference as an argument. It is not allowed to keep the pointer/reference to the provisional object if the connection is rejected by the library user's connection callback. -The *Server Connection* interface of a provisional object provides access to the method `GetClientIdentity()`, which returns information that can be useful for access control (TODO: TBD). Additional methods are available for established connections: `GetUserData()`, `Notify()`, `Reply()`, and `RequestDisconnect()`. These methods are thread-safe and can be called from non-callback threads is needed, although care needs to be taken not to call them after the corresponding disconnection callback. +The *Server Connection* interface of a provisional object provides access to the method `GetClientIdentity()`, which returns a `ClientIdentity{pid, uid, gid}` (see `server_types.h`) — the client process's OS-provided process ID (PID), user ID (UID), and primary group ID (GID), assuming a POSIX-compatible underlying OS — established once, at connection acceptance, and useful for server-side access control. A PID identifies a client process uniquely only among processes running simultaneously; the OS may reuse a PID for a different process afterwards. A UID identifies a client process uniquely only if the integrating system dedicates a UID to that client process; the UID and/or the primary GID can be used for access control decisions. Note that the Unix Domain Sockets backend, when built for QNX (used there for internal testing purposes only, since it is not the safety-certified transport on QNX), cannot retrieve real peer credentials and reports `ClientIdentity{0, 0, 0}` instead. Additional methods are available for established connections: `GetUserData()`, `Notify()`, `Reply()`, and `RequestDisconnect()`. These methods are thread-safe and can be called from non-callback threads is needed, although care needs to be taken not to call them after the corresponding disconnection callback. ### Server Connection initiation When a client requests a connection and there is enough memory in the *Server* object to accept another connection, a user-provided connection callback is called. The callback can check the client identity and either accept the connection or reject it with an error code. An error code equivalent to `EAGAIN` will direct the client to attempt to re-establish the connection later. This could be useful, for example, to drop some less-important connections and serve the more important incoming one when the connection limit in the user's part of the *Server* functionality implementation is reached. -To accept the connection, the callback returns a *User Data* object. The format of the object is still TODO: TBD; it looks like it can be a variant of `void*`, `std::uintptr_t`, and `score::cpp::pmr::unique_ptr`, where the former two can be used to reference user-managed storage (albeit likely with some MISRA exceptions) and the latter one manages the user data object lifetime internally in the Message Passing library (the destructor for the `IConnectionHandler` object will be called after the disconnection callback). +To accept the connection, the callback returns a *User Data* object. The format of the object is `UserData = std::variant>` (see `server_types.h`), where the former two can be used to reference user-managed storage (albeit likely with some MISRA exceptions) and the latter one manages the user data object lifetime internally in the Message Passing library (the destructor for the `IConnectionHandler` object will be called after the disconnection callback). ### Server callbacks diff --git a/score/message_passing/research/backlog.md b/score/message_passing/research/backlog.md index 7c98348bac..3481fc6ecd 100644 --- a/score/message_passing/research/backlog.md +++ b/score/message_passing/research/backlog.md @@ -35,6 +35,29 @@ a future cycle deliberately picks them up as its own change request. (`server_types.h`, `i_server_connection.h`) has since resolved these; if so, `client-server.md` is stale on this point. +## From the 2026-09-01 client-identity-and-userdata-docs cycle + +- `dependability/requirements/external_component_requirements.trlc` is **not wired into any Bazel + target** — `dependability/requirements/BUILD`'s `component_requirements` target only lists + `component_requirements.trlc` in `srcs`. `trlc --verify` has never validated this file, and it is + not part of `dependable_element_message_passing`'s `requirements` list either. Deciding which + target/component should own it (a new `component_requirements` target of its own? folded into + the existing one? something else given it represents requirements *towards* the environment + rather than *of* a component) is a build-structure decision for a dedicated future cycle. +- `TransportMechanismOnLinux` (`external_component_requirements.trlc`) was lowered from + `safety = ScoreReq.Asil.B` to `ScoreReq.Asil.QM` (`version` 1→2) in this cycle, per explicit + human confirmation, and no longer derives from `SafetyCertifiedTransportMechanism`. No longer an + open question. +- The UDS-on-QNX backend's inability to report real client identity (`ClientIdentity{0,0,0}`, + confirmed in `unix_domain/unix_domain_server.cpp`, `#ifdef __QNX__`) is currently captured only as + a `note` on the `IServerConnectionGetClientIdentityAPI` `CompReq` and in `client-server.md` + prose. The human explicitly chose to defer formalizing it as a proper `AoU` wired into the + `ConnectionContextDataWrong` FTA (`fta_connection_context_data_wrong.puml`) to a future + safety-analysis-focused cycle — see + `changes/2026-09-01-client-identity-and-userdata-docs/change_request.md`, Open Question 2. +- ~~`IServerConnection::GetUserData()` has the same gap...~~ — resolved: added the + `IServerConnectionGetUserDataAPI` `CompReq` in this same cycle, per explicit human confirmation. + ## Nice to have vs backlog Anything that is a *possible future improvement* rather than an *observed inconsistency* goes in diff --git a/score/message_passing/research/changes/2026-09-01-client-identity-and-userdata-docs/change_request.md b/score/message_passing/research/changes/2026-09-01-client-identity-and-userdata-docs/change_request.md new file mode 100644 index 0000000000..3baad2d791 --- /dev/null +++ b/score/message_passing/research/changes/2026-09-01-client-identity-and-userdata-docs/change_request.md @@ -0,0 +1,100 @@ +# Message Passing — Change Request: client-identity-and-userdata-docs + +## Trigger + +Continuing directly from the Cycle 0 baseline snapshot (`research/problem_statement.md`), the +human reviewed two open `TODO: TBD` markers in +`dependability/software_architectural_design/client-server.md` against the actual code and +supplied the missing facts: + +1. The `UserData` object format is **already decided and implemented**: `server_types.h` defines + `UserData = std::variant>`. + `client-server.md` still says "The format of the object is still TODO: TBD; it looks like it can + be a variant of...". +2. The `GetClientIdentity()` result is **already decided and implemented**: `server_types.h` + defines `struct ClientIdentity { pid_t pid; uid_t uid; gid_t gid; }` — the client's PID, UID, + and primary GID, assuming a POSIX-compatible OS. `client-server.md` still says "...returns + information that can be useful for access control (TODO: TBD)". + +In the same message, the human also raised a related, new customer-facing need and asked for a +requirements-wording cleanup: + +3. **New need**: customers of `message_passing` want the server side to be able to identify a + client by PID (unique only among concurrently running processes; a PID can be reused for a + different process over time) and, when the integrating system dedicates a UID per client + process, by UID. In addition, the client's UID and/or primary GID should be usable for + server-side access control decisions. This capability already exists in the code + (`IServerConnection::GetClientIdentity()` / `ClientIdentity`), but no formal `FeatReq`/`CompReq` + currently promises it, and no `CompReq` at all currently mandates the `GetClientIdentity` API + (found during impact analysis, see below). +4. **Safety/transport nuance**: Unix Domain Sockets are not ASIL B-compliant on QNX (the ASIL-B + path on QNX is QNX-native message passing, per the existing `SafetyCertifiedTransportMechanismUnderQNX` + requirement); ASIL is not currently a concern on Linux. The Unix Domain Sockets backend may be + used on QNX for internal testing purposes only, and — confirmed in + `unix_domain/unix_domain_server.cpp` (`#ifdef __QNX__ // no support for SO_PEERCRED on QNX`) — + it does not provide real client PID/UID/GID there (all three fields are reported as `0`). +5. **Wording cleanup**: `external_component_requirements.trlc`'s `OSProvidedSenderIdentity` and + `UnforgableSenderIdentity` records use "sender" where the component's established terminology + (see `research/problem_statement.md`) is "client" / "Client Connection" / "Server Connection". + The human asked to reframe them so identification happens **once per Server Connection**, after + which message passing guarantees the **integrity of the connection itself**, rather than + implying per-message re-verification. + +## Classification + +Mixed trigger, three parts (Core Principle 5): + +- **(1) and (2) — "wrong today"**: `client-server.md` is stale documentation drift. The facts were + decided and implemented in code; the architecture doc's `TODO: TBD` markers were simply never + updated to match. This is a defect in the frozen doc, not a new decision. +- **(3) — new need, with an incidentally-discovered pre-existing gap**: formalizing + PID/UID/GID-based client identification for access control is new content (nothing was "wrong" + before — the capability existed informally in code but was never promised as a requirement). + While tracing this, the downward trace also surfaced that `IServerConnection::GetClientIdentity` + — unlike `Reply`/`Notify`/`GetUserData`'s siblings `IServerConnectionReplyAPI`/ + `IServerConnectionNotifyAPI` — has **no** matching API-level `CompReq` at all. That omission is + closed here since it is the direct component-level counterpart of the new feature being added; + it is not itself a separately new ask, but the natural target layer for the new content. +- **(4) — orientation fact, not (yet) acted on as a requirement/AoU change**: this is safety- + relevant information about a **test-only backend limitation**, not a claim that any existing + frozen requirement is wrong today. `SafetyCertifiedTransportMechanismUnderQNX` already correctly + mandates QNX-native messaging for the QNX ASIL-B path, so the frozen requirement text is + consistent with the new information. See "Stated scope" below for how this is captured (a `note` + and a backlog entry, not a new `AoU`/FTA — see Open Questions). +- **(5) — "wrong today"**: a wording/terminology defect in two existing `CompReq` records that + never traced correctly to the component's established vocabulary. + +## Stated scope + +Per the human's message, taken at face value (impact analysis in `impact_analysis.md` may reveal a +different/larger true scope): + +- Update `client-server.md`'s two `TODO: TBD` passages to state the already-decided facts. +- Reword `OSProvidedSenderIdentity` / `UnforgableSenderIdentity` for consistent "client" + terminology and to reframe identification as a one-time, per-Server-Connection act followed by a + connection-integrity guarantee. +- Add formal requirement(s) capturing: identification by PID (with its concurrency-only/reuse-over- + time caveat), identification by UID (when the integrator dedicates one per client process), and + UID/GID usable for server-side access control. +- Capture the UDS-on-QNX-is-test-only-and-lacks-real-identity nuance so it is not lost, without + necessarily expanding into a full new `AoU`/FTA cycle (see Open Questions). + +## Open Questions + +1. **`TransportMechanismOnLinux` currently carries `safety = ScoreReq.Asil.B`.** The human's + phrase "we don't yet care about ASIL on Linux" could mean this classification should be + lowered (e.g. to `QM`) or annotated with a note/rationale. This is a safety-classification + change and is **not** made in this cycle without explicit confirmation — flagged here instead + (score-requirements guidance: "confirm the safety level rather than assuming it"). Left + untouched pending human decision. +2. **Should the UDS-on-QNX/test-only limitation become a proper `AoU` wired into the + `ConnectionContextDataWrong` FTA** (`fta_connection_context_data_wrong.puml`), per + `score-safety-analysis`'s normal AoU pattern? Doing that fully is a safety-analysis activity in + its own right (new `$BasicEvent`, matching `AoU` record, FTA edit) and was judged out of the + minimal scope of *this* cycle (which was about docs/requirements wording, not FMEA authoring). + For now the fact is captured as a `note` on the new `CompReq` and as a `backlog.md` entry for a + dedicated future safety-analysis cycle. Flagging for confirmation that this scoping choice is + acceptable. +3. `IServerConnection::GetUserData()` has the same gap as `GetClientIdentity()` did (no matching + API `CompReq`). Left as a `backlog.md` entry, not fixed here, since it is not part of what was + asked. Flagging in case the human wants it folded into this cycle instead of deferred. diff --git a/score/message_passing/research/changes/2026-09-01-client-identity-and-userdata-docs/evidence_bundle.md b/score/message_passing/research/changes/2026-09-01-client-identity-and-userdata-docs/evidence_bundle.md new file mode 100644 index 0000000000..1e112ead91 --- /dev/null +++ b/score/message_passing/research/changes/2026-09-01-client-identity-and-userdata-docs/evidence_bundle.md @@ -0,0 +1,65 @@ +# Message Passing — Evidence Bundle: client-identity-and-userdata-docs + +## Final change list + +| File | Change | +|---|---| +| `dependability/software_architectural_design/client-server.md` | Resolved 2 `TODO: TBD` prose passages (UserData variant shape; GetClientIdentity PID/UID/GID contents + UDS-on-QNX caveat). No version field (not a TRLC record). | +| `dependability/requirements/external_component_requirements.trlc` | Retired `OSProvidedSenderIdentity`, `UnforgableSenderIdentity`; added `OSProvidedClientIdentityPerConnection@1`, `ConnectionIdentityIntegrityGuaranteed@1`; lowered `TransportMechanismOnLinux` from ASIL B to QM (`version` 1→2, `derived_from` narrowed to `OSIndependentAPI@1`). | +| `dependability/requirements/feature_requirements.trlc` | Added `ClientIdentificationForAccessControl@1`. | +| `dependability/requirements/component_requirements.trlc` | Added `IServerConnectionGetClientIdentityAPI@1`, `IServerConnectionGetUserDataAPI@1`. | +| `research/problem_statement.md` | Updated requirement index entries; appended dated `## Changelog` note. | +| `research/backlog.md` | Added 4 findings (BUILD wiring gap, ASIL-on-Linux question, deferred AoU, GetUserData API gap). | + +## Version-bump table + +| Record | Old version | New version | Notes | +|---|---|---|---| +| `MessagePassing.OSProvidedSenderIdentity` | 1 | — (retired) | Zero downstream references confirmed before removal (Step 1). | +| `MessagePassing.UnforgableSenderIdentity` | 1 | — (retired) | Same. | +| `MessagePassing.OSProvidedClientIdentityPerConnection` | — | 1 (new) | Replaces `OSProvidedSenderIdentity`; see its `note` field. | +| `MessagePassing.ConnectionIdentityIntegrityGuaranteed` | — | 1 (new) | Replaces `UnforgableSenderIdentity`; see its `note` field. | +| `MessagePassing.ClientIdentificationForAccessControl` | — | 1 (new) | `FeatReq`, `derived_from = [MessagePassing.SystemMessagingProtocol@1]`. | +| `MessagePassing.IServerConnectionGetClientIdentityAPI` | — | 1 (new) | `CompReq`, `derived_from = [MessagePassing.ClientIdentificationForAccessControl@1]`. | +| `MessagePassing.IServerConnectionGetUserDataAPI` | — | 1 (new) | `CompReq`, `derived_from = [MessagePassing.ServerInterface@1]`. Added per explicit human confirmation (same gap `GetClientIdentity` had). | +| `MessagePassing.TransportMechanismOnLinux` | 1 | 2 | Lowered `safety` from `ScoreReq.Asil.B` to `ScoreReq.Asil.QM` per explicit human confirmation; `derived_from` narrowed from `[SafetyCertifiedTransportMechanism@1, OSIndependentAPI@1]` to `[OSIndependentAPI@1]` since it no longer claims a safety-certified transport. Zero downstream references confirmed before the bump. | + +No existing record's `version` was bumped in place for the identity/wording rework itself — every +record in that part of the cycle was either brand new or a retire-and-replace (identifiers +themselves were part of the defect, see `impact_analysis.md`). `TransportMechanismOnLinux` is the +one genuine in-place version bump in this cycle, made after Step 1 confirmed no downstream +references. + +## Ripple map + +Impact analysis (Step 1) found the ripple set was empty for the retired records (no +`derived_from`, FTA `$BasicEvent`, `lobster-tracing`, or coverage-lock reference pointed at them +anywhere in the repository) and that the new records need no re-pins elsewhere (`ServerInterface@1` +and `SystemMessagingProtocol@1`, their parents, are unmodified). `ConnectionContextDataWrong`'s +`interface` field already lists `GetClientIdentity`/`GetUserData`, so no `FailureMode` edit was +needed to bring the new `CompReq` under existing safety-analysis coverage. + +## Residual risk / deferred items + +Open questions 1 and 3 (from `change_request.md`) were resolved by explicit human confirmation and +acted on in this cycle (see version-bump table above). One item remains genuinely deferred: + +1. The UDS-on-QNX client-identity limitation is documented (doc prose + `CompReq` note) but not yet + backed by a proper `AoU`/FTA closure under `ConnectionContextDataWrong` — the human explicitly + chose to defer this to a future safety-analysis-focused cycle rather than author it now. +2. `external_component_requirements.trlc` remains unwired from any Bazel target; the edited records + were reviewed by hand (not `trlc --verify`'d) for this reason. A future cycle should decide the + correct Bazel wiring/ownership for this file. + +## Validation gate results (Step 6) + +``` +bazel test //score/message_passing/dependability/requirements:component_requirements_test \ + //score/message_passing/dependability/requirements:feature_requirements_test +→ //score/message_passing/dependability/requirements:component_requirements_test PASSED in 0.2s +→ //score/message_passing/dependability/requirements:feature_requirements_test PASSED in 0.2s +``` + +`external_component_requirements.trlc` has no test target to run (pre-existing gap, item 2 above). +Re-ran the same two targets after the follow-up edits (ASIL lowering, `GetUserData` `CompReq`) — +both still `PASSED`. diff --git a/score/message_passing/research/changes/2026-09-01-client-identity-and-userdata-docs/impact_analysis.md b/score/message_passing/research/changes/2026-09-01-client-identity-and-userdata-docs/impact_analysis.md new file mode 100644 index 0000000000..473935f7a6 --- /dev/null +++ b/score/message_passing/research/changes/2026-09-01-client-identity-and-userdata-docs/impact_analysis.md @@ -0,0 +1,95 @@ +# Message Passing — Impact Analysis: client-identity-and-userdata-docs + +## Upward trace (root-cause localization) + +- **`client-server.md` TODOs (items 1, 2).** Starting point: the two `TODO: TBD` sentences. + Walking upward: there is no requirement or diagram claiming a *different* answer for the + `UserData` shape or the `GetClientIdentity` contents — the doc simply never caught up with + `server_types.h`. The true origin is the doc itself (`software_architectural_design/ + client-server.md`), not a wrong decision one layer up. No `FeatReq`/`CompReq` needs to change to + fix this half of the cycle. +- **New PID/UID/GID identification/access-control need (item 3).** Walking upward from "customers + want to identify/authorize clients using OS identity data": the closest existing parent is + `MessagePassing.SystemMessagingProtocol@1` (`AssumedSystemReq`) — "a mechanism for IPC via a + client-server messaging protocol" — which is broad enough to be a sufficient, unmodified parent + for a new `FeatReq`. No existing `FeatReq` already covers identity/access-control (checked all 11 + records in `feature_requirements.trlc`), so the true origin for the *missing* content is the + feature layer, not a defect one layer higher. +- **Missing `IServerConnection::GetClientIdentity` API `CompReq` (found during downward trace, + folded in as part of item 3).** `i_server_connection.h` declares `GetClientIdentity()` today, + `IServerConnectionReplyAPI`/`IServerConnectionNotifyAPI` exist for its sibling methods `Reply`/ + `Notify`, but there is no `IServerConnectionGetClientIdentityAPI`-equivalent record anywhere in + `component_requirements.trlc`. Root cause: an omission at the `CompReq` layer when the API + Requirements section was originally authored, not a wrong decision at the `FeatReq` layer above. +- **Wording defect in `OSProvidedSenderIdentity`/`UnforgableSenderIdentity` (item 5).** These two + records derive from `MessagePassing.ServerInterface@1`, which is worded correctly ("registers + connection handlers and processes incoming requests" — no "sender" language). The defect is + local to these two `CompReq` records' own text/name, not inherited from a wrong parent. +- **UDS-on-QNX test-only limitation (item 4).** This is new orientation information about an + *existing, already-correct* requirement (`SafetyCertifiedTransportMechanismUnderQNX`, which + already correctly mandates QNX-native messaging, not UDS, as the QNX ASIL path). There is no + requirement to fix upward — the information is a caveat for wherever `GetClientIdentity` is + formalized, and a candidate future `AoU`, not a defect in an existing frozen record. + +## Downward trace (ripple set) + +| Current pin / reference | What it must become | +|---|---| +| `client-server.md` prose ("TODO: TBD" ×2) | Rewritten prose stating the resolved facts; not a versioned TRLC record, no re-pin mechanics apply — this is documentation, not a requirement/diagram with a version field. | +| `external_component_requirements.trlc: OSProvidedSenderIdentity`, `UnforgableSenderIdentity` — checked for any `derived_from`, FTA `$BasicEvent` alias, or `lobster-tracing` id pointing at them | **None found** (`grep` across the whole repo returned zero references besides this component's own `research/problem_statement.md`, which is orientation-only and gets updated in this cycle anyway). Safe to retire-and-replace with new identifiers in the same cycle rather than an in-place version bump, since the identifiers themselves (not just their content) are part of the defect being fixed. | +| `component_requirements.trlc` "API Requirements" section — no entry for `GetClientIdentity` | New `CompReq` added; nothing downstream to re-pin (genuinely new content, Core Principle 1(b)). | +| `feature_requirements.trlc` — no entry for identity/access-control | New `FeatReq` added; nothing downstream to re-pin. | +| `MessagePassing.ServerInterface@1` (`FeatReq`) | Unchanged — remains a valid, unmodified `derived_from` parent for both the reworded external-component records and the new `CompReq`. No version bump needed since its own content does not change. | +| `research/problem_statement.md` requirement index | Must be amended (component-wide living doc) to reflect: renamed external-component records, new `FeatReq`/`CompReq`, and a dated `## Changelog` entry pointing at this cycle, per `rules-score-actualize`'s "Keeping it current". | +| `FailureMode.ConnectionContextDataWrong` / `fta_connection_context_data_wrong.puml` | Checked: this FailureMode's `interface` field already lists `IServerConnection.GetClientIdentity, IServerConnection.GetUserData`, so the new formal identification requirement is already within its blast radius — **no change needed** to the FailureMode itself. Its FTA has no `$BasicEvent`/`ControlMeasure`/`AoU` yet at all (pre-existing gap, see `backlog.md`); adding the UDS-on-QNX caveat as a proper `AoU` there is deliberately deferred (Open Question 2 in `change_request.md`), not silently done. | +| `control_measures.trlc` | Checked: contains no records mitigating `ConnectionContextDataWrong`; unaffected either way — untouched in this cycle. | +| `private_api.puml` (`+GetClientIdentity()`) | Already lists the method signature with no behavioural claim to contradict; untouched. | +| Tests referencing `ClientIdentity`/`GetClientIdentity` (`qnx_dispatch_server_test.cpp`, `qnx_dispatch_server_to_client_test.cpp`, `unix_domain_server_test.cpp`) and the `GetClientIdentity` mock (`mock/server_connection_mock.h`) | Already exercise `pid`/`uid`/`gid` fields consistent with the newly-formalized requirement content; no test changes needed — the requirements are catching up to already-correct code/tests, not the other way around. | +| `dependability/BUILD` `dependable_element_message_passing.requirements` | Lists `feature_requirements` and `assumed_system_requirements` targets only; the new `FeatReq` lives in `feature_requirements.trlc`, already covered by the existing `feature_requirements` target reference — no BUILD change needed for the new `FeatReq`. | +| `dependability/requirements/BUILD` | **Pre-existing gap, unrelated to re-pinning**: `external_component_requirements.trlc` is not wired into any Bazel target at all (`component_requirements` target's `srcs` only lists `component_requirements.trlc`). This means `trlc --verify` has never validated this file, and it is edited in this cycle without automated coverage. Recorded as a `backlog.md` item; not fixed here (deciding which component/target should own it is a build-structure decision beyond this cycle's scope). | + +## Artifacts to touch + +- `dependability/software_architectural_design/client-server.md` — edit two paragraphs in place + (prose, not versioned TRLC — no version field to bump). +- `dependability/requirements/external_component_requirements.trlc` — retire + `OSProvidedSenderIdentity` and `UnforgableSenderIdentity`; add + `OSProvidedClientIdentityPerConnection` and `ConnectionIdentityIntegrityGuaranteed` at + `version = 1` each (new identifiers, so version starts fresh, per the retire-and-replace decision + above; both `derived_from = [MessagePassing.ServerInterface@1]`, unchanged parent). +- `dependability/requirements/feature_requirements.trlc` — add new `FeatReq` + `ClientIdentificationForAccessControl` (`version = 1`, `derived_from = + [MessagePassing.SystemMessagingProtocol@1]`). +- `dependability/requirements/component_requirements.trlc` — add new `CompReq` + `IServerConnectionGetClientIdentityAPI` under "API Requirements" (`version = 1`, `derived_from = + [MessagePassing.ClientIdentificationForAccessControl@1]`), with a `note` capturing the PID + reuse-over-time caveat, the UID-dedicated-per-client caveat, and the UDS-on-QNX test-only + limitation. +- `research/problem_statement.md` — update the requirement index entries affected and append a + dated `## Changelog` note. +- `research/backlog.md` — add: (a) `TransportMechanismOnLinux` ASIL classification open question, + (b) deferred full `AoU`/FTA wiring for the UDS-on-QNX limitation, (c) missing + `IServerConnectionGetUserDataAPI` `CompReq` gap (same shape of omission as `GetClientIdentity` + had), (d) `external_component_requirements.trlc` not wired into any Bazel target. + +## Artifacts explicitly NOT touched (and why) + +- `safety_analysis/failure_modes.trlc`, `safety_analysis/control_measures.trlc`, all `fta_*.puml` — + no failure mode needs a new/changed record for this cycle's content (`ConnectionContextDataWrong` + already covers `GetClientIdentity`/`GetUserData`); adding the UDS-on-QNX `AoU` properly is + explicitly deferred, not silently folded in. +- `assumed_system/aous.trlc` — left as the placeholder it is; not replaced with a real `AoU` in + this cycle (see Open Question 2). +- `assumed_system/assumed_system_requirements.trlc` — `SystemMessagingProtocol` is a sufficient, + correct parent as-is; no change needed. +- `dependability/software_architectural_design/*.puml` (`static_design.puml`, `public_api.puml`, + `private_api.puml`, `client_connection_activity_diagram.puml`, `server_client_sequence.puml`) — + no structural/diagram change implied by this cycle's content; `private_api.puml` already lists + `GetClientIdentity()` as a method signature. +- `TransportMechanismOnLinux` (`external_component_requirements.trlc`) — its `safety` field is + explicitly left untouched pending human confirmation (Open Question 1); only the two + "sender"-worded records are edited. +- Public headers / implementation (`server_types.h`, `i_server_connection.h`, + `unix_domain/unix_domain_server.cpp`, `qnx_dispatch/qnx_dispatch_server.cpp`) — these already + implement the now-formalized behaviour correctly; the requirements/docs are catching up to the + code, not the other way around. No code change in this cycle. diff --git a/score/message_passing/research/changes/2026-09-01-client-identity-and-userdata-docs/next_steps.md b/score/message_passing/research/changes/2026-09-01-client-identity-and-userdata-docs/next_steps.md new file mode 100644 index 0000000000..b973eaf263 --- /dev/null +++ b/score/message_passing/research/changes/2026-09-01-client-identity-and-userdata-docs/next_steps.md @@ -0,0 +1,14 @@ +# Message Passing — Next Steps: client-identity-and-userdata-docs + +Current step: **Step 7 — evidence bundle complete, cycle closed** (`rules-score-actualize` +lifecycle table). + +All three open questions were answered by the human and acted on in this cycle: + +1. `TransportMechanismOnLinux` lowered from ASIL B to QM (`version` 1→2), no longer derived from + `SafetyCertifiedTransportMechanism`. +2. UDS-on-QNX limitation deferred to a future safety-analysis-focused cycle (kept as a `CompReq` + `note` + `backlog.md` entry only, no new `AoU`/FTA this cycle). +3. `IServerConnectionGetUserDataAPI` `CompReq` added in this cycle rather than deferred. + +No further edits queued for this cycle. diff --git a/score/message_passing/research/changes/2026-09-01-client-identity-and-userdata-docs/work_log.md b/score/message_passing/research/changes/2026-09-01-client-identity-and-userdata-docs/work_log.md new file mode 100644 index 0000000000..6bf22afd6c --- /dev/null +++ b/score/message_passing/research/changes/2026-09-01-client-identity-and-userdata-docs/work_log.md @@ -0,0 +1,56 @@ +# Message Passing — Work Log: client-identity-and-userdata-docs + +Append-only, cycle-scoped. Never rewrite history. + +## 2026-09-01 + +- Step 0: Wrote `change_request.md` from the human's message resolving two `client-server.md` + `TODO: TBD` markers, a new PID/UID/GID client-identification/access-control need, a UDS-on-QNX + safety/test-only nuance, and a "sender" vs "client" terminology cleanup request. +- Step 1: Wrote `impact_analysis.md`. Upward trace found no defect above the doc/wording layer for + items 1/2/5; confirmed `SystemMessagingProtocol@1` is a sufficient unmodified parent for the new + `FeatReq`. Downward trace found zero references to `OSProvidedSenderIdentity`/ + `UnforgableSenderIdentity` anywhere in the repo (safe to retire-and-replace), found + `IServerConnection::GetClientIdentity` had no matching API `CompReq` at all (closed as part of + this cycle), confirmed `ConnectionContextDataWrong`'s `interface` field already covers + `GetClientIdentity`/`GetUserData` (no FailureMode change needed), and found + `external_component_requirements.trlc` is not wired into any Bazel target (pre-existing gap, + deferred to `backlog.md`). +- Step 2/4 (amend + add): edited `client-server.md` (2 paragraphs); retired + `OSProvidedSenderIdentity`/`UnforgableSenderIdentity` and added + `OSProvidedClientIdentityPerConnection`/`ConnectionIdentityIntegrityGuaranteed` in + `external_component_requirements.trlc`; added `ClientIdentificationForAccessControl` `FeatReq` in + `feature_requirements.trlc`; added `IServerConnectionGetClientIdentityAPI` `CompReq` in + `component_requirements.trlc`. +- Step 3 (cascade): none required — impact analysis found no downstream re-pins needed (no existing + references to the retired records; no FailureMode/FTA/lobster-tracing/test changes needed). +- Step 5 (retire): `OSProvidedSenderIdentity`/`UnforgableSenderIdentity` removed outright rather + than marked-then-removed-later, since the downward trace in Step 1 already confirmed (before any + edit) that nothing references them. +- Step 6 (validation): ran `bazel test //score/message_passing/dependability/requirements: + component_requirements_test //score/message_passing/dependability/requirements: + feature_requirements_test` — both `PASSED`. `external_component_requirements.trlc` could not be + validated this way (not wired into any target — see `backlog.md`); reviewed its syntax by hand + against the sibling frozen files' conventions instead. +- Also updated `research/problem_statement.md` (requirement index + dated Changelog entry) and + `research/backlog.md` (4 new findings) per `rules-score-actualize`'s "Keeping it current". +- Left three items explicitly open for human confirmation rather than deciding unilaterally: the + `TransportMechanismOnLinux` ASIL classification, whether to promote the UDS-on-QNX limitation to + a full `AoU`/FTA in this cycle vs. defer it, and whether to fold the `GetUserData` API `CompReq` + gap into this cycle. See `change_request.md`'s Open Questions. + +## 2026-09-01 (follow-up, same session) + +- Human answered all three open questions: lower `TransportMechanismOnLinux` to QM; defer the + UDS-on-QNX `AoU`/FTA; add the `GetUserData` API `CompReq` now. +- Edited `TransportMechanismOnLinux` in `external_component_requirements.trlc`: `safety` B→QM, + `version` 1→2, `derived_from` narrowed to `[OSIndependentAPI@1]` (dropped + `SafetyCertifiedTransportMechanism@1`, since QM no longer claims a safety-certified transport), + with a `note` explaining the rationale. Confirmed zero downstream references before bumping. +- Added `IServerConnectionGetUserDataAPI` `CompReq` in `component_requirements.trlc`, next to + `IServerConnectionGetClientIdentityAPI`. +- Re-ran `bazel test //score/message_passing/dependability/requirements:component_requirements_test + //score/message_passing/dependability/requirements:feature_requirements_test` — both `PASSED`. +- Updated `research/problem_statement.md`, `research/backlog.md`, this cycle's `next_steps.md`, + and `evidence_bundle.md` to reflect the resolved questions. Cycle closed. + diff --git a/score/message_passing/research/problem_statement.md b/score/message_passing/research/problem_statement.md index b646716337..d1488a8ab0 100644 --- a/score/message_passing/research/problem_statement.md +++ b/score/message_passing/research/problem_statement.md @@ -83,6 +83,9 @@ SystemMessagingProtocol@1` - `SingletonFreeImplementation` (B) — no singletons in the design. - `AllowsBoundedMonotonicMemoryAllocation` (B) — bounded monotonic allocation. - `AllowsResourceMockInjectionForTesting` (B) — resource mock injection for tests. +- `ClientIdentificationForAccessControl` (B) — server-side app gets OS-provided client identity per + Server Connection, for identification and access control. *(added in + changes/2026-09-01-client-identity-and-userdata-docs)* ### Component Requirements (`requirements/component_requirements.trlc`), grouped by section - *Behaviour Requirements*: `ServerCallbacksAreSequential`, `ServerProcessesSinglePendingRequest`, @@ -93,7 +96,9 @@ SystemMessagingProtocol@1` `IClientConnectionSendAPI`, `IClientConnectionSendWaitReplyAPI`, `IClientConnectionSendWithCallbackAPI`, `IServerConnectionReplyAPI`, `IServerConnectionNotifyAPI`, `ClientFactoryCreateAPI`, `ServerFactoryCreateAPI`, - `IClientConnectionGetStateAPI`. + `IClientConnectionGetStateAPI`, `IServerConnectionGetClientIdentityAPI`, + `IServerConnectionGetUserDataAPI` *(both added in + changes/2026-09-01-client-identity-and-userdata-docs)*. - *Server Unit Requirements*: `ServerPreallocatesConnectionObjects`, `ServerRingBufferQueueSizeConfigurable`, `ServerConnectionRefusal`, `ServerIConnectionHandlerDispatch`. @@ -106,9 +111,17 @@ SystemMessagingProtocol@1` ### External Component Requirements (`requirements/external_component_requirements.trlc`) (requirements towards the system / environment) - `SafetyCertifiedTransportMechanismUnderQNX` (B) — QNX uses QNX-message-passing. -- `TransportMechanismOnLinux` (B) — Linux uses Unix Domain Sockets. -- `OSProvidedSenderIdentity` (B) — server identifies sender by OS-provided UID. -- `UnforgableSenderIdentity` (B) — UID used for identification cannot be forged by the client. +- `TransportMechanismOnLinux` (QM, `version = 2`) — Linux uses Unix Domain Sockets. *(lowered from + B to QM in changes/2026-09-01-client-identity-and-userdata-docs — ASIL is not currently pursued + on Linux; no longer derives from `SafetyCertifiedTransportMechanism`)* +- `OSProvidedClientIdentityPerConnection` (B) — server identifies the client of a Server Connection + once, at accept time, by PID/UID/primary GID. *(replaces retired `OSProvidedSenderIdentity` in + changes/2026-09-01-client-identity-and-userdata-docs)* +- `ConnectionIdentityIntegrityGuaranteed` (B) — the established client identity cannot be forged + and remains valid for the Server Connection's whole lifetime. *(replaces retired + `UnforgableSenderIdentity` in changes/2026-09-01-client-identity-and-userdata-docs)* +- **Note**: this file is not currently wired into any Bazel target (see `backlog.md`); its content + is not validated by `trlc --verify` today. ### Failure Modes (`safety_analysis/failure_modes.trlc`), all ASIL B, `version = 1` - `IpcChannelUnavailable` — channel cannot be established/maintained. @@ -181,5 +194,10 @@ The other seven failure modes/FTAs (`IpcChannelUnavailable`, `NotificationNotDel ## Changelog -(none yet — this section is appended to, never rewritten, per cycle that touches the narrative -above; see `rules-score-actualize` SKILL.md "Keeping it current".) +- **2026-09-01** (`changes/2026-09-01-client-identity-and-userdata-docs`): resolved the two + `TODO: TBD` markers in `client-server.md` (UserData variant shape, GetClientIdentity contents); + retired `OSProvidedSenderIdentity`/`UnforgableSenderIdentity` and replaced them with + `OSProvidedClientIdentityPerConnection`/`ConnectionIdentityIntegrityGuaranteed`; added the + `ClientIdentificationForAccessControl` `FeatReq` and the `IServerConnectionGetClientIdentityAPI`/ + `IServerConnectionGetUserDataAPI` `CompReq`s; lowered `TransportMechanismOnLinux` from ASIL B to + QM (`version` 1→2). See that cycle's `evidence_bundle.md` for the full diff and rationale.