v0.6.18 — v0.6.17 の attestation を是正し、core と CLI を分離
v0.6.18 — v0.6.17 の attestation に誤りがありました。core と CLI を分離しました
⚠ 先に読むところ
1. v0.6.17 の attestation は、配った索引とは別のものを指していました
公開した直後に、自分で添付を検算して見つけました。
attestation が名乗る値 e9c72e2412fa6e21… ← **repo 側**の索引(releaseTag: null)
配布した索引の実測 a014768129b56e18… ← 受け手が計算する値
違う欄 releaseTag / releaseCommit(配布時に書き込む)
3 つの digest のうち 2 つは一致していました。test_counts.json と
validation-results.json は配布時にそのまま写すので同じ値になります。
索引だけが写しではありません——releaseTag と releaseCommit を配布時に書き込むためです。
**「ほとんど合ってしまう」のが危ないところでした。**ずれるのは
受け手が最初に引く 1 つだけです。
公開済みの v0.6.17 の asset は上書きしません。
docs/ERRATA.md §23 に記録し、
この版で直しました(測る先を配布物の側へ)。この欠陥を捕まえる検査も入れています。
v0.6.17 での影響は
attestation.releaseIndexSha256の 1 欄だけです。
SHA256SUMSは配布物から作っているので正しく、索引の検算はそちらで行えます。
2. core と CLI を分離しました。toolVersion も schemaVersion も上げていません
外部監査 P2(v0.6.15 / v0.6.16 / v0.6.17 で 3 回続けて指摘)にようやく着手しました。
新設 defaultIo()(cwd / argv / stdout / stderr / exit + filesystem 5 種)
差替 process.* と console.log の呼び出しを io 経由へ
残す 入口の判定 2 か所(この道具が起動されたのかを見るもの)
上げていない根拠を実測で示します。
出力 分離前に固定した **9 経路すべてが byte 一致**(基準は現在 10 経路。
10 本目は分離のあとに足した SOURCE_ARCHIVE_MISSING の経路)
出しうる code **82 種類のまま**(増減 0)
schemaVersion 2 のまま・配布 schema も不変
出力に出るか reachability は出力に 0 件(対照: stableReasonCode は 1 件)
**受け手の分岐は変わりません。**上げたくなったら、それは分離ではありません。
分離が「何も変えていない」ことは、分離の前に取った基準で確かめています
(test/fixtures/cli-output-baseline.v1.json・npm run check:cli-output)。
基準は repo に入っているので、受け手も同じものを回せます。
3. SOURCE_ARCHIVE_MISSING を実経路として踏みました
v0.6.17 で race-defensive(到達しうるが決定的には踏めない)と宣言した code です。
踏めました。「決定的には踏めない」は踏む試験を書いていなかっただけでした。
loadFromDir existsSync(abs) … 通る
lstatSync(abs) … ディレクトリでない → loadFromArchive へ
loadFromArchive existsSync(abs) … **ここで消えていればこの code**
同じ path に対する 2 回目の existsSync だけ false にすれば踏めます。
node:fs を差し替えて注入します——道具は 1 バイトも変えません
(globalThis.fetch の差し替えと同じ形)。
catalog race-defensive → **cli-route**
82 種類 = corpus 45 / cli-route 34 / defensive-invariant 3
両方向照合 この run で出た 79 種類・到達しないと宣言した 3 種類(実測と一致)
race-defensive は語彙表に残しました(未使用であることを試験で明示)。
4. io へ filesystem を足しましたが、この経路には効いていません
実測(2026-08-15):
同じ注入(node:fs の差し替え)を当てる
io に fs が無い版 → SOURCE_ARCHIVE_MISSING
io に fs を足した版 → SOURCE_ARCHIVE_MISSING
node:fs の差し替えは ESM の named import にも効くので、
io を経由してもしなくても同じように踏めます。
この経路を踏むために io へ fs を足す必要はありませんでした。
残した理由は先の話です——main(args, io) を抽出したあとは、
global を差し替えずに fs を注入できるようになります。
いまは「そのための土台」であって、いま効いているわけではありません。
効いていないものを効いていると書かないでおきます。
まだやっていないこと
- **実測が 1 件も来ていません。**ジャック内部の接点位置は全部仮定のままで、
導通測定も音響測定もしていません(verifiedPhysicalはfalse)。 - **
main(args, io)の抽出そのものは、まだです。**この版でやったのは
接点を 1 か所に集めたところまでで、done()はまだio.exitを叩きます。
戻り値だけで完結する形にするのは次です。 - BusyBox を oracle に足すこと。開発機にも CI にもありません。
- annotated tag への署名。
- 検算ツールの強化は試験した範囲までです。すべての細工に耐えることは示していません。
数えたもの
| v0.6.17 | v0.6.18 | |
|---|---|---|
| 単体テスト | 1352 | 1364(skip 0 / 失敗 0) |
| 検算ツール | toolVersion 20 |
変わらず 20 |
| CLI 結果契約 | schemaVersion 2 |
変わらず 2 |
| 止め方の名前(catalog) | 82 種類 | 変わらず 82 |
| うち到達しないと宣言 | 3 + race-defensive 1 |
3(race-defensive は未使用) |
| 出力の基準(経路) | (無し) | 10 経路(うち 9 件は分離前に固定) |
検証対象(validate:profiles) |
14 | 14 |
| schema | 25 | 25 |
| 記録された入力 | 32 | 32 |
| 区間 / event | TRS 23/32・TRRS 30/36 | 変わらず |
変わっていないもの
- **モデルの数値。**接点位置も走査結果も同じです。
verifiedPhysicalはfalse。実測記録は依然 0 件です。toolVersion20 / CLI 結果契約schemaVersion2。- 止め方の名前の一覧(82 種類)・
archivePolicy・status・終了コードの意味。