Skip to content

Record which liveness source owns a session, instead of inferring it from the ref - #135

Merged
MJohnson459 merged 2 commits into
mainfrom
session-liveness
Aug 13, 2026
Merged

Record which liveness source owns a session, instead of inferring it from the ref#135
MJohnson459 merged 2 commits into
mainfrom
session-liveness

Conversation

@MJohnson459

Copy link
Copy Markdown
Contributor

Record which liveness source owns a session

Reconciliation inferred the flavour of a refine round from the absence of a
session ref: no ref meant the interactive round, whose foreground pid genuinely
is the work. That could not tell a headless round whose ref capture timed out
apart from it, and for that one the pid is a --bg launcher dead within a
second — so the round was finalised failed while its agent went on rewriting
the body. The late-rewrite backstop corrects the marker afterwards, but not the
early exit from refining, which is what lets a second window hand a verdict to
a proposal whose body is about to be replaced.

Which source is authoritative is a property of the launch, so record it there:
sessions.liveness_source ('pid' | 'listing'), an additive column set by the
code that spawned the process. Dispatch and the headless refine record the
flavour of the agent's dispatch template — listing where the agent defines a
sessions verb, pid where it does not — and the interactive refine records pid,
being a foreground plan child. Reconciliation reads pid-authoritative sessions
by pid and listing-authoritative ones by listing, leaving a listing-authoritative
round with no ref unprobeable rather than guessed, exactly as a ref-less dispatch
already was.

Sessions open across the migration default to 'listing' — what every dispatch of
an agent with a sessions verb already was, and the direction that leaves a
session alone rather than finalising a live one.

DESIGN.md §5 gains the column (and the session_ref one it never recorded), §6
notes what each refine flavour records, and §8 states the rule that replaces the
ref-presence inference. Tests cover both flavours in voro-core and in
reconcile, including the headless round with no ref staying refining and the
interactive round still reconciling by pid under an agent with a listing.

Verified: cargo test --workspace, cargo clippy --workspace --all-targets -- -D warnings and cargo fmt --all clean; the migration applied to a copy of the
live database, which opened at user_version 17 with its open sessions defaulting
to 'listing' and none wrongly finalised.

Reconciliation inferred the flavour of a refine round from the absence of a
session ref: no ref meant the interactive round, whose foreground pid genuinely
is the work. That could not tell a headless round whose ref capture timed out
apart from it, and for that one the pid is a `--bg` launcher dead within a
second — so the round was finalised `failed` while its agent went on rewriting
the body. The late-rewrite backstop corrects the marker afterwards, but not the
early exit from `refining`, which is what lets a second window hand a verdict to
a proposal whose body is about to be replaced.

Which source is authoritative is a property of the launch, so record it there:
`sessions.liveness_source` ('pid' | 'listing'), an additive column set by the
code that spawned the process. Dispatch and the headless refine record the
flavour of the agent's `dispatch` template — listing where the agent defines a
`sessions` verb, pid where it does not — and the interactive refine records pid,
being a foreground `plan` child. Reconciliation reads pid-authoritative sessions
by pid and listing-authoritative ones by listing, leaving a listing-authoritative
round with no ref unprobeable rather than guessed, exactly as a ref-less dispatch
already was.

Sessions open across the migration default to 'listing' — what every dispatch of
an agent with a `sessions` verb already was, and the direction that leaves a
session alone rather than finalising a live one.

DESIGN.md §5 gains the column (and the `session_ref` one it never recorded), §6
notes what each refine flavour records, and §8 states the rule that replaces the
ref-presence inference. Tests cover both flavours in `voro-core` and in
reconcile, including the headless round with no ref staying `refining` and the
interactive round still reconciling by pid under an agent with a listing.

Verified: `cargo test --workspace`, `cargo clippy --workspace --all-targets -- -D
warnings` and `cargo fmt --all` clean; the migration applied to a copy of the
live database, which opened at user_version 17 with its open sessions defaulting
to 'listing' and none wrongly finalised.
Main landed three changes that touch the same seams as the recorded
liveness source: the schema-journal and project-viewer migrations (which
collide with this branch's 0017, renumbered here to 0019), the `logs`
verb for capped deaths, and task #390's rule that a live pid proves a
session live whatever the agent's listing says.

That last one meets this branch's `sessions.liveness_source` head on, and
the two compose rather than conflict: the recorded source names which
probe answers when the pid is silent, while a live pid still proves
liveness whichever source owns the row. §8 and the reconcile module doc
now say both. Main's fixtures that relied on the old inference are
pinned to the source they were always meant to have — the `logs` fixture
agent defines no `sessions` verb, so its launches are pid-authoritative,
and the tests that need the listing to decide now use a dead pid rather
than a live one, which under the merged rule would short-circuit them.
@MJohnson459
MJohnson459 merged commit 3f75217 into main Aug 13, 2026
6 checks passed
@MJohnson459
MJohnson459 deleted the session-liveness branch August 13, 2026 14:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant