Eliminate implicit-absence meanings from the wire before the baseline freezes #327
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#327
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?
Background
The pre-freeze review (parent #326) found that several wire shapes assign meaning to a field's absence. In proto3, absence cannot be told apart from "not sent by a peer that does not know the field", so every such meaning becomes ambiguous the moment the schema grows. Each case below is cheap to fix now (a
oneofarm or a required field) and costs a major bump after the baseline freezes.This does not reopen #47/#48/#313: it only asks that absence stop meaning something.
Cases
RetargetTarget.carrier— unset means "default local daemon". The common case costs no bytes, but a future carrier added beside it cannot be told apart from an old peer that sent nothing. Add an explicitDefaultarm (or document unset as permanently the default and reserve against ever giving it meaning).OpsStop.mode— unset meansif_empty. Same shape as (1): an unset oneof silently selects the safe posture today and silently misreads tomorrow's posture. Make it required or explicit.SessionAttach.id/id_prefix— sibling fields where exactly one is set, enforced by prose plus validator. Aoneof targetstates the same constraint in the schema, so non-Rust peers read it from the descriptor instead of a comment.GridThemeColoruses absent-Rgb= reset whileGridPaletteColorusesoneof { set, reset }. The latter fails a truncated write at decode instead of reading it as a reset. Unify on theoneofform.Acceptance criteria
felis.protocomments,docs/reference/ipc.mdmessage-family tables, andcrates/felis-protocol/src/convert/agree on the result.BREAKING.mdacknowledges the change against the merge-base per the pre-release rule.Parent: #326 (final interface simplification audit).
Related: #313 (protocol 1.0 baseline), #115 (baseline workflow).
Decision: do, P1 (reviewed)
All four cases verified against the tree. Policy applied uniformly: every mode-selecting
oneofhas named arms, and an unset union decodes asMissingOneof(malformed), so an unknown future arm on an old decoder fails closed instead of mapping to a default.RetargetTarget.carrier: add an explicit emptydefault_localarm.OpsStop.mode: add an explicit emptyif_emptyarm; unset becomes malformed, matchingSwitchScope.SessionAttach:id = 1,live_only = 2,id_prefix = 3are siblings today. Becomesoneof target { bytes id = 1; string id_prefix = 3; }withlive_only = 2untouched, so no active field moves or retypes.GridThemeColor: absentRgbmeans reset, whileGridPaletteColor's own comment rejects exactly that shape. Unify ononeof { set, reset }.Lands after #330 and #328 in the proto batch (own PR, rebased on the previous merge, own
base:line). Doc cascade:felis.protocomments,ipc.mdmessage-family tables,convert/,BREAKING.md,CHANGELOG.md.