From 920c7e6a21dd212cae3a0f50c21dc7050a693179 Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Mon, 28 Sep 2026 20:01:19 -0500 Subject: [PATCH 1/4] =?UTF-8?q?docs(csd):=20agent=202.12.1=20forwards=20no?= =?UTF-8?q?de=20surfaces=20=E2=80=94=20rewrite=20the=20CIRISAgent#1213=20r?= =?UTF-8?q?ows?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CIRISAgent#1213 closed via #1215 (released in agent 2.12.1, 2026-09-26): the node proxy now forwards any /v1 path the brain does not serve. The rows in CSD-005, 007, 045, 091, 092 and 102 that cited #1213 as missing reach through the agent now say reach works from agent 2.12.1, and that the client still calls the node URL directly, which works on every agent version. No `blocked_by: CIRISAgent#1213` existed in any typed block, so there was nothing to remove; check_csd_v3 passes on every CSD. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_0155SkTGdbwnSnR6tWBqJvUM --- FSD/CSD/CSD-005-people.md | 2 +- FSD/CSD/CSD-007-files.md | 5 +++-- FSD/CSD/CSD-045-node-self-standing.md | 11 +++++++---- FSD/CSD/CSD-091-user-chat.md | 10 ++++++---- FSD/CSD/CSD-092-share-contact-code.md | 2 +- FSD/CSD/CSD-102-communities.md | 3 ++- 6 files changed, 20 insertions(+), 13 deletions(-) diff --git a/FSD/CSD/CSD-005-people.md b/FSD/CSD/CSD-005-people.md index 721af3d4..47bd9259 100644 --- a/FSD/CSD/CSD-005-people.md +++ b/FSD/CSD/CSD-005-people.md @@ -139,7 +139,7 @@ tone, the `error` glyph, a hairline box and an uppercase label, and empty the | value | endpoint | owner | state | |---|---|---|---| -| contacts | `GET /v1/contacts` at the **node URL** | CIRISServer | live since 0.5.185. It read `$baseUrl` until this review, which the route gate charged to the agent front door and which, on a with-AI install, asked the agent (CIRISAgent#1213). Now `listContacts(nodeUrl)`, on the same active-node provider as the add, the code and the removal (`ContactsViewModel.nodeUrl`); pinned by `ContactCodeViewModelTest.theContactListIsReadFromTheNodeNotTheAgentFrontDoor` | +| contacts | `GET /v1/contacts` at the **node URL** | CIRISServer | live since 0.5.185. It read `$baseUrl` until this review, which the route gate charged to the agent front door and which, on a with-AI install, asked an agent that before 2.12.1 did not forward `/v1/contacts` (CIRISAgent#1213, closed by #1215; forwarded from agent 2.12.1). Now `listContacts(nodeUrl)`, on the same active-node provider as the add, the code and the removal (`ContactsViewModel.nodeUrl`); pinned by `ContactCodeViewModelTest.theContactListIsReadFromTheNodeNotTheAgentFrontDoor`. Calling the node URL directly works on every agent version, so it stays | | the picker's identities (Delegations reaches this screen in picker mode) | `GET /v1/federation/peers` | CIRISServer | live. A delegation target need not be a contact, so the picker reads the wider peer store; cited here because this screen calls it, and the checker had it as this screen's one uncited route | | add a contact | `POST /v1/contacts` | CIRISServer | live; returns `consent_prefixes` | | add by contact code | `POST /v1/contacts` with the code in `key_id` | CIRISServer | **live**: `AddContactRequest.key_id` takes a fed-ID **or** a fedcode and also accepts the aliases `code` and `contact` (`src/contacts_chat.rs:1732-1742` @ `046e1b39`). The client sends `key_id` (`CIRISApiClient.kt:1490`), so no client change is needed to send a code | diff --git a/FSD/CSD/CSD-007-files.md b/FSD/CSD/CSD-007-files.md index 8054d046..e3d3b440 100644 --- a/FSD/CSD/CSD-007-files.md +++ b/FSD/CSD/CSD-007-files.md @@ -183,8 +183,9 @@ Tags: `file_preview_text`, `file_not_rendered`, `file_save_blocked`, Sources: CIRISServer `origin/main` 046e1b39 (0.5.217), `src/drive.rs` and `src/media_gate.rs`; client lines are this branch. Every drive route is the node's and every call goes to the node URL (`ClientDrive`, read at call time; -never `$baseUrl` — CIRISAgent#1213 is closed, and an older agent still 404s -them). Rows marked "not called" are live on the node and not yet wired here. +never `$baseUrl`). Reach through the agent works from agent 2.12.1 +(CIRISAgent#1213, closed by #1215); an older agent 404s them, and the direct +node URL works on every agent version, so the client keeps calling it. Rows marked "not called" are live on the node and not yet wired here. | value | endpoint | owner | state | |---|---|---|---| diff --git a/FSD/CSD/CSD-045-node-self-standing.md b/FSD/CSD/CSD-045-node-self-standing.md index ea984922..0d009f41 100644 --- a/FSD/CSD/CSD-045-node-self-standing.md +++ b/FSD/CSD/CSD-045-node-self-standing.md @@ -55,8 +55,9 @@ screen: NodeSelfStanding nav_epistemic_node_self`. Shown on every build: the routes are the node's and need no agent. **It calls the node's address**, not `$baseUrl` — every method defaults `nodeUrl = LOCAL_NODE_URL` (`CIRISApiClient.kt`, `getSelfStanding` and -the six `self*` acts), because `/v1/admin/*` is not forwarded by the agent -(CIRISAgent#1213). +the six `self*` acts). The agent forwards `/v1/admin/*` to the node from agent +2.12.1 (CIRISAgent#1213, closed by #1215) and 404s it before that; the direct +node address works on every agent version, so the card keeps using it. ```yaml csd:shows registry_sha256: 95665a2c49627257be3ff84d10287aa49ef5b3cd8b7c6ec048ba6e6224dea839 @@ -151,7 +152,7 @@ error: {tag: banner_self_unreachable, renders: "'This node could not be reac | stop / resume accepting | `POST /v1/admin/self/stop-accepting` · `/resume-accepting` (`:4295`, `:4299`) | CIRISServer | live — `selfStopAccepting` / `selfResumeAccepting` | | declare / lift compulsion | `POST /v1/admin/self/compelled` · `/compulsion-lifted` (`:4303`, `:4307`) | CIRISServer | live — `selfDeclareCompelled` / `selfCompulsionLifted` | | request body, every act | `SelfCommit {delegation_id, reason, compelled_by?}` (`src/admin_ops.rs:3372-3384`): both required, `reason` refused by name when empty (`admin.refusal.reason_absent`); `compelled_by` read only by the compulsion declaration | CIRISServer | live — `SelfCommitRequest` | -| reach from a with-AI install | `/v1/admin/*` through the agent | CIRISAgent | **missing**: CIRISAgent#1213. The card calls the node URL directly, so it does not need it | +| reach from a with-AI install | `/v1/admin/*` through the agent | CIRISAgent | live from agent 2.12.1 (CIRISAgent#1213, closed by #1215); older agents 404. The card calls the node URL directly, which works on every agent version, so it does not depend on it | | a declaration that anyone else can see | the act writes a `hard_case:admin_action:{op}` row into persist's local `hard_case_events`: unsigned, no `cohort_scope`, not an attestation, so nothing replicates it | CIRISServer / CIRISPersist | **missing**: CIRISServer#675 | **Registry gap.** The row kind is `admin_action:{op}` (persist `hard_case.rs`), @@ -222,6 +223,8 @@ declaration: it cannot today, and that is the upstream gap in §3, not a client audit is honoured locally. What CC's purpose for the act implies, and the route doc promises, is that a *peer* can read it. That fails: the row is a local, unsigned table entry (CIRISServer#675). -- **Reach.** Node-only today (CIRISAgent#1213); the card uses the node address. +- **Reach.** Through the agent from agent 2.12.1 (CIRISAgent#1213, closed by + #1215); node-only before that. The card uses the node address, which works on + every agent version. - **Registry.** `hard_case:{kind}` cannot name the two-segment `admin_action:{op}` kind (see §3). diff --git a/FSD/CSD/CSD-091-user-chat.md b/FSD/CSD/CSD-091-user-chat.md index e3be108b..5dfeff8f 100644 --- a/FSD/CSD/CSD-091-user-chat.md +++ b/FSD/CSD/CSD-091-user-chat.md @@ -203,12 +203,14 @@ as a failure, once as a note. **Wrong-host risk: found and closed.** Every route here is the NODE's, on `:4243` — and until this review every one of them was called at `$baseUrl` (`startChat`, `listChatMessages`, `sendChatMessage`), which the route gate -charged to the agent front door and which, on a with-AI install, asked the -agent (CIRISAgent#1213). The sentence above used to read "none", written from +charged to the agent front door and which, on a with-AI install, asked an +agent that before 2.12.1 did not forward them (CIRISAgent#1213, closed by +#1215; reach through the agent works from agent 2.12.1). The sentence above used to read "none", written from the server side alone. The three calls now take the node URL from the same active-node provider People uses (`UserChatViewModel.nodeUrl`, `ChatApi`), and -`UserChatViewModelTest` pins where each goes. This surface does not exist on -the agent and does not ask it anything. +`UserChatViewModelTest` pins where each goes. This surface is not served by +the agent's brain and the client does not ask the agent for it: the direct node +URL works on every agent version. **What CC fixes for free, and the client obeys.** persist refuses a community-scoped promotion unless `attested_key_id == attesting_key_id` and every diff --git a/FSD/CSD/CSD-092-share-contact-code.md b/FSD/CSD/CSD-092-share-contact-code.md index 2fed85b8..15acf66a 100644 --- a/FSD/CSD/CSD-092-share-contact-code.md +++ b/FSD/CSD/CSD-092-share-contact-code.md @@ -137,7 +137,7 @@ private one, so the button here is the announce act and not the picker. | value | endpoint | owner | state | |---|---|---|---| -| the contact code | `GET {nodeUrl}/v1/self/contact-code?nodes=` (owner session, at the NODE URL — `contactsNodeUrl`, CIRISAgent#1213): `nodes` absent = every announced device, a comma list = exactly those, `none` = the fed-ID only (resolved through the public directory) | CIRISServer | **built, unreleased** (0.5.218; CIRISServer#673 still open). Readable on `origin/integ/0.5.218`: `src/self_devices.rs:611` `contact_code`, routed at `:869`. Ships with 0.5.218 | +| the contact code | `GET {nodeUrl}/v1/self/contact-code?nodes=` (owner session, at the NODE URL — `contactsNodeUrl`, which works on every agent version; reach through the agent works from agent 2.12.1, CIRISAgent#1213 closed by #1215): `nodes` absent = every announced device, a comma list = exactly those, `none` = the fed-ID only (resolved through the public directory) | CIRISServer | **built, unreleased** (0.5.218; CIRISServer#673 still open). Readable on `origin/integ/0.5.218`: `src/self_devices.rs:611` `contact_code`, routed at `:869`. Ships with 0.5.218 | | `nodes` encoding | comma list, trimmed, sorted, deduped; an empty list after trimming is a 400 (`:697-712`) | CIRISServer | readable | | the response | `key_id`, `code`, `qr_payload`, `format` (`fedcode-v3`), `ml_dsa_65_pubkey_sha256`, `available_nodes[{node_key_id,label?,announced,has_transport?,this_node}]`, `included_nodes[{key_id,transport_pubkey_ed25519_base64}]`, `nodes_without_transport[]`, `reachable_without_directory` (`:829-846`) | CIRISServer | readable; decoded 1:1 by `ContactCodeResponse` (`ContactCodeWireTest`) | | refusal for a private or foreign device | `self.node_not_announced` (400, detail names the refused ids) | CIRISServer | readable (`:716-728`); bundle key present (PR #113) | diff --git a/FSD/CSD/CSD-102-communities.md b/FSD/CSD/CSD-102-communities.md index d5f2f8db..cf015d20 100644 --- a/FSD/CSD/CSD-102-communities.md +++ b/FSD/CSD/CSD-102-communities.md @@ -149,7 +149,8 @@ by the same act. Verified against CIRISServer `origin/main` 046e1b39 (0.5.217; the routes landed in 0.5.216), `src/communities.rs`. Every call goes to the NODE URL (`nodeBaseUrl`, the local node), never `baseUrl` — on a with-AI install that is -the agent, which does not proxy these (CIRISAgent#1213). +the agent, which proxies these only from agent 2.12.1 (CIRISAgent#1213, +closed by #1215). The direct node URL works on every agent version, so it stays. `CommunitiesViewModelTest.every_call_goes_to_the_node_url_not_the_base_url` pins it. From ec61a1dac6a35c73dd0b602dfdb7592d41d65808 Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Mon, 28 Sep 2026 20:03:29 -0500 Subject: [PATCH 2/4] docs(flows): record why the six nav-only drafts do not promote on main None of csd-025, 036, 057, 066, 068, 087 loads with the loader on main: testing/gate/run_flows.py does not exist there, and FlowSpec.load refuses the `csd:` key every draft carries. The binder that reads it is in #97, still open. With `csd:` removed each parses, so the key is the only thing refused. csd-036 is additionally floored `unreleased`. The README table says so per row, and step 3 of "Promoting one" now reserves the green run for `verified`, matching what `testable` means on the promoted cards. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_0155SkTGdbwnSnR6tWBqJvUM --- testing/flows/drafts/README.md | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/testing/flows/drafts/README.md b/testing/flows/drafts/README.md index fd9e216c..54c9b7e1 100644 --- a/testing/flows/drafts/README.md +++ b/testing/flows/drafts/README.md @@ -66,25 +66,43 @@ Check first, in this order: 1. `python3 -m testing.gate.run_flows --flows testing/flows/drafts/` loads it; 2. its CSD's §5 declares the platforms it should be green on; -3. the CSD's `stage:` moves to `testable` only after a green run — a green run is - evidence for that edit, never the edit itself. +3. the CSD's `stage:` moves to `verified` only after a green run — a green run is + evidence for that edit, never the edit itself. `testable` means the spec is + complete and the flow is written; a card promoted there says in its §5 that + the flow has not yet run on the matrix. + +## Status on `main` (2026-09-28): none of the six nav-only flows promotes yet + +Tried for `csd-025`, `csd-036`, `csd-057`, `csd-066`, `csd-068` and `csd-087`. +None moved, for one reason common to all six and one extra for `csd-036`: + +- **They do not load with the loader on `main`.** `testing/gate/run_flows.py` + does not exist on `main`, and `FlowSpec.load` in `testing/gate/flow_spec.py` + refuses the `csd:` key every draft carries (`unknown key(s) ['csd']; allowed: + ['client', 'description', 'flow', 'steps', 'title']`). The binder that reads + `csd:` — and the runner that walks a hop — are in #97, still open. With `csd:` + removed each of the six parses, so the key is the only thing refused; removing + it would unbind the flow from its CSD, which is the wrong fix. They promote + when #97 lands. +- **`csd-036` is still floored `client: "unreleased"`**, so it would be refused + on every leg even once it loads. ## What is here | file | CSD | screen it needs | beyond nav, what else it waits on | |---|---|---|---| | `csd-006-receipt.yaml` | CSD-006 | Contacts + a contact | a second node to be a contact of; the matrix stands up one | -| `csd-025-system.yaml` | CSD-025 | System | nothing | -| `csd-036-network-ops.yaml` | CSD-036 | NetworkOps | nothing | -| `csd-057-wallet.yaml` | CSD-057 | Wallet | nothing | -| `csd-066-child-safety.yaml` | CSD-066 | ChildSafety | nothing | -| `csd-068-provision-accord-holder.yaml` | CSD-068 | ProvisionAccordHolder | nothing | +| `csd-025-system.yaml` | CSD-025 | System | nothing — **not promoted**: `csd:` key refused on `main` (#97) | +| `csd-036-network-ops.yaml` | CSD-036 | NetworkOps | **not promoted**: `csd:` key refused on `main` (#97), and floored `unreleased` | +| `csd-057-wallet.yaml` | CSD-057 | Wallet | nothing — **not promoted**: `csd:` key refused on `main` (#97) | +| `csd-066-child-safety.yaml` | CSD-066 | ChildSafety | nothing — **not promoted**: `csd:` key refused on `main` (#97) | +| `csd-068-provision-accord-holder.yaml` | CSD-068 | ProvisionAccordHolder | nothing — **not promoted**: `csd:` key refused on `main` (#97) | | `csd-069-accord-ceremony.yaml` | CSD-069 | AccordCeremony | its last step needs six FIPS tokens; it is `optional_step` | | `csd-081-login.yaml` | CSD-081 | Login | the observer step needs a second, non-owner account | | `csd-082-setup-with-ai.yaml` | CSD-082 | Setup | a node with no owner — the fixture claims one during sign-in | | `csd-083-setup-without-ai.yaml` | CSD-083 | Setup | same | | `csd-085-claim-node.yaml` | CSD-085 | ClaimNode | the no-signer step needs the local node stopped mid-flow | -| `csd-087-verify-agent.yaml` | CSD-087 | VerifyAgent | nothing — the refusal is the only state any node can produce | +| `csd-087-verify-agent.yaml` | CSD-087 | VerifyAgent | nothing — the refusal is the only state any node can produce. **Not promoted**: `csd:` key refused on `main` (#97) | | `csd-090-duty-conferral.yaml` | CSD-090 | DutyConferral | a node that knows an accord family | | `csd-091-user-chat.yaml` | CSD-091 | UserChat | a peered contact to have a room with | From 7628cc320169ad221619c367b99aa25bb7f79511 Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Mon, 28 Sep 2026 20:06:52 -0500 Subject: [PATCH 3/4] =?UTF-8?q?docs(csd):=20hold=20testable=20to=20CSD.md?= =?UTF-8?q?=20=E2=80=94=20ready-to-promote=20list=20at=20building?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CSD.md §1 makes `testable` a released floor AND a matrix run; no flow here has run on the matrix, and the runner that would (#97) is not on main. So CSD-005, 006 and 091 go back from `testable` to `building`, and they and the 19 cards whose spec passes check_csd_v3 at `testable` with a written flow (CSD-008, 032, 033, 036, 040, 045, 046, 047, 048, 049, 057, 068, 069, 081, 082, 090, 092, 100, 101) each open §5 with one line naming the flow and floor, and what promotes them. Stale "Flow: unwritten" headers on ten cards with drafts (040, 057, 068, 069, 081, 082, 083, 085, 087, 090) now name the draft. The drafts README's "Promoting one" now states the CSD.md bar for testable and verified. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_0155SkTGdbwnSnR6tWBqJvUM --- FSD/CSD/CSD-005-people.md | 9 +++++---- FSD/CSD/CSD-006-receipt.md | 4 +++- FSD/CSD/CSD-008-notes-to-self.md | 2 ++ FSD/CSD/CSD-032-network-identity.md | 2 ++ FSD/CSD/CSD-033-network-peers.md | 2 ++ FSD/CSD/CSD-036-network-ops.md | 2 ++ FSD/CSD/CSD-040-storage.md | 4 +++- FSD/CSD/CSD-045-node-self-standing.md | 2 ++ FSD/CSD/CSD-046-network-trust-graph.md | 2 ++ FSD/CSD/CSD-047-network-content.md | 2 ++ FSD/CSD/CSD-048-network-interfaces.md | 2 ++ FSD/CSD/CSD-049-network-queue.md | 2 ++ FSD/CSD/CSD-057-wallet.md | 4 +++- FSD/CSD/CSD-068-provision-accord-holder.md | 4 +++- FSD/CSD/CSD-069-accord-ceremony.md | 4 +++- FSD/CSD/CSD-081-login.md | 4 +++- FSD/CSD/CSD-082-setup-with-ai.md | 4 +++- FSD/CSD/CSD-083-setup-without-ai.md | 2 +- FSD/CSD/CSD-085-claim-node.md | 2 +- FSD/CSD/CSD-087-verify-agent.md | 2 +- FSD/CSD/CSD-090-duty-conferral.md | 4 +++- FSD/CSD/CSD-091-user-chat.md | 4 +++- FSD/CSD/CSD-092-share-contact-code.md | 2 ++ FSD/CSD/CSD-100-household.md | 2 ++ FSD/CSD/CSD-101-household-members.md | 2 ++ testing/flows/drafts/README.md | 17 ++++++++++++----- 26 files changed, 71 insertions(+), 21 deletions(-) diff --git a/FSD/CSD/CSD-005-people.md b/FSD/CSD/CSD-005-people.md index 47bd9259..2437ab04 100644 --- a/FSD/CSD/CSD-005-people.md +++ b/FSD/CSD/CSD-005-people.md @@ -5,7 +5,7 @@ **Reads with**: CSD-006 (the receipt it opens), CSD-091 (the chat a row opens), CSD-092 (the code card in its header), CSD-104 (the key check a row will offer once CIRISServer#683 lands) ```yaml csd:stage -stage: testable +stage: building owner: CIRISClient ``` @@ -219,6 +219,8 @@ again. On a fresh node with no contacts → `card_contacts_add` and no ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-005-people.yaml`, floor `>=0.5.225`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Platforms.** All five. The Contacts entry screen is what CIRISAgent's five-platform gate leans on; no tag it drives has changed. @@ -230,6 +232,5 @@ path. The removal end to end and the pasted code from another node, until deliberately NOT minted: the field already exists as `input_contacts_add_key`, and renaming it would break the tag the five-platform gate drives. -**Stated limit.** `testable` here means the flow is written against real tags -with a version floor; it has not yet run on the matrix in this review (no node -in the worktree). `verified` is the stage that says it ran. +**Stated limit.** The flow is written against real tags with a version floor; +it has not yet run on the matrix, so this card stays at `building`. diff --git a/FSD/CSD/CSD-006-receipt.md b/FSD/CSD/CSD-006-receipt.md index 703f0d8e..b5f37a97 100644 --- a/FSD/CSD/CSD-006-receipt.md +++ b/FSD/CSD/CSD-006-receipt.md @@ -4,7 +4,7 @@ **Flow**: `testing/flows/drafts/csd-006-receipt.yaml` (floor `>=0.5.225`) — driven on the first surface that binds the template (Contacts, CSD-005) ```yaml csd:stage -stage: testable +stage: building owner: CIRISClient ``` @@ -143,6 +143,8 @@ Bound per surface; CSD-005 §4 is the first instance. ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-006-receipt.yaml`, floor `>=0.5.225`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + A card CSD that binds this template asserts `visible:` on all five `receipt_*` tags after clicking its `btn_receipt_`; a card whose rows are furniture asserts `absent: [btn_receipt_*]` instead. diff --git a/FSD/CSD/CSD-008-notes-to-self.md b/FSD/CSD/CSD-008-notes-to-self.md index 84bf0cfd..5062834e 100644 --- a/FSD/CSD/CSD-008-notes-to-self.md +++ b/FSD/CSD/CSD-008-notes-to-self.md @@ -87,6 +87,8 @@ The new note is **not** listed under Files (CSD-007: `DriveEntry.isNote`). ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-008-notes-to-self.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Verified live** (desktop, scratch ciris-server 0.5.215, 2026-09-24): writing a note from the UI and reading it back from `/v1/notes`; a readable note rendering its body (the `open` / `here` token bug, fixed with a test). diff --git a/FSD/CSD/CSD-032-network-identity.md b/FSD/CSD/CSD-032-network-identity.md index 4d888946..e7aad3d7 100644 --- a/FSD/CSD/CSD-032-network-identity.md +++ b/FSD/CSD/CSD-032-network-identity.md @@ -121,6 +121,8 @@ expect: ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-032-network-identity.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Platforms.** All five; the bare-node variant on desktop and Android. **Not tested here.** The QR placeholders (`img_identity_qr_placeholder`, diff --git a/FSD/CSD/CSD-033-network-peers.md b/FSD/CSD/CSD-033-network-peers.md index 874e67ed..e0b697da 100644 --- a/FSD/CSD/CSD-033-network-peers.md +++ b/FSD/CSD/CSD-033-network-peers.md @@ -116,6 +116,8 @@ expect: ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-033-network-peers.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Platforms.** All five. The add-by-code path needs an agent; the bare-node leg asserts the sheet's "not on this node" copy instead. diff --git a/FSD/CSD/CSD-036-network-ops.md b/FSD/CSD/CSD-036-network-ops.md index dd5a9a7a..c9f7d7cc 100644 --- a/FSD/CSD/CSD-036-network-ops.md +++ b/FSD/CSD/CSD-036-network-ops.md @@ -152,6 +152,8 @@ That second block was written before the fix and failed; it now passes. ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-036-network-ops.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Platforms.** All five. The node-only variant needs the run-without-AI build, which is exactly where the defect showed. diff --git a/FSD/CSD/CSD-040-storage.md b/FSD/CSD/CSD-040-storage.md index d3467794..125f2cb0 100644 --- a/FSD/CSD/CSD-040-storage.md +++ b/FSD/CSD/CSD-040-storage.md @@ -1,7 +1,7 @@ # CSD-040 — Storage (My things › Everything I shared › Storage) **CSD**: CSD-040 · **Standard**: CSD/3 (`CSD.md`) · **Origin**: the Locked Spec, wave 1 -**Flow**: unwritten — the tags below are the contract the flow will drive +**Flow**: `testing/flows/drafts/csd-040-storage.yaml` (floor `unreleased`) ```yaml csd:stage stage: building @@ -179,6 +179,8 @@ itself; the fix landed (2026-09-28) and the block now asserts the sentence. ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-040-storage.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Platforms.** All five. The Postgres-only variant is a server-side fixture, not a client platform, and belongs in CIRISServer's matrix; this flow only needs the 503 to be reachable. diff --git a/FSD/CSD/CSD-045-node-self-standing.md b/FSD/CSD/CSD-045-node-self-standing.md index 0d009f41..36df70b0 100644 --- a/FSD/CSD/CSD-045-node-self-standing.md +++ b/FSD/CSD/CSD-045-node-self-standing.md @@ -195,6 +195,8 @@ arrives anyway. ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-045-node-self-standing.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Platforms.** All five, against a claimed node with an owner session. The with-AI legs exercise the node URL, not the agent port. The delegation-supplied path needs a 0.5.218 node; the typed fallback needs a 0.5.217 one, and the diff --git a/FSD/CSD/CSD-046-network-trust-graph.md b/FSD/CSD/CSD-046-network-trust-graph.md index b753d655..ac336e15 100644 --- a/FSD/CSD/CSD-046-network-trust-graph.md +++ b/FSD/CSD/CSD-046-network-trust-graph.md @@ -93,6 +93,8 @@ expect: ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-046-network-trust-graph.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Platforms.** All five; the canvas has no per-vertex tags, so the populated assertion is the canvas and the count is not assertable (the list, CSD-033, carries the count). diff --git a/FSD/CSD/CSD-047-network-content.md b/FSD/CSD/CSD-047-network-content.md index bb2fe530..e3bc7bb7 100644 --- a/FSD/CSD/CSD-047-network-content.md +++ b/FSD/CSD/CSD-047-network-content.md @@ -108,6 +108,8 @@ expect: ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-047-network-content.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Platforms.** All five, as the node's owner. A real fetch needs a second node holding a known digest; the matrix stands one up. diff --git a/FSD/CSD/CSD-048-network-interfaces.md b/FSD/CSD/CSD-048-network-interfaces.md index 0b0184f4..52d7d34f 100644 --- a/FSD/CSD/CSD-048-network-interfaces.md +++ b/FSD/CSD/CSD-048-network-interfaces.md @@ -96,6 +96,8 @@ expect: ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-048-network-interfaces.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Platforms.** All five. A LoRa or Bluetooth row needs hardware; the matrix asserts tcp. diff --git a/FSD/CSD/CSD-049-network-queue.md b/FSD/CSD/CSD-049-network-queue.md index bf9d192f..e5c2442f 100644 --- a/FSD/CSD/CSD-049-network-queue.md +++ b/FSD/CSD/CSD-049-network-queue.md @@ -133,6 +133,8 @@ expect: ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-049-network-queue.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Platforms.** All five. **Not tested here.** The five unmodelled diagnostic maps (§3); the sent/received diff --git a/FSD/CSD/CSD-057-wallet.md b/FSD/CSD/CSD-057-wallet.md index 486658aa..8f647e7a 100644 --- a/FSD/CSD/CSD-057-wallet.md +++ b/FSD/CSD/CSD-057-wallet.md @@ -1,7 +1,7 @@ # CSD-057 — Wallet (real money, in a circle, bound to a family that does not exist) **CSD**: CSD-057 · **Standard**: CSD/3 (`CSD.md`) · **Origin**: the Locked Spec, Rules tab -**Flow**: unwritten +**Flow**: `testing/flows/drafts/csd-057-wallet.yaml` (floor `>=0.5.224`) ```yaml csd:stage stage: building @@ -152,6 +152,8 @@ letting the warning quietly disappear would be testing the wrong half. ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-057-wallet.yaml`, floor `>=0.5.224`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Platforms.** All five, agent build. Plus a node build for the `wallet_unsupported` state in §2 once it exists. diff --git a/FSD/CSD/CSD-068-provision-accord-holder.md b/FSD/CSD/CSD-068-provision-accord-holder.md index fb56f7ea..eb0a01d1 100644 --- a/FSD/CSD/CSD-068-provision-accord-holder.md +++ b/FSD/CSD/CSD-068-provision-accord-holder.md @@ -1,7 +1,7 @@ # CSD-068 — Provision Accord Holder (the custody floor, in three steps) **CSD**: CSD-068 · **Standard**: CSD/3 (`CSD.md`) · **Origin**: the Locked Spec, wave 1 -**Flow**: unwritten +**Flow**: `testing/flows/drafts/csd-068-provision-accord-holder.yaml` (floor `>=0.5.224`) ```yaml csd:stage stage: building @@ -261,6 +261,8 @@ is `client: "unreleased"`). The pen moves when one does. ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-068-provision-accord-holder.yaml`, floor `>=0.5.224`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Platforms.** Desktop and Android in practice — the flow needs a USB path and a physical token, and the iOS/browser corners have neither. The screen composes on all five and the hop is derived on all five; only the ceremony itself is bounded. diff --git a/FSD/CSD/CSD-069-accord-ceremony.md b/FSD/CSD/CSD-069-accord-ceremony.md index 9e051fce..3c353d3b 100644 --- a/FSD/CSD/CSD-069-accord-ceremony.md +++ b/FSD/CSD/CSD-069-accord-ceremony.md @@ -1,7 +1,7 @@ # CSD-069 — Accord Genesis Ceremony (six keys, three humans, one artifact) **CSD**: CSD-069 · **Standard**: CSD/3 (`CSD.md`) · **Origin**: the Locked Spec, wave 1 -**Flow**: unwritten +**Flow**: `testing/flows/drafts/csd-069-accord-ceremony.yaml` (floor `>=0.5.224`) ```yaml csd:stage stage: building @@ -305,6 +305,8 @@ screen draws no tagged family line, so `accord:family` above is `proposed:`. ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-069-accord-ceremony.yaml`, floor `>=0.5.224`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Platforms.** Desktop in practice. Six FIPS YubiKeys and six USB volumes, each re-inserted, are not a thing any platform runner has; the screen composes on all five and the ceremony runs on one. diff --git a/FSD/CSD/CSD-081-login.md b/FSD/CSD/CSD-081-login.md index 608bfff1..054558ec 100644 --- a/FSD/CSD/CSD-081-login.md +++ b/FSD/CSD/CSD-081-login.md @@ -1,7 +1,7 @@ # CSD-081 — Login (the one door, and which one it is) **CSD**: CSD-081 · **Standard**: CSD/3 (`CSD.md`) · **Origin**: the Locked Spec, B10 -**Flow**: unwritten — the tags below are the contract the flow will drive +**Flow**: `testing/flows/drafts/csd-081-login.yaml` (floor `>=0.5.224`) ```yaml csd:stage stage: building @@ -219,6 +219,8 @@ expect: ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-081-login.yaml`, floor `>=0.5.224`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Platforms.** All five. `btn_local_login` / `input_username` / `input_password` / `btn_login_submit` are exactly the tags CIRISAgent's five-platform gate sends to this screen, and `session_fixture` cannot establish a session without them. diff --git a/FSD/CSD/CSD-082-setup-with-ai.md b/FSD/CSD/CSD-082-setup-with-ai.md index 14c1bad7..e11717eb 100644 --- a/FSD/CSD/CSD-082-setup-with-ai.md +++ b/FSD/CSD/CSD-082-setup-with-ai.md @@ -2,7 +2,7 @@ **CSD**: CSD-082 · **Standard**: CSD/3 (`CSD.md`) · **Origin**: the Locked Spec, B10 (the setup wizard) **Pairs with**: CSD-083 (the run-without-AI pass through the same screen) -**Flow**: partly written — `testing/gate/session_fixture.py` drives it today +**Flow**: `testing/flows/drafts/csd-082-setup-with-ai.yaml` (floor `>=0.5.224`); `testing/gate/session_fixture.py` also drives it during sign-in ```yaml csd:stage stage: building @@ -317,6 +317,8 @@ The node restarts and the app returns to **Login** with ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-082-setup-with-ai.yaml`, floor `>=0.5.224`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Platforms.** All five. Every input on the YOU and AI steps declares its sink at `SetupScreen.kt:201`, so they are drivable — with two exceptions below. diff --git a/FSD/CSD/CSD-083-setup-without-ai.md b/FSD/CSD/CSD-083-setup-without-ai.md index 85a81de4..4d1be897 100644 --- a/FSD/CSD/CSD-083-setup-without-ai.md +++ b/FSD/CSD/CSD-083-setup-without-ai.md @@ -2,7 +2,7 @@ **CSD**: CSD-083 · **Standard**: CSD/3 (`CSD.md`) · **Origin**: the Locked Spec, B10 (the setup wizard) **Pairs with**: CSD-082 (the with-AI pass through the same screen) -**Flow**: unwritten — `session_fixture` drives the with-AI pass; this one has no fixture +**Flow**: `testing/flows/drafts/csd-083-setup-without-ai.yaml` (floor `>=0.5.224`); `session_fixture` drives only the with-AI pass, so this one has no fixture ```yaml csd:stage stage: building diff --git a/FSD/CSD/CSD-085-claim-node.md b/FSD/CSD/CSD-085-claim-node.md index 60e68c13..3830fc48 100644 --- a/FSD/CSD/CSD-085-claim-node.md +++ b/FSD/CSD/CSD-085-claim-node.md @@ -1,7 +1,7 @@ # CSD-085 — Claim a node (binding a responsible party to an unowned key) **CSD**: CSD-085 · **Standard**: CSD/3 (`CSD.md`) · **Origin**: the Locked Spec, B10 · **Reads against**: `docs/FSD-remote-first-run-claim.md` -**Flow**: unwritten — and today unwritable; see §5 +**Flow**: `testing/flows/drafts/csd-085-claim-node.yaml` (floor `>=0.5.224`); its three text fields are not drivable yet and its no-signer step needs the local node stopped mid-flow (see §5) ```yaml csd:stage stage: building diff --git a/FSD/CSD/CSD-087-verify-agent.md b/FSD/CSD/CSD-087-verify-agent.md index 66b58c93..9a7bbb05 100644 --- a/FSD/CSD/CSD-087-verify-agent.md +++ b/FSD/CSD/CSD-087-verify-agent.md @@ -2,7 +2,7 @@ **CSD**: CSD-087 · **Standard**: CSD/3 (`CSD.md`) · **Origin**: the Locked Spec, B10 (a flow-only screen) **Overlaps**: reached only from ManageNodes, so it touches the node-identity area; raised with that card's author before writing -**Flow**: unwritten — the form is not drivable; see §5 +**Flow**: `testing/flows/drafts/csd-087-verify-agent.yaml` (floor `>=0.5.224`); `input_verify_hash` is not drivable (see §5), so it drives the refusal only ```yaml csd:stage stage: building diff --git a/FSD/CSD/CSD-090-duty-conferral.md b/FSD/CSD/CSD-090-duty-conferral.md index fe672a75..dd246c3e 100644 --- a/FSD/CSD/CSD-090-duty-conferral.md +++ b/FSD/CSD/CSD-090-duty-conferral.md @@ -1,7 +1,7 @@ # CSD-090 — Duty Conferral (two holders hand someone the authority to moderate) **CSD**: CSD-090 · **Standard**: CSD/3 (`CSD.md`) · **Origin**: the Locked Spec, leftovers -**Flow**: unwritten — the tags below are the contract the flow will drive +**Flow**: `testing/flows/drafts/csd-090-duty-conferral.yaml` (floor `>=0.5.224`) ```yaml csd:stage stage: building @@ -340,6 +340,8 @@ expect: ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-090-duty-conferral.yaml`, floor `>=0.5.224`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Platforms.** Desktop only, and not end to end. The ceremony needs two accord holders' YubiKeys, two humans and two PIV PINs; `testing/gate/node_fixture.py` produces none of them. What a suite can assert is everything up to `btn_duty_propose`: diff --git a/FSD/CSD/CSD-091-user-chat.md b/FSD/CSD/CSD-091-user-chat.md index 5dfeff8f..fc0dec1e 100644 --- a/FSD/CSD/CSD-091-user-chat.md +++ b/FSD/CSD/CSD-091-user-chat.md @@ -5,7 +5,7 @@ **Reads with**: CSD-005 (People, where a pair room starts), CSD-103 (the Chats tab that lists rooms), CSD-006 (the receipt every row carries) ```yaml csd:stage -stage: testable +stage: building owner: CIRISClient ``` @@ -294,6 +294,8 @@ and §5 disclaims it for the matrix. ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-091-user-chat.yaml`, floor `>=0.5.225`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Platforms.** All five for the transcript and the refusals; **two nodes** for anything that involves the other side, which `testing/gate/node_fixture.py` does not produce. A single-node suite can open a room, watch it sit in diff --git a/FSD/CSD/CSD-092-share-contact-code.md b/FSD/CSD/CSD-092-share-contact-code.md index 15acf66a..cfb98249 100644 --- a/FSD/CSD/CSD-092-share-contact-code.md +++ b/FSD/CSD/CSD-092-share-contact-code.md @@ -199,6 +199,8 @@ expect: ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-092-share-contact-code.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Platforms.** All five for the card. The copy → paste → contact round trip needs two nodes and runs on desktop. diff --git a/FSD/CSD/CSD-100-household.md b/FSD/CSD/CSD-100-household.md index 914aa7de..ee028e83 100644 --- a/FSD/CSD/CSD-100-household.md +++ b/FSD/CSD/CSD-100-household.md @@ -297,6 +297,8 @@ facts → confirm → the household is gone from the switcher. ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-100-household.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Platforms.** All five; the card calls only the node. **Tested (desktopTest).** `HouseholdsSupportTest`: the node's view decodes; diff --git a/FSD/CSD/CSD-101-household-members.md b/FSD/CSD/CSD-101-household-members.md index 7cdf3167..ea50861a 100644 --- a/FSD/CSD/CSD-101-household-members.md +++ b/FSD/CSD/CSD-101-household-members.md @@ -167,6 +167,8 @@ with either a `btn_household_member_pick_*` per contact or ## 5. QA plan +Spec complete and flow written (`testing/flows/drafts/csd-101-household-members.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). + **Platforms.** All five. **Tested (desktopTest).** The routing rule and the founder / member / quorum diff --git a/testing/flows/drafts/README.md b/testing/flows/drafts/README.md index 54c9b7e1..d15684fb 100644 --- a/testing/flows/drafts/README.md +++ b/testing/flows/drafts/README.md @@ -64,12 +64,19 @@ and `testing/gate/nav_map.py` derives the chain (`CSD.md` §2.0). Check first, in this order: -1. `python3 -m testing.gate.run_flows --flows testing/flows/drafts/` loads it; +1. `python3 -m testing.gate.run_flows --flows testing/flows/drafts/` loads it + (that module and the `csd:` binder arrive with #97; on `main` today + `FlowSpec.load` refuses the key — see below); 2. its CSD's §5 declares the platforms it should be green on; -3. the CSD's `stage:` moves to `verified` only after a green run — a green run is - evidence for that edit, never the edit itself. `testable` means the spec is - complete and the flow is written; a card promoted there says in its §5 that - the flow has not yet run on the matrix. +3. the CSD's `stage:` follows `CSD.md` §1, and is edited by hand, never inferred: + - `testable` needs the flow's `client:` floor to name a released version (not + `unreleased`) **and** the flow to run on the matrix; + - `verified` needs that run green on every platform the CSD's §5 declares. + + A green run is evidence for the edit, never the edit itself. A card whose spec + is complete and whose flow is written, but which has not met that bar, stays + at `building` and says so in one line at the top of its §5, so the promotion + is a mechanical flip once it does. ## Status on `main` (2026-09-28): none of the six nav-only flows promotes yet From 64e258ba7407b8eec649bc5d312852fbf8ac7305 Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Mon, 28 Sep 2026 20:26:59 -0500 Subject: [PATCH 4/4] fix(csd): make every "spec complete and flow written" line true (Codex on #128) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A §5 line that says a flow is written must mean the flow can go green on an ordinary matrix run. Per Codex's nine findings, and the same defect class found by scanning every optional step whose precondition was empty or only `screen:`: - testable needs a floor that is no longer `unreleased` (CSD.md §1), not a published version (that is `shipped`): README rule and every §5 line say so. - CSD-057: §4 describes the draft; the draft no longer asserts the spending, history and trust-warning cards WalletPage renders only with seeded state (disclaimed in §5); address and transfer steps are gated on their cards. - CSD-068 / CSD-069 Stage paragraphs: the floor is >=0.5.224; the matrix run is the only remaining condition. - CSD-069 draft: the completed-ceremony step asserts what AccordCeremony renders, not the re-mint sheet's remint_done_* (CSD-067). - CSD-040 §4: storage_error is real, not proposed. - CSD-081 draft: the observer and post-wizard steps are gated on card_observer_blocked and banner_setup_complete_relogin. - Gated on their own state: CSD-032, 033, 036 (both branches), 045 (plus typed / picked delegation steps), 048, 049, 090. - Line replaced by "Flow not complete" with the reason: CSD-006 (never opens a concrete receipt), CSD-047 (never picks a peer), CSD-082 (finish step ungatable), CSD-091 (a system-note-only room fails the history step). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_0155SkTGdbwnSnR6tWBqJvUM --- FSD/CSD/CSD-005-people.md | 2 +- FSD/CSD/CSD-006-receipt.md | 2 +- FSD/CSD/CSD-008-notes-to-self.md | 2 +- FSD/CSD/CSD-032-network-identity.md | 2 +- FSD/CSD/CSD-033-network-peers.md | 2 +- FSD/CSD/CSD-036-network-ops.md | 2 +- FSD/CSD/CSD-040-storage.md | 4 +- FSD/CSD/CSD-045-node-self-standing.md | 2 +- FSD/CSD/CSD-046-network-trust-graph.md | 2 +- FSD/CSD/CSD-047-network-content.md | 2 +- FSD/CSD/CSD-048-network-interfaces.md | 2 +- FSD/CSD/CSD-049-network-queue.md | 2 +- FSD/CSD/CSD-057-wallet.md | 51 +++++++++------- FSD/CSD/CSD-068-provision-accord-holder.md | 13 ++-- FSD/CSD/CSD-069-accord-ceremony.md | 10 ++-- FSD/CSD/CSD-081-login.md | 2 +- FSD/CSD/CSD-082-setup-with-ai.md | 2 +- FSD/CSD/CSD-090-duty-conferral.md | 2 +- FSD/CSD/CSD-091-user-chat.md | 2 +- FSD/CSD/CSD-092-share-contact-code.md | 2 +- FSD/CSD/CSD-100-household.md | 2 +- FSD/CSD/CSD-101-household-members.md | 2 +- testing/flows/drafts/README.md | 7 ++- testing/flows/drafts/csd-006-receipt.yaml | 4 ++ .../drafts/csd-032-network-identity.yaml | 2 + .../flows/drafts/csd-033-network-peers.yaml | 2 + testing/flows/drafts/csd-036-network-ops.yaml | 4 ++ .../drafts/csd-045-node-self-standing.yaml | 33 +++++++++- .../flows/drafts/csd-047-network-content.yaml | 17 ++++-- .../drafts/csd-048-network-interfaces.yaml | 2 + .../flows/drafts/csd-049-network-queue.yaml | 5 ++ testing/flows/drafts/csd-057-wallet.yaml | 60 ++++++++++++------- .../flows/drafts/csd-069-accord-ceremony.yaml | 18 +++--- testing/flows/drafts/csd-081-login.yaml | 14 ++++- .../flows/drafts/csd-090-duty-conferral.yaml | 1 + 35 files changed, 190 insertions(+), 93 deletions(-) diff --git a/FSD/CSD/CSD-005-people.md b/FSD/CSD/CSD-005-people.md index 2437ab04..026e44ba 100644 --- a/FSD/CSD/CSD-005-people.md +++ b/FSD/CSD/CSD-005-people.md @@ -219,7 +219,7 @@ again. On a fresh node with no contacts → `card_contacts_add` and no ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-005-people.yaml`, floor `>=0.5.225`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +Spec complete and flow written (`testing/flows/drafts/csd-005-people.yaml`, floor `>=0.5.225`); promotes to `testable` when the floor is no longer `unreleased` and the flow runs on the matrix (#97). **Platforms.** All five. The Contacts entry screen is what CIRISAgent's five-platform gate leans on; no tag it drives has changed. diff --git a/FSD/CSD/CSD-006-receipt.md b/FSD/CSD/CSD-006-receipt.md index b5f37a97..2fbdd0b1 100644 --- a/FSD/CSD/CSD-006-receipt.md +++ b/FSD/CSD/CSD-006-receipt.md @@ -143,7 +143,7 @@ Bound per surface; CSD-005 §4 is the first instance. ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-006-receipt.yaml`, floor `>=0.5.225`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +**Flow not complete.** `testing/flows/drafts/csd-006-receipt.yaml` (floor `>=0.5.225`) never opens a receipt: the hamburger's tag is `btn_receipt_`, a flow `click:` takes one literal tag, and no fixture seeds a contact whose key id the flow could name. Every fact step is therefore gated on `sheet_receipt` and always skips. It is complete when a seeded contact (or a runner that can click the first match of `btn_receipt_*`) lets it open a concrete receipt; until then this card is not ready to promote. A card CSD that binds this template asserts `visible:` on all five `receipt_*` tags after clicking its `btn_receipt_`; a card whose rows are furniture diff --git a/FSD/CSD/CSD-008-notes-to-self.md b/FSD/CSD/CSD-008-notes-to-self.md index 5062834e..1f4f1e0f 100644 --- a/FSD/CSD/CSD-008-notes-to-self.md +++ b/FSD/CSD/CSD-008-notes-to-self.md @@ -87,7 +87,7 @@ The new note is **not** listed under Files (CSD-007: `DriveEntry.isNote`). ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-008-notes-to-self.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +Spec complete and flow written (`testing/flows/drafts/csd-008-notes-to-self.yaml`, floor `unreleased`); promotes to `testable` when the floor is no longer `unreleased` and the flow runs on the matrix (#97). **Verified live** (desktop, scratch ciris-server 0.5.215, 2026-09-24): writing a note from the UI and reading it back from `/v1/notes`; a readable note diff --git a/FSD/CSD/CSD-032-network-identity.md b/FSD/CSD/CSD-032-network-identity.md index e7aad3d7..a8c3d975 100644 --- a/FSD/CSD/CSD-032-network-identity.md +++ b/FSD/CSD/CSD-032-network-identity.md @@ -121,7 +121,7 @@ expect: ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-032-network-identity.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +Spec complete and flow written (`testing/flows/drafts/csd-032-network-identity.yaml`, floor `unreleased`); promotes to `testable` when the floor is no longer `unreleased` and the flow runs on the matrix (#97). **Platforms.** All five; the bare-node variant on desktop and Android. diff --git a/FSD/CSD/CSD-033-network-peers.md b/FSD/CSD/CSD-033-network-peers.md index e0b697da..579b565e 100644 --- a/FSD/CSD/CSD-033-network-peers.md +++ b/FSD/CSD/CSD-033-network-peers.md @@ -116,7 +116,7 @@ expect: ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-033-network-peers.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +Spec complete and flow written (`testing/flows/drafts/csd-033-network-peers.yaml`, floor `unreleased`); promotes to `testable` when the floor is no longer `unreleased` and the flow runs on the matrix (#97). **Platforms.** All five. The add-by-code path needs an agent; the bare-node leg asserts the sheet's "not on this node" copy instead. diff --git a/FSD/CSD/CSD-036-network-ops.md b/FSD/CSD/CSD-036-network-ops.md index c9f7d7cc..15c34749 100644 --- a/FSD/CSD/CSD-036-network-ops.md +++ b/FSD/CSD/CSD-036-network-ops.md @@ -152,7 +152,7 @@ That second block was written before the fix and failed; it now passes. ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-036-network-ops.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +Spec complete and flow written (`testing/flows/drafts/csd-036-network-ops.yaml`, floor `unreleased`); promotes to `testable` when the floor is no longer `unreleased` and the flow runs on the matrix (#97). **Platforms.** All five. The node-only variant needs the run-without-AI build, which is exactly where the defect showed. diff --git a/FSD/CSD/CSD-040-storage.md b/FSD/CSD/CSD-040-storage.md index 125f2cb0..be9ca422 100644 --- a/FSD/CSD/CSD-040-storage.md +++ b/FSD/CSD/CSD-040-storage.md @@ -153,7 +153,7 @@ On a Postgres-only node, where `/v1/memory/stats` is a 503 stub: ```yaml expect: state: error - visible: ["proposed:storage_error"] + visible: [storage_error] absent: [card_storage_graph] ``` @@ -179,7 +179,7 @@ itself; the fix landed (2026-09-28) and the block now asserts the sentence. ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-040-storage.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +Spec complete and flow written (`testing/flows/drafts/csd-040-storage.yaml`, floor `unreleased`); promotes to `testable` when the floor is no longer `unreleased` and the flow runs on the matrix (#97). **Platforms.** All five. The Postgres-only variant is a server-side fixture, not a client platform, and belongs in CIRISServer's matrix; this flow only needs the diff --git a/FSD/CSD/CSD-045-node-self-standing.md b/FSD/CSD/CSD-045-node-self-standing.md index 36df70b0..be070997 100644 --- a/FSD/CSD/CSD-045-node-self-standing.md +++ b/FSD/CSD/CSD-045-node-self-standing.md @@ -195,7 +195,7 @@ arrives anyway. ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-045-node-self-standing.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +Spec complete and flow written (`testing/flows/drafts/csd-045-node-self-standing.yaml`, floor `unreleased`); promotes to `testable` when the floor is no longer `unreleased` and the flow runs on the matrix (#97). **Platforms.** All five, against a claimed node with an owner session. The with-AI legs exercise the node URL, not the agent port. The delegation-supplied diff --git a/FSD/CSD/CSD-046-network-trust-graph.md b/FSD/CSD/CSD-046-network-trust-graph.md index ac336e15..355167ab 100644 --- a/FSD/CSD/CSD-046-network-trust-graph.md +++ b/FSD/CSD/CSD-046-network-trust-graph.md @@ -93,7 +93,7 @@ expect: ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-046-network-trust-graph.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +Spec complete and flow written (`testing/flows/drafts/csd-046-network-trust-graph.yaml`, floor `unreleased`); promotes to `testable` when the floor is no longer `unreleased` and the flow runs on the matrix (#97). **Platforms.** All five; the canvas has no per-vertex tags, so the populated assertion is the canvas and the count is not assertable (the list, CSD-033, diff --git a/FSD/CSD/CSD-047-network-content.md b/FSD/CSD/CSD-047-network-content.md index e3bc7bb7..50ce9c4b 100644 --- a/FSD/CSD/CSD-047-network-content.md +++ b/FSD/CSD/CSD-047-network-content.md @@ -108,7 +108,7 @@ expect: ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-047-network-content.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +**Flow not complete.** `testing/flows/drafts/csd-047-network-content.yaml` (floor `unreleased`) never reaches the digest step: that needs a peer picked by `peer_pick_row_`, a `click:` takes one literal tag, and no fixture seeds a peer whose key id the flow could name. The digest steps are gated on `input_content_id` and always skip, so the flow is green without driving the half this card is about. It is complete when a seeded peer lets it pick one. Until then this card is not ready to promote. **Platforms.** All five, as the node's owner. A real fetch needs a second node holding a known digest; the matrix stands one up. diff --git a/FSD/CSD/CSD-048-network-interfaces.md b/FSD/CSD/CSD-048-network-interfaces.md index 52d7d34f..76da8489 100644 --- a/FSD/CSD/CSD-048-network-interfaces.md +++ b/FSD/CSD/CSD-048-network-interfaces.md @@ -96,7 +96,7 @@ expect: ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-048-network-interfaces.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +Spec complete and flow written (`testing/flows/drafts/csd-048-network-interfaces.yaml`, floor `unreleased`); promotes to `testable` when the floor is no longer `unreleased` and the flow runs on the matrix (#97). **Platforms.** All five. A LoRa or Bluetooth row needs hardware; the matrix asserts tcp. diff --git a/FSD/CSD/CSD-049-network-queue.md b/FSD/CSD/CSD-049-network-queue.md index e5c2442f..8d6a3216 100644 --- a/FSD/CSD/CSD-049-network-queue.md +++ b/FSD/CSD/CSD-049-network-queue.md @@ -133,7 +133,7 @@ expect: ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-049-network-queue.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +Spec complete and flow written (`testing/flows/drafts/csd-049-network-queue.yaml`, floor `unreleased`); promotes to `testable` when the floor is no longer `unreleased` and the flow runs on the matrix (#97). **Platforms.** All five. diff --git a/FSD/CSD/CSD-057-wallet.md b/FSD/CSD/CSD-057-wallet.md index 8f647e7a..be295ab4 100644 --- a/FSD/CSD/CSD-057-wallet.md +++ b/FSD/CSD/CSD-057-wallet.md @@ -130,34 +130,45 @@ missing `error` state, and a person on a node sees an empty wallet rather than ## 4. Flow (how) -Unwritten. It could be written today for everything up to the send — the -balance, the limits, the address copy and the address-validation error all run -on real tags — and now up to and including the ConfirmSheet: `btn_send_transfer` -with a clean address and amount opens `sheet_wallet_send`, and -`btn_wallet_send_cancel` closes it with nothing sent. **The confirm itself must -not be flowed against a live rail.** A flow that moves USDC to pass is not a -test. Loading and error on this page (`WalletPage.kt:310, :327`) are still -untagged. - -```yaml -# candidate — read-only, stops before btn_send_transfer -expect: - state: populated - visible: [card_wallet_balance, card_spending_progress, card_wallet_experimental, txt_wallet_address] -``` - -`card_wallet_experimental` is in that list deliberately: the screen already -renders an amber experimental warning, and a flow that asserts the balance while -letting the warning quietly disappear would be testing the wrong half. +Written: `testing/flows/drafts/csd-057-wallet.yaml` (floor `>=0.5.224`), +read-only, and it stops before the send. In order: + +1. **On the wallet** — `card_wallet_experimental` and `card_wallet_balance`, + the banner asserted with the first number, never after it. +2. **Fees and limits** — `card_wallet_paymaster`, `txt_paymaster_status`, + `card_wallet_limits`; `WalletPage.kt` renders all three whenever a status is + on screen. +3. **The address** (optional on the wallet having one, `WalletPage.kt:260`) — + `txt_wallet_address` and `btn_copy_address`. +4. **The form** (optional on `card_wallet_transfer`, which renders only for a + wallet with an address that is not receive-only, `:270`) — the three inputs + and `btn_send_transfer`. +5. **The form takes input** (optional on the same) — a zero address, `0` and a + memo are typed; `btn_send_transfer` is never pressed. +6. **Back** — `btn_wallet_back` leaves the card. + +**The confirm itself must not be flowed against a live rail.** A flow that +moves USDC to pass is not a test. Opening `sheet_wallet_send` and cancelling +with `btn_wallet_send_cancel` is safe, but it needs an address that passes the +validation and duplicate checks against a live agent, so it is not in the draft. + +`card_wallet_experimental` leads deliberately: the screen renders an amber +experimental warning, and a flow that asserts the balance while letting the +warning quietly disappear would be testing the wrong half. ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-057-wallet.yaml`, floor `>=0.5.224`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +Spec complete and flow written (`testing/flows/drafts/csd-057-wallet.yaml`, floor `>=0.5.224`); promotes to `testable` when the floor is no longer `unreleased` and the flow runs on the matrix (#97). **Platforms.** All five, agent build. Plus a node build for the `wallet_unsupported` state in §2 once it exists. **Not tested here.** +* `card_spending_progress`, `card_transaction_history` and `card_trust_warning`. + `WalletPage.kt` renders them only when the status carries spending limits + (`:265`), recent transactions (`:293`) or degraded hardware trust (`:298`); + the defaults are null, empty and false, and no fixture seeds a wallet in any + of those states. They are asserted once one does. * Sending. It moves real value on Base; the duplicate check and the address validation are the parts a flow can exercise safely. * Whether the balance is right. That is the chain's claim, relayed by the agent. diff --git a/FSD/CSD/CSD-068-provision-accord-holder.md b/FSD/CSD/CSD-068-provision-accord-holder.md index eb0a01d1..0c15739a 100644 --- a/FSD/CSD/CSD-068-provision-accord-holder.md +++ b/FSD/CSD/CSD-068-provision-accord-holder.md @@ -253,15 +253,16 @@ expect: touch, which no platform runner has; §5 says so rather than mocking it. **Stage.** Every tag is real and nothing in §3 is `unconfirmed`, so -`check_csd_v3.py` would admit `testable`. The card stays at `building` because -the lifecycle's other condition for `testable` — the flow's floor flips off -`unreleased` — is not met: no release carries this screen's custody row, copy -button or token banner yet (`testing/flows/drafts/csd-068-provision-accord-holder.yaml` -is `client: "unreleased"`). The pen moves when one does. +`check_csd_v3.py` would admit `testable`. The flow's floor is already off +`unreleased` — `testing/flows/drafts/csd-068-provision-accord-holder.yaml` is +`client: ">=0.5.224"`, and every tag it drives is a literal at v0.5.224 (the +custody row, copy button and token banner that came later are not in it). The +one remaining condition is that the flow runs on the matrix (#97); the card +stays at `building` until it does. ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-068-provision-accord-holder.yaml`, floor `>=0.5.224`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +Spec complete and flow written (`testing/flows/drafts/csd-068-provision-accord-holder.yaml`, floor `>=0.5.224`); promotes to `testable` when the floor is no longer `unreleased` and the flow runs on the matrix (#97). **Platforms.** Desktop and Android in practice — the flow needs a USB path and a physical token, and the iOS/browser corners have neither. The screen composes on diff --git a/FSD/CSD/CSD-069-accord-ceremony.md b/FSD/CSD/CSD-069-accord-ceremony.md index 3c353d3b..1679308a 100644 --- a/FSD/CSD/CSD-069-accord-ceremony.md +++ b/FSD/CSD/CSD-069-accord-ceremony.md @@ -305,7 +305,7 @@ screen draws no tagged family line, so `accord:family` above is `proposed:`. ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-069-accord-ceremony.yaml`, floor `>=0.5.224`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +Spec complete and flow written (`testing/flows/drafts/csd-069-accord-ceremony.yaml`, floor `>=0.5.224`); promotes to `testable` when the floor is no longer `unreleased` and the flow runs on the matrix (#97). **Platforms.** Desktop in practice. Six FIPS YubiKeys and six USB volumes, each re-inserted, are not a thing any platform runner has; the screen composes on all @@ -326,9 +326,11 @@ five and the ceremony runs on one. the person then kept the file is theirs. **Stage.** Every tag is real and §3 has no `unconfirmed`, so `check_csd_v3.py` -would admit `testable`; the card stays at `building` for the same reason as -CSD-068 — no release carries the phase line, the intro sentences or the -copy/save yet, and the draft flow's floor is `unreleased`. +would admit `testable`. The draft flow's floor is already off `unreleased` +(`client: ">=0.5.224"`): it drives only tags that v0.5.224 carries, and leaves +the later phase line, intro sentences, family line and copy/save unasserted. +As for CSD-068, the one remaining condition is that the flow runs on the +matrix (#97); the card stays at `building` until it does. * **The hop.** Unlike every other CSD in this area, the runner cannot walk to this screen, so "the entry exists" is asserted by the parent's CSD-067 flow and by nothing here. diff --git a/FSD/CSD/CSD-081-login.md b/FSD/CSD/CSD-081-login.md index 054558ec..6ee436b0 100644 --- a/FSD/CSD/CSD-081-login.md +++ b/FSD/CSD/CSD-081-login.md @@ -219,7 +219,7 @@ expect: ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-081-login.yaml`, floor `>=0.5.224`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +Spec complete and flow written (`testing/flows/drafts/csd-081-login.yaml`, floor `>=0.5.224`); promotes to `testable` when the floor is no longer `unreleased` and the flow runs on the matrix (#97). **Platforms.** All five. `btn_local_login` / `input_username` / `input_password` / `btn_login_submit` are exactly the tags CIRISAgent's five-platform gate sends diff --git a/FSD/CSD/CSD-082-setup-with-ai.md b/FSD/CSD/CSD-082-setup-with-ai.md index e11717eb..6c7dddec 100644 --- a/FSD/CSD/CSD-082-setup-with-ai.md +++ b/FSD/CSD/CSD-082-setup-with-ai.md @@ -317,7 +317,7 @@ The node restarts and the app returns to **Login** with ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-082-setup-with-ai.yaml`, floor `>=0.5.224`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +**Flow not complete.** `testing/flows/drafts/csd-082-setup-with-ai.yaml` (floor `>=0.5.224`) cannot go green on an ordinary matrix run as written: `the_claim_is_a_real_loading_state` presses Finish and asserts `setup_ownership_claiming` with `btn_next` absent. Its only precondition is `screen: Setup`, which always holds; whether Finish is live at all depends on the runner having an LLM key, and the loading state it asserts is transient, so an ordinary run can fail it either way. No tag marks the state it needs beforehand. It is complete when that step is gated on one (or split into a flow for a runner that holds a key); `FinalStepOnceTest` pins the behaviour meanwhile. Until then this card is not ready to promote. **Platforms.** All five. Every input on the YOU and AI steps declares its sink at `SetupScreen.kt:201`, so they are drivable — with two exceptions below. diff --git a/FSD/CSD/CSD-090-duty-conferral.md b/FSD/CSD/CSD-090-duty-conferral.md index dd246c3e..869b64ea 100644 --- a/FSD/CSD/CSD-090-duty-conferral.md +++ b/FSD/CSD/CSD-090-duty-conferral.md @@ -340,7 +340,7 @@ expect: ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-090-duty-conferral.yaml`, floor `>=0.5.224`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +Spec complete and flow written (`testing/flows/drafts/csd-090-duty-conferral.yaml`, floor `>=0.5.224`); promotes to `testable` when the floor is no longer `unreleased` and the flow runs on the matrix (#97). **Platforms.** Desktop only, and not end to end. The ceremony needs two accord holders' YubiKeys, two humans and two PIV PINs; `testing/gate/node_fixture.py` diff --git a/FSD/CSD/CSD-091-user-chat.md b/FSD/CSD/CSD-091-user-chat.md index fc0dec1e..6b758fdc 100644 --- a/FSD/CSD/CSD-091-user-chat.md +++ b/FSD/CSD/CSD-091-user-chat.md @@ -294,7 +294,7 @@ and §5 disclaims it for the matrix. ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-091-user-chat.yaml`, floor `>=0.5.225`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +**Flow not complete.** `testing/flows/drafts/csd-091-user-chat.yaml` (floor `>=0.5.225`) cannot go green on an ordinary matrix run as written: `a_room_with_history` is gated only on `chat_transcript`, which also renders for a room holding nothing but a system note (the single-node `awaiting_peer` room, `ChatScreen.kt`) and for a refusal over an empty room; `SystemNoteRow` carries no tag, so `count: chat_msg_* min 1` fails on the ordinary run and nothing on screen can gate it. It is complete when system notes are tagged or a two-node fixture seeds a message. Until then this card is not ready to promote. **Platforms.** All five for the transcript and the refusals; **two nodes** for anything that involves the other side, which `testing/gate/node_fixture.py` does diff --git a/FSD/CSD/CSD-092-share-contact-code.md b/FSD/CSD/CSD-092-share-contact-code.md index cfb98249..1e6ce3b7 100644 --- a/FSD/CSD/CSD-092-share-contact-code.md +++ b/FSD/CSD/CSD-092-share-contact-code.md @@ -199,7 +199,7 @@ expect: ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-092-share-contact-code.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +Spec complete and flow written (`testing/flows/drafts/csd-092-share-contact-code.yaml`, floor `unreleased`); promotes to `testable` when the floor is no longer `unreleased` and the flow runs on the matrix (#97). **Platforms.** All five for the card. The copy → paste → contact round trip needs two nodes and runs on desktop. diff --git a/FSD/CSD/CSD-100-household.md b/FSD/CSD/CSD-100-household.md index ee028e83..d92c611c 100644 --- a/FSD/CSD/CSD-100-household.md +++ b/FSD/CSD/CSD-100-household.md @@ -297,7 +297,7 @@ facts → confirm → the household is gone from the switcher. ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-100-household.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +Spec complete and flow written (`testing/flows/drafts/csd-100-household.yaml`, floor `unreleased`); promotes to `testable` when the floor is no longer `unreleased` and the flow runs on the matrix (#97). **Platforms.** All five; the card calls only the node. diff --git a/FSD/CSD/CSD-101-household-members.md b/FSD/CSD/CSD-101-household-members.md index ea50861a..021f88b5 100644 --- a/FSD/CSD/CSD-101-household-members.md +++ b/FSD/CSD/CSD-101-household-members.md @@ -167,7 +167,7 @@ with either a `btn_household_member_pick_*` per contact or ## 5. QA plan -Spec complete and flow written (`testing/flows/drafts/csd-101-household-members.yaml`, floor `unreleased`); promotes to `testable` when the floor is released and the flow runs on the matrix (#97). +Spec complete and flow written (`testing/flows/drafts/csd-101-household-members.yaml`, floor `unreleased`); promotes to `testable` when the floor is no longer `unreleased` and the flow runs on the matrix (#97). **Platforms.** All five. diff --git a/testing/flows/drafts/README.md b/testing/flows/drafts/README.md index d15684fb..c2e9f944 100644 --- a/testing/flows/drafts/README.md +++ b/testing/flows/drafts/README.md @@ -69,9 +69,10 @@ Check first, in this order: `FlowSpec.load` refuses the key — see below); 2. its CSD's §5 declares the platforms it should be green on; 3. the CSD's `stage:` follows `CSD.md` §1, and is edited by hand, never inferred: - - `testable` needs the flow's `client:` floor to name a released version (not - `unreleased`) **and** the flow to run on the matrix; - - `verified` needs that run green on every platform the CSD's §5 declares. + - `testable` needs the flow's `client:` floor to be no longer `unreleased` + (any `>=X` / `>X` form) **and** the flow to run on the matrix; + - `verified` needs that run green on every platform the CSD's §5 declares; + - `shipped` is the stage whose floor names a published version. A green run is evidence for the edit, never the edit itself. A card whose spec is complete and whose flow is written, but which has not met that bar, stays diff --git a/testing/flows/drafts/csd-006-receipt.yaml b/testing/flows/drafts/csd-006-receipt.yaml index 39a1d940..7e349d31 100644 --- a/testing/flows/drafts/csd-006-receipt.yaml +++ b/testing/flows/drafts/csd-006-receipt.yaml @@ -13,6 +13,10 @@ description: >- # row reads the wire (Contact.grant) since PR #101; 0.5.225 is the client whose # grant-less receipt no longer guesses the scope. client: ">=0.5.225" +# INCOMPLETE: no step clicks a concrete `btn_receipt_` -- `click:` takes a +# literal tag and no fixture seeds a contact with a known key id -- so every +# step gated on `sheet_receipt` skips. CSD-006 §5 says so; this flow is not +# evidence for the five facts until it opens a receipt. steps: - step_id: a_row_with_a_hamburger diff --git a/testing/flows/drafts/csd-032-network-identity.yaml b/testing/flows/drafts/csd-032-network-identity.yaml index 6ad616cf..e9b70a19 100644 --- a/testing/flows/drafts/csd-032-network-identity.yaml +++ b/testing/flows/drafts/csd-032-network-identity.yaml @@ -41,6 +41,8 @@ steps: - step_id: on_a_bare_node_the_aggregate_says_so title: Without an agent the Federation ID card names its absence optional_step: true + requires: + visible: [federation_id_card_not_on_this_node] expect: visible: [federation_id_card_not_on_this_node] absent: [banner_federation_error] diff --git a/testing/flows/drafts/csd-033-network-peers.yaml b/testing/flows/drafts/csd-033-network-peers.yaml index bd6a756a..c4e0ab02 100644 --- a/testing/flows/drafts/csd-033-network-peers.yaml +++ b/testing/flows/drafts/csd-033-network-peers.yaml @@ -29,6 +29,8 @@ steps: Optional because the matrix decides which of the three the node is in. What is never allowed is the fourth: the empty sentence over a read that failed. optional_step: true + requires: + visible: [list_peers] expect: state: populated visible: [list_peers] diff --git a/testing/flows/drafts/csd-036-network-ops.yaml b/testing/flows/drafts/csd-036-network-ops.yaml index 88211dc7..91996360 100644 --- a/testing/flows/drafts/csd-036-network-ops.yaml +++ b/testing/flows/drafts/csd-036-network-ops.yaml @@ -36,12 +36,16 @@ steps: the agent's to report. Neither branch is the Kotlin default; the tag's value is published so a default and a reading cannot be confused. optional_step: true + requires: + visible: [row_netops_mode] expect: one_of: {row_netops_mode: [CLIENT, PROXY, SERVER]} - step_id: on_a_node_build_the_mode_is_not_on_this_node title: Without an agent the mode card says why it has no reading optional_step: true + requires: + visible: [netops_not_on_this_node] expect: visible: [netops_not_on_this_node] absent: [row_netops_mode] diff --git a/testing/flows/drafts/csd-045-node-self-standing.yaml b/testing/flows/drafts/csd-045-node-self-standing.yaml index 6d875e00..43d2293f 100644 --- a/testing/flows/drafts/csd-045-node-self-standing.yaml +++ b/testing/flows/drafts/csd-045-node-self-standing.yaml @@ -52,13 +52,40 @@ steps: expect: visible: [input_self_reason, input_self_compelled_by, btn_self_review, btn_self_cancel] + - step_id: an_older_node_takes_a_typed_delegation + title: Where the node does not supply the owner's delegation, one is typed + description: >- + OwnerDelegationPicker renders input_self_delegation_id when the authority + is NotSupplied or Unreadable (SelfReaderOpsSection.kt, `tagPrefix = "self"`). + Skipped on a node that supplies it. + optional_step: true + requires: + visible: [input_self_delegation_id] + do: + - input: {input_self_delegation_id: "flow-check-delegation"} + expect: + visible: [btn_self_review] + + - step_id: several_delegations_pick_the_first + title: Where the node supplies several delegations, the first is picked + optional_step: true + requires: + visible: [opt_self_owner_delegation_0] + do: + - click: opt_self_owner_delegation_0 + expect: + visible: [btn_self_review] + - step_id: the_confirm_names_three_facts title: The ConfirmSheet names what is recorded, what it changes and who signs optional_step: true + requires: + visible: [btn_self_review] + absent: [text_self_no_owner_delegation] description: >- Optional because btn_self_review is enabled only once a delegation is known: - supplied by a 0.5.218 node, or typed on an older one. A matrix leg on an older - node types one first. + supplied by a 0.5.218 node, or typed / picked by the two steps above. It is + skipped on a node whose owner holds none (text_self_no_owner_delegation). do: - click: btn_self_review expect: @@ -68,6 +95,8 @@ steps: - step_id: cancel_leaves_the_standings_unchanged title: Cancelling the confirm records nothing optional_step: true + requires: + visible: [sheet_self_act] do: - click: btn_self_act_cancel expect: diff --git a/testing/flows/drafts/csd-047-network-content.yaml b/testing/flows/drafts/csd-047-network-content.yaml index 90443298..9a24b754 100644 --- a/testing/flows/drafts/csd-047-network-content.yaml +++ b/testing/flows/drafts/csd-047-network-content.yaml @@ -23,16 +23,19 @@ steps: expect: visible: [screen_federation_content, input_peer_search] - - step_id: the_digest_step_after_a_pick - title: Picking a peer opens the digest step + - step_id: clearing_the_search + title: Clearing the search leaves the pick step in place description: >- - Optional because it needs at least one peer. The row tag carries the peer's - key id; the matrix supplies it. - optional_step: true + The flow cannot pick a peer: the row tag is `peer_pick_row_`, a + `click:` takes one literal tag, and no fixture seeds a peer whose key id + the flow could name. So it clears the search and stops at the pick step; + the digest step below is gated on `input_content_id` and skips until a + seeded peer lets the flow open it (CSD-047 §5). do: - input: {input_peer_search: ""} expect: - count: {of: "peer_pick_row_*", min: 1} + screen: NetworkContent + visible: [input_peer_search] - step_id: a_bad_digest_keeps_fetch_shut title: A digest that is not 64 hex characters cannot be fetched @@ -41,6 +44,8 @@ steps: Asserting the button is present and the field took input is what a flow can do; the disabled state is the view model's validateContentId. optional_step: true + requires: + visible: [input_content_id] do: - input: {input_content_id: "not-a-digest"} expect: diff --git a/testing/flows/drafts/csd-048-network-interfaces.yaml b/testing/flows/drafts/csd-048-network-interfaces.yaml index 8b2de3d1..b437ca6f 100644 --- a/testing/flows/drafts/csd-048-network-interfaces.yaml +++ b/testing/flows/drafts/csd-048-network-interfaces.yaml @@ -23,6 +23,8 @@ steps: - step_id: a_medium_per_card title: A node carrying tcp traffic shows one tcp card, not one per peer optional_step: true + requires: + count: {of: "card_transport_*", min: 1} expect: state: populated visible: [card_transport_tcp] diff --git a/testing/flows/drafts/csd-049-network-queue.yaml b/testing/flows/drafts/csd-049-network-queue.yaml index ee31317d..70b78780 100644 --- a/testing/flows/drafts/csd-049-network-queue.yaml +++ b/testing/flows/drafts/csd-049-network-queue.yaml @@ -27,12 +27,17 @@ steps: - step_id: a_read_counter_is_a_number title: Once read, the queue depth is a number optional_step: true + requires: + visible: [text_queue_depth] expect: number: {text_queue_depth: {min: 0}} - step_id: the_replication_plane_has_a_standing title: A node that reports the plane shows its two standings by token optional_step: true + requires: + absent: [text_replication_not_reported] + visible: [card_queue_replication] expect: visible: [text_carriage_standing, text_receive_standing] one_of: {text_carriage_standing: [unreadable, not_exercised, idle, moving, withholding]} diff --git a/testing/flows/drafts/csd-057-wallet.yaml b/testing/flows/drafts/csd-057-wallet.yaml index 72da1f29..3b97a61e 100644 --- a/testing/flows/drafts/csd-057-wallet.yaml +++ b/testing/flows/drafts/csd-057-wallet.yaml @@ -1,13 +1,12 @@ csd: CSD-057 flow: csd_057_wallet -title: The wallet says it is experimental, names its limits, and warns before a send +title: The wallet says it is experimental, names its limits and fees, and offers a form it never submits description: >- CSD-057 §4, driven. Four agent routes are live and called (CIRISAgent routes/wallet.py:570/674/817/976, unchanged on main). The card is placed in Communities and Businesses > Rules with no `agentOnly` (CirclesNav.kt:119), so on a node build it answers from a synthesised value — - which is why the experimental banner and the trust warning are asserted before - any number is. + which is why the experimental banner is asserted before any number is. # Floor: card_wallet_experimental, card_wallet_balance, card_wallet_limits, # card_wallet_paymaster, card_wallet_address, card_spending_progress, # card_transaction_history, card_trust_warning, txt_wallet_address, @@ -17,6 +16,12 @@ description: >- # NOT asserted: wallet_loading, wallet_unsupported and text_wallet_no_transactions # are still `proposed:` in CSD-057 §2, so the loading state, the node refusal and # the empty history cannot be asserted at all. CSD-057 §5 carries that. +# NOT asserted: card_spending_progress, card_transaction_history and +# card_trust_warning. WalletPage.kt renders them only with spending limits +# (:265), recent transactions (:293) or degraded hardware trust (:298), and the +# defaults are null / empty / false. No fixture seeds that state, and a step +# whose only precondition is the card it asserts would assert nothing. CSD-057 +# §5 disclaims them until a seeded wallet exists. client: ">=0.5.224" steps: @@ -32,33 +37,42 @@ steps: expect: visible: [card_wallet_experimental, card_wallet_balance] - - step_id: the_address_and_the_paymaster - title: The address and who pays the fees are both on screen + - step_id: the_paymaster_and_the_limits + title: Who pays the fees, and the limits, are on screen description: >- txt_paymaster_status is the row that says whether a send costs the person - anything. A wallet that showed an address and not the paymaster invites a - transfer whose cost is unknown. + anything. PaymasterStatusCard and WalletLimitsCard render whenever a wallet + status is on screen (WalletPage.kt:250, :290), so both are asserted + unconditionally. expect: - visible: [card_wallet_address, txt_wallet_address, txt_paymaster_status] + visible: [card_wallet_paymaster, txt_paymaster_status, card_wallet_limits] - - step_id: limits_and_history - title: The spending limits and the transaction history each render + - step_id: the_address_when_the_wallet_has_one + title: A wallet with an address shows it, copyable + description: >- + WalletAddressCard renders only when the status carries an address + (WalletPage.kt:260). Optional on that state: skipped, loudly, on a wallet + with none. + optional_step: true + requires: + visible: [card_wallet_address] expect: - visible: [card_wallet_limits, card_spending_progress, card_transaction_history] + visible: [txt_wallet_address, btn_copy_address] - - step_id: a_send_is_warned_before_it_is_offered - title: The transfer form carries the trust warning + - step_id: the_transfer_form_when_sending_is_possible + title: A wallet that can send shows the whole form description: >- - Three inputs AND the warning, asserted together. This is the step that would - go red if the warning were ever moved behind a confirm dialog: CSD-057 §2 - requires it beside the form, where it is read before the amount is typed - rather than after. + WalletTransferCard renders only for a wallet that has an address and is + not receive-only (WalletPage.kt:270). When it is there, all three inputs + and the send button are. + optional_step: true + requires: + visible: [card_wallet_transfer] expect: visible: - - card_wallet_transfer - - card_trust_warning - input_recipient_address - input_transfer_amount + - input_transfer_memo - btn_send_transfer - step_id: the_transfer_form_takes_input @@ -66,14 +80,18 @@ steps: description: >- Input only — the flow never presses btn_send_transfer. A test that moves real value is not a test, and CSD-057 §5 says the happy path is out of scope for - that reason rather than for a technical one. + that reason rather than for a technical one. Optional on the form being + there, as above. + optional_step: true + requires: + visible: [input_recipient_address] do: - input: {input_recipient_address: "0x0000000000000000000000000000000000000000"} - input: {input_transfer_amount: "0"} - input: {input_transfer_memo: "flow check, never sent"} expect: screen: Wallet - visible: [btn_send_transfer, card_trust_warning] + visible: [btn_send_transfer] - step_id: back_leaves_the_card title: Back returns to Communities and Businesses > Rules diff --git a/testing/flows/drafts/csd-069-accord-ceremony.yaml b/testing/flows/drafts/csd-069-accord-ceremony.yaml index a02cb48b..fbb53922 100644 --- a/testing/flows/drafts/csd-069-accord-ceremony.yaml +++ b/testing/flows/drafts/csd-069-accord-ceremony.yaml @@ -9,9 +9,12 @@ description: >- `txt_ceremony_error`, which are still proposed. §5 disclaims them. # Floor: btn_accord_ceremony_begin/_back, btn_ceremony_provision, # input_ceremony_holder_name/_key_id/_usb_path/_pin, row_ceremony_slot_$label, -# accord_ceremony_success, accord_ceremony_genesis_json, remint_done_family and -# remint_done_holders are all `testable*` literals at v0.5.224 -# (ui/screens/AccordCeremonyScreen.kt and AccordScreen.kt). +# accord_ceremony_success and accord_ceremony_genesis_json are all `testable*` +# literals in ui/screens/AccordCeremonyScreen.kt at v0.5.224. The success card's +# `txt_ceremony_family` is newer than v0.5.224, so it is not asserted under this +# floor. remint_done_family / remint_done_holders are NOT this screen's: they +# are the Accord re-mint sheet's (AccordScreen.kt, CSD-067) and never render on +# AccordCeremony. client: ">=0.5.224" steps: @@ -59,12 +62,13 @@ steps: count: {of: "row_ceremony_slot_*", eq: 6} - step_id: a_completed_ceremony - title: A finished ceremony shows the genesis and names the family it minted + title: A finished ceremony shows the genesis it produced description: >- Optional, and honestly so: completing it needs six physical FIPS tokens with PINs and touches, which no platform runner has. `accord_ceremony_success` - alone would not be enough — the genesis JSON and the family the ceremony - produced are what make the success checkable rather than asserted. + alone would not be enough — the genesis JSON is what makes the success + checkable rather than asserted. Only what AccordCeremony renders is asserted + here; the re-mint sheet's `remint_done_*` rows belong to CSD-067. optional_step: true requires: screen: AccordCeremony @@ -74,8 +78,6 @@ steps: visible: - accord_ceremony_success - accord_ceremony_genesis_json - - remint_done_family - - remint_done_holders - step_id: back_to_accord title: Back returns to the Accord screen without minting anything diff --git a/testing/flows/drafts/csd-081-login.yaml b/testing/flows/drafts/csd-081-login.yaml index 21b4ef57..3651560c 100644 --- a/testing/flows/drafts/csd-081-login.yaml +++ b/testing/flows/drafts/csd-081-login.yaml @@ -47,21 +47,29 @@ steps: standing fixture does not create. The assertion is the point — `state: error` plus BOTH affordances, because a refusal with no next move is the shape CSD-081 §1 exists to forbid. + Its precondition is the refusal card itself (`observerBlocked`, + LoginScreen.kt:352), so an ordinary run with the owner account skips it + rather than failing; what it asserts when the card IS there is the two + ways forward. optional_step: true requires: screen: Login + visible: [card_observer_blocked] expect: state: error - visible: [card_observer_blocked, btn_choose_different_account, btn_reset_setup] + visible: [btn_choose_different_account, btn_reset_setup] - step_id: straight_from_the_wizard title: Arriving from a completed wizard says so, and names the owner description: >- Optional because it requires the run to have just completed setup. This is CIRISClient#48's settled answer rendered: the banner explains the re-login - instead of looking like a failure. + instead of looking like a failure. Its precondition is the banner + (`justCompletedSetup`, LoginScreen.kt:244), so an ordinary run skips it; + when the banner is there, the owner hint must be too. optional_step: true requires: screen: Login + visible: [banner_setup_complete_relogin] expect: - visible: [banner_setup_complete_relogin, txt_owner_hint] + visible: [txt_owner_hint] diff --git a/testing/flows/drafts/csd-090-duty-conferral.yaml b/testing/flows/drafts/csd-090-duty-conferral.yaml index a81602d7..f6dbcb08 100644 --- a/testing/flows/drafts/csd-090-duty-conferral.yaml +++ b/testing/flows/drafts/csd-090-duty-conferral.yaml @@ -113,6 +113,7 @@ steps: optional_step: true requires: screen: DutyConferral + visible: [duty_source_error] expect: absent: [duty_source_name, duty_source_quorum]