Skip to content

Run the suite on Linux and settle the Windows decision - #31

Open
QuintinBotes wants to merge 7 commits into
mainfrom
linux-ci
Open

Run the suite on Linux and settle the Windows decision#31
QuintinBotes wants to merge 7 commits into
mainfrom
linux-ci

Conversation

@QuintinBotes

Copy link
Copy Markdown
Owner

What this does

Two changes that belong together: running CI on Linux for the first time, and recording that Windows is not in the roadmap.

Linux in CI

§3.1 says the honest blocker for Linux is not macOS-specific code — the PTY layer has no macOS assumptions — it is that nothing has been run there. This PR runs it.

The CI job installs the webview and GTK libraries Tauri links against (because tervin-app is in the workspace and even cargo test needs them), plus zsh and vim, because the terminal tests drive real ones and skip silently when absent. A green run that skipped the tests that matter would be worse than a red one.

Clippy runs on Linux as well as macOS: cfg differences mean each platform compiles code the other does not, so a lint can be clean on one and not the other.

The README's platform claim does not change here. A green CI run proves the tests pass on Linux, not that the product is usable there. §3.1's exit criterion is a person having actually used it for a day.

Expect this red first time. That is the point: running CI on a new platform to find out what breaks, rather than assuming.

Windows settled as a refusal

ConPTY covers the PTY layer, but shell integration has no equivalent to ZDOTDIR, and Tervin's design assumes a Unix shell throughout — every agent runtime, every shell-integration hook, and the completion design (§3.2) depend on it. Solving that cleanly requires a design that does not exist, and macOS plus Linux is a coherent scope.

Windows moved from §3.1 (work to do) to §5 (settled refusals) with reasoning. Six doc locations updated: §1 baseline, §2 Warp gap table, §3.1 (renamed, Windows content removed, exit criterion updated), §5, §6 ordered plan, README and SECURITY known gaps.

Test plan

  • CI runs on Ubuntu and either passes or produces actionable failures
  • Clippy is clean on Linux (or failures are real and fixable)
  • README platform claim is unchanged
  • Windows appears in §5 with reasoning that matches the code's actual constraints

🤖 Generated with Claude Code

QuintinBotes and others added 3 commits August 3, 2026 00:32
§3.1 says the honest blocker for Linux is not that the code is macOS-specific,
it is that nothing has been run there. So this runs it.

The job installs the webview and GTK libraries Tauri links against, because
tervin-app is in the workspace and even `cargo test` needs them, plus zsh and
vim, because the terminal tests drive real ones and skip silently when they are
absent. A green run that skipped the tests that matter would be worse than a
red one.

Clippy runs here as well as on macOS: `cfg` differences mean each platform
compiles code the other does not, so a lint can be clean on one and not the
other.

The README's platform claim does not change. A green CI run proves the tests
pass on Linux, not that the product is usable there, and §3.1's exit criterion
is a person having actually used it for a day.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Windows is not in the roadmap: ConPTY covers the PTY layer but shell
integration has no equivalent to ZDOTDIR, and Tervin's design assumes a
Unix shell throughout. macOS and Linux is a coherent scope; Windows is
not. Moved to §5 with reasoning.

Six locations updated:
- §1 baseline: no Linux build (in CI; not yet claimed), no Windows
- §2 Warp gap table: Linux/close it, Windows/deliberately not
- §3.1: renamed to 'Linux build', removed Windows content, exit criterion
  is 'both' not 'all three'
- §5: Windows added with rationale
- §6 ordered plan: Linux in CI (not Linux and Windows)
- README.md and SECURITY.md: Linux not yet claimed, Windows not a target

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
§5 is for things Tervin will not build. Windows is not one of them: nothing in
the design forecloses it, and the cost is a shell-integration story nobody has
written rather than a decision against it. ConPTY already covers the PTY layer
behind portable-pty; the blocker is that there is no ZDOTDIR equivalent, so the
automatic injection in §3.1 does not carry over and §3.2's completion design
assumes a Unix shell.

So it moves to §6 "Later, or never" with that reasoning, and the comparison
table points at §6 instead of §5. The README says "not a target for now" and
names the blocker rather than implying the door is shut.

Linux stays unclaimed. CI running the suite is not the same as somebody having
used it, and §3.1's own exit criterion is a day of real use.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
QuintinBotes and others added 4 commits August 3, 2026 01:10
Linux CI failed on `a_large_burst_of_output_arrives_intact` with "line-2500
missing from a 5000-line burst". It reads as the coalescing pump dropping a
chunk under load. It is not: the pump never drops anything, and the test never
got as far as the burst.

A PTY echoes what is typed. The test typed a command ending in `echo BURST-DONE`
and then collected until the text contained `BURST-DONE`, which the echo of that
very command satisfies. Collection stopped 81 bytes in, holding nothing but the
echoed input line, and the missing output was then reported as lost data.

Reproduced in a Linux container and confirmed by dumping the raw stream, which
was exactly:

    "# i=0; while [ $i -lt 5000 ]; do echo line-$i; i=$((i+1)); done; echo BURST-DONE\r\n"

Every marker in this file was written the same way, so this was never specific
to the burst. `a_real_shell_receives_input_and_returns_output` waited for
`tervin-roundtrip-ok` after typing it, and its comment claims it proves output
comes back from a real shell. It did not: the echo alone satisfied it, and the
assertion after it read the input back. Same for the ordering test and the
shell-integration markers test, which also failed on Linux for this reason
rather than for two separate ones.

The markers are now typed split by an empty quote, so the echo reads
`B''URST-DONE` while the shell still prints `BURST-DONE` and only real output
can match. That keeps the sentinel readable at both ends, which a random nonce
would not.

macOS passed throughout, which is the whole argument for running this suite on
Linux: the shells differ, the timing differs, and a test that had never once
exercised the thing it names went unnoticed for as long as one platform was
generous about it.

No production code changes. terminal-core 7 of 7 pass on both platforms.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
With the PTY tests fixed, the Linux job got as far as the Blocks end-to-end
suite and failed six of its eight tests. The clearest one:

    left:  "cho tervin-block-one"
    right: "echo tervin-block-one"

The leading `e` was gone, and the assertion called it a command that "did not
survive the round trip", which points at the marker pipeline. The pipeline was
fine. The test slept a fixed 1200ms before typing, and zsh's line editor calls
`tcsetattr` with a flush when it initialises, which discards whatever has
already been typed. On a slower machine that sleep does not merely wait too
little; it eats the front of the first command.

So the sleeps are gone and the test waits for `133;B`, which the injected
integration emits once the prompt is drawn and the shell is reading. Measured on
zsh: 485ms for the first prompt and 17ms for each one after, against a guess of
1200ms that was both too slow and not slow enough.

Bash does not send `133;B` here, which is worth recording beyond this file. It
is a login shell and the marker is appended to `PS1` by the injected rc, so
anything setting `PS1` afterwards drops it. Verified rather than assumed: bash
waited out both waits while zsh answered in milliseconds. Blocks still form for
bash, because the other 133 markers arrive, but a feature keyed on `PromptEnd`
is getting nothing from that shell.

A shell that reports no prompt is therefore asked once and then left alone,
falling back to the spacing this file used before. Asking again only buys
another wait for an answer that is not coming, and doing that per command is
what turned a 32-second file into a 90-second one on the first attempt.

The macOS bash test was already 31.9s before any of this: bash 3.2 forms no
Blocks, which the test explicitly allows, so the collection loop waits out its
deadline. That is unchanged and not introduced here. The file goes 31.9s to
35.5s on macOS, and the zsh tests it exists for are now exact rather than timed.

8 of 8 pass on macOS, and on Linux under zsh 5.9 and bash 5.2.37.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Waiting for `133;B` was not enough, and CI said so with the same `cho` where the
test typed `echo`. The marker lives inside `PS1`, so it is emitted when the
prompt is *printed*. zsh's line editor then calls `tcsetattr` with a flush,
which discards whatever arrived in between. A printed prompt and a reading shell
are different states, and the first character of the first command was landing
in the gap between them.

That gap is a function of load, which is why this reproduced on CI running
`cargo test --workspace` and never once when this crate was run on its own.

So readiness is no longer inferred from output. The test sends a newline and
waits for the prompt drawn in reply: a prompt that appears *after* input was
sent is one the shell could only have drawn by having read it. If that newline
is swallowed too, the shell was not ready and it asks again, up to five times.
An empty line runs no command, so no Block forms and the exact block counts
these tests assert are unchanged.

The point of the change is that it no longer depends on timing at all. The
previous two attempts both replaced one duration with a better duration, which
is the same bet at longer odds.

8 of 8 on macOS, and on Linux under `cargo test --workspace`, which is the load
that produced the failure. Verified in a container before pushing rather than
after, which is what the previous two attempts got wrong.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@QuintinBotes

Copy link
Copy Markdown
Owner Author

Parking this: Linux is deferred, macOS is the focus for now.

Worth recording what it found before it goes quiet, because it earned its keep. Three defects surfaced here, none of which macOS ever showed:

  1. The PTY suite passed on its own echo. Every marker was satisfied by the terminal echoing back the command that was typed, so a_real_shell_receives_input_and_returns_output had never proven output came back from a real shell. The burst test stopped collecting 81 bytes in and reported the un-produced output as dropped data.
  2. The Blocks suite typed into shells that were not ready, losing the leading character of each first command.
  3. A real product bug behind (2): a shell's line editor calls tcsetattr with TCSAFLUSH and discards queued input, so anything Tervin writes to a pane too early is destroyed rather than delayed. That affects restored sessions and commands Tervin issues on the user's behalf, on every platform.

(3) is fixed in #35, along with the test-soundness fixes from this branch, both targeting main. So the valuable half of this work is landing regardless.

What stays here unmerged: the Linux CI job itself, and the doc changes moving Windows to §5 and describing support as macOS-and-Linux. That wording needs revisiting if Linux stays deferred.

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