The Evaluation Rubric
Score yourself honestly. This rubric is for you; a generous self-assessment costs you the only thing it could have given.
Scoring: 0 = absent · 1 = attempted · 2 = works · 3 = works and I can explain every part.
The only score that matters is 3. A 2 means you have a program; a 3 means you have understanding, which was the point.
Part 1: Unix Process and Terminal Semantics (Section 1)
| # | Criterion | 0 | 1 | 2 | 3 |
|---|---|---|---|---|---|
| 1.1 | A PTY pair allocated with raw syscalls, no PTY crate | ||||
| 1.2 | The child's session, controlling terminal, and fds set up correctly | ||||
| 1.3 | The complete spawn syscall list, in order, with each one's failure mode, from memory | ||||
| 1.4 | termios raw mode with restore on every exit path including panic | ||||
| 1.5 | A single poll loop over stdin, master, and signals | ||||
| 1.6 | Async-signal-safe signal handling (one write in the handler) | ||||
| 1.7 | SIGWINCH → TIOCGWINSZ → TIOCSWINSZ, verified with vim and top | ||||
| 1.8 | SIGCHLD → waitpid(WNOHANG) in a loop; exit code propagated | ||||
| 1.9 | Linux EIO vs. macOS EOF handled explicitly, with a comment naming both | ||||
| 1.10 | Partial writes handled; a 100 KB paste arrives intact | ||||
| 1.11 | All seven Section 1 experiments performed, with written predictions | ||||
| 1.12 | Job control explained: sessions, groups, foreground group, tcsetpgrp, SIGHUP |
Section 1 total: ___ / 36
Part 2: The Terminal Core (Section 2)
| # | Criterion | 0 | 1 | 2 | 3 |
|---|---|---|---|---|---|
| 2.1 | A real VT state machine with every state, not if chains | ||||
| 2.2 | The split-input property holds at chunk sizes 1, 2, 3, 7, 13, ∞ over the whole corpus | ||||
| 2.3 | UTF-8 decoding inside Ground, with incomplete sequences buffered | ||||
| 2.4 | Parameters, intermediates, and OSC payloads all bounded | ||||
| 2.5 | A fuzz target run ≥10 minutes clean, corpus committed | ||||
| 2.6 | Pending wrap implemented and explicitly tested | ||||
| 2.7 | Scroll regions, with sub-region scrolls excluded from scrollback | ||||
| 2.8 | The alternate screen, with no scrollback, enforced structurally | ||||
| 2.9 | Erase honoring the current background color | ||||
| 2.10 | SGR: all attributes, 16/256/truecolor, both semicolon and colon forms | ||||
| 2.11 | Wide characters with the spacer invariant, property-tested | ||||
| 2.12 | Combining marks absorbing, bounded, leading-mark case handled | ||||
| 2.13 | OSC: title (sanitized), hyperlinks (interned, scheme-checked), clipboard (policy) | ||||
| 2.14 | Terminal replies queued, not written; rate-limited | ||||
| 2.15 | Damage tracking, including the two-row cursor rule | ||||
| 2.16 | ≥10 golden cases with checked-in snapshots |
Section 2 total: ___ / 48
Part 3: The Graphical Frontend (Section 3)
| # | Criterion | 0 | 1 | 2 | 3 |
|---|---|---|---|---|---|
| 3.1 | A window with a working shell; vim, top, and yes all behave | ||||
| 3.2 | Correct font metrics; you can state ascent/descent/gap/advance for your font | ||||
| 3.3 | The baseline rule; no clipped descenders | ||||
| 3.4 | A glyph atlas with a measured hit rate >99% | ||||
| 3.5 | Damage tracking with a printable dirty-row count | ||||
| 3.6 | Idle CPU ~0%, verified with top | ||||
| 3.7 | yes does not freeze the UI (read/render decoupled) | ||||
| 3.8 | Resize in the correct order, with HiDPI handled | ||||
| 3.9 | Every key in the encoding table implemented and unit-tested | ||||
| 3.10 | DECCKM honored, including the modified-arrow asymmetry | ||||
| 3.11 | Bracketed paste with envelope-escape protection | ||||
| 3.12 | Mouse reporting with the Shift bypass and 1-based coordinates | ||||
| 3.13 | Selection with wrapped-line joining and no trailing padding | ||||
| 3.14 | All modes reset on every exit path |
Section 3 total: ___ / 42
Part 4: The Multiplexer (Section 4)
| # | Criterion | 0 | 1 | 2 | 3 |
|---|---|---|---|---|---|
| 4.1 | N sessions, all read and parsed, input to the active one only | ||||
| 4.2 | A layout tree with exact tiling, property-tested over 1,000 trees | ||||
| 4.3 | Per-pane resize in the correct order, with the no-op guard | ||||
| 4.4 | Compositing with borders, junctions, and a status line | ||||
| 4.5 | A correctly daemonized server (double fork, setsid, SIGPIPE ignored) | ||||
| 4.6 | A socket in a per-user directory, 0700, ownership verified, stale sockets reclaimed | ||||
| 4.7 | A framed protocol with a version handshake and round-trip tests | ||||
| 4.8 | kill -9 on the client leaves shells running, proven with ps | ||||
| 4.9 | Panes read and parsed with zero clients attached | ||||
| 4.10 | Attach repaints from state, verified with the alt-screen case | ||||
| 4.11 | A documented multi-client resize policy, with the zero-client rule | ||||
| 4.12 | Two clients rendering and typing; a stalled client blocks nobody | ||||
| 4.13 | The prefix key parsed client-side, with the literal escape | ||||
| 4.14 | cargo tree -p terminal-mux shows no GUI crates |
Section 4 total: ___ / 42
Part 5: Architecture (Section 5)
| # | Criterion | 0 | 1 | 2 | 3 |
|---|---|---|---|---|---|
| 5.1 | The boundary audit passing, in CI | ||||
| 5.2 | terminal-protocol and terminal-core build for wasm32 | ||||
| 5.3 | #![deny(missing_docs)] with the docs actually written | ||||
| 5.4 | Four consumers of one unmodified core | ||||
| 5.5 | The forty-line headless simulator | ||||
| 5.6 | Configuration passed down, never a global | ||||
| 5.7 | Platform behavior as configuration, not cfg | ||||
| 5.8 | A boundary-defense document with "known tensions" | ||||
| 5.9 | Every pub item justifiable in one sentence | ||||
| 5.10 | (Optional) A C ABI with a CI-tested C example |
Section 5 total: ___ / 30
Part 6: Testing and Observability
| # | Criterion | 0 | 1 | 2 | 3 |
|---|---|---|---|---|---|
| 6.1 | Unit tests: normal, boundary, and degenerate for every sequence | ||||
| 6.2 | Property tests over five structural invariants | ||||
| 6.3 | The four required PTY integration tests | ||||
| 6.4 | Golden tests with the UPDATE_GOLDEN discipline documented | ||||
| 6.5 | Differential tests against vte, with divergences documented | ||||
| 6.6 | Fuzz targets including the chunking-equivalence assertion | ||||
| 6.7 | terminal-debugger with all nine capabilities | ||||
| 6.8 | Debug channels: switchable, cheap when off, never to the debugged terminal | ||||
| 6.9 | Record/replay, with the bytewise mode | ||||
| 6.10 | The compatibility matrix for eleven programs | ||||
| 6.11 | The test suite runs in under ten seconds |
Section 6 total: ___ / 33
Part 7: Understanding (The Part That Matters)
Scored by explanation, not by code. Answer out loud, from memory, to someone else.
| # | Criterion | 0 | 1 | 2 | 3 |
|---|---|---|---|---|---|
| 7.1 | Define TTY, PTY, line discipline, emulator, shell, and multiplexer without using each other | ||||
| 7.2 | Trace one keystroke through all fifteen layers of the mux path | ||||
| 7.3 | Explain who echoes, and prove it in one command | ||||
| 7.4 | Explain Ctrl+C: the byte, the flag, the signal, the exact recipients | ||||
| 7.5 | Explain why tmux keeps shells alive, in one sentence | ||||
| 7.6 | Explain why a mux server contains a terminal emulator | ||||
| 7.7 | Explain pending wrap and its visible bug | ||||
| 7.8 | Explain why UTF-8 decoding belongs inside the parser's ground state | ||||
| 7.9 | Explain why repaint-from-state beats replay, with the alt-screen case | ||||
| 7.10 | Defend every crate boundary with the capability it protects | ||||
| 7.11 | Explain what breaks with pipes instead of a PTY — ten concrete differences | ||||
| 7.12 | Who owns the terminal screen? One sentence, and defend it |
Section 7 total: ___ / 36
Part 8: The Write-Up
| # | Criterion | 0 | 1 | 2 | 3 |
|---|---|---|---|---|---|
| 8.1 | Scope stated honestly, including what does not work | ||||
| 8.2 | Architecture explained well enough to predict where a bug lives | ||||
| 8.3 | The hardest bug: a case where your model was wrong, not a typo | ||||
| 8.4 | Four design decisions with alternatives, criteria, and costs | ||||
| 8.5 | "What I would do differently", specific and actionable | ||||
| 8.6 | Real measurements, with the method stated | ||||
| 8.7 | "What I still do not understand", named honestly |
Section 8 total: ___ / 21
The Total
Section 1 Unix semantics ___ / 36
Section 2 Terminal core ___ / 48
Section 3 Graphical frontend ___ / 42
Section 4 Multiplexer ___ / 42
Section 5 Architecture ___ / 30
Section 6 Testing & tooling ___ / 33
Section 7 Understanding ___ / 36
Section 8 Write-up ___ / 21
─────────────────────────────────────────
TOTAL ___ / 288
| Range | Meaning |
|---|---|
| 250–288 | You could contribute meaningfully to Alacritty, WezTerm, Ghostty, or zellij tomorrow. |
| 200–249 | You understand terminals better than most people who work on them. Find the gaps in Section 7 and close them. |
| 150–199 | You built it and it works. The understanding is uneven — re-read the chapters behind your lowest scores. |
| 100–149 | You have a working program and a partial model. Redo the experiments; that is where the gap is. |
| < 100 | You skipped the experiments, or you used a crate you were told not to use. Both are recoverable; go back. |
The Weighting, Explained
Section 7 is worth as much as Section 1. That is deliberate.
You can build a working terminal by copying code. You cannot explain one without having understood it. The rubric is weighted so that a beautiful implementation you cannot explain scores lower than a rougher one you can — because the second engineer can fix it at 3 a.m. and the first cannot.
Learning Priority #10 was:
Build enough of each part manually that I can explain it without relying on abstractions I do not understand.
Section 7 is that priority, scored.
Honest Self-Assessment: A Method
Scoring yourself is hard. Two techniques that make it less so:
1. The explanation test. For every criterion you want to score 3, explain it out loud to someone who does not know terminals — or to a recording. If you hesitate, hedge, or say "it just works," it is a 2.
2. The modification test. For every criterion you want to score 3, name a change to that component and estimate how long it would take. If you cannot estimate, you do not understand it well enough to score 3.
"Add DECSCUSR (cursor shape) support." → 20 minutes. I know where. ✓ 3
"Change the Cell representation to interned." → I would have to go and look. 2
"Make resize reflow instead of truncate." → No idea where to start. 1
A Note on Scoring Zero
A zero on an optional criterion (the C ABI, GPU rendering) is fine and expected. A zero on a required one is information: it tells you exactly which chapter to re-read and which experiment to redo.
The rubric is not a grade. It is a map of what you know, and its only purpose is to point at the parts you do not.
Return to the capstone, or to the introduction to re-answer the twelve questions.