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
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ jobs:
- run: rustup toolchain install ${{ matrix.rust }} --profile minimal --component rustfmt,clippy
- run: cargo +${{ matrix.rust }} test --locked
- run: cargo +${{ matrix.rust }} run --locked --example retry_command
- run: cargo +${{ matrix.rust }} run --locked --example context_walkthrough
- run: python3 tools/context_evidence.py --check
- run: cargo +${{ matrix.rust }} fmt --check
- run: cargo +${{ matrix.rust }} clippy --locked --all-targets -- -D warnings
- run: cargo +${{ matrix.rust }} publish --dry-run --locked --registry crates-io
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## Unreleased

- Add a runnable context walkthrough: a host edit followed by Undo restores the
value but invalidates an old draft; Reset does not rebase its captured context.
- Generate a front-page diagram from the example's output and source hashes;
verify both on Rust 1.88 and stable in CI. Include the renderer in source packages.
- Put concrete behavior, local-helper trade-offs and host responsibilities first in
the README. Public API, runtime behavior and published versions are unchanged.

## 0.1.0-alpha.4

Published to [crates.io](https://crates.io/crates/edit-session/0.1.0-alpha.4) on
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ readme = "PACKAGE.md"
publish = ["crates-io"]
keywords = ["editing", "draft", "validation", "undo", "no-std"]
categories = ["no-std", "gui"]
include = ["src/**", "tests/**", "examples/**", "docs/**", "README.md", "PACKAGE.md", "CHANGELOG.md", "LICENSE-*", "Cargo.toml", "Cargo.lock"]
include = ["src/**", "tests/**", "examples/**", "docs/**", "tools/context_evidence.py", "README.md", "PACKAGE.md", "CHANGELOG.md", "LICENSE-*", "Cargo.toml", "Cargo.lock"]

[[example]]
name = "retry_command"
Expand Down
1 change: 1 addition & 0 deletions PACKAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ must retain the draft for retry, use the borrowed-preview/check pattern in the
Check the live value and context again on every attempt.

- [API source and contracts](https://github.com/PerchAnton/edit-session/blob/main/src/lib.rs)
- [Runnable example: Undo restores a value but leaves an old draft stale](https://github.com/PerchAnton/edit-session/blob/main/docs/CONTEXT_WALKTHROUGH.md)
- [Changelog](https://github.com/PerchAnton/edit-session/blob/main/CHANGELOG.md)
- [Integration evidence and limits](https://github.com/PerchAnton/edit-session/blob/main/docs/ADOPTION.md)
- [Report a bug](https://github.com/PerchAnton/edit-session/issues/new?template=bug_report.yml)
Expand Down
46 changes: 42 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,55 @@
# edit-session

Draft editing with document, target and revision checks. A standalone Rust library;
the separate [interaction-check](https://github.com/PerchAnton/interaction-check) tool is
an optional way to test consumer workflows, not a dependency of this crate.
Keep an editable draft separate from live data, then check that its document, target
and revision are still current before the host applies a change. A standalone Rust
library: `no_std`, zero runtime dependencies, Rust 1.88+.

[![CI](https://github.com/PerchAnton/edit-session/actions/workflows/ci.yml/badge.svg?branch=main&event=push)](https://github.com/PerchAnton/edit-session/actions/workflows/ci.yml)

**[Download](#current-prerelease)** · **[Try recovery](#retry-after-a-rejected-command)** · **[Use the library](#use-from-another-project)** · **[Evidence](#evidence-and-trade-offs)** · **[License](#license)**
**[First example](#same-value-different-edit)** · **[Try recovery](#retry-after-a-rejected-command)** · **[Install](#use-from-another-project)** · **[Evidence](#evidence-and-trade-offs)** · **[License](#license)**

## Same value, different edit

![An executable example: an old draft starts at revision 42. Another edit changes the value from 100 to 120; Undo restores 100 at revision 44. The old draft remains stale, including after Reset.](docs/assets/context-walkthrough.svg)

From a checkout of this repository, run:

```sh
cargo run --locked --example context_walkthrough
```

The example prints four states and asserts the actual library results. A value-only
comparison would accept the restored value after Undo. The host-supplied revision
still differs, so `check` and `finish` return `ContextChanged`. **Reset changes the
preview; it does not rebase an old draft onto the current document.**

This is an original synchronous teaching model, verified **27 October 2026**, not a
new application regression or a benchmark. The diagram is generated from its output
and checked in CI. [Walkthrough and host responsibilities](docs/CONTEXT_WALKTHROUGH.md)
· [Example source](examples/context_walkthrough.rs) · [Raw evidence](docs/evidence/context-walkthrough.json).

| Your situation | Reasonable choice |
| --- | --- |
| A small dialog already has correct draft logic | Keep the local helper unless a concrete gap justifies a dependency |
| Several consumers need the same draft validity contract | Evaluate this library against their native regression tests |
| The host command can fail and the user must retry | Use the [borrowed-preview recovery pattern](docs/RECOVERY.md); retain fields until the command succeeds |
| You need widgets, rendering, Undo history or transaction rollback | Those remain responsibilities of the host application |

The host supplies stable identities, advances revisions, and keeps the check and
command on the same serialized edit path. A correct local helper can provide the
same protection; this example does not claim less code or faster execution.
The separate [interaction-check](https://github.com/PerchAnton/interaction-check)
development tool is optional. Neither project depends on the other.

## Current prerelease

**[0.1.0-alpha.4 on crates.io](https://crates.io/crates/edit-session/0.1.0-alpha.4) · published 27 October 2026 (Europe/Kyiv) · Rust 1.88+**

**[API documentation](https://docs.rs/edit-session/0.1.0-alpha.4/edit_session/)** · [Download the crate](https://crates.io/api/v1/crates/edit-session/0.1.0-alpha.4/download) · [SHA-256 and installation evidence](docs/evidence/release-alpha4.json) · [Changelog](CHANGELOG.md) · [Use as a dependency](#use-from-another-project)

<details>
<summary>Published package snapshot and verification</summary>

![edit-session alpha 4, published on crates.io 27 October 2026: 0 runtime dependencies, 25 scoped checks and a 34.2 KiB source archive. Check live state, attempt the host command, retain fields and draft on rejection, and close on success.](docs/assets/release.svg)

Release snapshot: **16 lifecycle tests + 8 host-example tests + 1 doctest**,
Expand All @@ -28,6 +64,8 @@ tracks current main, while release facts stay tied to the tagged commit. The
[previous GitHub release](https://github.com/PerchAnton/edit-session/releases/tag/v0.1.0-alpha.3)
remains available.

</details>

Trying the alpha? [Report a bug](https://github.com/PerchAnton/edit-session/issues/new?template=bug_report.yml)
with your revision and a short sequence of calls, or read the [alpha compatibility policy](docs/RELEASING.md#alpha-compatibility).

Expand Down
83 changes: 83 additions & 0 deletions docs/CONTEXT_WALKTHROUGH.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Same value, different edit

An open draft remembers the value and context from when editing began. If another
action changes the document and Undo restores the original value, the old draft is
still based on an earlier revision. Comparing only values misses that history.

Run the [complete Rust example](../examples/context_walkthrough.rs) from a checkout:

```sh
cargo run --locked --example context_walkthrough
```

It calls the real library, uses no third-party dependencies, and checks its results
with assertions. It is an original synchronous teaching model, not a GUI test or a
newly discovered bug in an application. Rust 1.88+ is sufficient.

| Action | Live value | Host revision | Draft preview | `check` |
| --- | ---: | ---: | ---: | --- |
| Open draft, propose 75 | 100 | 42 | 75 | `Ok(())` |
| Another host edit | 120 | 43 | 75 | `ContextChanged` |
| Host Undo | 100 | 44 | 75 | `ContextChanged` |
| Reset the old draft | 100 | 44 | 100 | `ContextChanged` |

The original revision remains 42. `finish` returns `ContextChanged`, including after
Reset. The host must reject or dismiss this stale draft rather than apply it to the
newer state. A deliberate reload/reopen can start a **new** session; Reset cannot.

![Values and revisions from the executable walkthrough.](assets/context-walkthrough.svg)

## What the application must supply

The library does not observe edits or increment revisions. The application supplies
stable document and target identities, and a revision that changes on every relevant
edit, Undo and Redo. A wrapping or reused revision can make a different state appear
current; choose a counter/identity scheme that avoids reuse during a session's lifetime.

Use owned snapshots or immutable shared values. Cloning a pointer to shared mutable
storage does not isolate the draft. Equality must cover all relevant fields.

Freshness checks and command execution must share the application's serialized edit
path. A successful check followed by a separately scheduled write is not protected
from intervening changes. The library provides no lock or transaction rollback.

For a host command that may reject an edit, use the existing
[retry example](RECOVERY.md): check, borrow the preview, try the atomic host command,
and close only after success. Retain raw input on rejection. Calling `finish` first
consumes the session and is not a retry strategy.

## Why use a library instead of a small struct?

A correct local helper can implement the same checks. This example demonstrates the
contract, not code savings or an advantage over that helper. The reusable part is one
tested implementation of draft validity, original/preview values and context checks.
It is worth a dependency only when consumers need that shared contract.

| Existing situation | Reasonable choice |
| --- | --- |
| A simple dialog with working local draft logic | Keep the local helper unless a concrete gap is demonstrated |
| Several consumers need the same draft contract | Evaluate edit-session against the same native regression tests |
| Preview, workspace reload or backup already solves the need | Keep that workflow; a new dependency needs a separate reason |
| A useful regression can be expressed as a native Rust test | Use that test; interaction-check is optional |
| A renderer, Undo engine, asynchronous transaction or conflict merge is missing | Solve that in the host; this library does not provide it |

These choices reflect [Oculante, SSBH Editor and Tarsier feedback](ADOPTION.md#what-feedback-changes-our-approach).
The [PdfCraft evidence](ADOPTION.md#a-demonstrated-failure-in-a-real-consumer) concerns a
complete proposed consumer patch, including host changes. It does not prove that an
external crate is preferable to a local helper, and neither integration is adopted.

## Reproduce the diagram

```sh
cargo build --locked --example context_walkthrough
python tools/context_evidence.py
python tools/context_evidence.py --check
```

Python is used only to render/verify the repository graphic; using the crate and
running its Rust examples do not require it. Pass `--binary PATH` if Cargo uses a
custom target directory. The script runs the example's `--json` mode, records its
output and LF-normalized source hashes in [the snapshot](evidence/context-walkthrough.json),
and renders the SVG from those values. CI checks both on Rust 1.88 and stable.
These walkthrough assertions are separate from the existing 16 lifecycle tests,
8 recovery tests and one compile-fail doctest; they are not new upstream regressions.
16 changes: 16 additions & 0 deletions docs/assets/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# README overview asset

## Executable context walkthrough

`context-walkthrough.svg` is generated from the real output of
[the Rust example](../../examples/context_walkthrough.rs), recorded on 27 October
2026 in [JSON](../evidence/context-walkthrough.json). The example asserts that a host
edit, Undo and Reset leave an old draft stale. It is a synchronous teaching model,
not an additional application regression or a performance measurement.

Build with `cargo build --locked --example context_walkthrough`, then run
`python tools/context_evidence.py` from the repository root. Add `--check` to verify
the saved output, LF-normalized source hashes and SVG without rewriting them.
The existing Rust 1.88/stable CI matrix runs this check. See the
[walkthrough](../CONTEXT_WALKTHROUGH.md) for responsibilities and reproduction.

## Earlier measured overview

`overview.svg` is an editable, self-contained vector graphic. It uses system fonts,
explicit light-background colors, a title and a description, with no scripts, external
fonts, images or trackers. The repository README repeats its measurements as accessible
Expand Down
38 changes: 38 additions & 0 deletions docs/assets/context-walkthrough.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 46 additions & 0 deletions docs/evidence/context-walkthrough.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"recorded_date": "2026-10-27",
"scope": "Original synchronous teaching model; actual edit-session API, no GUI or upstream test claim",
"source_hash_format": "SHA-256 of UTF-8 text with LF line endings",
"source_files": {
"src/lib.rs": "878d877fc7c8874230c93aafd8321613b3c02b4dcf94865f2629e21fa088a74c",
"examples/context_walkthrough.rs": "4a8fd1642ba38900d757e010e2ce6287e5272c296207a7381e0e4d24e95c307c"
},
"result": {
"rows": [
{
"action": "Open draft",
"live": 100,
"revision": 42,
"preview": 75,
"value_matches_original": true,
"check": "Ready"
},
{
"action": "Host edits",
"live": 120,
"revision": 43,
"preview": 75,
"value_matches_original": false,
"check": "ContextChanged"
},
{
"action": "Host undoes",
"live": 100,
"revision": 44,
"preview": 75,
"value_matches_original": true,
"check": "ContextChanged"
},
{
"action": "Reset draft",
"live": 100,
"revision": 44,
"preview": 100,
"value_matches_original": true,
"check": "ContextChanged"
}
],
"finish": "ContextChanged"
}
}
Loading