[v0.1/IPC Review] Decide unresolved grid registry handles before decoder freeze #308
Labels
No labels
priority/P0
priority/P1
priority/P2
release/v0.1.0
status/blocked
status/planned
type/bug
type/design
type/test-gap
type/tracker
No milestone
No project
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
natsukium/felis#308
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Parent: #12
Problem
The grid registry contract and the client's failure policy disagree at the semantic boundary.
The IPC reference guarantees that every
ClusterorHyperlinkentry named by aRowDeltais sent before that row. A missing entry is therefore impossible between honest peers. The same reference nevertheless tells a client to treat an unreceived id as "not here yet", degrade the cell, and keep the connection.ShadowScreen::applysimilarly drops zero, over-cap, or over-length registry entries and later resolves a missing handle asNone.This conflicts with the connection-local corruption policy: silently skipping an unreadable grid update leaves the client drawing a screen that differs from the daemon, while closing only this attachment permits a clean rehydrate and leaves the session running.
It also freezes an awkward decoder boundary. The IPC explanation records that narrowing accepted values after v1 ships is a compatibility break that needs a real old-peer answer. If invalid registry references should close the connection, that choice belongs before the first release.
Decision to make before the v0.1 contract freezes
Prefer treating daemon-impossible registry values and unresolved row references as semantic corruption:
Valid sparse delivery remains supported. "Sparse" means that unrelated ids may be absent; it does not mean that a row may reference an absent id.
If degraded rendering is retained, the explanation should define why this semantic invariant differs from the other fatal grid invariants, what later event repairs an already-applied row, and which malformed values are intentionally tolerated. "Not here yet" is not sufficient under the documented registry-before-row order.
Acceptance criteria
ShadowError, IPC reference/explanation, grid data-model docs, andCHANGELOG.mdagree.Principle check
Evidence
crates/felis-client-core/src/shadow.rs:263(ShadowScreen::apply)crates/felis-client-core/src/shadow.rs:321(GridMsg::Hyperlink)crates/felis-client-core/src/shadow.rs:333(GridMsg::Cluster)crates/felis-client-core/src/shadow.rs:405(row decode/apply)crates/felis-daemon/src/serve/streaming.rs(ship_referenced)docs/reference/ipc.md"Corruption" and "Registry delivery"docs/explanation/architecture/ipc.md"A corrupt frame ends the connection" and the pre-release narrowed-decoder warningdocs/explanation/data-model/grid-and-cells.md"Referenced-before-use is causal, not positional"Direction agreed 2026-09-21 after three
soldesign-review rounds (final verdict PASS). Full plan and batch order: see the comment on #12.ShadowErrorand closes only that attachment; reconnect/rehydrate recovers.Resize-race tolerance is kept only for row indices/widths within
MAX_GRID_ROWS/MAX_GRID_COLS. Unresolved cluster/hyperlink handles in adecoded row are corruption; degraded rendering is removed. Id 0, over-cap
ids and over-length text are rejected before allocation.