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
Prove and lock Herdr-only for parent plan #463. Local PTY, the env/CLI switch, and sqlite session/profile authority are already gone (#436 Tasks 8–9 / #451 / #452). Task 1 (#464 on task-1-rename-pty-layer) renamed the session layer off pty. Task 2 (#465 on task-2-delete-twocode-runtime) deleted every TWOCODE_RUNTIME / --twocode-runtime trace. What survives is leftover live vocabulary (pty_sessions in current-state docs and DROP-by-name tests, portable-pty in comments, integration_pty_db.rs, absence-asserts that still embed deleted *_pty_* identifiers) and the missing repo lock. This task adds that audit and makes the live tree pass it. Same IPC semantics, same clicks and labels. No Local anything.
Herdr is the profile authority. sqlite profiles is not source of truth (the table is DROPped). projects / project_groups / checkout_notes stay in 2code sqlite. Default-runtime switch and deleting Local/PTY/profiles rows already shipped in #436 — do not re-litigate or re-add them. Never let Local and Herdr own the same worktree (Local is gone; do not bring it back). Do not change interaction. Naming leftover identifiers is not a click/label redesign.
This is #463 Task 3, not #394 Task 3 (#404), not #436 Task 3 (#441), and not #458 Task 3 (#461). Do not implement or close those tickets here.
Dependencies: Parent plan #463. Prerequisites: #464 (Task 1), #465 (Task 2). Stack on task-2-delete-twocode-runtime. Open task tickets from #394 / #436 / #458, leftover gaps (#396, #397, #398, #399, #401), line-count trackers, and #466 (share the user Herdr session) are out of scope.
Work to complete
Clear leftover live pty vocabulary so the lock can pass
Parent-plan grep -rn "pty" is the intent (live tree, not applied migration history). Do not run that literal command as the lock: it matches empty / is_empty / empty.tsx. Use a word-boundary scan (\\bpty) plus the exclusions below. Uppercase PTY in docs/herdr-integration.md that means Herdr’s own pane process (DSR/DA “as PTY input”, workspace.close kills the pane PTY) stays — that is Herdr ownership, not Local vocabulary.
Rewrite current-state text that still names deleted identifiers (pty_sessions, pty_output_chunks, pty_logs, handler/pty.rs / infra::pty / service::pty, portable-pty, create_pty_session / attach_pty_output / …) as if they were live, or as the only way to say “gone”:
Production comments: session.rs (“Not a sqlite pty_sessions row”), runtime.rs / herdr.rs module docs, handler/shell.rs (portable_pty / ConPTY spawn — keep the App Execution Alias skip; rewrite the comment so it does not cite a deleted spawn path).
Rename live test identifiers that still say pty: src-tauri/tests/integration_pty_db.rs (file + pty_sessions_table_is_dropped), *_local_pty* / production_source_has_no_local_pty_runtime / list_omits_leftover_sqlite_pty_sessions / drop_pty_sessions_keeps_projects_and_notes test names. Behavior stays.
Do not edit src-tauri/migrations/. Do not edit openspec/changes/archive/. Do not sweep website/ blogs or live openspec/specs/ (not application code; not this lock’s tree).
Replace deleted-name absence-asserts with durable invariants
Same rule as Task 2: a test that only contains("pty_sessions") / contains("create_pty_session") / contains("portable-pty") / contains("INSERT INTO pty_sessions") keeps the deleted vocabulary in the live tree and will fail the lock.
Current schema: after embedded migrations, user tables are exactly projects, project_groups, checkout_notes (plus Diesel’s schema-migrations table). Rewrite integration_pty_db.rs (after rename), db.rsinit_db / drop_pty_sessions_keeps_projects_and_notes, and herdr.rssqlite_session_ids() to that allowlist. Re-adding a session or profile table fails the allowlist without naming the dropped table.
docs_client_mode.rs, runtime.rsproduction_source_has_no_local_pty_runtime, herdr.rsgui_detach_is_not_pane_close / stream_pty_output negatives, terminalTransport.test.tsgetPtySessionHistory / restorePtySession negatives: pin current names and structure (terminal IPC, TerminalSessionRecord, handler/terminal.rs, Herdr-only RuntimeBackend). Do not keep a forbidden-string list of deleted *_pty_* IPC.
Keep/strengthen existing structure proofs that name deleted types only if those literals are not pty / the deleted flag: LocalAdapter, RuntimeBackend::Local, mod local, select_gui_backend does not read env/argv (Task 2). The new audit owns “these must not return”.
Applied-history exception (exclude from the vocabulary scan, do not rewrite to a lie): src-tauri/tests/integration_migrations.rs and db.rsdrop_profiles_migration_copies_notes seed SQL must still use the historical table name because they replay a pre-DROP schema. That is the same class of history as src-tauri/migrations/.
Add the audit test and state the invariant
Add one Rust test (prefer src-tauri/tests/ or a service integration test) that walks the repo and fails if any of these reappear in the scanned tree:
a Local adapter or RuntimeBackend::Local variant (LocalAdapter, mod local, runtime/local.rs)
a portable-pty / native_pty_system / 2code ConPTY spawn dependency (Cargo.toml / production source; not the Windows App Execution Alias skip in handler/shell.rs)
an env- or flag-selected backend (std::env::var / std::env::args in select_gui_backend / RuntimeSelector / build_gui_runtime — keep Task 2’s distinction: Herdr sidecar extra_env / XDG_CONFIG_HOME is isolation, not backend selection)
a sqlite session/profile store used as authority (live Diesel schema / repo modules / production INSERT/UPDATE of those tables; projects stay)
live pty vocabulary (word-boundary pty, including pty_sessions, portable-pty, create_pty_session)
the deleted runtime-switch name (construct the needle at runtime so the audit source does not contain that flag)
Scan exclusions (document them next to the command): src-tauri/migrations/, src-tauri/tests/integration_migrations.rs, the drop_profiles_migration_copies_notes seed in db.rs, **/target/**, lockfiles, node_modules/, src/generated/, src/paraglide/, src-tauri/binaries/, openspec/, website/.
Construct pty / flag needles in the audit source (format! / concat) so the audit file itself does not reintroduce the vocabulary it forbids.
State the invariant in docs/architecture.md Design Decisions and root AGENTS.md anti-patterns without naming the deleted flag: no Local adapter; no env or CLI flag selects a runtime backend; GUI RuntimeRouter is always Herdr (fail closed); sqlite profile/session tables are not authority; live identifiers do not use Local session-layer names. Keep AGENTS.md / CLAUDE.md copies in sync where they already share that anti-pattern line. Point at the test, not a hand-run ritual.
Report the exact scan command and its output in the implementation reply (empty match list on this branch). Suggested shape (adjust to the test’s real walker): rg -n --hidden -g '!src-tauri/migrations/**' -g '!**/target/**' -g '!**/*lock*' -g '!**/node_modules/**' -g '!src/generated/**' -g '!src/paraglide/**' -g '!src-tauri/binaries/**' -g '!openspec/**' -g '!website/**' -g '!src-tauri/tests/integration_migrations.rs' '\\bpty'
plus the constructed flag scan. The test is the lock; the command is the evidence.
Prove behavior is unchanged
App still builds. Existing suites pass: GUI backend is always Herdr; Herdr-down still fail-closes; New Tab / write / resize / scroll / close / attach still hit RuntimeRouter; restore is still reattach of a live pane_id; projects still round-trip in sqlite; DROP migrations still leave the catalog.
Do not add a Settings runtime toggle, a new env/CLI switch, a Local adapter, or sqlite profiles / session authority.
If line count grows past the estimate, open a tracking issue; do not fold #466 or leftover gaps into this branch.
Likely files and directories
New: a repo-walk audit test under src-tauri/tests/ (or src-tauri/crates/service/tests/) that fails on Local / spawn-dep / env-flag backend / sqlite session-profile authority / live pty vocabulary / the deleted runtime-switch name.
Do not change:src-tauri/migrations/, src-tauri/tests/integration_migrations.rs historical seed SQL (exclude from the scan), sidecar pin v0.9.0, IPC command names, Settings runtime toggle (gone), Git/file-tree/notes/tab UI, lib.rs naming HerdrRuntimeSync, flattened-split mapping, Diesel schema.rs by hand, openspec/, website/, #466 namespace work.
Estimated changes: 250–500 lines total, additions plus deletions, including tests and docs; excluding generated files, lockfile churn and binary artifacts. Material scope growth (rewriting website/ / openspec/, sharing the user Herdr session, leftover capability gaps) should become a separate issue.
Acceptance criteria
A repo-walk audit test fails if any of these reappear in the scanned live tree: Local adapter / RuntimeBackend::Local, portable-pty / ConPTY spawn dependency, env- or flag-selected backend, sqlite session/profile store as authority, word-boundary pty vocabulary, or the deleted runtime-switch name. The implementation reply quotes the exact command and its output (empty matches).
The scan uses word-boundary pty (so empty / is_empty do not fail) and excludes src-tauri/migrations/, lockfiles, target/, node_modules/, generated/paraglide/binaries, openspec/, website/, integration_migrations.rs, and the pre-DROP seed in db.rs. It does not exclude current-state docs, AGENTS.md, production comments, or non-history tests.
Live current-state docs and AGENTS.md / CLAUDE.md copies describe Herdr-only RuntimeRouter and live pane_id sessions without advertising deleted pty_* module/IPC/table names as live vocabulary. The invariant is stated in docs/architecture.md and AGENTS.md without naming the deleted flag. Copies that already share text stay in sync.
Current-schema tests assert the live sqlite allowlist (projects / project_groups / checkout_notes) instead of grepping a dropped table name. Historical migration filenames and integration_migrations.rs seed SQL stay. TWOCODE_RUNTIME still appears nowhere (Task 2); the new test keeps it that way without putting that literal in docs.
No behavior change. No Local adapter / portable-pty spawn / new env-flag backend. sqlite profiles is not source of truth. projects still round-trip in sqlite. No second events.subscribe. lib.rs still does not name HerdrRuntimeSync. v0.9.0 pin unchanged. GUI exit still does not server stop.
Named UX exceptions: none new. Existing Herdr-backed exceptions stay (route ids workspace_id; tab ids pane_id; splits flattened as extra tabs; non-git New Profile is folder workspace.create; Herdr-down New Tab errors). The audit and vocabulary cleanup are not a click/label redesign.
Migrations under src-tauri/migrations/ are untouched. openspec/ and website/ are untouched.
Tests: cargo test --workspace from src-tauri (or cargo test --workspace --exclude code where GTK is unavailable), including the new audit. Frontend lint/typecheck/tests if terminalTransport.test.ts (or other frontend fixtures) change. bun run typegen only if IPC signatures change (none expected); do not hand-edit src/generated/.
No push. No pull request.
Out of scope
Parent-plan Task 1 (session-layer rename) and Task 2 (flag-name purge); already done on this stack.
Renaming or editing files under src-tauri/migrations/. Rewriting integration_migrations.rs historical seed SQL.
Reintroducing a Local adapter, Settings runtime toggle, portable-pty spawn, or sqlite profiles / session-table authority.
Changing the Herdr-only runtime decision, the v0.9.0 pin, GUI exit / server stop, flattened-split mapping, IPC command names, or Git/file-tree/notes/tab UI.
Sweeping website/ blogs or openspec/ specs/archive. Implementing #466.
No behavior change. This is a documentation/test lock. Same IPC semantics, same clicks and labels.
No Local anything. Do not reintroduce an adapter, env flag, CLI flag, dependency, or fallback path, not even behind a cfg or a comment — including a differently named successor to the deleted runtime switch.
Migrations are history. Do not rename or edit files under src-tauri/migrations/.
Frontend callers move with the commands. This task must not rename IPC; if an accidental rename happens, update generated bindings and every caller in the same commit.
Do not treat sqlite profiles as source of truth. projects stay in 2code sqlite.
Never let Local and Herdr own the same worktree (Local is already removed; do not bring it back).
Do not change interaction unless the old UX cannot be backed by Herdr. This task has no named interaction exception.
One task; stack on task-2-delete-twocode-runtime. Do not push. Do not open a PR.
Why this is next
#463 has three tasks. Task 1 (#464) and Task 2 (#465) are done on task-2-delete-twocode-runtime. Task 3 is the remaining prove-and-lock audit; the phase is not closed until that test exists and leftover live pty vocabulary is gone. The leftover open gaps (#396/#397/#398/#399/#401) are Linux-unverifiable or upstream-capability leftovers, not in-flight replacements for this work. #461 is #458 Task 3 (line-count trackers). #404 is #394 Task 3 (sidecar). #441 is #436 Task 3 (profile list). #466 is a different parent plan.
Summary
Prove and lock Herdr-only for parent plan #463. Local PTY, the env/CLI switch, and sqlite session/profile authority are already gone (#436 Tasks 8–9 / #451 / #452). Task 1 (#464 on
task-1-rename-pty-layer) renamed the session layer offpty. Task 2 (#465 ontask-2-delete-twocode-runtime) deleted everyTWOCODE_RUNTIME/--twocode-runtimetrace. What survives is leftover live vocabulary (pty_sessionsin current-state docs and DROP-by-name tests,portable-ptyin comments,integration_pty_db.rs, absence-asserts that still embed deleted*_pty_*identifiers) and the missing repo lock. This task adds that audit and makes the live tree pass it. Same IPC semantics, same clicks and labels. No Local anything.Herdr is the profile authority. sqlite
profilesis not source of truth (the table is DROPped).projects/project_groups/checkout_notesstay in 2code sqlite. Default-runtime switch and deleting Local/PTY/profilesrows already shipped in #436 — do not re-litigate or re-add them. Never let Local and Herdr own the same worktree (Local is gone; do not bring it back). Do not change interaction. Naming leftover identifiers is not a click/label redesign.This is #463 Task 3, not #394 Task 3 (#404), not #436 Task 3 (#441), and not #458 Task 3 (#461). Do not implement or close those tickets here.
Dependencies: Parent plan #463. Prerequisites: #464 (Task 1), #465 (Task 2). Stack on
task-2-delete-twocode-runtime. Open task tickets from #394 / #436 / #458, leftover gaps (#396, #397, #398, #399, #401), line-count trackers, and #466 (share the user Herdr session) are out of scope.Work to complete
Clear leftover live
ptyvocabulary so the lock can passgrep -rn "pty"is the intent (live tree, not applied migration history). Do not run that literal command as the lock: it matchesempty/is_empty/empty.tsx. Use a word-boundary scan (\\bpty) plus the exclusions below. UppercasePTYindocs/herdr-integration.mdthat means Herdr’s own pane process (DSR/DA “as PTY input”,workspace.closekills the pane PTY) stays — that is Herdr ownership, not Local vocabulary.pty_sessions,pty_output_chunks,pty_logs,handler/pty.rs/infra::pty/service::pty,portable-pty,create_pty_session/attach_pty_output/ …) as if they were live, or as the only way to say “gone”:docs/architecture.md,docs/configuration.md,docs/data-flow.md,docs/api-reference.md,docs/herdr-integration.md(current-state sentences and task-status rows; keep verified probe facts and v0.9.0). Say sqlite session/profile tables are DROPped and sessions are livepane_ids; do not keep the applied SQL name as live vocabulary. Applied names remain insrc-tauri/migrations/.AGENTS.md/CLAUDE.md,src-tauri/AGENTS.md/src-tauri/CLAUDE.md(including thetests/tree linepty_db),src-tauri/crates/service/AGENTS.md/ CLAUDE.md twin. Keep copies in each directory in sync.session.rs(“Not a sqlitepty_sessionsrow”),runtime.rs/herdr.rsmodule docs,handler/shell.rs(portable_pty/ ConPTY spawn — keep the App Execution Alias skip; rewrite the comment so it does not cite a deleted spawn path).pty:src-tauri/tests/integration_pty_db.rs(file +pty_sessions_table_is_dropped),*_local_pty*/production_source_has_no_local_pty_runtime/list_omits_leftover_sqlite_pty_sessions/drop_pty_sessions_keeps_projects_and_notestest names. Behavior stays.src-tauri/migrations/. Do not editopenspec/changes/archive/. Do not sweepwebsite/blogs or liveopenspec/specs/(not application code; not this lock’s tree).Replace deleted-name absence-asserts with durable invariants
contains("pty_sessions")/contains("create_pty_session")/contains("portable-pty")/contains("INSERT INTO pty_sessions")keeps the deleted vocabulary in the live tree and will fail the lock.projects,project_groups,checkout_notes(plus Diesel’s schema-migrations table). Rewriteintegration_pty_db.rs(after rename),db.rsinit_db/drop_pty_sessions_keeps_projects_and_notes, andherdr.rssqlite_session_ids()to that allowlist. Re-adding a session or profile table fails the allowlist without naming the dropped table.docs_client_mode.rs,runtime.rsproduction_source_has_no_local_pty_runtime,herdr.rsgui_detach_is_not_pane_close/stream_pty_outputnegatives,terminalTransport.test.tsgetPtySessionHistory/restorePtySessionnegatives: pin current names and structure (terminal IPC,TerminalSessionRecord,handler/terminal.rs, Herdr-onlyRuntimeBackend). Do not keep a forbidden-string list of deleted*_pty_*IPC.pty/ the deleted flag:LocalAdapter,RuntimeBackend::Local,mod local,select_gui_backenddoes not read env/argv (Task 2). The new audit owns “these must not return”.src-tauri/tests/integration_migrations.rsanddb.rsdrop_profiles_migration_copies_notesseed SQL must still use the historical table name because they replay a pre-DROP schema. That is the same class of history assrc-tauri/migrations/.Add the audit test and state the invariant
src-tauri/tests/or a service integration test) that walks the repo and fails if any of these reappear in the scanned tree:RuntimeBackend::Localvariant (LocalAdapter,mod local,runtime/local.rs)portable-pty/native_pty_system/ 2code ConPTY spawn dependency (Cargo.toml / production source; not the Windows App Execution Alias skip inhandler/shell.rs)std::env::var/std::env::argsinselect_gui_backend/RuntimeSelector/build_gui_runtime— keep Task 2’s distinction: Herdr sidecarextra_env/XDG_CONFIG_HOMEis isolation, not backend selection)INSERT/UPDATEof those tables;projectsstay)ptyvocabulary (word-boundarypty, includingpty_sessions,portable-pty,create_pty_session)src-tauri/migrations/,src-tauri/tests/integration_migrations.rs, thedrop_profiles_migration_copies_notesseed indb.rs,**/target/**, lockfiles,node_modules/,src/generated/,src/paraglide/,src-tauri/binaries/,openspec/,website/.pty/ flag needles in the audit source (format!/ concat) so the audit file itself does not reintroduce the vocabulary it forbids.docs/architecture.mdDesign Decisions and rootAGENTS.mdanti-patterns without naming the deleted flag: no Local adapter; no env or CLI flag selects a runtime backend; GUIRuntimeRouteris always Herdr (fail closed); sqlite profile/session tables are not authority; live identifiers do not use Local session-layer names. Keep AGENTS.md / CLAUDE.md copies in sync where they already share that anti-pattern line. Point at the test, not a hand-run ritual.rg -n --hidden -g '!src-tauri/migrations/**' -g '!**/target/**' -g '!**/*lock*' -g '!**/node_modules/**' -g '!src/generated/**' -g '!src/paraglide/**' -g '!src-tauri/binaries/**' -g '!openspec/**' -g '!website/**' -g '!src-tauri/tests/integration_migrations.rs' '\\bpty'plus the constructed flag scan. The test is the lock; the command is the evidence.
Prove behavior is unchanged
RuntimeRouter; restore is still reattach of a livepane_id;projectsstill round-trip in sqlite; DROP migrations still leave the catalog.profiles/ session authority.Likely files and directories
src-tauri/tests/(orsrc-tauri/crates/service/tests/) that fails on Local / spawn-dep / env-flag backend / sqlite session-profile authority / liveptyvocabulary / the deleted runtime-switch name.src-tauri/tests/integration_pty_db.rs→ a schema-allowlist test file whose name does not containpty.src-tauri/crates/infra/src/db.rscurrent-schema DROP asserts;src-tauri/crates/service/src/runtime.rs/runtime/herdr.rsleftoverptyidentifiers andsqlite_session_ids;src-tauri/crates/service/tests/docs_client_mode.rs;src/features/terminal/lib/terminalTransport.test.tsif it still embeds deleted*Pty*IPC names.src-tauri/crates/model/src/session.rs, runtime/herdr module docs,src-tauri/src/handler/shell.rsApp Execution Alias comment.docs/architecture.md,docs/configuration.md,docs/data-flow.md,docs/api-reference.md,docs/herdr-integration.md(vocabulary / task-status rows only),AGENTS.md,CLAUDE.md,src-tauri/AGENTS.md,src-tauri/CLAUDE.md,src-tauri/crates/service/AGENTS.md(+ CLAUDE.md twin).src-tauri/migrations/,src-tauri/tests/integration_migrations.rshistorical seed SQL (exclude from the scan), sidecar pin v0.9.0, IPC command names, Settings runtime toggle (gone), Git/file-tree/notes/tab UI,lib.rsnamingHerdrRuntimeSync, flattened-split mapping, Dieselschema.rsby hand,openspec/,website/, #466 namespace work.Estimated changes: 250–500 lines total, additions plus deletions, including tests and docs; excluding generated files, lockfile churn and binary artifacts. Material scope growth (rewriting
website//openspec/, sharing the user Herdr session, leftover capability gaps) should become a separate issue.Acceptance criteria
RuntimeBackend::Local,portable-pty/ ConPTY spawn dependency, env- or flag-selected backend, sqlite session/profile store as authority, word-boundaryptyvocabulary, or the deleted runtime-switch name. The implementation reply quotes the exact command and its output (empty matches).pty(soempty/is_emptydo not fail) and excludessrc-tauri/migrations/, lockfiles,target/,node_modules/, generated/paraglide/binaries,openspec/,website/,integration_migrations.rs, and the pre-DROP seed indb.rs. It does not exclude current-state docs, AGENTS.md, production comments, or non-history tests.RuntimeRouterand livepane_idsessions without advertising deletedpty_*module/IPC/table names as live vocabulary. The invariant is stated indocs/architecture.mdandAGENTS.mdwithout naming the deleted flag. Copies that already share text stay in sync.projects/project_groups/checkout_notes) instead of grepping a dropped table name. Historical migration filenames andintegration_migrations.rsseed SQL stay.TWOCODE_RUNTIMEstill appears nowhere (Task 2); the new test keeps it that way without putting that literal in docs.profilesis not source of truth.projectsstill round-trip in sqlite. No secondevents.subscribe.lib.rsstill does not nameHerdrRuntimeSync. v0.9.0 pin unchanged. GUI exit still does notserver stop.workspace_id; tab idspane_id; splits flattened as extra tabs; non-git New Profile is folderworkspace.create; Herdr-down New Tab errors). The audit and vocabulary cleanup are not a click/label redesign.src-tauri/migrations/are untouched.openspec/andwebsite/are untouched.cargo test --workspacefromsrc-tauri(orcargo test --workspace --exclude codewhere GTK is unavailable), including the new audit. Frontend lint/typecheck/tests ifterminalTransport.test.ts(or other frontend fixtures) change.bun run typegenonly if IPC signatures change (none expected); do not hand-editsrc/generated/.Out of scope
src-tauri/migrations/. Rewritingintegration_migrations.rshistorical seed SQL.profiles/ session-table authority.server stop, flattened-split mapping, IPC command names, or Git/file-tree/notes/tab UI.website/blogs oropenspec/specs/archive. Implementing #466.Standing constraints
src-tauri/migrations/.profilesas source of truth.projectsstay in 2code sqlite.profilesrows already shipped in Plan: 2code as a Herdr client (profiles derived from Herdr) #436; this task does not re-litigate those decisions and does not change them.task-2-delete-twocode-runtime. Do not push. Do not open a PR.Why this is next
#463 has three tasks. Task 1 (#464) and Task 2 (#465) are done on
task-2-delete-twocode-runtime. Task 3 is the remaining prove-and-lock audit; the phase is not closed until that test exists and leftover liveptyvocabulary is gone. The leftover open gaps (#396/#397/#398/#399/#401) are Linux-unverifiable or upstream-capability leftovers, not in-flight replacements for this work. #461 is #458 Task 3 (line-count trackers). #404 is #394 Task 3 (sidecar). #441 is #436 Task 3 (profile list). #466 is a different parent plan.