Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions FSD/CSD/CSD-005-people.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```

Expand Down Expand Up @@ -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 |
Expand Down Expand Up @@ -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 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.

Expand All @@ -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`.
4 changes: 3 additions & 1 deletion FSD/CSD/CSD-006-receipt.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```

Expand Down Expand Up @@ -143,6 +143,8 @@ Bound per surface; CSD-005 §4 is the first instance.

## 5. QA plan

**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_<keyId>`, 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_<id>`; a card whose rows are furniture
asserts `absent: [btn_receipt_*]` instead.
5 changes: 3 additions & 2 deletions FSD/CSD/CSD-007-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
|---|---|---|---|
Expand Down
2 changes: 2 additions & 0 deletions FSD/CSD/CSD-008-notes-to-self.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 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
rendering its body (the `open` / `here` token bug, fixed with a test).
Expand Down
2 changes: 2 additions & 0 deletions FSD/CSD/CSD-032-network-identity.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 no longer `unreleased` 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`,
Expand Down
2 changes: 2 additions & 0 deletions FSD/CSD/CSD-033-network-peers.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 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.

Expand Down
2 changes: 2 additions & 0 deletions FSD/CSD/CSD-036-network-ops.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 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.

Expand Down
6 changes: 4 additions & 2 deletions FSD/CSD/CSD-040-storage.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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]
```

Expand All @@ -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 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
503 to be reachable.
Expand Down
13 changes: 9 additions & 4 deletions FSD/CSD/CSD-045-node-self-standing.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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`),
Expand Down Expand Up @@ -194,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 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
path needs a 0.5.218 node; the typed fallback needs a 0.5.217 one, and the
Expand Down Expand Up @@ -222,6 +225,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).
2 changes: 2 additions & 0 deletions FSD/CSD/CSD-046-network-trust-graph.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 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,
carries the count).
Expand Down
2 changes: 2 additions & 0 deletions FSD/CSD/CSD-047-network-content.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ expect:

## 5. QA plan

**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_<keyId>`, 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.

Expand Down
2 changes: 2 additions & 0 deletions FSD/CSD/CSD-048-network-interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 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.

Expand Down
2 changes: 2 additions & 0 deletions FSD/CSD/CSD-049-network-queue.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 no longer `unreleased` and the flow runs on the matrix (#97).

**Platforms.** All five.

**Not tested here.** The five unmodelled diagnostic maps (§3); the sent/received
Expand Down
53 changes: 33 additions & 20 deletions FSD/CSD/CSD-057-wallet.md
Original file line number Diff line number Diff line change
@@ -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`)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Seed or condition the Wallet's optional status cards

The newly declared Wallet flow unconditionally expects card_transaction_history, card_spending_progress, and card_trust_warning, but WalletPage.kt renders them only for nonempty transactions, non-null spending, and hardwareTrustDegraded == true; the defaults are empty/null/false, and this flow declares no fixture that changes them. A normal healthy or fresh wallet will therefore fail this draft before it can run on the matrix, so these assertions need deterministic seeded data or optional preconditions matching the states they test.

Useful? React with 👍 / 👎.


```yaml csd:stage
stage: building
Expand Down Expand Up @@ -130,32 +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 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.
Expand Down
15 changes: 9 additions & 6 deletions FSD/CSD/CSD-068-provision-accord-holder.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -253,14 +253,17 @@ 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 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
all five and the hop is derived on all five; only the ceremony itself is bounded.
Expand Down
Loading
Loading