Rituals pattern: diff, then apply #187

Open
opened 2026-10-04 20:20:35 +00:00 by peterswimm · 4 comments
Owner

Part of #177. Shares visuals with the code output pattern.

What it's for: before anything is written or changed, show what will change and let the person accept all, accept some, or nothing. Doing a dry run first is the norm for anything that writes.

Where it shows up today

  • ritual shim export --check reports drift but can't show it as a diff and apply it. shim create / update writes immediately with no preview.
  • ritual init creates a project file after a y/N, without showing its contents.
  • The macOS ritual composer previews the form but not the ritual it will create.
  • Wish edits save straight away (see the wish edit issue).

Please design

  • Before/after view: side by side and inline, and when to use which
  • Accept or reject per change or per file
  • The apply step, and the record it leaves (every apply writes a lineage entry)
  • "Nothing to change" and "this conflicts with a newer version" states

Acceptance criteria

  • Spec covers the diff views, partial accept, apply, the lineage record, no-change and conflict states.
  • Added/removed colours by token name, contrast-checked in both themes.
  • Say whether diff becomes a new block type. Decided: yes (#177).
  • CLI version.
Part of #177. Shares visuals with the code output pattern. **What it's for:** before anything is written or changed, show what will change and let the person accept all, accept some, or nothing. Doing a dry run first is the norm for anything that writes. ## Where it shows up today - `ritual shim export --check` reports drift but can't show it as a diff and apply it. `shim create / update` writes immediately with no preview. - `ritual init` creates a project file after a `y/N`, without showing its contents. - The macOS ritual composer previews the form but not the ritual it will create. - Wish edits save straight away (see the wish edit issue). ## Please design - Before/after view: side by side and inline, and when to use which - Accept or reject per change or per file - The apply step, and the record it leaves (every apply writes a lineage entry) - "Nothing to change" and "this conflicts with a newer version" states ## Acceptance criteria - [ ] Spec covers the diff views, partial accept, apply, the lineage record, no-change and conflict states. - [ ] Added/removed colours by token name, contrast-checked in both themes. - [x] Say whether `diff` becomes a new block type. **Decided: yes ([#177](https://git.toilville.dev/Toilville/toilville-design/issues/177#issuecomment-26060)).** - [ ] CLI version.
Member

Two clarifications to #187, from the #181 review (accepted by @peterswimm on 2026-10-20). No new design.

1. Wish field-patch summaries are not this pattern.

  • The change summary in #181 may reuse #187's diff visuals, including the line-diff language for multi-line text.
  • It is not the diff-then-apply pattern. A wish patch has no per-field accept or reject. The person accepts the whole patch or goes back to the form.
  • Nobody should build partial-accept machinery for wish patches. #187's accept all, accept some or nothing applies to the pattern defined here, not to #181 wish commands.

2. The "conflicts with a newer version" state needs a distinct API result.

  • It is shown only when the API returns a distinct conflict result.
  • A generic 409 is a rejection. The renderer does not infer a concurrent-edit conflict from it.
  • Until the API returns that result, this state is an engineering dependency, not a design deliverable.
Two clarifications to #187, from the #181 review (accepted by @peterswimm on 2026-10-20). No new design. **1. Wish field-patch summaries are not this pattern.** - The change summary in #181 may reuse #187's diff visuals, including the line-diff language for multi-line text. - It is not the diff-then-apply pattern. A wish patch has no per-field accept or reject. The person accepts the whole patch or goes back to the form. - Nobody should build partial-accept machinery for wish patches. #187's accept all, accept some or nothing applies to the pattern defined here, not to #181 wish commands. **2. The "conflicts with a newer version" state needs a distinct API result.** - It is shown only when the API returns a distinct conflict result. - A generic 409 is a rejection. The renderer does not infer a concurrent-edit conflict from it. - Until the API returns that result, this state is an engineering dependency, not a design deliverable.
Author
Owner

ill work on that

ill work on that
Author
Owner

Closing — the two clarifications are in, and the engineering dependency is filed.

Your 2026-10-16 comment settled both sibling edits:

  1. Wish field-patch summaries are not this pattern. The #181 change summary may reuse these visuals, including the line-diff language for multi-line text, but it has no per-field accept — the person accepts the whole patch or goes back to the form. Nobody should build partial-accept machinery for wish patches, and nobody should assume reuse the other way. That closes the contradiction I raised in both directions.
  2. "Conflicts with a newer version" needs a distinct API result. Shown only when the API returns one; a generic 409 stays a rejection and the renderer does not infer a concurrent-edit conflict from it.

I said I'd work on the second. It is now Toilville/rituals-api-spec#22, item 7.

What I found measuring it: Outcome is applied | noop | rejected | duplicate in all three surfaces — the DB function, ritual-core::wish_command::Outcome and openapi.yaml's WishCommandResult/ParlayCommandResult. There is no conflict member anywhere, so the state depends on that one addition and on nothing else. DiffStatus already has a conflict member for this block, so #22 notes the command-result analogue should read consistently with it rather than invent a second word for the same thing.

The remaining acceptance criteria — the diff views, partial accept, apply, the lineage record, no-change, the token names with contrast checks in both themes, and the CLI version — are all answered by the diff block as shipped in schemas/forge_block.json 1.2 and the #177 umbrella decision. Nothing here is waiting on you.

**Closing — the two clarifications are in, and the engineering dependency is filed.** Your 2026-10-16 comment settled both sibling edits: 1. **Wish field-patch summaries are not this pattern.** The #181 change summary may reuse these visuals, including the line-diff language for multi-line text, but it has no per-field accept — the person accepts the whole patch or goes back to the form. Nobody should build partial-accept machinery for wish patches, and nobody should assume reuse the other way. That closes the contradiction I raised in both directions. 2. **"Conflicts with a newer version" needs a distinct API result.** Shown only when the API returns one; a generic 409 stays a rejection and the renderer does not infer a concurrent-edit conflict from it. I said I'd work on the second. It is now **Toilville/rituals-api-spec#22, item 7**. What I found measuring it: `Outcome` is `applied | noop | rejected | duplicate` in all three surfaces — the DB function, `ritual-core::wish_command::Outcome` and `openapi.yaml`'s `WishCommandResult`/`ParlayCommandResult`. There is no `conflict` member anywhere, so the state depends on that one addition and on nothing else. `DiffStatus` already has a `conflict` member for this block, so #22 notes the command-result analogue should read consistently with it rather than invent a second word for the same thing. The remaining acceptance criteria — the diff views, partial accept, apply, the lineage record, no-change, the token names with contrast checks in both themes, and the CLI version — are all answered by the `diff` block as shipped in `schemas/forge_block.json` 1.2 and the #177 umbrella decision. Nothing here is waiting on you.
Author
Owner

Reopened — I closed this on a wrong reading of my own, and the correction matters to you rather than to me.

My close comment said the remaining criteria "are all answered by the diff block as shipped in schemas/forge_block.json 1.2 and the #177 umbrella decision". That is only true of the data contract. I checked the schema and treated it as the spec; it is not. Three criteria are still open, and all three are presentation:

  • Criterion 1, the diff views — "side by side and inline, and when to use which" is still undecided. What the schema does cover is the rest of that line: partial accept (apply.granularity is all | file | hunk), the apply step (DiffApply.action_id), the lineage record ("every apply writes a lineage entry"), and the no_change and conflict statuses. So the criterion is part-done, by the block rather than by a decision.
  • Criterion 2, added/removed colours by token name, contrast-checked in both themes — not decided anywhere I can find.
  • Criterion 4, the CLI version — not decided.

The two clarifications you added on 2026-10-16 stand, and nothing about them is reopened:

  1. Wish field-patch summaries may reuse these visuals but are not this pattern — no per-field accept, whole patch or back to the form.
  2. "Conflicts with a newer version" is shown only when the API returns a distinct conflict result; a generic 409 stays a rejection.

The second is filed as engineering: Toilville/rituals-api-spec#22, item 7. All three surfaces have Outcome as applied | noop | rejected | duplicate with no conflict member, so that state depends on that one addition and nothing else. That part is off your plate.

What I'd ask of you here

Criteria 2 and 4 are shared with #186 (code and file output), which is also open with no decision on it — same token-names-with-contrast-checks ask, same CLI ask, and #187 was written as "shares visuals with the code output pattern". Taking them together is probably one decision rather than two, and I'd rather you make it once.

No rush from me, and nothing is blocked on it: the diff block ships and the engineering dependency is tracked. This is about the ratified presentation, not about unblocking work.

**Reopened — I closed this on a wrong reading of my own, and the correction matters to you rather than to me.** My close comment said the remaining criteria "are all answered by the `diff` block as shipped in `schemas/forge_block.json` 1.2 and the #177 umbrella decision". That is only true of the **data** contract. I checked the schema and treated it as the spec; it is not. Three criteria are still open, and all three are presentation: - **Criterion 1, the diff views** — "side by side and inline, and when to use which" is still undecided. What the schema *does* cover is the rest of that line: partial accept (`apply.granularity` is `all | file | hunk`), the apply step (`DiffApply.action_id`), the lineage record ("every apply writes a lineage entry"), and the `no_change` and `conflict` statuses. So the criterion is part-done, by the block rather than by a decision. - **Criterion 2, added/removed colours by token name, contrast-checked in both themes** — not decided anywhere I can find. - **Criterion 4, the CLI version** — not decided. The two clarifications you added on 2026-10-16 stand, and nothing about them is reopened: 1. Wish field-patch summaries may reuse these visuals but are **not** this pattern — no per-field accept, whole patch or back to the form. 2. "Conflicts with a newer version" is shown only when the API returns a distinct conflict result; a generic 409 stays a rejection. The second is filed as engineering: **Toilville/rituals-api-spec#22, item 7**. All three surfaces have `Outcome` as `applied | noop | rejected | duplicate` with no `conflict` member, so that state depends on that one addition and nothing else. That part is off your plate. ## What I'd ask of you here Criteria 2 and 4 are shared with **#186** (code and file output), which is also open with no decision on it — same token-names-with-contrast-checks ask, same CLI ask, and #187 was written as "shares visuals with the code output pattern". Taking them together is probably one decision rather than two, and I'd rather you make it once. No rush from me, and nothing is blocked on it: the `diff` block ships and the engineering dependency is tracked. This is about the ratified presentation, not about unblocking work.
Sign in to join this conversation.
No description provided.