v0.6.17 — v0.6.16 は NOT_READY。CLI 結果の契約を v2 へ
v0.6.17 — v0.6.16 は NOT_READY です。CLI 結果の契約を v2 へ上げます
⚠ 先に読むところ
1. v0.6.16 は、版を据え置いたまま公開契約を広げていました
v0.6.16 の道具の出力は、1 つも v0.6.15 の schema を通りません。
同じ schemaId / schemaVersion: 1 を名乗りながら、言語が 3 か所広がっていました。
repo 自身の判定器で実測(2026-08-15・両 tag の実物):
diffSchemaObjects(v0.6.15 の v1, v0.6.16 の v1) = **BUMP**
WIDEN /properties/stableReasonCode/enum
+ CLI_ARGUMENTS_MISSING, SOURCE_FETCH_TIMEOUT
WIDEN /properties/archivePolicy/properties/coverage/properties/reasonCodeFamilies/items/enum + usage
WIDEN /properties/archivePolicy/properties/reasonCodeFamilies/items/enum + usage
対照 同じ schema どうしなら HOLD(何にでも BUMP と言う判定器ではない)
外部監査の指摘より影響が広いことが分かりました。
監査は「新しい 2 つの code を返す結果が不適合」としていましたが、
usage 族は archivePolicy に載るのですべての出力に出ます。ajv で実測:
v0.6.15 の v1 schema に当てる
引数不足の出力(CLI_ARGUMENTS_MISSING) → 不適合(3 か所)
**`OK` の正常な出力** → **不適合(2 か所)**
公開済みの asset は上書きしません。
docs/ERRATA.md §17 で
NOT_READY へ再分類しました。
受け手への影響は限定されます。 profile の数値・区間・event は変わりません。
使えないのは「v0.6.16 の出力を、後の版の schema で検証すること」だけです。
v0.6.16 が出した保存済みの結果は、v0.6.16 と一緒に配った v1 schema で検証してください。
v1 のファイルは変更していません。
2. schemaVersion が 2 に、toolVersion が 20 になります
v0.6.16 v0.6.17
schemaId …source-verifier-cli-result.v1 → …source-verifier-cli-result.v2
schemaVersion 1 → 2
toolVersion 19 → 20
配布ファイル名 source-verifier-cli-result.v1.schema.json → …v2.schema.json
ファイル名で引いている lock は、schema 検査へ到達する前に「ファイルが無い」で止まります。
対応は同梱の contract-migration.v1.json(renamedAssets)にあります。
止め方の名前の一覧・archivePolicy・status・終了コードの意味は変わっていません。
v1 → v2 で変わるのは、名乗る版だけです。
3. なぜ検査が通したか——母集団が 11 版のあいだ止まっていました
test/schemaVersioningPolicy.test.ts
const LATEST_TAG = 'v0.5.1' ← ここが母集団を決めていた
source-verifier-cli-result は v0.6.11 の新設なので、一度も母集団に入っていません。
コメントには「上げた回はここを新しい tag へ進める」と書いてありましたが、進みませんでした。
対照(2026-08-15): BUMP が実在する状態で v0.6.16 の検査を回すと **57/57 全緑**
「比較した本数 === 母集団の本数」という空振り検査は付いていました。
数えていたのは古いほうの一覧です。
v0.6.17 では、直前 release を package.json の版数から毎回その場で決め、
母集団を現行の schema 全部(git add していないものも含む)にしました。
この反例を違反として捕まえる回帰試験も入れています。
証拠の由来を、契約が要求するようにしました
v0.6.16 は testCountsSha256 / testCountsGeneratedFromCommit / testCountsGeneratedAt を
**書いてはいましたが、schema が要求していませんでした。**変異対照:
v2(旧) v3(新)
基準(無変更) 適合 適合
3 欄をそれぞれ消す 適合 **不適合**
SHA を 63 桁 / commit を短縮 / 日付を壊す 適合 **不適合**
未知項目を足す 適合 **不適合**
監査は「狭める変更なので HOLD_RECORD」と想定していましたが、判定器の実測は BUMP でした。
testEvidence は oneOf の中にあり、判定器は枝の言語について単調でないことを理由に
判定不能を返します。判定器を緩めず、validation-results を v3 へ上げました。
2 つの証拠を結び直しました
release:stage は、test_counts.json の鮮度と READY を別々に見ていました。
片方だけ作り直した状態は、どちらの検査も単体では通ります。
基準(無変更) 通す
test_counts だけ更新 **止める**
validation だけ更新 **止める**
SHA / commit / 日付 を偽装 **止める**
testEvidence ごと消す **止める**
関門を切り出してから測っています。release:stage を丸ごと回すと
手前の鮮度検査が先に落ちて全件が同じ exit 1 になり、
「この関門が効いた」の証拠になりません(実際に一度そう測って読み違えました)。
最終関門を通ったことが、配布物から読めるようになりました
release-stage-attestation.v1.json を足しました。
validation-results.releaseReadinessStatus: READY は release:evidence 時点の判定で、
最終関門を通った証拠ではありません。
**索引には入れません。**索引はこれより前に作られ、これは索引を読んでから作るので、
入れると 1 回の実行で収束しません。SHA256SUMS がこの記録の sha256 を持ちます。
**この記録も自己申告です。**作った側が作った側を検査した結果でしかなく、
受け手の独立検証を置き換えません。
終了コード 3 に、機械で読める目印を付けました
stderr の 1 行目: TRS_JACK_VERIFIER_INTERNAL_CONTRACT_FAILURE
**説明文は版ごとに書き換わります。**文言でなくこの 1 語で分岐してください。
通常の CLI 結果 schema へ INTERNAL_ERROR は足していません
——壊れた道具が schema 適合の検証結果を捏造するほうが危ないためです。
到達性の語彙を作りました
SOURCE_ARCHIVE_MISSING を defensive-invariant(論理的に起こりえない)から
race-defensive(確認と使用の間で消されれば到達する)へ移しました。外部監査の指摘どおりです。
あわせて、両方向の照合が reachability !== 'defensive-invariant' という
文字列の否定で群を分けていたのを、語彙表から引く形にしました。
否定で分けていると、新しい種類を足した瞬間に黙ってどちらかへ入ります。
まだやっていないこと
- **実測が 1 件も来ていません。**ジャック内部の接点位置は全部仮定のままで、
導通測定も音響測定もしていません(verifiedPhysicalはfalse)。 - **core と CLI の分離をしていません。**v0.6.16 の notes で「次の版で着手します」と
書きましたが、**この版でも着手していません。**外部監査も
「先に契約の versioning を閉じ、その次の独立版で着手するのが妥当」としています。
**この版は P0 の是正です。**次の版の最初に着手します。 - BusyBox を oracle に足すこと。開発機にも CI にもありません。
- annotated tag への署名。
- 検算ツールの強化は試験した範囲までです。すべての細工に耐えることは示していません。
SOURCE_ARCHIVE_MISSINGを実経路として踏んでいません。
race-defensiveは「確認と使用の間で消されれば到達する」という分類であって、
実際に踏んだ記録ではありません。踏むには filesystem を差し替える必要があり、
それは core / CLI 分離のあとになります。- 由来の検査(
release:evidence)の範囲は、artifacts/とdocs/を含みません。
含めると、証拠を書く工程が自分の書き込みで「古くなった」と判定して収束しません。
最終判定はrelease:stageが実際に測り直して行います。
再生成の途中で、新しい門が自分を止めました
**第3段の順序を間違えました。**第1段・第2段で artifact を作り直したあと、
manifest と索引がまだ追随していない状態で件数を数えたので、
突合の試験が 26 件落ちました。
記録された値 failed 26 / exitCode 1 / allPassed false
門の反応 releaseReadiness NOT_READY・release:stage が拒否
生成は止めず、配布を止める設計どおりです——件数の照合が落ちている間は
件数を更新できない、という循環を避けるためにこの形にしてあります。
正しい順序(release:evidence → test:count → release:evidence)で回し直しました。
数えたもの
| v0.6.16 | v0.6.17 | |
|---|---|---|
| 検算ツール | toolVersion 19 |
20 |
| 出力契約 | …cli-result.v1 / schemaVersion 1 |
…cli-result.v2 / 2 |
| 止め方の名前(catalog) | 82 種類 | 変わらず 82 |
| うち到達しないと宣言 | 4(defensive-invariant) |
3 + race-defensive 1 |
| schema | 23 | 25(cli-result.v2 と validation-results.v3 を新設) |
| 検証結果の契約 | validation-results.v2 |
validation-results.v3 |
| version 検査の母集団 | v0.5.1 の 21 本 | 現行の 25 本 |
変わっていないもの
- **モデルの数値。**接点位置も走査結果も同じです。
葉ノードで比較して実測しています(感度 artifact: 由来まわりの差 10 件・モデル数値の差 0 件。
対照として 1 つの値を 0.001 動かすと「モデル数値の差 1 件」が出ます)。 verifiedPhysicalはfalse。実測記録は依然 0 件です。- 止め方の名前の一覧・
archivePolicy・status・終了コードの意味。 - 過去 release の asset。