Commit 4a4d792
* Manual `hyp detach` retracts its attach marker so rejoin re-attaches (#217)
Manual `hyp detach` reversed a client's on-disk settings but left an
orphaned `status: "done"` attach marker in `client-actions.json`. The
action reconciler is level-triggered against that marker, so the next
`hyp join`'s forward gap short-circuits on `done` and never re-attaches:
detach-via-config-drop was rejoin-recoverable while detach-via-CLI was
not, and the two disagreed side by side in `hyp status`.
Fix: after a successful disk reversal, `detachClientViaCore` now retracts
the client's `attach` marker via a new `clearClientActionMarker` helper on
the reconciler module (which owns the marker store) — the same
`delete markers[requestKey]` the reconciler's `reverse()` does once its
disk undo succeeds. This keeps the single core undo's two call sites (CLI
detach and reconciler reverse) from drifting, honoring LLP 0045 §Part 3
(the marker is a self-describing undo record that must not outlive its own
effect being reversed). The retraction is best-effort and atomic
(tmp+rename, mode 0600), and runs even on a no-op reversal so a stale
marker over already-clean settings is still cleared.
Regression test drives the full join -> detach -> rejoin cycle end to end:
the real reconciler attaches (marker done + settings written), the real
`hyp detach` command reverses settings and retracts the marker, and a
second reconcile re-attaches while an un-detached sibling stays attached.
It fails on master at the marker-retract assertion and passes with the fix.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Detach marker retract: preserve the #212 probe-less invariant + cover the guard
Dual-review fixes on the #217 fix (PR #223).
Finding 2 (major): detachClientViaCore cleared the attach marker
unconditionally, even on `changed:false`. But `changed:false` is
overloaded: probe-HAVING means "already clean" (safe to clear); probe-LESS
means "cannot reverse, no probe to replay" (#212). The daemon reverse()
KEEPS the marker for a probe-less descriptor; the CLI was dropping it,
re-orphaning the settings the #212/#213 invariant protects. Gate the
clearClientActionMarker call on `descriptor.attachProbe` so the CLI mirrors
reverse(): clear for a probe-having client (changed:true or already-clean),
keep for a probe-less one. Correct the comment (it claimed it behaved
"exactly as reverse() does", which was wrong for the probe-less case).
Finding 3 (minor): unit-test clearClientActionMarker's untested branches -
missing file/bucket/key each return false and write no file; an emptied
bucket is dropped while a sibling `backfill` bucket and its keys survive.
Finding 4 (nit): cover the best-effort + changed:false semantics through the
real CLI detach path - a probe-having client with already-clean settings
still has its stale marker cleared; a probe-less client keeps its marker (the
finding-2 guard, mirroring reverse()); a throwing retraction does not fail
the detach. Mutation check: removing the `attachProbe` guard fails the
probe-less test.
Finding 5 (nit): replace a U+2014 em dash in test prose with a colon
(AGENTS.md bans em dashes; @ref glosses excepted).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent fdfdf69 commit 4a4d792
4 files changed
Lines changed: 591 additions & 0 deletions
File tree
- src/core
- cli
- config
- test/core
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
| 25 | + | |
25 | 26 | | |
26 | 27 | | |
27 | 28 | | |
| |||
3671 | 3672 | | |
3672 | 3673 | | |
3673 | 3674 | | |
| 3675 | + | |
| 3676 | + | |
| 3677 | + | |
| 3678 | + | |
| 3679 | + | |
| 3680 | + | |
| 3681 | + | |
| 3682 | + | |
| 3683 | + | |
| 3684 | + | |
| 3685 | + | |
| 3686 | + | |
| 3687 | + | |
| 3688 | + | |
| 3689 | + | |
| 3690 | + | |
| 3691 | + | |
| 3692 | + | |
| 3693 | + | |
| 3694 | + | |
| 3695 | + | |
| 3696 | + | |
| 3697 | + | |
| 3698 | + | |
| 3699 | + | |
| 3700 | + | |
| 3701 | + | |
| 3702 | + | |
| 3703 | + | |
| 3704 | + | |
| 3705 | + | |
| 3706 | + | |
3674 | 3707 | | |
3675 | 3708 | | |
3676 | 3709 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
329 | 329 | | |
330 | 330 | | |
331 | 331 | | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| 21 | + | |
20 | 22 | | |
21 | 23 | | |
22 | 24 | | |
| |||
444 | 446 | | |
445 | 447 | | |
446 | 448 | | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
0 commit comments