検証台帳¶
検証計画 の基線と、実機検証で見つかった失敗ごとの処置を記録する。 数値はすべて実行した出力から転記する。未実行のものは「未実行」と書く。
Sections 1 through 3 are historical results for the commits named in each entry. They do not establish that the current working tree passes those checks.
1. 基線(P0)¶
対象コミット: f3a5d87(main と同一)。実行環境: aarch64-darwin。
§3の進捗表にある1420df3はP0基線作業のコミットで、ここに記録した測定対象はf3a5d87である。
1.1 in-process スイート(sandbox 外)¶
コマンド: nix develop --command sbcl --script run-tests.lisp(launchd 経由)
| 実行 | TMPDIR | total | passed | skipped | failed | errored | exit |
|---|---|---|---|---|---|---|---|
| 1 回目 | 既定(/tmp 配下) |
1405 | 1404 | 0 | 0 | 1 | 1 |
| 2 回目 | getconf DARWIN_USER_TEMP_DIR を指定したが nix develop が /tmp/nix-shell.XXXX を作るため実質 /tmp 配下 |
1405 | 1404 | 0 | 0 | 1 | 1 |
1 回目の errored は project filesystem integration without a root > reports missing project
roots through every project command(t/integration/project-missing-root-test.lisp)。
条件は HOST-KIT operation :CALL-WITH-TEMPORARY-DIRECTORY failed on #P"/tmp/nix-shell.XXXX/"、
期待した "No project root found" が出ない。原因はこのホストの /tmp/Makefile で、Makefile は
+project-marker-names+ に含まれる(packages/feature/project/src/domain-project.lisp)。
一時ディレクトリの祖先にマーカーが無いことをテストが前提にしており、Nix sandbox では成立するが
ホスト実行では環境依存になる。2 回目も同一テストが同一条件で errored になり、再現は決定的。処置は §2 に積む。
同じ実行で、main-run-loom 系テストの間に alternate-screen 切り替えと 80x24 の空白フレームが
ジョブの stdout に書き出されている(出力の先頭 ESC[?1049h ESC[2J)。テストが描画先を実端末の
stdout に流している観察であり、判定には影響しない。処置は §2 に積む。
1.2 nix flake check¶
コマンド: nix flake check --print-build-logs。exit 0。aarch64-darwin の 6 check
(default, build, coverage, docs, formatting, paredit-lint)を実行。x86_64-linux は
--all-systems 無しのため省略と警告される。
1.3 PTY E2E(P2 基線)¶
コマンド:
out=$(nix build --no-link --print-out-paths .#default)
HOME=$(mktemp -d) LOOM_BINARY="$out/bin/loom" python3 t/e2e/loom-test.py
結果: 12 件 PASS、12 E2E tests passed、exit 0。到達コマンドは 120 件中 12 件。
1.4 slop grep¶
対象: src packages t docs README.md loom.asd flake.nix run-tests.lisp scripts .github
| 項目 | 生ヒット | 判定後 | コマンド |
|---|---|---|---|
| em dash(英語散文) | 18 | 4 行 / 3 ファイル | grep -rnP '\x{2014}' <scope>、requirements-daily-driver.md(日本語、15 行)を除外 |
| 空虚な強調語 | 10 | 0 | grep -rniE '\b(robust\|comprehensive\|seamless\|successfully\|significantly\|powerful\|elegant)\b' <scope>。10 件はすべて exit 状態を述べる事実記述 |
| ヘッジ | 0 | 0 | grep -rniE '\b(essentially\|basically\|arguably)\b' <scope> |
| 宣言と締めの言い直し | 0 | 0 | grep -rniE 'in this (section\|article\|document)\|^overall,\|in summary\|it is worth noting' <scope> |
| 署名を言い直す docstring | 33 | 3 | grep -rn '"Return true' src packages を全件読んで判定 |
| 参照ゼロの export | 1(prefix-argument-p) |
grep -rn '\bprefix-argument-p\b' src packages t が export 行のみ |
|
| 定義ファイル外で未参照の export | 6 | buffer-position、buffer-span、buffer-read-only-error-buffer、editor-bookmark、prefix-argument-magnitude、prefix-argument-negative-p |
|
| roadmap の自賛表現 | 2 | 2 | grep -c 'actively hardened\|verified engineering baseline' docs/src/project/roadmap.md |
command-spec 件数 |
120 | grep -ohE '\(command-spec\s+("[a-zA-Z0-9-]+"\|nil)' src/application/command-definitions*.lisp |
1.5 Part 2 着手前の再測定¶
対象は Part 1 完了後の 514c5a3 とし、Part 2 の編集前に親コミットを直接検査した。
英語散文の em dash は 4 行 / 3 ファイル、Return true の docstring は 32 件で、うち
3 件を署名の言い直しと判定した。公開 export の対象は 7 件、roadmap の自賛表現は 2 件だった。
1.6 Part 2 完了時の再測定¶
| 項目 | 着手前 | 完了後 | 判定とコマンド |
|---|---|---|---|
| 英語散文の em dash | 4 行 / 3 ファイル | 0 行 / 0 ファイル | perl -ne 'print if /\\x{2014}/' README.md docs/src packages/README.md src packages .github |
Return true docstring |
32 件、冗長 3 件 | 29 件、冗長 0 件 | grep -rn '\"Return true' src packages を全件再読 |
| 対象 export | 7 件 | 0 件 | src/package-exports.lisp の全体トークン照合 |
| roadmap の自賛表現 | 2 件 | 0 件 | grep -Eic 'actively hardened|verified engineering baseline' docs/src/project/roadmap.md |
| SWANK のソケット実装 | 未実装 | 未実装 | grep -rln 'socket\\|usocket\\|sb-bsd-sockets\\|swank' src packages は出力なし、exit 1 |
残った successfully は終了状態や処理結果を記述する文であり、署名だけを言い直す文ではない。
overall width/height はウィンドウ寸法の用語であり、締めの言い直しではない。
2. 処置台帳(P3 以降)¶
| # | 発見元 | 対象 | 症状 | 判断 | 状態 |
|---|---|---|---|---|---|
| 1 | 基線 §1.1 | t/integration/project-missing-root-test.lisp |
一時ディレクトリの祖先にプロジェクトマーカーがあると errored になる | 修正(テスト内で未作成の専用マーカー名を使い、ホスト祖先の環境に依存しない) | closed |
| 2 | 基線 §1.1 | t/integration/main-run-loom-test.lisp ほか %run-loom を呼ぶテスト |
描画の escape 列がテストランナーの stdout に混入する | 据え置き(判定には影響しない stdout ノイズで、今回の配線修理の対象外) | deferred |
| 3 | P1 ハーネス | t/e2e/loom_e2e/screen.py(観察のみ、製品側の処置は未決) |
描画は各行を全幅で埋めて素の LF で終える。pyte はこの列を LNM 無しで食わせると deferred autowrap が LF をまたいで残り、行が 1 つずれる。ハーネス側は LNM を有効にして回避した。実端末での見え方は作者の日常使用で問題が出ていないため製品側は据え置き | 観察 | open |
| 4 | P2 PTY E2E | t/e2e/scenarios/tooling.py:200-211 の terminal |
M-x terminal RET 後に /bin/sh の警告は画面へ出るが、printf terminal-e2e RET は端末子プロセスへ届かず、画面に Buffer *Loom-Terminal* is read-only が出る。再現: nix run .#e2e -- --only tooling/terminal |
修正(terminal-input-event-p は真だったが、RET に通常の newline-command が束縛され (null command) が偽になり、端末分岐が選ばれなかった。特殊キーを端末へ送り、:enter は子シェルが受理する LF にした) |
closed |
| 5 | P2 PTY E2E | t/e2e/scenarios/lsp.py:92-95 の lsp-completion-at-point |
nixd 起動経路後の completion で No LSP session for this buffer がミニバッファに出て、期待した completion 結果が現れない。再現: nix run .#e2e -- --only lsp/completion |
修正(session は束縛済みだったが initialize 応答を drain する前で initialized-p が偽だった。要求コンテキストで初期化を待ち、main loop の background polling に LSP を加えた) |
closed |
| 6 | P2 PTY E2E | t/e2e/scenarios/lsp.py:97-100 の lsp-find-definition |
nixd 起動経路後の definition で No LSP session for this buffer がミニバッファに出て、期待した定義結果が現れない。再現: nix run .#e2e -- --only lsp/find-definition |
修正(#5 と同じ初期化応答の処理漏れを共有していた) | closed |
3. 過去の進捗¶
| Phase | 状態 | コミット | 検証 |
|---|---|---|---|
| P0 基線 | 完了 | 1420df3 |
§1 |
| P1 ハーネス | 完了 | a8c7f09(flake: pyte と apps.e2e)、22b7415(t/e2e 再構成) |
nix run .#e2e を 2 回連続実行、いずれも 12 passed, 0 failed, 12 total、commands covered: 12 / 120、exit 0。nix run .#e2e -- --list が 12 件を列挙。固定 sleep はハーネスから除去済み(grep -rn 'time.sleep' t/e2e はプロセス終了待ちの 1 箇所のみ) |
| P2 全コマンド | 完了 | a76ee02, a7cdca3, 6f3db63, 86d09a3, 4298135, 6b6187a |
nix run .#e2e -- --list は 120/120、未カバー 0。nix run .#e2e は 107 passed, 3 failed, 110 total。失敗 3 件は §2 の #4-#6 に記録済み |
| P3 配線処置 | 完了 | 473b43f, c2e2cbf, fbbbf7f |
PTY E2E は 110 passed, 0 failed, 110 total、commands covered: 120 / 120、exit 0。in-process は launchctl 経由で 1408 passed, 0 skipped, 0 todo, 0 failed, 0 errored, 1408 total、exit 0。nix flake check --print-build-logs は all checks passed!、exit 0。#1/#4/#5/#6 は closed、#2 は対象外として deferred |
| P5 CI | 実装済み | cb5022c |
nix build .#default は実測 3.73 秒、nix run .#e2e は実測 28.47 秒。いずれも exit 0。E2E は 110 passed, 0 failed, 110 total、commands covered: 120 / 120。この実測を根拠に E2E ジョブの timeout-minutes は 10 とした。CI の両ジョブは未実行 |
| 統合(presentation) | 完了 | 9bbca23, cc0380d, f892bb4, e6ae4d5 |
nix run .#e2e は 110 passed, 0 failed, 110 total、commands covered: 120 / 120、未カバー 0、exit 0。launchctl 経由の in-process は 1427 passed, 0 skipped, 0 todo, 0 failed, 0 errored, 1427 total、exit 0。nix flake check は all checks passed!、exit 0。nix build --no-link --print-out-paths .#default は exit 0。実PTY は mode-line、C-x 2/C-x 3 の mode-line 分離、C-SPC の緑背景、M-x terminal の pty-integration 出力を画面ダンプで確認し、exit 0 |
| 診断可視化実機 | 完了 | 514c5a3, ed0b49c |
実 nixd を使った一時 PTY スクリプトが exit 0。診断付き画面は mode-line に Diag: E1 W1、診断範囲は赤背景、リージョン重畳は緑背景と診断範囲の赤背景を同一画面で確認。LSP セッション無しと診断ゼロでは Diag: が無く、40 列の長い日本語名でも mode-line は cells=40 で折り返さなかった。 |
| P4 Documentation: 要件書と slop | 完了 | ccb2c34 |
requirements-daily-driver.md を現行の判断記録へ書き直し、FR-000 から FR-010 の状態、対象言語、SWANK と LSP の境界、v5 永続化境界、Org の範囲を記録。dead export 7 件、冗長 docstring 3 件、roadmap 自賛 2 件、英語 em dash 4 行 / 3 ファイルを除去。 |
4. Development verification and open criteria¶
This section groups evidence by gate and workstream, not chronology. Use the phase table in section 3 for project order.
The table records intermediate working-source checks on aarch64-darwin across evolving source revisions. Per-row source SHAs were not recorded, and the check sets changed as gates were added; the rows do not describe one revision or the latest edits. Subsequent findings and checks follow the table; earlier passes do not clear gates affected by later changes.
| Gate | Observation | Remaining criterion |
|---|---|---|
| Source suite | sbcl --script run-tests.lisp, using the declared SBCL 2.6.7 and ASDF dependencies from the Nix test derivation: exit 0; 1467 passed, 0 skipped, 0 todo, 0 failed, 0 errored, 1467 total. This run includes the UTF-16 and document-synchronization fixes. The CLI subprocess limit remained 40000 ms |
This host run does not establish Linux CI or sandbox behavior. The earlier CLI timeout cause remains unestablished |
| Executable | ASDF loaded the working source and sb-ext:save-lisp-and-die produced an executable; exit 0. loom --version returned loom 0.1.0; exit 0. nix build --no-link --no-update-lock-file --print-out-paths .#default .#docs also exited 0. The fresh executable from the full flake check's build derivation passed python3 t/e2e/loom-test.py --binary <nix-built-executable> --require-full-coverage: exit 0; 113 passed, 0 failed, 113 total, and 120/120 commands covered. Its source snapshot matched all 442 working Lisp and ASDF files by SHA-256 |
These local results do not establish Linux CI or author acceptance |
| PTY suite | python3 t/e2e/loom-test.py --binary <built-executable> --require-full-coverage: exit 0; 113 passed, 0 failed, 113 total, with 120/120 commands covered and no unknown or uncovered commands. This includes real Unicode definition navigation and return, completion insertion, and the deadline preflight. Before adding the Unicode scenario, a full rerun passed all 112 scenarios; exit 0 |
An earlier full run reported 111 passed and 1 timeout in the no-completions scenario. Neither the isolated pass nor the full reruns establish that timeout's cause. These runs do not establish accurate wide-character text rendering; see the rendering finding below |
| E2E CLI coverage | From t/e2e, python3 -m unittest -v test_deadline test_cli: exit 0; all 37 tests passed, including all 8 CLI tests. Before the runner fix, the CLI tests had 2 failures: a selected subset reported commands from unselected scenarios, and --require-full-coverage incorrectly returned success. Runtime coverage now uses selected scenarios. python3 loom-test.py --list compared all registered scenarios and reported 120/120 commands, no uncovered or unknown names; exit 0 |
These CLI unit tests replace process execution with mocks. They establish selection, reporting, and exit-status behavior. The list command establishes static manifest coverage, not real command execution or a passing PTY suite |
| Deadline preflight | From t/e2e, python3 -m unittest -v test_deadline test_cli: exit 0; all 29 deadline tests passed alongside the 8 CLI tests. A separate real-process probe with a 0.3-second scenario budget and 0.1-second cleanup reserve closed and reaped three registered children and their FDs |
Earlier failures of the PTY-close, multi-session, and long-finalizer tests remain unexplained; a later pass does not establish their cause. Exhausted cleanup reports remaining scratch directories rather than guaranteeing removal. No time budget or existing process/removal assertion was relaxed |
| Documentation | After the common and feature API corrections, both mkdocs build --strict --config-file docs/mkdocs.yml --site-dir <temporary-directory> and nix build --no-link --no-update-lock-file --print-out-paths .#docs exited 0. Eight generated Nix pages had nonempty main content and checklist navigation links. A later strict build covering the Unicode and renderer findings also exited 0; its generated checklist retained all 11 Not run results, and its feature API page contained 18 package sections |
Later documentation edits require rechecking. The generated checklist is not author acceptance evidence |
| Nix sandbox tests | Building the fresh flake test derivation with nix build --no-link --print-build-logs --print-out-paths <test-derivation> exited 0: 1464 passed, 3 skipped, 0 todo, 0 failed, 0 errored, 1467 total. The CLI subprocess test passed in 22.595 seconds under its unchanged 40000 ms limit. This source includes the UTF-16, synchronization, test-helper, and benchmark corrections |
The three sandbox skips cover real PTY and child-process lifecycle tests. The host source suite exercised them, but these results do not establish Linux CI. The earlier sandbox CLI timeout cause remains unestablished |
| Nix coverage | Building the fresh flake coverage derivation with nix build --no-link --print-build-logs --print-out-paths <coverage-derivation> exited 0: 1464 passed, 3 skipped, 0 todo, 0 failed, 0 errored, 1467 total. Expressions: 19981/20891 (95.64%); branches: 1909/2034 (93.85%). Parsing the generated HTML confirmed nonempty linked reports and matching totals for the 259 product-source files. No exclusions were accepted |
The report also contains 179 test-harness pages; those pages are not included in the product coverage rates. Coverage does not establish author acceptance or unexecuted platform behavior |
| Full Nix checks | nix flake check --no-update-lock-file --print-build-logs: exit 0 on aarch64-darwin. Outputs exist for all six gates: build, tests, coverage, documentation, formatting, and structural parsing. Formatting reported zero changed files; pinned Paredit 1.6.2 parsed 442 files with 0 parse errors. All 442 Lisp and ASDF inputs still matched the built source by SHA-256 |
Nix omitted x86_64-linux. The dependency fixup warning below remains unresolved; the successful command does not establish author acceptance or correct wide-character rendering |
| Host structural parse | paredit inspect workspace --output json ., using Paredit 1.6.3: exit 0; 442 parsed files, 0 parse errors. The generated report's paths and byte counts matched every current Lisp and ASDF file |
Structural parsing does not establish runtime behavior. This host result supplements the pinned Paredit 1.6.2 flake check |
| FR-V07 | Cold-read findings were corrected in 14 Lisp files. Their non-string source was unchanged, and all 14 passed paredit inspect check --file <path>; exit 0. Later word-motion and file-save docstring corrections passed Paredit checks. Both selected first-save tests passed; exit 0. Documentation review corrected package paths, command-registry responsibilities, auto-save overrides, file-tree generations, ANSI terminal behavior, syntax matching, and common API signatures and return values. A static comparison found all 382 exported names in the corresponding sections for 18 feature packages; exit 0. The cold-read scope includes all repository Markdown pages and all comments and docstrings in the Lisp source, tests, and scripts; path manifests were compared with the actual files |
Export-name presence and prose review do not establish runtime behavior. The Lisp reader required manual inspection of reader-evaluation forms, as described below |
| FR-V08 | The author checklist exists; no author results have been supplied | All manual results remain Not run |
During the Paredit dependency's Nix fixup, the audit-tmpdir.sh file-classifier |
||
subprocess exited with Segmentation fault: 11, although the full flake check |
||
| exited 0. The script waits for its audit handlers but not for the classifier; | ||
| therefore the overall exit status does not establish a completed temporary-path | ||
| audit. Separate inspection found one regular file in the installed dependency, | ||
| the Mach-O executable. Its bytes contained no Nix build-temporary-directory | ||
reference, otool -l exited 0 with no such reference, and |
||
codesign --verify --strict exited 0. These artifact checks do not explain the |
||
| classifier failure or replace the interrupted audit. An isolated classifier | ||
pipeline using the original isELF and isScript functions with the build's |
||
| Bash 5.3.15 passed three cases: a script control, a Mach-O control, and the | ||
| Paredit executable. Each pipeline exited 0; the build-time failure was not | ||
| reproduced. No audit was disabled and no dependency build configuration was | ||
| changed. |
Further test-helper cold-read corrections affected
t/test-helpers-core.lisp, t/integration/main-test-support.lisp,
t/integration/command-keybinding-consistency-test.lisp, and
t/integration/frame-layout-wrapping-test.lisp. Their docstrings now identify
the sandbox flag rather than guessing platform or PTY availability, describe the
startup state and disk-backed child lister, cite the actual keymap path, and avoid
claiming every wrapping-enabled buffer has more display rows than logical lines.
Each file passed paredit inspect check --file <path>; exit 0.
The cold-read manifests cover rg --files src packages -g '*.lisp',
t/*.lisp, t/unit/*.lisp, t/integration/*.lisp, scripts/*.lisp, and
run-tests.lisp. Source docstring extraction initially stopped at a #. form;
the completed extraction plus manual inspection of src/package.lisp was
compared with the actual source paths. The other reader-evaluation locations,
src/package-application.lisp and
packages/feature/evaluation/src/infrastructure-lisp-evaluator.lisp, were also
read directly. Test and script extraction finished with exit 0, and its manifest
matched the actual input paths. Comments were read separately from docstrings.
This establishes the reviewed prose scope, not the correctness of every function.
sbcl --script scripts/benchmark-concurrency.lisp initially exited 1 because its
file-tree runtime calls still used the former LOOM namespace. The calls now use
LOOM/FEATURE/FILE-TREE. The corrected script exited 0, accepted all eight
requests, and checked that each asynchronous result matched its synchronous
control. This run establishes that the documented benchmark is executable;
it is not evidence for a production performance claim.
The scratch-allocation regression delivers a real SIGALRM after creating a real
temporary directory but before returning its pathname. Before the fix,
test_alarm_before_scratch_return_removes_directory failed because the session
had not retained the pathname; exit 1. Session.__enter__ now blocks the alarm
only while allocating and retaining the pathname, then restores the prior signal
mask inside its existing cleanup boundary. The creation-failure regression checks
that the original error and signal mask are preserved without starting a process.
The project marker predicate previously lowercased only its input, so configured
mixed-case markers such as Cargo.toml and Makefile did not match. The regression
failed before the fix; exit 1. The predicate now compares marker names with
string-equal. The regression checks original, lowercase, and uppercase spellings
for every configured marker. All 22 selected project tests passed after the fix;
exit 0. This predicate defect does not establish a defect in filesystem root
discovery, which uses a different lookup path.
The host's SBCL 2.6.0 also errored in two directory-race tests when formatting
wildcard pathnames. A standalone namestring call on a simple-base-string
pathname reproduced the same error without loading Loom. The declared SBCL 2.6.7
passed that control, all 12 selected directory-creation tests, and the full source
suite. No test path or assertion was changed to conceal the host runtime defect.
LSP positions use UTF-16 code units, while buffer columns count Common Lisp characters. Three regressions failed before conversion at the completion, definition, and diagnostic-rendering boundaries; exit 1. All six selected UTF-16 tests passed after the fix; exit 0. The checks include a supplementary Unicode character, surrogate-interior offsets, and offsets beyond line end.
A wire trace also showed a definition request preceding didOpen. Rendering
previously synchronized the document only after processing the command.
Completion and definition commands now synchronize before sending a supported
request. All four ordering regressions failed before the fix; exit 1. All four
passed afterward; exit 0. They check didOpen, versioned didChange, request
ordering, and the absence of redundant changes for unchanged text.
An initial verification-only executable omitted :save-runtime-options t, so
SBCL consumed --help and --version. That full PTY run reported 110 passed
and 2 failed; exit 1. The replacement executable uses the runtime-option setting
from the project's ASDF program build. Both CLI scenarios then passed in the
full run reported above. The first result is a probe-construction failure, not
evidence of a production CLI regression.
The Unicode definition scenario checks outgoing UTF-16 offsets after an astral
character, incoming definition offsets, and restoration of the original point.
A direct JSON-RPC probe without Loom found that the pinned nixd rejected offsets
11 and 12 in the reference identifier with unknown node type for definition,
but offset 13 returned the definition range 11 through 16 on line 1. The scenario
requests inside the identifier at buffer column 12, which maps to UTF-16 offset
13; without conversion, offset 12 fails. This server boundary behavior remains
unfixed and is not evidence against Loom's offset conversion.
Wide-character rendering exposed a separate dependency defect. With only cl-tty-kit 1.6.1
loaded, a fresh eight-column renderer emits あ X for input あX and 😀 X
for input 😀X; the ASCII control emits aX. All three probes exited 0.
The screen writer stores a spacer cell after a wide character, and
src/render-style.lisp in that dependency emits every cell's character, including
the spacer. A pyte control fed /* 😀 */ value directly preserves the single
space after the emoji; the Loom PTY screen contains two. The passing cursor
assertions do not establish correct text placement. The dependency source was
consulted read-only; no adjacent checkout was edited.
The Nix build now applies patches/cl-tty-kit-wide-character-rendering.patch
to that dependency. It skips only continuation cells during output, keeps real
spaces, normalizes incremental ranges that start inside a wide character, and
uses the same range rules for output-length estimates. Replacing a wide lead
also marks its former continuation cell for output, including when that cell
lies just beyond the screen's dirty range. Row boundaries constrain both rules.
The focused command loading the patched dependency and running
cl-weave:run-all with :name-filter "wide-character ANSI output" and
:pass-with-no-tests nil exited 0 on host SBCL 2.6.0: all 20 selected tests passed,
with no skipped, failed, or errored tests. Before the final patch, the same
20-test selection exited 1 with 13 passes and 7 failures: one output-length
estimate and six wide-to-narrow replacement cases. These focused results are
not a full-suite or author-acceptance result.
A PTY run of the intermediate patch passed full-screen text placement but
failed during wide-to-narrow deletion. A direct pyte control reproduced the
orphan continuation cell after overwriting only the wide lead; explicitly
writing its following space cleared it. The final patch includes that write.
The intermediate PTY failure remains part of the verification history.
python3 t/e2e/loom-test.py --binary <fresh-nix-built-executable> --only ansi-wide
then exited 0: both scenarios passed, including the 30-test deadline preflight.
The incremental scenario checks exact reconstructed text and cursor positions
through Japanese and emoji insertion, space insertion, deletion, and replacement,
then verifies changed file bytes before exiting. An earlier test-only timeout
waited for a save message that the save command does not emit; the file assertion
now observes bytes different from the initial fixture. This focused selection
does not cover the command registry; a full PTY rerun remains required.
The patched dependency's rendering selection also passed 83 tests with no skips,
failures, or errors; exit 0. The complete upstream test system could not load
because CL-PROLOG was unavailable. The render-only result does not establish
that the complete upstream suite passes.
PTY child processes now inherit only the parent's PATH; their HOME, TERM,
SHELL, LANG, and LC_ALL come from the harness. A regression supplies a
synthetic credential and LOOM_INIT_FILE in the parent environment and verifies
that neither reaches the child. python3 -B -m unittest discover -s t/e2e -p
'test_*.py' exited 0 with all 38 tests passing. Explicit process environments
remain caller-controlled replacements rather than inheriting the parent.
The discovered LSP command now requires an exact yes after review. All 15
selected discovery and session-start tests passed on declared SBCL 2.6.7;
exit 0. These include constructor and initialization-send failures that preserve
the old session, and replacement with an old transport that fails during receive
or close. Neither replacement failure probe demonstrated a product defect.
A full PTY run reported 115 passes and one failure, with all 120 registered
commands covered; exit 1. The rejection scenario expected /tmp while discovery
returned its canonical macOS pathname. Canonicalizing the fixture directory
preserves all provenance, rejection, restoration, and no-process assertions.
The isolated scenario then passed, with its 30-test deadline preflight; exit 0.
This does not establish a passing full PTY run after the harness correction.
An intermediate Nix run reported 1,492 passes, three skips, and one failure out of 1,496 tests; exit 1. The CLI integration test exceeded its unchanged 40-second test deadline. A subsequent sequential build used the following command:
All six aarch64-darwin checks passed; exit 0. Both test and coverage runs reported 1,497 passes, three sandbox skips, and no failures or errors out of 1,500 tests. The CLI test took 3.848 seconds in the test run and 4.574 seconds in coverage. Coverage was 20,049/20,959 expressions (95.66%) and 1,913/2,038 branches (93.87%). The earlier deadline failure remains unexplained; this pass does not identify its cause. Linux checks were omitted. These results precede the follow-up work to make long LSP review text navigable while the trust prompt is active.
From t/e2e, this focused run passed all six selected tests; exit 0:
python3 -m unittest -v \
test_deadline.ScenarioDeadlineTests.test_alarm_before_scratch_return_removes_directory \
test_deadline.ScenarioDeadlineTests.test_scratch_creation_failure_restores_alarm_signal_mask \
test_deadline.ScenarioDeadlineTests.test_expired_locale_setup_does_not_allocate_scratch_directory \
test_deadline.ScenarioDeadlineTests.test_session_setup_failure_removes_scratch_directory \
test_deadline.ScenarioDeadlineTests.test_session_screen_setup_failure_closes_registered_process \
test_deadline.ScenarioDeadlineTests.test_session_setup_preserves_original_error_when_cleanup_fails
Long LSP command review verification¶
The trust prompt now accepts PageDown, PageUp, C-v, and M-v for navigating
wrapped review text without changing the answer. The integration cases cover
empty answers, cancellation, and exact yes, including restoration of the
original viewport and preservation of the existing session until approval.
The following check includes these changes and the wide-character dependency patch. All six aarch64-darwin checks passed; exit 0:
Both test and coverage runs reported 1,506 passes, three sandbox skips, and no failures or errors out of 1,509 tests. The CLI test took 1.737 seconds in the test run and 3.878 seconds in coverage, within its unchanged 40-second deadline. Coverage was 20,085/20,995 expressions (95.67%) and 1,917/2,042 branches (93.88%). The structural check inspected 442 Lisp and ASDF files without errors. Formatting changed no files. Linux checks were omitted.
The full PTY run used the executable produced by that build:
It exited 0 with all 117 scenarios passing and all 120 registered commands
covered. The deadline preflight passed all 30 tests. The long-review scenario
checks both paging key pairs, unchanged answers, original-buffer restoration,
and absence of a child before approval. After exact yes, it observes the child
PID and a diagnostic from the running server, then checks that the process exits
after lsp-stop, before quitting the editor. The full run also includes the
previously corrected rejection fixture and both exact-text wide-character
rendering scenarios. These results supersede the earlier partial PTY reruns,
not the author's outstanding real-terminal acceptance checks.
The source suite also ran outside the Nix sandbox, using the declared SBCL 2.6.7
and an explicit CL_SOURCE_REGISTRY containing this checkout and the declared
Nix dependencies, including the patched terminal renderer:
It exited 0 with 1,509 passes, no skips, and no failures or errors out of 1,509 tests. This exercises the three cases skipped in the sandbox; it does not establish Linux behavior or replace author acceptance.
Linux CI verification¶
CI run 38114178710
checked commit 3dbc8a11d999ccd2e6a8d1ffec1d25d965beaa9a on x86_64-linux.
Both jobs completed successfully. The workflow ran:
timeout --signal=TERM --kill-after=15s 1800s nix flake check --print-build-logs
nix build .#default --print-build-logs
timeout --signal=TERM --kill-after=15s 600s nix run .#e2e
All six flake checks passed: build, tests, formatting, strict documentation, structural lint, and coverage. Both test and coverage runs reported 1,506 passes, three sandbox skips, and no failures or errors out of 1,509 tests. Coverage was 20,081/20,991 expressions (95.66%) and 1,917/2,042 branches (93.88%). Structural lint inspected 442 Lisp and ASDF files without errors; formatting changed no files. The workflow's diff-hygiene check also passed.
The PTY job built the executable from the same commit and passed all 117 scenarios, covering all 120 registered commands with none uncovered. Its deadline preflight passed all 30 tests. This includes the real-server LSP scenarios and the wide-character rendering scenarios described above.
Together with the preceding aarch64-darwin results, this establishes the two automated platform gates for this source revision. The author's real-terminal acceptance checklist remains unrun; these results do not clear that release gate.
Release archive validation¶
The archive verifier now checks the digest against the exact archive basename and copies only the expected regular files into a private directory. It rejects duplicate or unexpected members, traversal paths, links, special files, and sparse files before extraction. Archive ownership and executable or special permission bits are not restored. Packaging refuses existing artifacts, including dangling symbolic links.
On aarch64-darwin with Python 3.9.6, the following run passed all 25 tests; exit 0:
The known-good controls include GNU and PAX archives, reversed member order,
and an archive produced by the packaging script. The packaging fixture replaces
nix-store with a checked stub; this run does not establish real closure import
or offline startup.
The same dangling-link cases were also run against the preceding published packaging script without changing the working copy:
LOOM_PACKAGE_REVISION=1c2a2600ff40bd91396749570d8381d9bea75667 \
python3 -B t/release/test-archives.py -v \
PackageTests.test_dangling_directory \
PackageTests.test_dangling_archive \
PackageTests.test_dangling_checksum
That comparison exited 1: the directory case passed, but the archive and checksum cases created their dangling links' targets. Both cases pass with the current script and leave the target absent.
The release workflow checks out an explicit version tag, records the verified commit, and builds that commit rather than resolving the tag again. Before creating a draft release, it checks the live remote tag against the verified commit. Shell syntax, ShellCheck, and actionlint passed; these static checks do not establish a live release run. The author's real-terminal acceptance remains required before release.
The current checkout also passed the exact PTY app on aarch64-darwin:
It exited 0: all 30 deadline preflight tests and all 117 scenarios passed, covering all 120 registered commands. This confirms the current automated terminal gate, not real-terminal input-method behavior or the cause of earlier intermittent failures.
Lower-level terminal library gate¶
The full cl-tty-kit/test system initially failed to load because it still
depended on the former cl-prolog system and package. No tests ran in that
attempt. The compatibility patch updates the test dependency and package
references to cl-prolog-kit; it does not change the test assertions. Prolog
and the test runner are check-only dependencies, not runtime dependencies.
The cl-tty-kit flake check loads the entire test system and calls
cl-weave:run-all without a test filter. An empty selection is a failure.
The upstream suite's 120-second timeout is retained, with the script check's
600-second process limit and 30-second termination grace period.
Linux CI for 7f7fdb8d9434dd96debd059b99de7344162c7076
completed successfully:
nix flake check --print-build-logs: all seven checks passed. The lower-level suite passed all 1,696 tests, with no skips, failures, or errors. Loom's test and coverage runs each passed 1,506 tests and skipped three out of 1,509. Coverage was 20,081/20,991 expressions (95.66%) and 1,917/2,042 branches (93.88%).nix run .#e2e: the deadline preflight passed all 30 tests. All 117 PTY scenarios passed, covering all 120 registered commands with none uncovered.python3 -B t/release/test-archives.py -v: all 25 tests passed.- The offline archive job packaged the real closure, restored it into an empty store, verified closure completeness and its profile GC root, and started the restored executable without network access.
All three CI jobs exited successfully. These Linux results do not establish the author's real-terminal acceptance or a completed release.
On aarch64-darwin, the same lower-level check failed in three unchanged attempts:
nix build path:.#checks.aarch64-darwin.cl-tty-kit --no-link --no-update-lock-file --print-build-logs
All attempts exited 1 with test suite timed out after 120 seconds during
compilation. None produced a test-count summary, so none establishes a
passing suite or a test-case regression. The timeout covers loading the test
system as well as running it. The host had high load during these attempts;
its contribution to the timeout is unverified. No timeout or assertion was
changed. These attempts did not clear the Darwin lower-level gate. A subsequent
passing run is recorded below; the author's real-terminal acceptance remains
outstanding, and release has not proceeded.
Release guard corrections¶
The push-triggered release now checks out the event commit and verifies that the checkout matches it before recording the build revision. Manual runs still resolve the requested tag once. Both trigger paths use the same per-tag concurrency group, and the live remote tag check remains before draft creation.
Archive validation now requires the expected numeric version and compares the restored executable's complete version output with that exact line. The previous check accepted a different numeric version and extra output; isolated fixtures reproduced both defects before the correction. Both workflow callers supply the expected version.
Draft creation refuses a tag that already has a release. It uses create-only GitHub CLI operations and exact asset paths rather than updating an existing release or replacing its assets. Release-list and creation errors remain fatal. The remote-tag check is not an atomic guarantee against an external tag update between that check and creation.
Local checks on aarch64-darwin passed:
bash -n scripts/test-release.sh
python3 -B t/release/test-archives.py -v
python3 -B t/release/test-workflow.py -v
Each command exited 0. The archive suite selected and passed all 30 tests; the workflow suite selected and passed all 11 tests. The new cases execute the real archive script or workflow shell bodies with isolated Nix, Git, and GitHub CLI fixtures. They do not establish real Linux store restoration or live GitHub release behavior. The Linux CI results below cover real store restoration on the corrected revision. No release was created, published, or overwritten during validation.
The following static checks also exited 0:
nix run nixpkgs#actionlint -- .github/workflows/release.yml .github/workflows/ci.yml
nix run nixpkgs#shellcheck -- scripts/test-release.sh
paredit --dry-run inspect check --file scripts/check-cl-tty-kit.lisp
An independent source review found no additional concrete implementation defect
in the release corrections. The fixtures for .github/workflows/release.yml and
.github/workflows/ci.yml execute extracted shell bodies, not GitHub's checkout
expressions, output wiring, permissions, or job scheduling. Those connections
were inspected in the workflow files. The CI workflow subsequently ran on
GitHub; the release workflow itself has not been invoked for these corrections.
Darwin lower-level verification¶
The lower-level check now logs test-system loading and compilation progress before running the full suite. Its 120-second timeout still covers loading and execution; the selected suite, assertions, and rejection of an empty suite are unchanged.
nix build path:.#checks.aarch64-darwin.cl-tty-kit --no-link --no-update-lock-file --print-build-logs
This run exited 0 after reporting 1,696 passed, zero skipped, zero todo, zero failed, and zero errored, out of 1,696 tests. Both compilation and execution completed inside the existing gate. This result clears the Darwin lower-level check for the diagnostic change; it does not establish the cause of the earlier timeouts or validate the release corrections on Linux.
Linux CI on the corrected revision¶
CI run 38130828081
completed successfully on 1e30fd01b66bfa50ebe5199dbfd9c19fa813813b.
All three jobs passed: sandboxed checks, real PTY E2E, and offline archive
restoration. The following commands exited 0 in those jobs:
python3 -B t/release/test-archives.py -v
python3 -B t/release/test-workflow.py -v
timeout --signal=TERM --kill-after=15s 1800s nix flake check --print-build-logs
nix build .#default --print-build-logs
timeout --signal=TERM --kill-after=15s 600s nix run .#e2e
bash scripts/package-release.sh result loom-ci-x86_64-linux "$RUNNER_TEMP/dist"
sudo env "PATH=$(dirname "$(command -v nix)"):/usr/bin:/bin" \
bash scripts/test-release.sh "$RUNNER_TEMP/dist/loom-ci-x86_64-linux.tar.gz" "$version"
The archive and workflow fixture suites passed 30 and 11 tests respectively. The lower-level suite passed all 1,696 tests without skips. The Loom suite passed 1,506 tests and skipped three real-child-process cases in the sandbox: terminal session output, LSP session lifecycle errors, and LSP transport roundtrip. There were no failed or errored tests. The coverage run selected the same suite and reported 20,081/20,991 expressions (95.66%) and 1,917/2,042 branches (93.88%).
Outside the sandbox, the E2E preflight passed 30 tests and all 117 PTY scenarios passed. The manifest comparison reported 120/120 commands covered and none uncovered. This is separate evidence from the sandboxed child-process skips.
The archive job packaged 29 store paths, restored the complete closure into an
empty store, verified the profile GC root, and started the restored executable
offline on Linux. Its version check compared the complete output against the
source version, 0.1.0; the help output contained Usage: loom [PATH].
Darwin verification on the corrected revision¶
The real PTY E2E run used the same corrected source revision:
It exited 0 after passing all 30 preflight tests and 117 PTY scenarios. The manifest comparison reported 120/120 commands covered and none uncovered.
The full Darwin check did not pass on its first run:
It exited 1. The Loom suite reported 1,505 passed, three skipped, one failed,
and zero errored, out of 1,509 tests. The failure was MAIN CLI integration >
passes process arguments to cl-cli and exits successfully, which exceeded the
unchanged 40-second per-test limit after 40.315 seconds. The test source is
unchanged from the preceding revision. This result does not establish a code
regression or an environmental cause. The interrupted coverage check is not a
passing result.
An isolated rebuild of the same immutable test derivation also exited 1 after the same case exceeded its limit at 40.251 seconds. Outside the Nix sandbox, both the isolated CLI cases and the complete suite passed with the pinned SBCL, an empty home directory, and the same dependency registry. A sandbox diagnostic run with child-start, source-registry, and system-load tracing then passed. That instrumented run was not used to clear the production gate.
After these probes, the unmodified test and coverage derivations were rebuilt:
nix build '/nix/store/2cbxjyph3i5kd2m4pb1c5qyn4f6pakym-loom-test-0.1.0.drv^*' --no-link --print-build-logs
nix build '/nix/store/054g2q9ikpd00s0752gpjgpp6460s1bw-loom-coverage-0.1.0.drv^*' --no-link --print-build-logs
Both exited 0 on the corrected source revision. Each selected all 1,509 tests and reported 1,506 passed, three skipped, zero failed, and zero errored. The previously failing CLI case passed in 1.363 seconds in the uninstrumented test run. Its assertions and 40-second limit were unchanged. The coverage run reported 20,085/20,995 expressions (95.67%) and 1,917/2,042 branches (93.88%), wrote its HTML report, and completed successfully. These passing rebuilds do not explain the earlier timeouts; no timing-related production change was made.
The full Darwin check was then repeated with the updated verification record.
The same nix flake check path:. --no-update-lock-file --print-build-logs
command exited 0, reporting all eight checks passed. The Loom and coverage
checks each passed 1,506 tests with three skips, zero failures, and zero errors;
the CLI case passed in 1.978 seconds in the test check. The parser check read
443 Lisp files without errors, and the configured Nix formatter completed
without changes. That formatter does not check Markdown. Linux results above
are from the separate CI run, not from this Darwin invocation.
The author's eleven real-terminal acceptance rows remain Not run. Automated
checks do not establish Japanese IME usability or author acceptance. No draft
or published release has been created.
5. W0-1 仕様書コミット後の基線¶
docs/src/notes/requirements-modern-editor.mdをバイト単位で複製し、コミット5f24574071e69b053b65f2f15cfe770ee2b37b3fをorigin/mainへ反映した。このコミットを実機基線として、macOS arm64で.#defaultのバイナリを実PTYから観測した。アプリ、テスト、ハーネスの変更はない。
仕様2.2にある端末縮小後の自動再描画は再現しなかった。確認条件と結果は「仕様2.2の維持項目」に記録した。
ビルドと自動テスト¶
| コマンド | 結果 |
|---|---|
nix build .#docs --print-build-logs |
exit 0。生成HTMLを確認した。 |
nix build .#default --no-link --print-out-paths |
exit 0。 |
nix flake check --print-build-logs |
exit 1。通常のLoomテストは1,506件成功、3件skip。同じCLIテストは39.643秒で成功した。Coverage側は1,505件成功、3件skip、1件error。CoverageではMAIN CLI integration > passes process arguments to cl-cli and exits successfullyが60.232秒でタイムアウトした。t/package.lispはテスト期限を40秒、t/integration/main-cli-test.lispは子プロセス期限を60秒に設定している。Coverageがテスト期限を越えて実行した理由は未特定で、どちらの上限も変更していない。実行時は16コア環境でload averageが108だったと操作者から連絡があった。高負荷下のタイムアウトとして記録する。失敗時点のuptime値は採取していない。節4の40.315秒の結果は別実行である。 |
nix run .#e2e |
exit 0。事前テスト30件、PTYシナリオ117件が成功し、コマンド網羅は120/120。実行時間は約108.8秒。シナリオのタイムアウトはなかった。 |
nix develop --command sbcl --script run-tests.lisp |
未完了。31分待ってもNixクライアントはdaemonからの応答を待ち、SBCLは起動しなかった。起動したジョブにSIGTERMを送り、ラッパーはexit 1(interrupted by the user)で終了した。テストは未実行。 |
E2Eと起動計測は16コアのマシンに別プロジェクトのビルドが並行する高負荷下で行った。E2E開始時のuptimeは1:51 up 2 days, 16:08, 1 user, load averages: 98.76 88.10 66.57、終了時は1:53 up 2 days, 16:10, 1 user, load averages: 74.13 83.94 67.66だった。E2Eシナリオにタイムアウトはなく、単独再実行はしていない。
D1〜D17の実機観測¶
| ID | 基線で観測した結果 |
|---|---|
| D1 | ↓、→、End、Home、Delete、PgDnで移動せず、カーソルは行頭に残った。続けて入力したXは行頭に入った。再現。 |
| D2 | XYの後のC-x C-uは初回に変化せず、2回目で戻った。X、RET、Yの後に2回押すとXと改行が残った。M-x undoも同様。再現。 |
| D3 | 200行ファイルの先頭でC-vを3回押しても、M-x scroll-up-commandを実行しても先頭行に残った。再現。 |
| D4 | SGRマウス入力1件でTYPE-ERRORとなり、exit 1。再現。 |
| D5 | 同一ファイルを開き直すとディスク内容の別バッファが開き、未保存の旧バッファは残った。C-x bの候補名はどちらもf.txt。再現。 |
| D6 | マウスとブラケットペーストの端末モードは有効にならず、貼り付けたTABは空白1つになった。再現。 |
| D7 | TABは1セルで表示された。結合文字の後のカーソル列が描画とずれ、ZWJ絵文字は👩だけ表示した。再現。 |
| D8 | RETでLisp、Nixのどちらも自動インデントしなかった。再現。 |
| D9 | Markdownの# helloでM-;を押して保存してもファイルは# hello\nのままで、コメントにならなかった。再現。 |
| D10 | find-fileのTABは曖昧なパス候補を絞らなかった。M-xではsave-buがsave-bufferに補完された。再現。 |
| D11 | 保存後のWrote表示とM-w後のOSC 52はなかった。内部kill ringのコピーと貼り付けは動作した。再現。 |
| D12 | C-zは何も起こさなかった。SIGTSTPで停止したとき端末はcookedになったが、SIGCONT後にrawへ戻らなかった。再現。 |
| D13 | 5,000行での1キー応答中央値は2バッチで0.0797秒、0.0369秒。20,000行では0.2849秒、0.1627秒。両バッチで行数の多い側が遅く、再現。 |
| D14 | 存在しないファイル、+2、+2:3、複数パスはいずれもexit 64。再現。 |
| D15 | M-x kill-loom-abortは利用できず、SIGTERMではexit 0。再現。 |
| D16 | 不正UTF-8はexit 70。CRLFファイルの編集後はab\rZ\ncd\r\nになった。再現。 |
| D17 | initエラー、非TTY stdinはいずれもexit 1。SIGHUP後に端末のICANON/ECHOは無効のまま。再現。 |
D13と起動の時間値は高負荷下の参考値である。起動は5回ずつ2バッチ測定し、中央値は0.1361秒と0.4308秒、10サンプル全体の中央値は0.1819秒だった。NFR-02の上限0.3秒をバッチごとの中央値がまたいだため、安定した合否は判定しない。仕様2.2の記録値0.11秒とも単純比較しない。起動計測前後のuptimeは1:51 up 2 days, 16:08, 1 user, load averages: 100.87 88.88 67.10から1:51 up 2 days, 16:08, 1 user, load averages: 106.49 90.24 67.71だった。
D13の測定中に採ったuptimeは次のとおり。すべて高負荷下の測定である。
| データ量とバッチ | 測定前後のuptime |
|---|---|
| 5,000行、第1 | 前後とも1:51 up 2 days, 16:08, 1 user, load averages: 106.49 90.24 67.71 |
| 20,000行、第1 | 1:51 up 2 days, 16:08, 1 user, load averages: 106.49 90.24 67.71から1:52 up 2 days, 16:08, 1 user, load averages: 106.77 90.57 67.96 |
| 5,000行、第2 | 前後とも1:52 up 2 days, 16:08, 1 user, load averages: 106.77 90.57 67.96 |
| 20,000行、第2 | 前後とも1:52 up 2 days, 16:08, 1 user, load averages: 106.77 90.57 67.96 |
docs/src/notes/requirements-modern-editor.md の2.2にある維持項目¶
| 項目 | 結果 |
|---|---|
保存してGit commit、保存せず終了、確認でdを選ぶフロー |
成功。破棄後も既存コミットメッセージとclean状態を保った。 |
一時Gitリポジトリでgit rebase -iのコミットdrop |
成功。対象コミットとファイルだけが履歴から外れた。 |
| crontab型の待機と読み戻し | 成功。親プロセスはLoom終了を待ち、編集後の内容を読み戻した。 |
| 既存ファイルへの保存 | inode、600/755のmode、symlink、hardlinkを維持し、追加ファイルを作らなかった。成功。 |
| BOMと末尾改行なしの保存 | 元のバイト列を維持した。成功。 |
| 80x24から60x12への端末縮小 | TIOCGWINSZで12x60を確認したが、キー入力前のPTY出力は0バイトで再描画しなかった。仕様2.2を再現せず。 |
| 起動時間 | 上記の高負荷計測を記録。 |
| ## W0-2: PTY E2E harness |
The pre-change source at 071c407 passed 117/117 PTY scenarios and reported
120/120 commands covered with HOME=$(mktemp -d) nix run .#e2e (exit 0). The
pre-rebase source commit e41d392 passed 118/118, including the new
harness resize and typed observations self-test, with
env HOME=$(mktemp -d) nix run .#e2e (exit 0). The rebase added the
runtime/command-trace scenario from origin/main. The final run on source
commit 8f0958e passed 119/119 scenarios and covered 120/120 commands with the
same command (exit 0). All 117 baseline scenarios remained passing.
After a later fetch/rebase of origin/main, the same command again passed
119/119 scenarios and covered 120/120 commands (exit 0).
The harness self-test checked the actual PTY window size (6, 80), terminal
cell attributes, file bytes, and raw CSI output in output.pty. Its result JSON
records each observation's type, actual value, expected value, and pass state;
examples include screen text, cell attributes, file bytes, external state, and
PTY output. In the final run, the artifact directory printed by the command
contained harness-resize-and-typed-observations-2ddeaf1104/result.json,
output.pty, and trace.jsonl; the trace file held three records for
newline, save-buffer, and save-buffers-kill-terminal. The
runtime/command-trace scenario separately checked these records in order:
forward-char/key/1, execute-extended-command/key/2,
backward-char/mx/3, and save-buffers-kill-terminal/key/4.
keys.RET changed the default Enter byte from LF (\n) to CR (\r). The
pre-rebase 118-scenario and final 119-scenario full runs passed with CR.
One intermediate run failed project file commands. The screen then showed
only a prefix of the project-root prompt, and the same scenario failed when run
alone. The scenario previously waited for that prefix; it now waits for the
full expected root. Its isolated rerun and the final full run passed. This
supports a prompt-render timing race diagnosis. No timeout was extended.
The --benchmarks mode reports measurements without failing against the NFR
targets. NFR-01 targets opening a 100,000-line, 5 MB file within 1.0 second and
input-to-redraw p95 within 50 ms; NFR-02 targets the first screen within 0.3
second. Redraw p95 uses 25 cursor-move samples. Each scenario kept the existing
10-second total and 5-second execution deadlines. Numerical results below are
高負荷下の参考値 and do not characterize Loom performance. The operator
reported load average 108 on 16 cores earlier in the run.
| Run | Measurement | Value |
|---|---|---|
| 1 | Startup to first screen (NFR-02) | 0.0736 s (高負荷下の参考値) |
| 1 | Redraw p95 (NFR-01, 25 samples) | 1.0042 ms (高負荷下の参考値) |
| 1 | Open 100,000-line / 5 MB file (NFR-01) | No valid measurement; 5-second execution deadline expired |
| 2 | Startup to first screen (NFR-02) | 0.0793 s (高負荷下の参考値) |
| 2 | Redraw p95 (NFR-01, 25 samples) | 0.8956 ms (高負荷下の参考値) |
| 2 | Open 100,000-line / 5 MB file (NFR-01) | No valid measurement; 5-second execution deadline expired |
| Isolated retry | Open 100,000-line / 5 MB file (NFR-01) | No valid measurement; 5-second execution deadline expired |
Two runs of env HOME=$(mktemp -d) nix run .#e2e -- --benchmarks exited 1 when
the large-file benchmark timed out; a separate run of that scenario alone also
exited 1 at the unchanged 5-second execution deadline. Because each report run
stops at that failure, neither produced a combined benchmark summary; the
completed startup and redraw values remain in their per-scenario result files.
These timeouts do not establish whether the NFR-01 open target passes or fails.
For the post-rebase source code, the following checks exited 0; the docs build was repeated after the final ledger edit:
PYTHONPATH=t/e2e python3 -m unittest -v test_cli test_deadline test_harness
python3 -m py_compile t/e2e/loom-test.py t/e2e/loom_e2e/*.py t/e2e/scenarios/*.py t/e2e/test_cli.py t/e2e/test_harness.py
env HOME=$(mktemp -d) nix run .#e2e
nix flake check --print-build-logs
nix build .#docs --no-link --print-build-logs
The Python unit suite passed all 58 tests. The final PTY run passed 119/119 scenarios and covered 120/120 commands. After the later rebase, the Nix flake check also exited 0 with all checks passing. Its default and coverage checks each passed 1504 tests, skipped 3, and reported 0 failures and 0 errors; coverage measured 20340/21278 expressions (95.59%) and 1946/2082 branches (93.47%).
An earlier nix flake check --print-build-logs exited 1 after two tests exceeded
their existing 40-second test timeout: %run-loom / enables and restores raw
mode against a real terminal descriptor, then returns 0 and MAIN CLI
integration / passes process arguments to cl-cli and exits successfully.
The isolated retry nix build .#checks.aarch64-darwin.default --no-link
--print-build-logs then passed; those tests completed in 0.148 and 13.945
seconds, respectively. A subsequent full flake check exited 0 with all seven
checks passing. The later post-rebase flake check also exited 0. This sequence
does not establish why the first run timed out; no timeout was changed.
The full check warned that x86_64-linux was omitted on this Darwin host and
that the E2E app has no meta attribute. Nix's auditTmpdir hook has printed a
broken pipe from find and a segmentation fault in its file-classifier
pipeline during a loom package install and docs installs. In the final check,
one docs install printed this fault; a later docs install emitted no such
diagnostic, and the coverage logs did not. The builds and full checks exited 0,
but completion of the affected scans is unverified. The cause was not
established.
Independent review follow-up¶
The static review of source 5fc06fc is resolved below. The runner's status
records whether a scenario completed without an exception. W0-4 must use
observation_class == "effect-verified" as its sole acceptance gate;
exit-code-only is one of the observation classes and does not pass that gate.
| Finding | Status | Resolution |
|---|---|---|
| Precondition observations | Done | Session wait helpers and the PTY-size self-check record purpose=precondition. All ten probe_command scenarios in the final run completed with observation_class: exit-code-only. |
| PTY resize redraw | Done | The self-test expands the PTY from 8 to 12 rows, drains already available PTY bytes before resizing, and checks the mode line at the new row after input triggers a redraw. With the redraw call in src/application/event-loop.lisp temporarily disabled, the same scenario failed on a blank mode-line row. The temporary source change was restored. |
| Observation API | Done | Public observe_* methods no longer accept passed=. Screen-text observations read the selected screen region or row from Session.screen; assertions use the observation result. |
| Trace collection | Closed by W0-3 | W0-3 removed the wrapper from t/e2e/scenarios/trace.py and records session.trace_bytes. The final runtime/command-trace result is effect-verified and records the expected 13 trace events. |
| Result identity | Done | Every runner-produced result.json contains binary_realpath and declared_commands. All 120 binary_realpath values pointed to executable files, and all 120 declared command lists were present. |
| Scenario failure handling | Done | The runner catches scenario Exception values at the scenario boundary, saves a failed result, and continues the suite. CLI tests cover ValueError, KeyError, TypeError, and RuntimeError. |
| Duplicate scenario names | Done | The registry raises ValueError when a duplicate scenario name is decorated. |
| PTY output classification | Done | pty_output is an effect observation. The four CLI scenarios were effect-verified; observation_class is the single verification criterion. |
| Trace line counts | Done | Each Session observation method snapshots trace_lines when called, before internal reads and matching. This is a conservative boundary: trace rows appended after the method begins cannot be counted for that observation. The resize self-test recorded counts from 0 through 5 alongside a five-line trace. |
Other review cleanup¶
expected=None now means an absent file, with a
sentinel distinguishing no expectation. Observation matching is shared with
assertions. Unused keys.NAMED and registry.covered_commands were removed.
layout.validate_dimensions is shared by the session, PTY, and screen. The
benchmark report imports its deadline values from deadline.py. Module-level
key byte constants were removed; Session.key resolves each name through its
selected terminal profile.
The normal resize self-test passed alone with the unchanged 5-second execution
budget: env HOME=$(mktemp -d) nix run .#e2e -- --only 'harness resize'
returned 0 for 1/1 scenario. The negative run disabled
%render-event-loop-frame temporarily and ran the same scenario alone. It
returned 1 after the row-10 mode-line observation remained blank. The harness preflight passed 70/70 tests
in both runs. No timeout was extended.
The final full run after rebasing on origin/main used
env HOME=$(mktemp -d) nix run .#e2e and returned 0: 120/120 scenarios passed
and 120/120 commands were covered. The baseline classified 114 scenarios as
effect-verified; the final run classified 18 that way. Of the 114 baseline
scenarios, 100 now have a stricter classification: 97 are exit-code-only and
3 are effect-unverified. They still passed functionally; their lane owners
must add explicit effect observations in W3. The final run also classified the
new --dump-catalog scenario as none because it recorded no observations.
The 97 transitions to exit-code-only are:
- Other:
ansi-wide-diff,ansi-wide-full,bookmarks set jump list delete,file-tree toggle,keyboard macro,major mode editing,numeric prefix,project find file,project search,register copy and insert,register point and jump,workspace switching. - Editing:
editing/auto-save-current-buffer,editing/auto-save-mode,editing/backward-kill-word,editing/comment-line,editing/delete-backward-char,editing/delete-char,editing/indent-for-tab-command,editing/kill-line,editing/kill-region,editing/kill-ring-save,editing/kill-sexp,editing/kill-word,editing/mark-whole-buffer,editing/narrow-to-region,editing/newline,editing/open-line,editing/redo,editing/replace-string,editing/set-mark-command,editing/toggle-auto-save,editing/toggle-read-only,editing/undo,editing/widen,editing/write-file,editing/yank,editing/yank-pop. - LSP:
lsp/completion,lsp/completion-success,lsp/diagnostics,lsp/find-definition,lsp/find-definition-success,lsp/find-definition-unicode,lsp/pop-definition,lsp/start,lsp/stop. - Macros:
macros/eval-buffer,macros/eval-expression,macros/execute-extended-command. - Movement:
movement/backward-barf-sexp,movement/backward-char,movement/backward-sexp,movement/backward-slurp-sexp,movement/backward-up-list,movement/backward-word,movement/beginning-of-buffer,movement/down-list,movement/end-of-buffer,movement/exchange-point-and-mark,movement/forward-barf-sexp,movement/forward-sexp,movement/forward-slurp-sexp,movement/forward-word,movement/fullwidth cursor column,movement/goto-line,movement/isearch-backward,movement/isearch-forward,movement/move-beginning-of-line,movement/move-end-of-line,movement/next-line,movement/previous-line,movement/raise-sexp,movement/scroll-down-command,movement/scroll-up-command,movement/search-backward,movement/search-forward,movement/set-mark-command,movement/splice-sexp,movement/wrap-round,movement/wrapped next-line. - Tooling:
tooling/format-current-buffer,tooling/format-on-save-mode,tooling/git-diff,tooling/git-diff-staged,tooling/git-stage-file,tooling/git-status,tooling/git-unstage-file,tooling/pipe-command,tooling/set-format-command,tooling/terminal,tooling/terminal-stop. - UI:
ui/execute-extended-command,ui/help,ui/keyboard-quit,ui/save-buffers-kill-terminal,ui/toggle-truncate-lines.
The three effect-unverified transitions are lsp/trust-review,
session save and load, and startup without path. Their observations include
effect types without a passing expected value. runtime/command-trace remains
effect-verified: W0-3 now observes the nonempty trace. The startup directory
scenario was already exit-code-only in the baseline and is not part of the
100 transitions.
After the final rebase, nix flake check --print-build-logs exited 0 with all
eight checks passing on aarch64-darwin; Nix omitted x86_64-linux. The coverage
derivation reported 1507 passed, 3 skipped, and 0 failed or errored.
W0-4 path generation and coverage report¶
The W0-4 report evaluated source commit
d22873984258842af0271716b88d9818b34ac4de on aarch64-darwin. The command
env HOME="$(mktemp -d)" nix run .#e2e exited 0. Its preflight ran 135 Python
tests; all passed. The runner prints the temporary artifact directory and the
path-coverage.json path within it.
The eleven real-terminal acceptance rows in the
author checklist remain Not run.
All 120 E2E scenarios completed without an exception (status=passed), and
command coverage was 120/120. These counts do not mean that path coverage
passed. The W0-2 observation contract excludes preconditions from classification;
only scenarios classified as effect-verified qualify for path acceptance.
The classifier removes purpose=precondition observations first. It reports
none when none remain, effect-verified when one or more effect types remain
and every effect has an expected value with passed=true, and
effect-unverified when any effect lacks either condition. With no effect
types, only exit_code observations produce exit-code-only; other remaining
types produce observations-only. Effect types are screen_text, cell_attrs,
cursor, file_bytes, external_state, and pty_output; the implementation
is in t/e2e/loom_e2e/results.py.
| Scenario observation class | Scenarios |
|---|---|
none |
1 |
effect-verified |
18 |
effect-unverified |
3 |
exit-code-only |
98 |
observations-only |
0 |
The generator applies rules R1–R8 from
docs/src/notes/requirements-modern-editor.md section 7.2 to the JSON from
bin/loom --dump-catalog, then compares required paths with every t/paths.sexp
under the repository. At the time of this run, the root t/paths.sexp was the
only ledger file.
The generated catalog contains 750 required paths. The report marked 0 as
passing and 0 as excluded. It lists 749 paths as not-in-ledger and one as
no-observation; the JSON report includes all 750 failed path IDs in
missing_paths.
The no-observation row is the generated R1 key path for save-buffer in
file and buffer commands. The scenario is globally effect-verified, but its
file_bytes observation is a precondition because wait_for_file records file
waits that way, including the wait after saving. The scenario types ! into
the buffer before invoking save-buffer; the resulting screen text !beta
would still appear if saving wrote nothing. The screen observation therefore
cannot verify the file effect declared by the :observe (:file_bytes) field in
the t/paths.sexp path ledger. No non-precondition file_bytes observation is
available. The scenario is unchanged; W3-3 must add the file-effect assertion.
Current trace rows contain command, route, seq, and pid, but no entry.
A key path therefore cannot pass the trace check until its exact entry is
recorded. The missing entry is not this path's current failure reason because
it fails the declared-effect-type check first.
The one matched path fails the declared-effect check before trace attribution, so the attribution-window rule adds no further count change in this run. The remaining 749 paths fail ledger lookup.
The report attributes an observation only to the latest traced command included
by its trace_lines snapshot. That command's trace row must match the path's
route and, when available, entry; the next trace row closes the attribution
window. Every command listed by the generated path needs a declared effect
observation in its own window. The t/paths.sexp ledger's :observe types
define which observations can satisfy that requirement. This prevents a screen
value that already existed before save-buffer, or an effect from only the last
command in a multi-command scenario, from covering the path.
Each Session observation method snapshots trace_lines when called. For
values read inside the method, this is before sampling, matching, and
serialization. A trace row appended after that snapshot is excluded, even if
it appears before the observation record is serialized.
The report therefore fails closed when the snapshot cannot prove that a target
command was already traced; it does not infer ordering from a later file read.
| Rule | Required | not-in-ledger |
no-observation |
|---|---|---|---|
| R1 | 218 | 217 | 1 |
| R2 | 211 | 211 | 0 |
| R3 | 210 | 210 | 0 |
| R4 | 8 | 8 | 0 |
| R5 | 60 | 60 | 0 |
| R6 | 32 | 32 | 0 |
| R7 | 7 | 7 | 0 |
| R8 | 4 | 4 | 0 |
Lane IDs refer to the W3 ownership table in section 11.6 of
requirements-modern-editor.md.
| Lane | Required | not-in-ledger |
no-observation |
|---|---|---|---|
| W3-1 | 9 | 9 | 0 |
| W3-2 | 20 | 20 | 0 |
| W3-3 | 42 | 41 | 1 |
| W3-4 | 125 | 125 | 0 |
| W3-5 | 3 | 3 | 0 |
| W3-6 | 62 | 62 | 0 |
| W3-7a | 25 | 25 | 0 |
| W3-7b | 103 | 103 | 0 |
| W3-8 | 62 | 62 | 0 |
| W3-9 | 40 | 40 | 0 |
| W3-10 | 175 | 175 | 0 |
| W3-11 | 84 | 84 | 0 |
On this source commit, nix flake check --print-build-logs exited 0 on
aarch64-darwin. All eight checks passed; the coverage derivation reported 1507
passed, 3 skipped, and 0 failed or errored. Nix omitted x86_64-linux and
warned that the E2E app lacks meta.