feat(pi,opencode): preserve dropped session data via events + Turn.model; remove dead Turn.extra plumbing#125
Open
akesling wants to merge 5 commits into
Open
feat(pi,opencode): preserve dropped session data via events + Turn.model; remove dead Turn.extra plumbing#125akesling wants to merge 5 commits into
akesling wants to merge 5 commits into
Conversation
…rvation claims Turn.extra was removed from the toolpath-convo IR in an earlier change, but codex/opencode/pi kept dead *_extras() functions that unconditionally returned None (plus the now-unreachable branches they fed), gemini's projector looked up extra["gemini"] in a map that was always empty, and doc comments across providers still claimed provider-namespaced extras were preserved on round-trip. This is behavior-preserving cleanup: every dead-code claim was verified before removal, the plumbing and the simplifications it enables were removed, and the stale comments (plus the codex.md/gemini.md/pi.md format docs and affected crate READMEs) now describe what's actually dropped.
|
🔍 Preview deployed: https://aade66db.toolpath.pages.dev |
…re-materialize them on projection ModelChange / ThinkingLevelChange / Label entries were discarded by session_to_view (and therefore lost on any Path round-trip). They now land in ConversationView.events (model_change / thinking_level_change / label, payload fields in event data), which the shared derive already emits as conversation.event steps and extract_conversation restores. PiProjector re-materializes those events as real Pi entries with their original ids and parentIds, inserting each directly after its parent for sane file order; foreign event types (e.g. Claude attachments) are still skipped rather than emitted as garbage entries. New pi -> view -> Path -> view -> pi integration tests prove the entries survive with ids, parentIds, and payloads intact, and that the projected JSONL re-parses through Pi's own reader.
…art.snapshot events
Two previously-dropped pieces of opencode data now ride existing IR
affordances:
- User messages' wire model.modelID lands on Turn.model (same
bare-modelID convention as assistant turns; providerID has no IR home
and still falls back to the projector default). The projector writes
it back into the projected user message. Known limitation, asserted in
the round-trip test: the user model survives the view-level chain but
not the Path layer - the shared derive attributes model via the step
actor (agent:{model}) and user steps carry human:user, so closing that
would need a toolpath-convo change (out of scope here).
- Snapshot SHAs from step-start / step-finish / snapshot parts now also
ride ConversationView.events as part.snapshot events (data: snapshot
SHA + part kind). A message's snapshot events chain linearly (first
parents to the message, subsequent to the previous snapshot event) so
the derived Path keeps its all-steps-on-head-ancestry shape. The
projector groups events back to their turn by walking parent links and
restores the step-start SHA onto StepStart and the step-finish SHA
onto StepFinish - snapshot SHAs survive a full Path round-trip, so a
re-imported projection can regenerate diffs.
Also tightens compaction_roundtrip.rs: its module doc claimed derive
does not emit conversation.event steps (stale - it does, and a new test
asserts the part.compaction event survives derive -> extract); the
remaining documented gap is that the projector only consumes
part.snapshot events, not compaction parts.
Behavior-adding changes on this branch (pi metadata entries via events; opencode user model + snapshot-SHA events). The .1 patch numbers are claimed by sibling PRs #121/#122 currently in flight, so both crates skip to .2. All five sites updated: crate Cargo.toml, root workspace dependency, site/_data/crates.json, CHANGELOG top section, Cargo.lock. No path-cli / toolpath-cli / toolpath-convo bumps.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Started as a cleanup of dead
Turn.extraplumbing; grew to actually recover the provider data that removal exposed as dropped, using only current format affordances (ConversationView.events,Turn.model) — no new IR fields, no reintroduced provider blob.Part 1 — data now preserved (was silently dropped)
events.ModelChange/ThinkingLevelChange/Labelwere discarded at read time andview.eventswas always empty. They now rideConversationView.events(typedevent_type+ payload indata) and the projector re-materializes them as real Pi entries with their original ids/parentIds. Round-trip test: a session with a ModelChange and a Label survives pi → view → Path → view → pi intact.Turn.model. User messages carrymodel.modelIDon the wire but user turns hardcodedmodel: None; now mapped like assistant turns (bare modelID, empty→None) and written back on projection. Survives the view-level round-trip; documented that Path-level restoration isn't attempted (the kind'sconversation.appendhas nomodelfield and user steps arehuman:user, notagent:{model}).events.step-start/step-finishsnapshot SHAs were dropped on projection, so a re-imported session couldn't regenerate diffs. They now rideview.events(part.snapshot) and the projector restores them onto the right step parts. Round-trip test proves the SHAs survive. In the course of this I found thecompaction_roundtrip.rs"event does not survive derive→extract" comment was stale — the shared events pathway does round-trip; corrected and pinned with a new test.Part 2 — dead plumbing removed + docs corrected (original scope)
*_extras()helpers (codex/opencode/pi) that unconditionally returnedNoneand everything reachable only through them (~450 lines in pi alone), and gemini's always-emptyextra["gemini"]lookups. Every removal verified closed over its uses;apply_turn_metadatain claude was kept (it does real cwd/git-branch work — the audit mislabeled it) with only its doc corrected.docs/agents/formats/codex.mdcorrected to state what's actually dropped. Still-dropped items keep honest "dropped" wording: codexencrypted_content, claude per-lineversion/userType, cursorcheckpointId/requestId/richText, gemini per-thought timestamps andtool/totalcounters.Known fidelity edges (documented in-code)
Versions & verification
toolpath-pi0.6.0 → 0.6.2,toolpath-opencode0.5.0 → 0.5.2 (the .1 patches are claimed by sibling PRs #121/#122 in flight — noted in each CHANGELOG).toolpath-convountouched. No path-cli/toolpath-cli bumps. Fullcargo build/test/clippy -D warnings/doc --workspacegreen; TDD (red-first) on every added behavior, both view-level and full-chain (Graph JSON) integration tests.Part of a six-PR consistency series from a cross-harness audit; CHANGELOG/version lines may conflict with sibling PRs — resolve by keeping both entries.