Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
305 commits
Select commit Hold shift + click to select a range
cc4d856
derive: keep the first line's indentation so comment stripping is ide…
claude Nov 1, 2026
394c734
derive: always leave something unreachable in the reach fault sweep
claude Nov 1, 2026
c09d38c
derive: cap land stacks and check the deadline during replays
claude Nov 1, 2026
cf88630
derive: fuzz the comment lexer's own idempotence, not the checked result
claude Nov 1, 2026
3c13842
derive: find a merge's bases once per side in a review
claude Nov 1, 2026
8b7c60b
derive: refuse a self-naming skiplist on every read path
claude Nov 1, 2026
a3199a5
derive: refuse a land stack only once it is longer than the cap
claude Nov 1, 2026
8714991
docs: note in ADR 0071 that edits after a split resolution conflict
claude Nov 1, 2026
fc5047f
Merge main after #237 was squash-merged
claude Nov 2, 2026
1e2f9ba
server: add header-read, idle and body idle timeouts and a connection…
claude Nov 1, 2026
c884a0d
server: require a declared body type on write routes and local hosts …
claude Nov 1, 2026
1c89b66
server: keep internal error detail in the log, warn on an open metric…
claude Nov 1, 2026
8cf2ef8
ci: run the remote workflow in the production environment and declare…
claude Nov 1, 2026
04bfbc0
soak: derive tokens and signing keys from a random per-run secret
claude Nov 1, 2026
3b7be7c
cli: keep idle pooled connections below the server's header-read timeout
claude Nov 1, 2026
6d2d97f
server: refuse peer URL prefixes that name only part of a host
claude Nov 1, 2026
9a9ff37
Merge main after #238 was squash-merged
claude Nov 2, 2026
a8b5a02
derive: keep blame's skiplists across requests and its answer at the …
claude Nov 2, 2026
c656b35
docs: record one server's capacity in the mixed swarm
claude Nov 2, 2026
c9307a5
derive: keep the skiplist cache methods on Repo, not in the tests module
claude Nov 2, 2026
9849934
Merge main after #239 was squash-merged
claude Nov 2, 2026
6eca5fd
derive: share cached tree nodes and keep root trees in memory
claude Nov 2, 2026
7ee7813
Merge main after #240 was squash-merged
claude Nov 2, 2026
1aebc21
derive: jump between changes on linear chains in blame walks
claude Nov 2, 2026
01b2056
Merge main after #243 was squash-merged
claude Nov 2, 2026
c63d0c6
store: copy the whole tree below every tree node a backup copies
claude Nov 2, 2026
a6b085c
Merge main after #244 was squash-merged
claude Nov 2, 2026
9e8b757
server: limit glibc malloc arenas to two at startup
claude Nov 2, 2026
2ae6756
server: report not ready while the blob store's pack index loads
claude Nov 2, 2026
9052506
Merge main after #245 was squash-merged
claude Nov 2, 2026
0bcd41f
verify: accept a rebased-origin row whose original was swept
claude Nov 2, 2026
254c6bd
Merge main after #246 was squash-merged
claude Nov 2, 2026
651b1c7
docs: compare many agents landing with Git, and Leep before and after
claude Nov 2, 2026
6fd5001
Merge remote-tracking branch 'origin/main' into ccr-94e2aa7d-5xfs9k
claude Nov 2, 2026
c7d8e57
store: share file syncs between concurrent loose blob puts
claude Nov 2, 2026
6ea97e7
Merge remote-tracking branch 'origin/main' into ccr-94e2aa7d-5xfs9k
claude Nov 2, 2026
9f76f26
derive: walk missing history in batches when indexing
claude Nov 2, 2026
b274bd0
Merge remote-tracking branch 'origin/main' into ccr-94e2aa7d-5xfs9k
claude Nov 2, 2026
b27df19
docs: close milestones M1 to M4
claude Nov 2, 2026
9712103
Merge remote-tracking branch 'origin/main' into ccr-94e2aa7d-5xfs9k
claude Nov 3, 2026
c528aee
soak: measure a million changesets of history
claude Nov 3, 2026
7b45544
Merge remote-tracking branch 'origin/main' into ccr-94e2aa7d-5xfs9k
claude Nov 3, 2026
38ac4f6
derive: checkpoint long blames and finish them past a timeout
claude Nov 3, 2026
03b6796
Merge remote-tracking branch 'origin/main' into ccr-94e2aa7d-5xfs9k
claude Nov 3, 2026
7648dc2
derive: read skiplists off the land path's critical section
claude Nov 3, 2026
5c8000a
derive: keep creates to one metadata connection
claude Nov 3, 2026
4b8ae22
Merge remote-tracking branch 'origin/main' into ccr-94e2aa7d-5xfs9k
claude Nov 3, 2026
1dc9f93
test: start the failed-flush pipeline test from an idle land leader
claude Nov 3, 2026
4f2b25d
Merge remote-tracking branch 'origin/main' into ccr-94e2aa7d-5xfs9k
claude Nov 3, 2026
06b86fa
store: retire replaced packs durably
claude Nov 3, 2026
18c9449
store: never leave a republished pack retired
claude Nov 3, 2026
8079fa0
Merge remote-tracking branch 'origin/main' into ccr-94e2aa7d-5xfs9k
claude Nov 3, 2026
883d98a
ci: guard performance with operation budgets and a ratio bench
claude Nov 3, 2026
5de83ad
Merge remote-tracking branch 'origin/main' into ccr-94e2aa7d-5xfs9k
claude Nov 3, 2026
d5f6ac0
log: answer short logs in fewer round trips
claude Nov 3, 2026
0fac0c2
Merge remote-tracking branch 'origin/main' into ccr-94e2aa7d-5xfs9k
claude Nov 3, 2026
6285f3f
derive: keep blames of tracked files current as changes land
claude Nov 3, 2026
137342f
Merge remote-tracking branch 'origin/main' into ccr-94e2aa7d-5xfs9k
claude Nov 3, 2026
b326679
meta: keep a warm floor of Postgres connections in servers
claude Nov 3, 2026
4fc8197
Merge remote-tracking branch 'origin/main' into ccr-94e2aa7d-5xfs9k
claude Nov 3, 2026
57ff4ab
docs: add Postgres memory sizing guidance
claude Nov 3, 2026
f64bdd9
leep-meta: keep the Postgres URL query in snapshot test databases
claude Nov 3, 2026
4974297
core: test /v1 response compatibility with older servers
claude Nov 3, 2026
022e63e
git: refuse shallow clones on import with a clear error
claude Nov 3, 2026
fe84c86
Merge remote-tracking branch 'origin/main' into ccr-94e2aa7d-5xfs9k
claude Nov 3, 2026
e4be1ee
cli: show diffs, quieter logs, clearer review status and conflict mar…
claude Nov 3, 2026
9a0ad3d
Merge remote-tracking branch 'origin/main' into ccr-94e2aa7d-5xfs9k
claude Nov 3, 2026
854a87a
review: carry verdicts across identical rebases, and answer policy re…
claude Nov 3, 2026
7e4c205
review: requests, an inbox, and who created each change
claude Nov 3, 2026
dba0509
Merge remote-tracking branch 'origin/main' into wt/reviewreq
claude Nov 3, 2026
dff16c7
review: let the newest verdict win across carried candidates, and bou…
claude Nov 3, 2026
d1db398
review: take back regardless of clock order
claude Nov 3, 2026
59f9e55
review: trust only server links when closing requests, and bound requ…
claude Nov 3, 2026
b827ab3
Merge remote-tracking branch 'origin/main' into ccr-94e2aa7d-5xfs9k
claude Nov 3, 2026
e0e0f4e
Merge branch 'wt/reviewreq' into ccr-94e2aa7d-5xfs9k
claude Nov 3, 2026
f2f5f1e
Merge remote-tracking branch 'origin/main' into ccr-94e2aa7d-5xfs9k
claude Nov 4, 2026
e77b67e
docs: label Linux path-history size as v3 and cite v4
claude Nov 4, 2026
442d2ff
core: cover later-added optional /v1 fields in compat tests
claude Nov 4, 2026
62831d3
leep-meta: test and fix replace_db URL handling
claude Nov 4, 2026
c199e2a
leep-git: refuse a shallow repository in the mirror
claude Nov 4, 2026
b3c9426
Merge remote-tracking branch 'origin/main' into ccr-94e2aa7d-5xfs9k
claude Nov 4, 2026
87324cc
test: keep queued land batches whole however slowly they replay
claude Nov 4, 2026
b3bc4b8
cli: leave no .leep behind when init cannot list the files
claude Nov 4, 2026
eafa0a9
test: run soak_smoke until a backup beside the swarm has sealed
claude Nov 4, 2026
56d0050
test: keep leep-meta Postgres tests out of the shared public schema
claude Nov 4, 2026
f1767bd
test: give soak_smoke ten minutes to see its backup
claude Nov 4, 2026
7f5cbb1
Merge remote-tracking branch 'origin/main' into ccr-94e2aa7d-5xfs9k
claude Nov 4, 2026
8666919
review: close requests when their reviewed change lands, and show who…
claude Nov 4, 2026
8055fbc
review: in the no-log fallback close only by content
claude Nov 4, 2026
3849d0a
merge main
claude Nov 4, 2026
1c691f4
cli: guide review requests and wait for verdicts
claude Nov 4, 2026
18d7870
cli: put Created-by after Author and neutralize the shallow refusal
claude Nov 4, 2026
10e53a4
docs: keep changelog entries apart as fragments in changelog.d
claude Nov 4, 2026
f97c9f1
docs: point the persistent-format skill at changelog fragments
claude Nov 4, 2026
b24aec0
merge main
claude Nov 4, 2026
c9eb16a
derive: measure the busy-file blame test on a paused clock
claude Nov 4, 2026
68a3f4c
review: carry verdicts across client rebases the server would have made
claude Nov 4, 2026
69c562c
docs: record ADR 0089 on carrying verdicts across client rebases
claude Nov 4, 2026
1281d40
review: bound carry merges by lines, run each once, and skip collecte…
claude Nov 4, 2026
2e362c5
docs: record the carry merge bounds and what origins report
claude Nov 4, 2026
c7d2fa3
merge main
claude Nov 4, 2026
3aef0fa
gitobj: move the git object codec into its own crate
claude Nov 4, 2026
c174455
derive: derive git ids of blobs, trees and changesets
claude Nov 4, 2026
30012d8
git: record the store's commit style once and keep every exporter to it
claude Nov 4, 2026
f339529
docs: record ADR 0090 on the git wire protocol and its derived git ids
claude Nov 4, 2026
5ccc826
docs: record paths git refuses as a phase 2 requirement in ADR 0090
claude Nov 4, 2026
429d2d6
derive: cover the git kinds in the drop and droppability checks
claude Nov 4, 2026
f68cf7d
checks: add check attestations and server-moved known-good refs
claude Nov 4, 2026
4455e55
checks: protect checked refs, take good in culprits, test promotion
claude Nov 4, 2026
0233bfa
checks: refuse attestations of rebased copies by their creator
claude Nov 4, 2026
4401031
cli: add leep checks post, status, ref and culprits
claude Nov 4, 2026
6a7a2ec
mcp: add leep_checks_status and leep_checks_culprits
claude Nov 4, 2026
8b2f055
checks: catch green up when the checks policy loads or changes
claude Nov 4, 2026
a62efbb
docs: describe check attestations and known-good refs (ADR 0091)
claude Nov 4, 2026
82555b5
e2e: find a planted break among twenty lands with a fake CI loop
claude Nov 4, 2026
d110284
e2e: read checks ref JSON while the ref is red
claude Nov 4, 2026
b71de45
meta: write a derived row only if absent, and record the git style wi…
claude Nov 4, 2026
00a81e3
derive: let a wrong git style be dropped with every id derived under it
claude Nov 4, 2026
351edff
docs: say how ADR 0090's reverse rows, crashes and style undo behave
claude Nov 4, 2026
317ef68
docs: name put_derived_if_absent and the style's undo in FORMATS
claude Nov 4, 2026
41fa65a
checks: record the creator of server merges so they cannot be attested
claude Nov 4, 2026
a0154be
checks: reserve the green/ namespace for promotions
claude Nov 4, 2026
622c220
checks: page culprits and limit the ref history reads
claude Nov 4, 2026
5dc5129
checks: take results only for changesets a ref holds, and let repair …
claude Nov 4, 2026
ea20d2b
checks: answer a ref's check status before a look-alike ref
claude Nov 4, 2026
dcc9a57
docs: cover the checks review fixes in ADR 0091 and the guides
claude Nov 4, 2026
6dcf0ec
merge main
claude Nov 4, 2026
02fac94
review: carry verdicts only to identical changes on declared paths
claude Nov 4, 2026
dd44044
docs: record identical-only review carry in ADR 0092
claude Nov 4, 2026
9943fd1
review: let a subdirectory tighten but never loosen carry identical
claude Nov 4, 2026
b370a98
review: refuse OWNERS lines that misspell a carry directive
claude Nov 4, 2026
fd7a436
review: close requests at land under the head the land was judged on
claude Nov 4, 2026
0f4a46a
review: refuse carry lines in any case and oversized OWNERS with 422
claude Nov 4, 2026
3580474
docs: note case-insensitive carry lines, ownerless noparent, mixed fl…
claude Nov 4, 2026
70f062d
merge main
claude Nov 4, 2026
e54443b
merge main into the checks work
claude Nov 4, 2026
f459737
merge the checks work (ADR 0091)
claude Nov 4, 2026
e2b9846
meta: count a claimed lease's time left from the claim's own stamp
claude Nov 4, 2026
3d493a2
server: name each path's OWNERS files and identical-only source
claude Nov 4, 2026
5089f0f
meta: drop each Postgres test schema and database, failing tests too
claude Nov 4, 2026
843f8e8
server: drop the Postgres schemas the server tests create
claude Nov 4, 2026
4780aaa
test: share the leep-meta database guard in the end-to-end suite
claude Nov 4, 2026
11560f5
test: drop the soak database on every exit but a kept failure
claude Nov 4, 2026
8e2ee44
docs: ask new storage backends' tests to clean up their namespaces
claude Nov 4, 2026
3d05d23
cli: smooth the review loop real agents tripped over
claude Nov 4, 2026
30aa729
docs: document review guidance, exit 7, review show and trailers
claude Nov 4, 2026
db44e2f
docs: add a changelog fragment for lease timing and test cleanup
claude Nov 4, 2026
7dcb6b3
merge main
claude Nov 4, 2026
6c69e91
merge the CLI review ergonomics work
claude Nov 4, 2026
8acd284
merge main
claude Nov 4, 2026
22b975a
merge the lease timing and test cleanup work
claude Nov 4, 2026
8b1abd4
merge main
claude Nov 5, 2026
91357d8
derive: budget the meta calls of one land's search derivation
claude Nov 5, 2026
da9cbf2
derive: store directory filters as patches on keyframes (ADR 0094)
claude Nov 5, 2026
4914bc8
derive: name tree-trigrams-v2 in fuzz targets, tests and comments
claude Nov 5, 2026
028bfd4
docs: record ADR 0094, directory filters as patches on keyframes
claude Nov 5, 2026
b53a2f0
derive: derive a patch again when its keyframe is gone
claude Nov 5, 2026
bc35653
docs: promoted keyframes, dangling patches and the re-measured sizes
claude Nov 5, 2026
d960db2
merge the search filter patches work (ADR 0094)
claude Nov 5, 2026
d557694
core: add the CoordStore contract and session API types
claude Nov 9, 2026
4a20f7d
meta: keep sessions in migration 0009 on SQLite and Postgres
claude Nov 9, 2026
269beba
derive: infer sessions from changesets and end them when they land
claude Nov 9, 2026
d1340d7
server: serve /v1/sessions and keep sessions current
claude Nov 9, 2026
967f399
cli: add `leep session` and `leep who`
claude Nov 9, 2026
5b1dca8
server: update a changeset's session before answering its create
claude Nov 9, 2026
aacf0e2
mcp: add leep_session_start and leep_who
claude Nov 9, 2026
c724e6f
test: show two agents' sessions with `leep who`
claude Nov 9, 2026
567392c
docs: add ADR 0095 on coordination state and document sessions
claude Nov 9, 2026
855cd96
test: run the two-agent sessions test on Postgres too
claude Nov 9, 2026
dbe2476
core: accept any token name as a session's principal
claude Nov 9, 2026
82d68f8
meta: keep a revived session out of the retention sweep
claude Nov 9, 2026
7d8529d
merge main
claude Nov 9, 2026
40b2b6f
merge coordination sessions (ADR 0095)
claude Nov 9, 2026
8757748
core: keep control characters and long names out of session paths
claude Nov 9, 2026
0b972b6
meta: keep the SQLite sweep off the write lock and survive lost beats
claude Nov 9, 2026
9fa1dea
derive: bound session inference by its timeout and cap beats per token
claude Nov 9, 2026
d04c5a1
server: seed the session update without cloning the changeset
claude Nov 9, 2026
d2dcd1c
cli: escape agent-written session text and forget an ended session
claude Nov 9, 2026
d292192
mcp: fence session keys and paths, and mark only your own session
claude Nov 9, 2026
d5c77c3
docs: record the review fixes to sessions in ADR 0095
claude Nov 9, 2026
e343d37
merge coordination session review fixes
claude Nov 10, 2026
d380608
deps: record the bundled SQLite advisory until sqlx allows the fix
claude Nov 10, 2026
9bdaa32
coord: fold a wide changeset's paths until few are left, test by count
claude Nov 10, 2026
0473fbc
core: find the session paths near a path for overlap notices
claude Nov 10, 2026
95da89d
core: add notice types to the session, create and land answers
claude Nov 10, 2026
8bd67df
derive: rank overlap notices and flag duplicate sessions
claude Nov 10, 2026
e95eb21
derive: answer notices on declarations and test every level
claude Nov 10, 2026
b40aad0
server: carry overlap notices in answers and serve /v1/notices
claude Nov 10, 2026
2f3543f
cli: show overlap notices on stderr and add `leep who --overlaps`
claude Nov 10, 2026
9be4524
mcp: put notices in every tool result and add leep_overlaps
claude Nov 10, 2026
f066b0b
test: warn two agents on one file before either lands
claude Nov 10, 2026
8a46ae6
docs: add ADR 0096 on overlap notices and duplicate flags
claude Nov 10, 2026
42f52b1
mcp: count leep_overlaps in the stdio tool list test
claude Nov 10, 2026
8604b79
core: leave the coord store empty after the near_paths contract
claude Nov 10, 2026
7607f6a
derive: measure the slow-store notice bound on a paused clock
claude Nov 10, 2026
32585c0
derive: never forget an unexpired said notice
claude Nov 10, 2026
21dd8b3
derive: keep no notice memory for sessions told nothing
claude Nov 10, 2026
67c58f2
derive: count a crowded path of theirs once, not once per file of mine
claude Nov 10, 2026
423a504
derive: compute notice parts apart and walk lands in batches
claude Nov 10, 2026
e69438a
derive: bound GET /v1/sessions/{id}/overlaps
claude Nov 10, 2026
9ce8a8f
derive: flag fewer false duplicates
claude Nov 10, 2026
e3260d1
coord: answer claims and exact matches first from near_paths
claude Nov 10, 2026
982f2c0
server: compute a land's notices before the hook that ends its session
claude Nov 10, 2026
a4354b7
cli: give up asking for notices after 3 seconds
claude Nov 10, 2026
fa3c18c
mcp: check said-once notices against the server, not the poll timer
claude Nov 10, 2026
01dba43
test: give the two agents of the notices e2e their own tokens
claude Nov 10, 2026
119cff0
derive: say each other session once, at its highest level
claude Nov 10, 2026
05a3480
mcp: show dotted and dashed names, and escape separators in fences
claude Nov 10, 2026
06e57b7
docs: record the review fixes to overlap notices in ADR 0096
claude Nov 10, 2026
2da46b1
merge the branch's earlier, already-squashed history
claude Nov 10, 2026
a4a8cf4
core: add context pack request and answer types (ADR 0097)
claude Nov 10, 2026
b38f0a0
derive: assemble context packs from queries the server already answers
claude Nov 10, 2026
3943534
server: answer POST /v1/context
claude Nov 10, 2026
a0a28c9
cli: add leep context and leep work start
claude Nov 10, 2026
a99a069
mcp: add leep_task_start, leep_context and the review request tools
claude Nov 10, 2026
4a46a2d
test: a second agent's context shows the first agent's live work
claude Nov 10, 2026
00ae9cd
docs: record context packs in ADR 0097
claude Nov 10, 2026
0cfe12b
cli: retry a shed context pack, and keep a started session when it fails
claude Nov 10, 2026
6fd71d6
cli: ask about at most 64 paths, and keep a resumed session's scope
claude Nov 10, 2026
8c110e8
docs: say what a context pack's search permit covers
claude Nov 10, 2026
8b2dc1a
derive: keep a red ref and the caller out of their own way in a pack
claude Nov 10, 2026
6c07a70
cli: read past answered review requests in the inbox
claude Nov 10, 2026
538e88c
mcp: escape C1 controls in the fence and name slashed checks
claude Nov 10, 2026
6079653
merge the branch's earlier, already-squashed history
claude Nov 10, 2026
e6855a2
mcp: record the pack's head as a new task session's base
claude Nov 10, 2026
6e5b008
derive: name a rebased land's creator in a context pack's history
claude Nov 10, 2026
9040fef
e2e: twenty-agent coordination demo, as a test and a script
claude Nov 10, 2026
1ce540b
merge the branch's earlier, already-squashed history
claude Nov 10, 2026
e195f97
mcp: give a task session a base even when its pack is shed
claude Nov 10, 2026
d9b451e
derive: rank a pack's live work by the agent's own paths
claude Nov 10, 2026
8e80d7c
derive: tell the first of a duplicate pair on its next answer
claude Nov 10, 2026
ee51db3
coord: name the target ref on creates so inferred sessions hear lands
claude Nov 10, 2026
8d5c7c7
derive: say when a landed change is a duplicate's land of the task
claude Nov 10, 2026
2739895
derive: group repeated owners and history rows in context packs
claude Nov 10, 2026
1e36883
e2e: assert the coordination demo's friction fixes
claude Nov 10, 2026
29f8e88
derive: keep every landed notice of a duplicate's session
claude Nov 10, 2026
6e41386
derive: keep a pack's live work when the task-key listing fails
claude Nov 10, 2026
c7bd98a
derive: never tag a land as a duplicate's on an unread creator
claude Nov 10, 2026
f780847
derive: read a task key's live and landed sessions apart
claude Nov 10, 2026
c22c7d3
coord: forget a revived session's task key and follow a commit's ref
claude Nov 10, 2026
2892bfb
coord: take a target-less session's ref from --default-ref and say so
claude Nov 10, 2026
edd17af
cli: show a notice's unknown `via` as FORMATS says
claude Nov 10, 2026
1ee3f7d
e2e: make the demo's new claims say something, and retry a status
claude Nov 10, 2026
25b5448
server: list LEEP_DEFAULT_REF in the environment example
claude Nov 10, 2026
ab82a0d
merge the branch's earlier, already-squashed history
claude Nov 10, 2026
a63a35d
notices: say which notices stop a land, and name the shared file
claude Nov 10, 2026
29e2210
mcp: stop a land for overlaps the agent has not seen
claude Nov 10, 2026
ad0b75a
notices: say a notice again when it comes to stop a land
claude Nov 10, 2026
9036f68
mcp: land a stopped changeset only with force, on its own ref
claude Nov 10, 2026
f3166a7
merge the branch's earlier, already-squashed history
claude Nov 10, 2026
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
18 changes: 18 additions & 0 deletions changelog.d/mcp-preflight.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
### MCP lands stop for overlaps the agent has not seen
- **Changed.** `leep_commit_and_land` and `leep_resolve_and_land` check
the notices their commit got before landing (ADR 0096 amendment): a
possible duplicate, a claim on or another session on one of the
changed files, or a land on one of them since the base, not shown to
the agent before, stops the call with `status: stopped` (not an
error), the changeset it made, its ref and every such notice. The
stopped changeset lands only with `force: true`; calling again reuses
it, and without `force` stops again. `near`, directory scopes and
related files never stop a land.
- **Changed.** A changeset create's answer carries every notice that
stops a land of its files, past the cap of three, and a notice is said
again when it comes to stop a file it did not stop before. Notices name
the file two sessions share rather than a directory holding it, and a
`landed` notice names the request's file it changed.
- **Fixed.** `leep_task_start` asks once more for a context pack the
server shed with a `Retry-After` of at most 2 s, instead of reporting
"Context unavailable" at once.
6 changes: 6 additions & 0 deletions crates/leep-cli/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,12 @@ impl Client {
all
}

/// The notices gathered so far, left for [`Client::take_notices`]: for
/// a caller that decides something on them before they are shown.
pub fn pending_notices(&self) -> Vec<Notice> {
self.notices.lock().unwrap().clone()
}

/// Forget the gathered notices `shown` says were already shown (in a
/// context pack printed with them), so none is said twice.
pub fn forget_notices(&self, shown: impl Fn(&Notice) -> bool) {
Expand Down
99 changes: 99 additions & 0 deletions crates/leep-core/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1257,6 +1257,59 @@ pub struct Notice {
pub untrusted: NoticeText,
}

impl Notice {
/// Whether this notice stops an agent's land before it happens (the
/// pre-flight check, ADR 0096 amendment), for a change of the files
/// `changes`. The one place the rule lives:
/// - `possible_duplicate`, and a duplicate's land (`landed` by
/// `task_key`), always stop;
/// - otherwise [`path_stops_land`] on the other side's path
/// (`untrusted.other_path`);
/// - anything met only through a related file (`via`) never stops.
///
/// Only the other side's path is read, never which of mine the server
/// paired it with, so a notice found through a directory of mine still
/// stops when their path is one of my files. The paths compared are
/// agent-written (`untrusted`): they decide only whether to stop, never
/// what is shown outside the fence.
pub fn stops_land<S: AsRef<str>>(&self, changes: &[S]) -> bool {
if self.via.is_some() {
return false;
}
if self.level == "possible_duplicate"
|| (self.level == "landed" && self.by.as_deref() == Some("task_key"))
{
return true;
}
self.untrusted
.other_path
.as_deref()
.is_some_and(|theirs| path_stops_land(&self.level, theirs, changes))
}
}

/// Whether another side's path `theirs`, met at `level`, stops a land of
/// the files `changes` ([`Notice::stops_land`]): `landed` and `same_file`
/// when `theirs` is one of the files itself (a directory someone scoped
/// does not stop), `claimed` when it is one of them or a directory holding
/// one; `near` and levels not known here never.
pub fn path_stops_land<S: AsRef<str>>(level: &str, theirs: &str, changes: &[S]) -> bool {
let theirs = theirs.trim_end_matches('/');
let is = |c: &S| c.as_ref() == theirs;
let holds = |c: &S| {
let c = c.as_ref();
theirs.is_empty()
|| (c.len() > theirs.len()
&& c.starts_with(theirs)
&& c.as_bytes()[theirs.len()] == b'/')
};
match level {
"landed" | "same_file" => changes.iter().any(is),
"claimed" => changes.iter().any(|c| is(c) || holds(c)),
_ => false,
}
}

/// `GET /v1/notices`: the notices for the caller's session named by
/// `Leep-Session`, each said once (ADR 0096).
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
Expand Down Expand Up @@ -2155,6 +2208,52 @@ pub struct SearchResponse {
mod tests {
use super::*;

#[test]
fn which_notices_stop_a_land() {
let n = |level: &str, mine: &str, theirs: &str| Notice {
level: level.into(),
session: Some(1),
principal: None,
changeset: None,
count: None,
by: None,
similarity: None,
via: None,
landed_on: None,
untrusted: NoticeText {
path: Some(mine.into()),
other_path: Some(theirs.into()),
..Default::default()
},
};
let changes = ["src/a.rs"];
// Their own file is mine, whichever of mine it was paired with; a
// scope above it is not enough.
assert!(n("same_file", "src/a.rs", "src/a.rs").stops_land(&changes));
assert!(n("same_file", "src", "src/a.rs").stops_land(&changes));
assert!(!n("same_file", "src/a.rs", "src").stops_land(&changes));
assert!(!n("same_file", "src", "src/b.rs").stops_land(&changes));
// A claim on my file or a directory above it.
assert!(n("claimed", "src/a.rs", "src").stops_land(&changes));
assert!(n("claimed", "src/a.rs", "src/").stops_land(&changes));
assert!(n("claimed", "src", "src/a.rs").stops_land(&changes));
assert!(!n("claimed", "src", "src/b.rs").stops_land(&changes));
assert!(!n("claimed", "src/a.rs", "sr").stops_land(&changes));
assert!(n("possible_duplicate", "src", "src").stops_land(&changes));
assert!(n("landed", "src", "src/a.rs").stops_land(&changes));
assert!(!n("landed", "src", "src/b.rs").stops_land(&changes));
let mut dup_land = n("landed", "src", "src/b.rs");
dup_land.by = Some("task_key".into());
assert!(dup_land.stops_land(&changes));
// Never: near, an unknown level, a related file, no changes.
assert!(!n("near", "src/a.rs", "src/a.rs").stops_land(&changes));
assert!(!n("conflict", "src/a.rs", "src/a.rs").stops_land(&changes));
let mut related = n("claimed", "src/a.rs", "src/a.rs");
related.via = Some("related".into());
assert!(!related.stops_land(&changes));
assert!(!n("claimed", "src/a.rs", "src").stops_land::<&str>(&[]));
}

#[test]
fn rebase_onto_shapes_are_stable() {
let a = ChangesetId(Hash::of_blob(b"a"));
Expand Down
Loading
Loading