Skip to content

Commit a8a0bb5

Browse files
committed
docs(config): specify autosave interaction contract
1 parent 42be1cd commit a8a0bb5

4 files changed

Lines changed: 142 additions & 5 deletions

File tree

openspec/changes/netclaw-config-command/design.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,29 @@ placeholder shell renders.
138138
Leaf editors get substantive round-trip and smoke coverage. Routed handoffs
139139
get shallow routing coverage only.
140140

141+
### D11. Inline config editors autosave completed actions through one shared contract
142+
143+
Inline config editors use a shared autosave interaction component instead of
144+
page-specific save buttons or one-off status text. The standard behavior is:
145+
146+
- `Esc` backs out or cancels incomplete input; it never saves.
147+
- Completed actions save immediately after validation.
148+
- Text and multi-field input becomes a completed action only when accepted
149+
with `Enter` / Apply.
150+
- Toggles, audience changes, enable/disable, add/remove, and confirmed reset
151+
actions are completed actions.
152+
- Structural validation failures block writes and leave disk unchanged.
153+
- Runtime/probe failures may offer `Save anyway` only after the structurally
154+
valid draft is known.
155+
- Each write is section-preserving and field-scoped to the editor's ownership
156+
boundary.
157+
158+
Alternative considered: explicit `[s] Save` staged editing. Rejected because
159+
the existing config surfaces behave like action editors, and mixing staged
160+
edits with navigation caused operators to lose unrelated channel configuration.
161+
The safer user model is “doing the thing saves the thing,” with `Esc` reserved
162+
for navigation/cancel.
163+
141164
## Risks / Trade-offs
142165

143166
- The domain-oriented IA introduces more navigation depth.
@@ -151,6 +174,9 @@ get shallow routing coverage only.
151174
- Exposure-mode auto-pairing can fail on inconsistent state.
152175
Mitigation: fail loudly and route to doctor/docs/#875 rather than doing
153176
inline repair.
177+
- Autosave can surprise operators if every keypress writes.
178+
Mitigation: only completed actions autosave; incomplete text entry remains
179+
an in-memory draft until accepted with `Enter` / Apply.
154180

155181
## Migration Plan
156182

openspec/changes/netclaw-config-command/proposal.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,22 @@ Source PRDs: `PRD-004-cli-onboarding-and-config.md`,
8181
it edits before save, including local references and external probes when
8282
relevant. Structurally invalid config remains non-overridable; runtime or
8383
probe failures MAY offer `Save anyway`.
84+
- Inline leaf editors use one shared autosave interaction contract: completed
85+
actions persist immediately after validation, `Esc` only navigates or
86+
cancels incomplete input, and there is no explicit save key for ordinary
87+
config edits.
88+
- Autosaves are atomic and section-preserving. An editor writes only the
89+
fields it owns; disabling a provider or feature preserves dormant values,
90+
while destructive removal requires an explicit reset/confirm action.
8491
- Round-trip preservation and test assertions are semantic, not
8592
byte-identical.
8693
- Leaf editors receive substantive round-trip and smoke coverage. Routed
8794
handoffs receive shallow routing coverage only.
8895

8996
**In scope (MVP):** `netclaw config`, domain-oriented dashboard IA, routed
9097
handoffs for providers/models, leaf editors for the in-scope areas above,
91-
generalized validation behavior, exposure-mode dialogs within the existing
98+
generalized validation behavior, shared autosave interaction behavior,
99+
section-preserving persistence, exposure-mode dialogs within the existing
92100
config shape, missing-install refusal, and coverage aligned to leaf-vs-
93101
routed responsibilities.
94102

@@ -124,6 +132,7 @@ sections.
124132
- Exposure-mode editing and validation.
125133
- Test surface for leaf editors, routing coverage, and generalized save
126134
validation.
135+
- Shared config TUI interaction component for autosaving completed actions.
127136

128137
**Security and operational impact:**
129138

@@ -135,3 +144,7 @@ sections.
135144
- Validation behavior is generalized beyond issue `#1151`; structural
136145
invalidity still blocks writes, while runtime reachability failures can
137146
be overridden with `Save anyway`.
147+
- Navigation no longer implies persistence. Completed config actions save
148+
immediately, while `Esc` remains safe navigation/cancel behavior.
149+
- Section-preserving writes prevent one editor or provider action from
150+
deleting unrelated persisted configuration.

openspec/changes/netclaw-config-command/specs/netclaw-config-command/spec.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,83 @@ Runtime/probe failures MAY present `Save anyway`.
190190
- **THEN** the editor may show `Save anyway`
191191
- **AND** the operator can choose to persist the structurally valid config
192192

193+
### Requirement: Inline config editors autosave completed actions consistently
194+
195+
Every inline `netclaw config` leaf editor SHALL use a shared autosave
196+
interaction contract. The UI SHALL NOT require an explicit save key for
197+
ordinary config edits.
198+
199+
Completed actions SHALL save immediately after validation. Completed actions
200+
include accepted text or multi-field forms, toggles, audience changes,
201+
enable/disable actions, add/remove actions, and confirmed reset actions.
202+
Incomplete text input SHALL remain an in-memory draft until accepted with
203+
`Enter` or an equivalent Apply action.
204+
205+
`Esc` SHALL only navigate back or cancel incomplete input. It SHALL NOT save
206+
pending edits and SHALL NOT be required to complete a save.
207+
208+
All autosaves SHALL be atomic: validation SHALL complete before files are
209+
written, and failed validation SHALL leave persisted config and secrets
210+
unchanged.
211+
212+
#### Scenario: Completed toggle autosaves immediately
213+
214+
- **GIVEN** an inline config leaf editor contains a boolean toggle
215+
- **WHEN** the operator toggles the setting
216+
- **THEN** the editor validates the resulting state
217+
- **AND** persists the change immediately when validation succeeds
218+
- **AND** shows a saved status without asking the operator to press a save key
219+
220+
#### Scenario: Esc cancels draft text without persisting
221+
222+
- **GIVEN** an inline config leaf editor contains a text field
223+
- **AND** the operator has typed a draft value but has not accepted it
224+
- **WHEN** the operator presses `Esc`
225+
- **THEN** the editor navigates back or cancels the draft
226+
- **AND** the persisted config is unchanged
227+
228+
#### Scenario: Invalid completed action writes nothing
229+
230+
- **GIVEN** an inline config leaf editor contains a structurally invalid draft
231+
- **WHEN** the operator accepts the action
232+
- **THEN** validation fails
233+
- **AND** no config or secrets file is modified
234+
- **AND** the UI shows the validation error
235+
236+
### Requirement: Inline config persistence is section-preserving
237+
238+
Inline config leaf editors SHALL persist only the sections, providers,
239+
fields, and sidecar files they own. Saving one provider or sub-area SHALL NOT
240+
delete or reset unrelated providers, inactive values, secrets, audiences, or
241+
sidecar files.
242+
243+
Disable actions SHALL preserve dormant configuration and secrets while writing
244+
only the runtime-enabled flag. Destructive removal SHALL require an explicit
245+
reset/confirm action and SHALL be scoped to the confirmed target.
246+
247+
#### Scenario: Disabling one channel provider preserves its dormant setup
248+
249+
- **GIVEN** Slack has saved channels, audiences, allowed users, and secrets
250+
- **WHEN** the operator disables Slack from the Channels config area
251+
- **THEN** Slack `Enabled` is persisted as `false`
252+
- **AND** Slack channels, audiences, allowed users, and secrets remain
253+
persisted
254+
255+
#### Scenario: Saving one channel provider does not wipe another provider
256+
257+
- **GIVEN** Slack and Discord both have saved channel configuration
258+
- **WHEN** the operator adds a Discord channel and the action autosaves
259+
- **THEN** the Discord addition is persisted
260+
- **AND** the saved Slack configuration remains present and unchanged except
261+
for any explicit Slack action the operator completed
262+
263+
#### Scenario: Reset is the only provider-destructive action
264+
265+
- **GIVEN** a provider has saved channel configuration and secrets
266+
- **WHEN** the operator confirms reset for that provider
267+
- **THEN** only that provider's config and secrets are removed
268+
- **AND** other providers remain unchanged
269+
193270
### Requirement: Coverage follows leaf ownership
194271

195272
Leaf editors SHALL receive substantive round-trip and smoke coverage.

openspec/changes/netclaw-config-command/tasks.md

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,32 @@
116116

117117
## 14. Coverage
118118

119-
- [ ] 14.1 Add substantive round-trip tests for leaf editors.
120-
- [ ] 14.2 Add substantive smoke tapes for leaf editors.
121-
- [ ] 14.3 Use semantic preservation assertions, not byte-identical file
119+
- [ ] 14.1 Add shared autosave contract tests for every inline config leaf:
120+
completed actions persist, `Esc` does not save incomplete drafts, and
121+
invalid completed actions write nothing.
122+
- [ ] 14.2 Add substantive round-trip tests for leaf editors.
123+
- [ ] 14.3 Add substantive smoke tapes for leaf editors.
124+
- [ ] 14.4 Use semantic preservation assertions, not byte-identical file
122125
assertions.
123-
- [ ] 14.4 Add shallow routing coverage for routed handoffs only.
126+
- [ ] 14.5 Add shallow routing coverage for routed handoffs only.
127+
128+
## 16. Shared autosave config interaction
129+
130+
- [ ] 16.1 Introduce a shared autosave interaction component/contract for
131+
inline config editors.
132+
- [ ] 16.2 Remove explicit save-key behavior and copy from inline config
133+
editors; completed actions autosave instead.
134+
- [ ] 16.3 Ensure `Esc` only navigates/cancels and never persists edits.
135+
- [ ] 16.4 Ensure each autosave validates before writing and leaves files
136+
unchanged on validation failure.
137+
- [ ] 16.5 Ensure writes are section-preserving and field-scoped to editor
138+
ownership boundaries.
139+
- [ ] 16.6 Harden Channels persistence so provider enable/disable, add/remove,
140+
audience, allowed-user, direct-message, and credential actions autosave
141+
provider-granular changes without wiping unrelated providers.
142+
- [ ] 16.7 Add the regression: seed Slack and Discord, add a Discord channel,
143+
disable Slack, press `Esc`, and verify only completed autosaves occurred
144+
with Slack dormant setup preserved.
124145

125146
## 15. Quality gates
126147

0 commit comments

Comments
 (0)