You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Porting a moving target: freeze, checkpoint, or continuous tracking #253
How does the port track a codebase that keeps shipping? The original plan's premise — a final Python release, then port a frozen tree — is dead: Python shipped 0.0.12 → 0.0.27 after that "final" release, and other open maps (Launch latency #139, Launch benchmarking #193, stale-cache #244) are still landing Python changes.
To settle:
Freeze, checkpoint, or continuous tracking: does the port target a pinned tag that advances deliberately (rebase the port on each release?), or does Python enter a feature-freeze once the port starts, or something between?
Who pays the sync cost: does a Python change that lands mid-port create a port-side obligation immediately, at the next checkpoint, or only at cutover parity-check time?
What the other open maps are told: does anything become "don't bother, the port covers it" (the trap Decide: Rust rewrite — go or no-go #53's amendment already reversed once — fixed code ports better than deferred fixes), or does everything land in Python as normal?
The coexistence contract: both implementations read/write the same ~/.cache/devlaunch state during the parallel period — same metadata.json schema version, same completion cache. What guarantees keep them from corrupting each other, and does schema evolution freeze until cutover?
breadcrumb: tracking model — continuous tracking of main; no freeze, no checkpoint tags
The port targets whatever is on main, continuously. This ratifies what #252 structurally decided rather than making a fresh choice: with the Rust workspace in-repo (rust/) and the harness being the existing pytest suite on main run against both binaries per push, there is no second tree to pin — every commit to main is automatically the port's target, and the required rust-parity job measures the drift on every push. A checkpoint model would need a test-suite snapshot divergent from main's (machinery with no consumer); a freeze contradicts observed reality (#139/#193/#244 are landing Python changes; the "final release then port a frozen tree" premise already died once, 16 releases past its "final" release) and the #53 lesson — fixed code ports better than deferred fixes, so Python improving mid-port is a feature the harness inherits, not drift to prevent.
Who pays for a Python change that breaks parity, and when → next breadcrumb.
breadcrumb: sync cost — debt-at-landing via annotated manifest growth; and an owner steer that shrinks the window
(b) Debt-at-landing. A Python PR that changes behavior pinned by a parity test the Rust side already passes may grow the expected-failure manifest with an annotated debt row (test id + reason + PR link), keeping the required rust-parity job green while making the drift explicit and enumerable. This resolves what #252's two-way ratchet left open: manifest growth is legal only in a PR that changes Python behavior, and the row must name that PR — the manifest's git history stays an honest drift dashboard. Fixing the Rust side in the same PR is permitted, never obligated. Python velocity is never hostage to the port; the debt can never be forgotten because the cutover criterion (empty manifest, #252) is the payment deadline. New test files are already handled by the ledger lint's forced disposition (#252); this rule covers behavior changes under existing tests.
Owner steer (2026-08-18): the port execution will be a single agent-driven big-bang port — one Rust version brought up in one concentrated pass, not incremental milestones drifting alongside Python for months. The moving-target window is therefore short: the pass itself plus the manifest-draining tail. The debt mechanism above is sized for that window, not for a long campaign.
breadcrumb: what the other maps are told — Python is frozen; after 2026-08-18 all new work is Rust (owner fiat)
Owner steer (2026-08-18): "python is dead. after today its all rust." This supersedes the ticket's premise that other maps keep landing Python changes. Effective today, Python is feature-frozen: no new Python features or improvements land, from any map. The remaining work on #139/#193/#244 resumes post-cutover, in Rust — their open tickets target the Rust tree once it ships. This is the freeze the ticket asked about after all, but arrived at from the opposite direction: not "freeze so the port can catch a still-moving target" but "the port starts now and everything else waits for it," which is coherent precisely because the port is one concentrated agent-driven pass (previous breadcrumb), not a months-long campaign a freeze would starve.
What survives of the moving-target machinery:
Continuous tracking of main (Q1) stands — trivially satisfied now, since main's Python side stops moving.
The debt mechanism (Q2) stands as the escape hatch, not the norm: the one legal Python change left is an emergency fix to released 0.0.x (Distribution and CI plan: every channel, per-platform #254 explicitly allows an emergency Python patch pre- or post-cutover). Such a fix lands with its annotated manifest debt row exactly per Q2.
The Decide: Rust rewrite — go or no-go #53 "fixed code ports better" concern is moot for the freeze window: it warned against deferring known fixes for months; a few weeks of concentrated port with an emergency hatch is not that.
The port scope is therefore frozen at today's origin/main — the 0.0.27-era tree the #249 inventory measured (modulo commits since; the port agent reads main at its start commit, and anything that lands after that is emergency-hatch drift, visible in the manifest).
breadcrumb: coexistence contract — coexistence is parity; schema frozen at v2; migration ported; cutover migrates nothing
Schema frozen at v2 through cutover — trivially guaranteed by the Python freeze; the Rust side is likewise forbidden from bumping the schema until after cutover. Rust reads and writes schema-v2 metadata.jsonbyte-compatibly (same version header per Build: harden metadata storage (guarded load, atomic save) #56, same sections, same unknown-field preservation and newer-version tolerance), pinned Grade A by the existing boundary tests. Completion caches identical: same paths (completions.json/completions.bash), formats, atomic-rename writes, mtime-freshness semantics.
Same lock protocol: Rust takes the same fd-lock on the same lock-file path (fd-lock crate, already in the Refresh the port inventory: what 0.0.11 → 0.0.27 added to the port #249 inventory). Byte-compatible v2 + same locks makes the two binaries indistinguishable writers — no separate coexistence mechanism exists or is needed.
The v1→v2 migration (worktree/migration.py) is ported, not dropped: a user jumping from a pre-Build: parse workspace ids at one boundary (injective scheme) #64 0.0.x straight to 0.1.0 has uncommitted work in v1-named clone dirs, and stranding it is what the correctness tiebreaker forbids. It is test-covered and already counted in the inventory's 26 modules.
The cutover release migrates nothing: 0.1.0 opens a 0.0.27 cache and just works.
Settled in a grilling session 2026-08-18 (owner + agent), grounded in the state machinery on origin/main (worktree/storage.py schema v2 + #56 version header, worktree/migration.py, worktree/locks.py, the completion caches in dl.py) and #252's harness decisions. Mid-session the owner issued a steer that collapsed most of this ticket's premise: "python is dead. after today its all rust." Full trail in the breadcrumbs above.
1. Tracking model: continuous tracking of main
No checkpoint tags, no snapshot to rebase against — this ratifies what #252 structurally decided. With the Rust workspace in-repo and the harness being the existing pytest suite on main run against both binaries per push, every commit to main is automatically the port's target and the required rust-parity job measures drift per push. A checkpoint model would need a divergent test-suite snapshot (machinery with no consumer).
2. Sync cost: debt-at-landing via annotated manifest growth
A Python change that breaks a parity test the Rust side already passes may grow the expected-failure manifest with an annotated debt row (test id + reason + PR link), keeping rust-parity green while making the drift explicit and enumerable. This closes what #252's two-way ratchet left open: manifest growth is legal only in a PR that changes Python behavior, and the row must name that PR. Same-PR Rust fixes are permitted, never obligated. The cutover criterion (empty manifest, #252) is the payment deadline — debt can never be forgotten. New test files are already handled by the ledger lint's forced disposition (#252).
3. Owner steer: Python is frozen; the port is one big-bang pass
Two steers (2026-08-18) reshape everything downstream:
The port execution is a single agent-driven big-bang pass — one Rust version brought up in one concentrated effort, not incremental milestones drifting alongside Python for months.
The port scope is therefore frozen at the main commit the port agent starts from; anything landing after that is emergency-hatch drift, visible in the manifest. The freeze is coherent where the old "final Python release" premise wasn't, precisely because the port is a concentrated pass with a hard cutover gate rather than a months-long campaign: the #53 lesson ("fixed code ports better than deferred fixes") warned against deferring known fixes indefinitely, not for a few weeks with an escape hatch.
4. Coexistence contract: coexistence is parity
metadata.json schema frozen at v2 through cutover — guaranteed on the Python side by the freeze, and the Rust side is likewise forbidden from bumping it until after cutover. Rust reads/writes schema v2 byte-compatibly: same version header (Build: harden metadata storage (guarded load, atomic save) #56), same sections, same unknown-field preservation and newer-version tolerance. Grade A, pinned by the existing boundary tests.
Completion caches identical: same paths (completions.json/completions.bash), same formats, atomic-rename writes, mtime-freshness semantics.
Same lock protocol: the same fd-lock on the same lock-file path (fd-lock crate, per the Refresh the port inventory: what 0.0.11 → 0.0.27 added to the port #249 inventory). Byte-compatible v2 + same locks makes the two binaries indistinguishable writers — no separate coexistence mechanism exists or is needed.
The v1→v2 migration is ported, not dropped: a user jumping from a pre-Build: parse workspace ids at one boundary (injective scheme) #64 0.0.x straight to 0.1.0 has uncommitted work in v1-named clone dirs; stranding it is what the correctness tiebreaker forbids.
The cutover release migrates nothing: 0.1.0 opens a 0.0.27-era cache and just works.
Activity
blooop commentedon Aug 18, 2026
breadcrumb: tracking model — continuous tracking of
main; no freeze, no checkpoint tagsThe port targets whatever is on
main, continuously. This ratifies what #252 structurally decided rather than making a fresh choice: with the Rust workspace in-repo (rust/) and the harness being the existing pytest suite on main run against both binaries per push, there is no second tree to pin — every commit tomainis automatically the port's target, and the requiredrust-parityjob measures the drift on every push. A checkpoint model would need a test-suite snapshot divergent frommain's (machinery with no consumer); a freeze contradicts observed reality (#139/#193/#244 are landing Python changes; the "final release then port a frozen tree" premise already died once, 16 releases past its "final" release) and the #53 lesson — fixed code ports better than deferred fixes, so Python improving mid-port is a feature the harness inherits, not drift to prevent.Who pays for a Python change that breaks parity, and when → next breadcrumb.
blooop commentedon Aug 18, 2026
breadcrumb: sync cost — debt-at-landing via annotated manifest growth; and an owner steer that shrinks the window
(b) Debt-at-landing. A Python PR that changes behavior pinned by a parity test the Rust side already passes may grow the expected-failure manifest with an annotated debt row (test id + reason + PR link), keeping the required
rust-parityjob green while making the drift explicit and enumerable. This resolves what #252's two-way ratchet left open: manifest growth is legal only in a PR that changes Python behavior, and the row must name that PR — the manifest's git history stays an honest drift dashboard. Fixing the Rust side in the same PR is permitted, never obligated. Python velocity is never hostage to the port; the debt can never be forgotten because the cutover criterion (empty manifest, #252) is the payment deadline. New test files are already handled by the ledger lint's forced disposition (#252); this rule covers behavior changes under existing tests.Owner steer (2026-08-18): the port execution will be a single agent-driven big-bang port — one Rust version brought up in one concentrated pass, not incremental milestones drifting alongside Python for months. The moving-target window is therefore short: the pass itself plus the manifest-draining tail. The debt mechanism above is sized for that window, not for a long campaign.
blooop commentedon Aug 18, 2026
breadcrumb: what the other maps are told — Python is frozen; after 2026-08-18 all new work is Rust (owner fiat)
Owner steer (2026-08-18): "python is dead. after today its all rust." This supersedes the ticket's premise that other maps keep landing Python changes. Effective today, Python is feature-frozen: no new Python features or improvements land, from any map. The remaining work on #139/#193/#244 resumes post-cutover, in Rust — their open tickets target the Rust tree once it ships. This is the freeze the ticket asked about after all, but arrived at from the opposite direction: not "freeze so the port can catch a still-moving target" but "the port starts now and everything else waits for it," which is coherent precisely because the port is one concentrated agent-driven pass (previous breadcrumb), not a months-long campaign a freeze would starve.
What survives of the moving-target machinery:
main(Q1) stands — trivially satisfied now, sincemain's Python side stops moving.The port scope is therefore frozen at today's
origin/main— the 0.0.27-era tree the #249 inventory measured (modulo commits since; the port agent readsmainat its start commit, and anything that lands after that is emergency-hatch drift, visible in the manifest).blooop commentedon Aug 18, 2026
breadcrumb: coexistence contract — coexistence is parity; schema frozen at v2; migration ported; cutover migrates nothing
metadata.jsonbyte-compatibly (sameversionheader per Build: harden metadata storage (guarded load, atomic save) #56, same sections, same unknown-field preservation and newer-version tolerance), pinned Grade A by the existing boundary tests. Completion caches identical: same paths (completions.json/completions.bash), formats, atomic-rename writes, mtime-freshness semantics.fd-lockcrate, already in the Refresh the port inventory: what 0.0.11 → 0.0.27 added to the port #249 inventory). Byte-compatible v2 + same locks makes the two binaries indistinguishable writers — no separate coexistence mechanism exists or is needed.worktree/migration.py) is ported, not dropped: a user jumping from a pre-Build: parse workspace ids at one boundary (injective scheme) #64 0.0.x straight to 0.1.0 has uncommitted work in v1-named clone dirs, and stranding it is what the correctness tiebreaker forbids. It is test-covered and already counted in the inventory's 26 modules.blooop commentedon Aug 18, 2026
Resolution
Settled in a grilling session 2026-08-18 (owner + agent), grounded in the state machinery on origin/main (
worktree/storage.pyschema v2 + #56 version header,worktree/migration.py,worktree/locks.py, the completion caches indl.py) and #252's harness decisions. Mid-session the owner issued a steer that collapsed most of this ticket's premise: "python is dead. after today its all rust." Full trail in the breadcrumbs above.1. Tracking model: continuous tracking of
mainNo checkpoint tags, no snapshot to rebase against — this ratifies what #252 structurally decided. With the Rust workspace in-repo and the harness being the existing pytest suite on
mainrun against both binaries per push, every commit tomainis automatically the port's target and the requiredrust-parityjob measures drift per push. A checkpoint model would need a divergent test-suite snapshot (machinery with no consumer).2. Sync cost: debt-at-landing via annotated manifest growth
A Python change that breaks a parity test the Rust side already passes may grow the expected-failure manifest with an annotated debt row (test id + reason + PR link), keeping
rust-paritygreen while making the drift explicit and enumerable. This closes what #252's two-way ratchet left open: manifest growth is legal only in a PR that changes Python behavior, and the row must name that PR. Same-PR Rust fixes are permitted, never obligated. The cutover criterion (empty manifest, #252) is the payment deadline — debt can never be forgotten. New test files are already handled by the ledger lint's forced disposition (#252).3. Owner steer: Python is frozen; the port is one big-bang pass
Two steers (2026-08-18) reshape everything downstream:
The port scope is therefore frozen at the
maincommit the port agent starts from; anything landing after that is emergency-hatch drift, visible in the manifest. The freeze is coherent where the old "final Python release" premise wasn't, precisely because the port is a concentrated pass with a hard cutover gate rather than a months-long campaign: the #53 lesson ("fixed code ports better than deferred fixes") warned against deferring known fixes indefinitely, not for a few weeks with an escape hatch.4. Coexistence contract: coexistence is parity
metadata.jsonschema frozen at v2 through cutover — guaranteed on the Python side by the freeze, and the Rust side is likewise forbidden from bumping it until after cutover. Rust reads/writes schema v2 byte-compatibly: sameversionheader (Build: harden metadata storage (guarded load, atomic save) #56), same sections, same unknown-field preservation and newer-version tolerance. Grade A, pinned by the existing boundary tests.completions.json/completions.bash), same formats, atomic-rename writes, mtime-freshness semantics.fd-lockcrate, per the Refresh the port inventory: what 0.0.11 → 0.0.27 added to the port #249 inventory). Byte-compatible v2 + same locks makes the two binaries indistinguishable writers — no separate coexistence mechanism exists or is needed.Routed onward