Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35b3de0d59 | ||
|
|
379a1ba8fd | ||
|
|
f4f85bc54c | ||
|
|
8e4f1d92fc | ||
|
|
e7acd530c5 | ||
|
|
903a2c566e | ||
|
|
806de25068 | ||
|
|
e0420d57a3 |
@@ -0,0 +1,125 @@
|
||||
# P19-03 実装提出報告
|
||||
|
||||
提出状態。受入は未確定。原受入「7名×3ルートの到達表があり、未制作内容は欠損として残る。」を維持する。14/88は変更しない。
|
||||
|
||||
## 変更範囲
|
||||
|
||||
Repair 1開始点e0420d57a381a1644357f0590536e1d47c9bca9fから、このディレクトリの指定5ファイルのみを変更した。原本、原子要件、work packages、decisions、TASK_SPEC、選定記録、frozen pins、ゲーム入力、marker registryは変更していない。git書込み、他worker起動、Runner操作、ゲーム起動は行っていない。素材追加なし。
|
||||
|
||||
## 要件と検査の対応
|
||||
|
||||
|TASK_SPEC implementation_requirements順|成果物|検査|
|
||||
|---|---|---|
|
||||
|1: 原7名×3ルート|REACHABILITY_TABLE.json / .md|expectedのPEOPLE/ROUTES、原本118–124行、atomic entityと21セルの完全一致。test_exact_cell_product|
|
||||
|2: 8カテゴリ、共通/人物固有の分離|JSON common_rules / cells.categories|CATEGORIES全件のcanonical比較。test_categories_and_citations|
|
||||
|3: 原本本文・行・status・anchorのsource SHA・owner|JSONの各共通項目/人物固有項目、catalog_evidence|expected.evidence/cite、verify。test_stale_record_evidence / test_owner_and_status|
|
||||
|4: 欠損、理由、担当、未知値pending|各character_specific、pending、natural_route_complete=false|test_no_invented_values_or_completion。D05/D08は未回答のまま|
|
||||
|5: docs内stdlibチェッカー/自己試験|check_reachability_table.py / test_reachability_table.py|stdlib importsのみ。選択対象外のdocs内配置|
|
||||
|6: read-only --check、厳密な表/Markdown|verify / verify_records / markdown|test_json_and_types / test_markdown_drift。--checkは書込み分岐を通らない|
|
||||
|7: 全frozen source mapと各identity|binding / selection|1368選択ファイルの完全map、marker/policy/engine、184-suite roster、329 .gd、baseline、spec→pins SHA。test_full_frozen_map_and_identities / test_real_source_and_baseline_changes|
|
||||
|8: UI/Runtime/save/Windowsの適用性|JSON route_support、MDルート別適用性|各ルートをcanonical比較。汎用UIラベル、原本登録Runtime、専用snapshotの限定証拠をcommon_rulesで参照|
|
||||
|9: 有意な負例と3種の正例|test_reachability_table.py|欠落/重複/誤人物/誤route/カテゴリ/引用/古い本文・SHA/値創作/誤完成/owner・status/JSON型/Markdown、実ファイル読込差替え、map差分とpins/marker/policy/engine改変。全3statusを含む正例|
|
||||
|10: P13パターン・原文保全|checkerのexpected/verify/markdown、原資料のbase blob照合|tools/check_p13_content_difference.pyのcanonical生成・厳密比較・read-only Git blob証拠パターンを参照。元ファイルは無変更|
|
||||
|11: 報告・残課題・外部gate|本報告、JSON accounting|正式試験・全単位独立レビュー・統合/finalは未実行と明記|
|
||||
|
||||
原子要件はB-7.1〜B-7.6をsource_group_idsに含む61件の完全レコードを読込対象とし、JSON authority_snapshotsに保持する。人物キーと原名はそのentityから確認し、原本§6の順で並べた。原本§6は114–135行、§7は136–161行であり、実際の見出しと本文を照合した。人物別の原本仕様がない部分を共通ルールから創作していない。中断/保存の人物固有手順は原本に定義されず、work_packagesのP19-02受入が所有する欠損として残した。
|
||||
|
||||
指定されたoriginal_relationship_state.gdには7名のrosterはなく、汎用subject_id等の明示入力検証のみがある。既存unique catalogのヒロインはheroine_anriのみ。監査IDには既存atomic entity.key(anri/fine/tomari/amelia/liz/mimi/satsuki)を使い、他6名の実装catalog ID、ライバル対応、初期値を創作していない。この実装欠損は表の欠損であり、原7名を削減する理由にしていない。
|
||||
|
||||
## Repair 1: 4指摘の対応
|
||||
|
||||
編集前に build/owner-handoff/p19-review-r01/ の ACTUAL_OPUS_REPAIR_DIRECTION.json、ACTUAL_WHOLE_UNIT_REVIEW.json、SPEC_HASH_REPRESENTATIONS.json を読んだ。
|
||||
|
||||
- MEDIUM: coassignment_attack / zero_break / love_actions / threshold_route_loss と旧UIのlegacy_evidenceを追加。固定anchorの実際の本文・行・Git blob OID・file-bytes SHA-256を保持する。原本準拠statusはmissing、旧実装分類はlegacy_not_originalに統一。P18-01は一対一変換を禁止し、旧数値・日次制限は原本として未承認と明記した。UI定数は実際には98–101行であり、89–97行の無関係なラベルを除いた。共通ルール参照により各該当セルへ結び付けた。所有者・原本欠損・natural_route_complete=falseを維持。
|
||||
- LOW 独立試験: validate_legacyは候補とcanonicalの比較とは独立に、git showで固定anchorのソースを読み、引用行本文とgit rev-parseによるblob OID、現ファイルとの一致を検査する。test_independent_legacy_source_evidenceは実際のJSONと実ファイルを開き、git hash-object --stdin(書込みなし)でOIDを独立計算し、関数名とshield_broken/EXCLUSIVE_LOCKEDも確認。test_legacy_evidence_required_independentlyは対象全項目の証拠削除・空配列・無条件not implemented・古いOID/本文を拒否する。
|
||||
- LOW 中断参照: 全21セルのinterruption_cancellationに原本148・153行の本文とbaseline hash、および343–355行のconfirm_route_lockをlegacy_not_originalとして追加。人物固有欠損と担当は維持。
|
||||
- LOW ハッシュ表示: 263a01b943d8056727335fb76977c010298e1c229077f8da76e48683ba2e89bb は TASK_SPEC.json file-bytes SHA-256。3af3d9b931edc5449796662ad69bb6f67c80b48827a86565b1952931db68dd15 は Runner git-show stripped-UTF-8 contract spec_sha256。上記SPEC_HASH_REPRESENTATIONS.jsonのunchanged_file=trueが証拠であり、両者は同じ無変更ファイルを表す。checker定数と出力にも区別を反映。Git blob OIDは別のgit_blob_oidフィールドでありfile-bytes SHA-256とは区別する。
|
||||
|
||||
## Repair 1の実行記録(過去のローカル確認)
|
||||
|
||||
以下は正式Runner実行ではない。記録済み修復指示に基づき3登録コマンドをローカル実行した。
|
||||
|
||||
生成 — exit 0
|
||||
|
||||
```sh
|
||||
python3 -B /Users/korizatou114/Projects/TheTree-managed-worktrees/p19-03-reachability/P19-03-TABLE-implement/docs/plans/original-completion-2026-10-02/execution/p19-03/check_reachability_table.py --project-root /Users/korizatou114/Projects/TheTree-managed-worktrees/p19-03-reachability/P19-03-TABLE-implement --write
|
||||
```
|
||||
|
||||
p19-table — exit 0
|
||||
|
||||
```sh
|
||||
python3 -B /Users/korizatou114/Projects/TheTree-managed-worktrees/p19-03-reachability/P19-03-TABLE-implement/docs/plans/original-completion-2026-10-02/execution/p19-03/check_reachability_table.py --project-root /Users/korizatou114/Projects/TheTree-managed-worktrees/p19-03-reachability/P19-03-TABLE-implement --check
|
||||
```
|
||||
|
||||
p19-negative — exit 0
|
||||
|
||||
```sh
|
||||
python3 -B /Users/korizatou114/Projects/TheTree-managed-worktrees/p19-03-reachability/P19-03-TABLE-implement/docs/plans/original-completion-2026-10-02/execution/p19-03/test_reachability_table.py --project-root /Users/korizatou114/Projects/TheTree-managed-worktrees/p19-03-reachability/P19-03-TABLE-implement
|
||||
```
|
||||
|
||||
p19-source-binding — exit 0
|
||||
|
||||
```sh
|
||||
python3 -B /Users/korizatou114/Projects/TheTree-managed-worktrees/p19-03-reachability/P19-03-TABLE-implement/docs/plans/original-completion-2026-10-02/execution/p19-03/check_reachability_table.py --project-root /Users/korizatou114/Projects/TheTree-managed-worktrees/p19-03-reachability/P19-03-TABLE-implement --source-binding-only
|
||||
```
|
||||
|
||||
--writeの実際の呼出しは同一checkout内で相対スクリプトパスと --project-root . を使用(上記は絶対パス表記)。--checkはMarkdownのバイト完全一致を確認。自己試験は12件OK。source bindingは1368ファイル一致、file_equality=true、actual_commit=e0420d57a381a1644357f0590536e1d47c9bca9f、native_evidence_reuse_accepted=false。git diff --checkはexit 0。構文は上記Python実行で確認。最初の編集用here-documentは一時ファイル作成制限でexit 1、変更は行われず、python3 -cで再実行してexit 0。native full・ゲーム起動・git書込み・Runner操作・他エージェント起動は行っていない。
|
||||
|
||||
## 残る親成果・ゲームの欠損
|
||||
|
||||
- P18-01: 原本3軸/盾の通常UI、承認済み初期値、本来の全単位受入。P18-02/03: 同配置・軽減・ブレイク・接触・閾値・確定遷移。既存旧汎用モデルの閾値を原本へ転用しない。
|
||||
- P19-01/02: 原本行動と全3種決闘、勝敗・費用・盾/履歴の一度だけ反映、通常入口、停止/取消/離脱/保存再開。原本状態保持のbackendを自然ルート完成としない。
|
||||
- P20-01/02/03: スキル/章・全エンド・図鑑と新規からの通常到達。P26-01/02/03: 人物別必要内容、状態接続、完成資産と制作受入。人物固有イベント/条件/履歴/立ち絵差分は欠損。
|
||||
- D05、D08はpending。未知の閾値・率・初期値もpendingのまま。P04の既存D05選択、P13の4件の制作followupも未解決。
|
||||
- この文書単位のnative GUI/Windows実行は適用外。global same-Windows、held gestures、全ゲーム受入はopen。固定入力一致から既存native証拠の正式再利用承認を推定していない。
|
||||
- Runnerの3 validator、原本§6–7と元受入に対する実装者から独立したwhole-unit Opus review、その後の通常prepare-integration/finalが必要。どの完了数・元台帳も変更していない。
|
||||
|
||||
|
||||
## Repair 2: BASE定義projectionと台帳更新の分離
|
||||
|
||||
開始点Sは806de25068bc423136063791afcea811d251ee1b。編集前にACTUAL_OPUS_REPAIR2_DIRECTION.jsonとACTUAL_FAILED_INTEGRATION.json、immutable TASK_SPECと既存チェッカーを確認。最新run指示に従い、実マージ候補の作成・検証は実装担当では行わない。指定5ファイルのみを変更する。Repair 1の4修正を保持し、任意の低3指摘は延期したまま。
|
||||
|
||||
### 実差分とallowlistの根拠
|
||||
|
||||
git showによるBASE 8ca9263とmain 6e17caeのkey-level比較を行った。candidate 1875b03のwork_packages.jsonは6e17caeと完全一致。差分は次だけ(配列index 19=P19、remaining_deliverables index 2=P19-03):
|
||||
|
||||
|JSON path|差分|
|
||||
|---|---|
|
||||
|/19/current_summary|変更|
|
||||
|/19/updated_at_jst|変更|
|
||||
|/19/remaining_deliverables/2/current_execution|TASK_SPEC.jsonからROOT_CURRENT_ACCEPTANCE_STATUS.jsonへの参照更新|
|
||||
|/19/remaining_deliverables/2/current_summary|変更|
|
||||
|/19/remaining_deliverables/2/progress_summary|変更|
|
||||
|/19/remaining_deliverables/2/remaining_gaps/0, /1|通常integration/final待ちの進捗説明へ更新|
|
||||
|/19/remaining_deliverables/2/evidence|1件から2件|
|
||||
|/19/remaining_deliverables/2/submitted_commit|806de25068bc423136063791afcea811d251ee1bを追加|
|
||||
|/19/remaining_deliverables/2/updated_at_jst|変更|
|
||||
|
||||
package allowlistはstate / legacy_state / current_summary / updated_at_jst。unit allowlistはstate / current_execution / remaining_gaps / updated_at_jst / submitted_commit / current_summary / progress_summary / evidence。state系は通常進捗遷移として明示的に許可し、同じ実registerに既存のキーだけを採用した。通常finalの完了時刻・source-ref用に、BASEの他unitで既に使われるcompleted_at_jst(P13-03)、implementation_commit(P13-03)、integrated_commit(P13-02)、integration_commit(P13-03)、normal_integration_candidate(P04-01)だけをunit階層で追加許可した。キーのprefixや任意のtimestamp/source_refキーは許可しない。allowlistの値は進捗メタデータとしてprojectionから全体を除外する。
|
||||
|
||||
それ以外の全キーは未知キーを含め再帰的な値・型・有無を保ち、BASE projectionと比較する。30 package / 88 unitのID・順序・件数、全title/work/acceptance、phase/parent/depends_on/requirement_ids/decisions/supplement_ids/owner_roles/state_scope等を固定する。atomic_requirements.jsonとdecisions.jsonは実main差分なしのため引き続きbyte-exact。D05/D08のstatus/answerは変更不可。selection recordもbyte-exact。
|
||||
|
||||
所有者集合・原子要件・authority_snapshotsはBASE blobのみから読む。各snapshotはanchored_base_commit、BASE blobのsha256、projected recordsを保持する。work packagesは全30/88定義を保持し、進捗を除外した。表の21セル、共通ルール・引用・status・owner・欠損・pending/null値は変更していない。Markdownには固定参照の説明だけを追加した。--writeは1回実行、--checkは読込み専用。
|
||||
|
||||
### Repair 2 ローカル実行
|
||||
|
||||
cwdとproject-rootは /Users/korizatou114/Projects/TheTree-managed-worktrees/p19-03-reachability/P19-03-TABLE-implement。
|
||||
以下は正式Runner試験ではない。実際の呼出しは各scriptをdocs/plans/original-completion-2026-10-02/execution/p19-03/配下の相対パスで指定し、--project-rootには上記実絶対パスを指定した。
|
||||
|
||||
- python3 -B docs/plans/original-completion-2026-10-02/execution/p19-03/check_reachability_table.py --project-root /Users/korizatou114/Projects/TheTree-managed-worktrees/p19-03-reachability/P19-03-TABLE-implement --write: exit 0。
|
||||
- p19-table: python3 -B docs/plans/original-completion-2026-10-02/execution/p19-03/check_reachability_table.py --project-root /Users/korizatou114/Projects/TheTree-managed-worktrees/p19-03-reachability/P19-03-TABLE-implement --check: exit 0。
|
||||
- p19-source-binding: python3 -B docs/plans/original-completion-2026-10-02/execution/p19-03/check_reachability_table.py --project-root /Users/korizatou114/Projects/TheTree-managed-worktrees/p19-03-reachability/P19-03-TABLE-implement --source-binding-only: exit 0。
|
||||
|
||||
上記3呼出しのstdoutはaudit_integrity=pass、formal_acceptance=pending_runner_and_independent_review、actual_commit=806de25068bc423136063791afcea811d251ee1b、selected_files=1368、anchor=1b07b87d3736e777932315a4bdde8b70cbf9cb23、file_equality=true、native_evidence_reuse_accepted=false。spec file-bytesとRunner contractの両hashも従来値のまま。
|
||||
|
||||
実mainおよび失敗candidateの実blobをPath.read_bytes差替えで読ませる自己試験は、生成JSONとMarkdownのbyte完全一致を検証する。実registerの書換え・一時worktree・mergeは不要。合成完了/source-ref例も同じ検査を通す。各定義フィールドの変更・削除、package/unit objectの未知キー追加、package/unit/各定義listの件数/順序変更、D05/D08承認、atomic/decisions/selectionの変更を個別subtestで拒否する。既存12テストは維持。
|
||||
|
||||
実merged-candidate確認: **Root preflight pending**。新S提出と通常validation後、Rootが最新main上の実Sについてラベル付き非正式isolated preflightで同じ3チェッカーを実行する。その後に別Opus whole-original re-review、通常prepare-integration/finalが必要。今回のローカル成功やworker exit 0は受入ではない。正式進捗14/88は維持。native GUI/Windowsは本単位に適用外、global Windowsとゲーム受入はopen。
|
||||
|
||||
自己試験の探索版2回は全recordや深い履歴データの同型フィールドまで反復走査して時間がかかったため中断(各exit 130、KeyboardInterrupt)。package/unitの異なる定義キーごとに変更・削除を検査し、ネストした定義値は全体を比較する形へ整理した。BASE blobを一度実読込して負例ループ内で再利用し、各負例ごとのgit show起動を省いた。検査対象・既存controlは削除していない。shell here-documentを用いた初回の読取り差分確認は環境の一時ファイル制約で失敗(exit 1)、python3 -cで同じ確認を実行した。
|
||||
|
||||
最終p19-negative呼出し: python3 -B docs/plans/original-completion-2026-10-02/execution/p19-03/test_reachability_table.py --project-root /Users/korizatou114/Projects/TheTree-managed-worktrees/p19-03-reachability/P19-03-TABLE-implement
|
||||
|
||||
exit 0、出力: Ran 16 tests in 16.285s / OK。実main/candidate正例、合成final正例、全package/unit定義フィールド負例と既存controlを含む。git diff --checkもexit 0。最終差分は指定5ファイルのみ。生成前後のJSONを比較しauthority_snapshots以外の全フィールドが一致することも静的確認した。
|
||||
|
||||
同じp19-tableコマンドを絶対scriptパスで再確認(exit 0、同じpass出力)。呼出し前後にこのディレクトリの全通常ファイルSHA-256 mapを比較し一致: Read-only byte determinism: pass。最終git diff --checkもexit 0。
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"purpose": "Nonformal Root diagnostic actual S+latestMain; not usual prepare-integration candidate, not owner-approved, no original credit",
|
||||
"S": "903a2c566e73cebc874a6499410a1243bc190a63",
|
||||
"M": "6e17cae5c9f0133fc3eb19e58572977f4151de7c",
|
||||
"preflight_commit": "7f9b63b0c281d57be4abec1c576e5abef273ca78",
|
||||
"preflight_tree": "5fd36ac7825980524f7d14137434a7866dd114ac",
|
||||
"source": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p19-03-reachability/P19-03-TABLE-root-preflight-5343471e",
|
||||
"root_pid": 49701,
|
||||
"time_ns": 1792235765159907000,
|
||||
"normal_integration_or_final_satisfied": false,
|
||||
"passed": true,
|
||||
"all3_original_checks_passed": true,
|
||||
"actual_report": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/66089140e92a48b2bc96ea67ca597b58-root-preflight.json",
|
||||
"time_end_ns": 1792235786176952000,
|
||||
"new_native_runs": 0,
|
||||
"whole_original_acceptance": false,
|
||||
"task_state_unchanged": "review_pending"
|
||||
}
|
||||
+81
-18
@@ -1,28 +1,28 @@
|
||||
{
|
||||
"at_jst": "2026-10-17T19:58:24.516684+09:00",
|
||||
"at_jst": "2026-10-17T20:29:39.555420+09:00",
|
||||
"plan_id": "P19-03",
|
||||
"registered_task": "P19-03-TABLE",
|
||||
"project": "the-tree-p19-03-reachability",
|
||||
"S": "806de25068bc423136063791afcea811d251ee1b",
|
||||
"S": "903a2c566e73cebc874a6499410a1243bc190a63",
|
||||
"implementation_model": "gpt-6.1-sol",
|
||||
"actual_model_decision": "c767de1cd89d40e5a23964f2e62ce4c6",
|
||||
"state": "whole_original_review_passed_integration_final_pending",
|
||||
"state": "completed_original_P19_03",
|
||||
"original_acceptance": "7名×3ルートの到達表があり、未制作内容は欠損として残る。",
|
||||
"original_units": 88,
|
||||
"formally_completed": 14,
|
||||
"new_credit": 0,
|
||||
"formally_completed": 15,
|
||||
"new_credit": 1,
|
||||
"registered_validation": {
|
||||
"passed": true,
|
||||
"artifact": "ROOT_FORMAL_VALIDATION_806DE25.json",
|
||||
"artifact": "ROOT_FORMAL_VALIDATION_903A2C5.json",
|
||||
"checks": [
|
||||
"p19-table",
|
||||
"p19-negative",
|
||||
"p19-source-binding"
|
||||
],
|
||||
"self_tests": 12
|
||||
"self_tests": 16
|
||||
},
|
||||
"actual_reviewer": {
|
||||
"id": "38eaaacdb31b4c76bcf982987816a391",
|
||||
"id": "565d4f21c12b451da2d5a7dd462d099b",
|
||||
"status": "finished_pass"
|
||||
},
|
||||
"reviewer_model": "claude-opus-5-5",
|
||||
@@ -31,12 +31,9 @@
|
||||
"markers_policy_engine_roster_parse_default_player_same": true,
|
||||
"full184_21903_329parse_186ended_reuse_qualified": true,
|
||||
"new_native_runs": 0,
|
||||
"artifact": "ROOT_EXACT_GAME_INPUT_REUSE_806DE25.json"
|
||||
"artifact": "ROOT_EXACT_GAME_INPUT_REUSE_903A2C5.json"
|
||||
},
|
||||
"required_before_acceptance": [
|
||||
"Normal actual integrationC/M and independent candidate source/input equality",
|
||||
"Normal final and existing exact real-owner main authorization, thenledger/push; no new humanSHA speech fabricated"
|
||||
],
|
||||
"required_before_acceptance": [],
|
||||
"source_gaps_preserved": [
|
||||
"Six missing productioncatalog IDs are not fabricated; table audit uses existing original atomic entity keys",
|
||||
"D05/D08 and unknown values/content remain missing or pending; backend/generic labels are not natural route completion",
|
||||
@@ -46,19 +43,85 @@
|
||||
"Initial registered {worktree} invocation failed before scripts opened; exact-root adapter madeactual3sameSchecks run, repairs0/source/config/policy unchanged",
|
||||
"Initial full inline review rejected beforeinference at actual1milliontoken providerlimit; completefile/diff sourceviews retainalloriginalbytes, no file/bytecaps, sameOpus5.5/sourceS"
|
||||
],
|
||||
"normal_integration_candidate": null,
|
||||
"repairs": 1,
|
||||
"normal_integration_candidate": "8e4f1d92fc2a2e8f1dd187e661cf52b13e4e51d4",
|
||||
"repairs": 2,
|
||||
"repair_cap": null,
|
||||
"whole_original_review": {
|
||||
"run_id": "38eaaacdb31b4c76bcf982987816a391",
|
||||
"run_id": "565d4f21c12b451da2d5a7dd462d099b",
|
||||
"status": "pass",
|
||||
"critical_high_medium": 0,
|
||||
"low": 3,
|
||||
"artifact": "ROOT_WHOLE_REVIEW_806DE25.json"
|
||||
"artifact": "ROOT_WHOLE_REVIEW_903A2C5.json"
|
||||
},
|
||||
"actual_repair_worker": {
|
||||
"id": "bf8a86e053044bfea0051253fefb2ec7",
|
||||
"status": "finished"
|
||||
},
|
||||
"repair_scope": "Same5Docfiles: legacy presence vsoriginalconformance for4clauses, independent source-presence/evidence-loss tests, route-ending interruption crossrefs, precise hash labels. No game/values/pins/roster changes."
|
||||
"repair_scope": "Same5Docfiles: legacy presence vsoriginalconformance for4clauses, independent source-presence/evidence-loss tests, route-ending interruption crossrefs, precise hash labels. No game/values/pins/roster changes.",
|
||||
"actual_preflight": {
|
||||
"passed": true,
|
||||
"source": "903a2c566e73cebc874a6499410a1243bc190a63",
|
||||
"preflight_commit": "7f9b63b0c281d57be4abec1c576e5abef273ca78",
|
||||
"main": "6e17cae5c9f0133fc3eb19e58572977f4151de7c",
|
||||
"normal_integration_or_final_satisfied": false,
|
||||
"artifact": "ROOT_ACTUAL_NONFORMAL_MAIN_PREFLIGHT_903A2C5.json"
|
||||
},
|
||||
"previous_actual_integration_failure": {
|
||||
"commit": "1875b032b7f6a8525fb6ccec0574e21769943c95",
|
||||
"reason": "Checker incorrectly froze mutable workpackages metadata; now definition projection remainsfailclosed, originalfactsunchanged",
|
||||
"artifact": "ROOT_FAILED_FORMAL_INTEGRATION_806DE25.json"
|
||||
},
|
||||
"table_fact_comparison": {
|
||||
"only_changed": "authority_snapshots representation",
|
||||
"all21cells_rules_statuses_owners_gaps_unchanged": true,
|
||||
"artifact": "ROOT_TABLE_FACT_COMPARISON_806_TO_903.json"
|
||||
},
|
||||
"registered_task_state": "completed",
|
||||
"normal_main_base": "e7acd530c5d43313534d0b6ee23c915aba3cf70a",
|
||||
"source_on_main": true,
|
||||
"normal_final": {
|
||||
"passed": true,
|
||||
"commit": "8e4f1d92fc2a2e8f1dd187e661cf52b13e4e51d4",
|
||||
"artifact": "ROOT_NORMAL_FINAL_C8E4F1D9.json"
|
||||
},
|
||||
"whole_original_P19_03_accepted": true,
|
||||
"whole_game_accepted": false,
|
||||
"related_open_work": [
|
||||
"P18/P19-01/P19-02/P20/P26 natural gameplay, all7character-specific content and6productioncatalogIDs",
|
||||
"D05/D08 and unapproved initial/threshold/rate values remain unanswered or missing",
|
||||
"SameWindows/globalgame acceptance and heldgestures stillopen; docaudit OSexecution notapplicable"
|
||||
],
|
||||
"normal_final_pending": false,
|
||||
"closure_evidence": [
|
||||
{
|
||||
"path": "ROOT_WHOLE_REVIEW_903A2C5.json",
|
||||
"actual_original": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/565d4f21c12b451da2d5a7dd462d099b/result.json",
|
||||
"bytes": 5470,
|
||||
"sha256": "779e58c3d31556ea25ae3fe134dccc0335a8ab14dd675ea80f97c51768223550"
|
||||
},
|
||||
{
|
||||
"path": "ROOT_NORMAL_INTEGRATION_C8E4F1D9.json",
|
||||
"actual_original": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/83e6d08d9ac245d6b35941ac165d3318-integration.json",
|
||||
"bytes": 854,
|
||||
"sha256": "aa6148bc06f9ab9f9ef28364d8511b6beca4a5d4a4b6d1299f7d769bb9b44f78"
|
||||
},
|
||||
{
|
||||
"path": "ROOT_NORMAL_FINAL_C8E4F1D9.json",
|
||||
"actual_original": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/213aafebe6254110bf349c25b6036d92-final.json",
|
||||
"bytes": 848,
|
||||
"sha256": "4c5ec540ff0b527d37454b16cb392b14aff1ae598c445722d9625b30b91d8ea6"
|
||||
},
|
||||
{
|
||||
"path": "ROOT_RUNNER_COMPLETED_TRACEABILITY.json",
|
||||
"actual_original": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/traceability/P19-03-TABLE.json",
|
||||
"bytes": 5090,
|
||||
"sha256": "b433a6b52bb722fa8e9cdc2a161abbca71693f45926bb5c7bf1b00716d3d7f5a"
|
||||
},
|
||||
{
|
||||
"path": "ROOT_EXACT_C8E4F1D9_QUALIFICATION.json",
|
||||
"actual_original": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p19-03-reachability/.runtime/coordinator-start-20261017/EXACT_C8E4F1D9_P19_QUALIFICATION.json",
|
||||
"bytes": 2584,
|
||||
"sha256": "f15125c39a2cf2b42618dfbd9c9a9834f5c32c6b8f256b245de80a7b460ebcc0"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"actual_review": "565d4f21c12b451da2d5a7dd462d099b",
|
||||
"findings": [
|
||||
{
|
||||
"severity": "low",
|
||||
"message": "test_actual_main_and_candidate_metadata names commits by abbreviated SHA (6e17cae, 1875b03). The test only works where those objects exist. That holds in the current repository, but full SHAs, or a clear explanation of the dependency, would make it more reproducible."
|
||||
},
|
||||
{
|
||||
"severity": "low",
|
||||
"message": "Three low notes from the previous review (806de25) are still deferred: (1) per-entry function-name markers for every legacy citation, (2) the label on the Repair 1 local actual_commit line, (3) aligning the snapshot_container range to function boundaries. This deferral is allowed. Item (2) is already addressed by the 「過去のローカル確認」 label."
|
||||
},
|
||||
{
|
||||
"severity": "low",
|
||||
"message": "Most data-level negative tests still compare the document against the same expected() canonical. The checker's hardcoded facts (statuses, owners) are therefore protected from tampering by self-comparison, not proven correct by the tests. I separately confirmed in the actual source and work_packages that the classifications and owners are correct."
|
||||
}
|
||||
],
|
||||
"disposition": "Optional nonblocking hardening/clarity only. All required original audit conditions passed independent semantic review and normal integration/final.",
|
||||
"preserved_reproduction_fixture": {
|
||||
"full_commit": "1875b032b7f6a8525fb6ccec0574e21769943c95",
|
||||
"remote_branch": "codex/p19-03-integration-fixture-1875b03",
|
||||
"fetch_if_single_branch_clone": "git fetch origin refs/heads/codex/p19-03-integration-fixture-1875b03:refs/remotes/origin/codex/p19-03-integration-fixture-1875b03",
|
||||
"other_required_commit": "6e17cae5c9f0133fc3eb19e58572977f4151de7c",
|
||||
"no_main_adoption_of_failed_fixture": true
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"S": "903a2c566e73cebc874a6499410a1243bc190a63",
|
||||
"C": "8e4f1d92fc2a2e8f1dd187e661cf52b13e4e51d4",
|
||||
"M": "e7acd530c5d43313534d0b6ee23c915aba3cf70a",
|
||||
"candidate_worktree": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p19-03-reachability/P19-03-TABLE-integration-69419f96",
|
||||
"all1368_game_inputs_marker_policy_engine_roster_parse_default_player_identical": true,
|
||||
"all8_reviewed_doc_artifacts_byte_identical": {
|
||||
"docs/plans/original-completion-2026-10-02/execution/p19-03/ACTUAL_OPUS_NEXT_ORIGINAL_UNIT_SELECTION.json": {
|
||||
"bytes": 5614,
|
||||
"sha256": "c3c8d7367d67c6f8b74ae620357de631f8e4a158940c4d019f71e897900a1c29"
|
||||
},
|
||||
"docs/plans/original-completion-2026-10-02/execution/p19-03/FROZEN_GAME_INPUT_PINS.json": {
|
||||
"bytes": 234047,
|
||||
"sha256": "6c778226a4cc6d0b0d682500759e7d4229c926a27bd2e247b00b9c3e5f1a2fb0"
|
||||
},
|
||||
"docs/plans/original-completion-2026-10-02/execution/p19-03/IMPLEMENTATION_REPORT.md": {
|
||||
"bytes": 16909,
|
||||
"sha256": "07ec5fd2a50c328ac01859807913315023e4e8b550f11457fc8345b4606573b9"
|
||||
},
|
||||
"docs/plans/original-completion-2026-10-02/execution/p19-03/REACHABILITY_TABLE.json": {
|
||||
"bytes": 1609120,
|
||||
"sha256": "9904095c19742bac2871ea62347543cfc6169771454bc7419fccc2ac1e95779c"
|
||||
},
|
||||
"docs/plans/original-completion-2026-10-02/execution/p19-03/REACHABILITY_TABLE.md": {
|
||||
"bytes": 133432,
|
||||
"sha256": "afb99eede4c8b4a9aca4bf3113c88acc02998f0aec3c8f89ebd6179042b4f887"
|
||||
},
|
||||
"docs/plans/original-completion-2026-10-02/execution/p19-03/TASK_SPEC.json": {
|
||||
"bytes": 8290,
|
||||
"sha256": "263a01b943d8056727335fb76977c010298e1c229077f8da76e48683ba2e89bb"
|
||||
},
|
||||
"docs/plans/original-completion-2026-10-02/execution/p19-03/check_reachability_table.py": {
|
||||
"bytes": 23419,
|
||||
"sha256": "d2b78349ee95dcdd30d2aa7d1f2be41d8d82abd14bbe73f4394e3227fd1a2b43"
|
||||
},
|
||||
"docs/plans/original-completion-2026-10-02/execution/p19-03/test_reachability_table.py": {
|
||||
"bytes": 14770,
|
||||
"sha256": "d6cc4ceb770e9e329d0f2087a7fdf973ef8470a6f98072f2c37118f9ed8c6901"
|
||||
}
|
||||
},
|
||||
"exact_184_21903_329parse_186ended_native_evidence_reuse_qualified": true,
|
||||
"actual_independent_whole_original_review": "565d4f21c12b451da2d5a7dd462d099b",
|
||||
"critical_high_medium": 0,
|
||||
"low": 3,
|
||||
"normal_candidate_integration_passed": true,
|
||||
"new_native_runs": 0,
|
||||
"normal_final_pending": true,
|
||||
"original_unit_credit": 0,
|
||||
"authority": "Existing explicit human main-update+commit/push authorization; no new SHA-specific human speech is claimed",
|
||||
"time_ns": 1792236328462308000
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"artifact_S": "903a2c566e73cebc874a6499410a1243bc190a63",
|
||||
"existing_product_C": "65f07bf5eaa759a8e2e17c7bdbbbdbceb24ee373",
|
||||
"old_actual_native_S": "a7e3069b167511b3194242b3403fbcc35244a526",
|
||||
"all1368_selected_source_settings_assets_tests_tools_byte_equal": true,
|
||||
"marker_policy_engine_roster_parse_default_player_equal": true,
|
||||
"scope": "All source_refs keys exactly equal; no file set was narrowed or omitted. New doc-only audit helpers are outside this unchanged pre-existing selection algorithm.",
|
||||
"native_full_evidence_reuse_qualified": true,
|
||||
"new_native_runs": 0,
|
||||
"existing_full": {
|
||||
"actual_suites": 184,
|
||||
"missing_marker_paths": [],
|
||||
"remaining_unexecuted_tests": [],
|
||||
"available_marker_checks": 21903,
|
||||
"actual_all_roster_checks": 21903,
|
||||
"strict_accepted_checks": 21903,
|
||||
"verified": true,
|
||||
"composed": true,
|
||||
"original_full_attempt_passed": false,
|
||||
"whole_original_acceptance": false,
|
||||
"parse_checks": 329,
|
||||
"setup_phases": 2,
|
||||
"owned_ended": 186,
|
||||
"tested_source": "a7e3069b167511b3194242b3403fbcc35244a526",
|
||||
"engines_started": 0,
|
||||
"verifier_sha256": "d00bf46bfcc0e0bb197edd284a3ae14610ca710507831e18e071a79461946e8a"
|
||||
},
|
||||
"previous_actual_whole_backend_Opus_review": "ead8e74b9683404d8cf3d97bca118726",
|
||||
"P19_whole_original_acceptance": "pending actual independent semantic review of full original §6–7, all21cells and all source/status/owner/gap claims, then normalintegration/final",
|
||||
"time_ns": 1792235874948502000
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"task_id": "P19-03-TABLE",
|
||||
"commit": "1875b032b7f6a8525fb6ccec0574e21769943c95",
|
||||
"kind": "integration",
|
||||
"checks": [
|
||||
{
|
||||
"id": "p19-table",
|
||||
"exit_code": 1,
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/3dff1e2121844313a07c39c5f8d57842",
|
||||
"passed": false
|
||||
},
|
||||
{
|
||||
"id": "p19-negative",
|
||||
"exit_code": 5,
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/07a0ef3637d64512b6338f4b21dbfbad",
|
||||
"passed": false
|
||||
},
|
||||
{
|
||||
"id": "p19-source-binding",
|
||||
"exit_code": 0,
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/0d2aac5d24564ab6ab517bad0d3eca74",
|
||||
"passed": true
|
||||
}
|
||||
],
|
||||
"passed": false
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"task_id": "P19-03-TABLE",
|
||||
"commit": "903a2c566e73cebc874a6499410a1243bc190a63",
|
||||
"kind": "validation",
|
||||
"checks": [
|
||||
{
|
||||
"id": "p19-table",
|
||||
"exit_code": 0,
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/de99282b6b4049f4932747d96ae9acae",
|
||||
"passed": true
|
||||
},
|
||||
{
|
||||
"id": "p19-negative",
|
||||
"exit_code": 0,
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/471595c34bc84eab924953516ee8642d",
|
||||
"passed": true
|
||||
},
|
||||
{
|
||||
"id": "p19-source-binding",
|
||||
"exit_code": 0,
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/24589f23e8884d268bf37fb86b05ed46",
|
||||
"passed": true
|
||||
}
|
||||
],
|
||||
"passed": true
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"task_id": "P19-03-TABLE",
|
||||
"commit": "8e4f1d92fc2a2e8f1dd187e661cf52b13e4e51d4",
|
||||
"kind": "final",
|
||||
"checks": [
|
||||
{
|
||||
"id": "p19-table",
|
||||
"exit_code": 0,
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/3e87d070e02045d3b10f1ac05a864fc7",
|
||||
"passed": true
|
||||
},
|
||||
{
|
||||
"id": "p19-negative",
|
||||
"exit_code": 0,
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/d73482521c484f1595cfae5b0abb0dba",
|
||||
"passed": true
|
||||
},
|
||||
{
|
||||
"id": "p19-source-binding",
|
||||
"exit_code": 0,
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/2a9d3970f4b8415cb784a4a556729219",
|
||||
"passed": true
|
||||
}
|
||||
],
|
||||
"passed": true
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"task_id": "P19-03-TABLE",
|
||||
"commit": "8e4f1d92fc2a2e8f1dd187e661cf52b13e4e51d4",
|
||||
"kind": "integration",
|
||||
"checks": [
|
||||
{
|
||||
"id": "p19-table",
|
||||
"exit_code": 0,
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/8387e3805df94f448d9eaefae379cb4c",
|
||||
"passed": true
|
||||
},
|
||||
{
|
||||
"id": "p19-negative",
|
||||
"exit_code": 0,
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/4c9f9b10eb3b497b960137c50f1053b6",
|
||||
"passed": true
|
||||
},
|
||||
{
|
||||
"id": "p19-source-binding",
|
||||
"exit_code": 0,
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/bc9693db775f42c99ee06d53ee169755",
|
||||
"passed": true
|
||||
}
|
||||
],
|
||||
"passed": true
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
{
|
||||
"contract": {
|
||||
"id": "P19-03-TABLE",
|
||||
"title": "P19-03 分岐の到達性:原7名×3ルートの全到達表と未制作欠損監査",
|
||||
"requirement_ids": [
|
||||
"P19-03"
|
||||
],
|
||||
"acceptance_ids": [
|
||||
"P19-03"
|
||||
],
|
||||
"spec_ref": "docs/plans/original-completion-2026-10-02/execution/p19-03/TASK_SPEC.json",
|
||||
"base_commit": "8ca9263fee1ec4374d97c01fda82b95e1df6a977",
|
||||
"worker": "codex",
|
||||
"allowed_paths": [
|
||||
"docs/plans/original-completion-2026-10-02/execution/p19-03/**"
|
||||
],
|
||||
"depends_on": [],
|
||||
"resource_locks": [
|
||||
"p19-route-reachability-audit"
|
||||
],
|
||||
"validation_ids": [
|
||||
"p19-table",
|
||||
"p19-negative",
|
||||
"p19-source-binding"
|
||||
],
|
||||
"max_repair_attempts": null,
|
||||
"spec_sha256": "3af3d9b931edc5449796662ad69bb6f67c80b48827a86565b1952931db68dd15"
|
||||
},
|
||||
"implementation_commit": "903a2c566e73cebc874a6499410a1243bc190a63",
|
||||
"integration_commit": "8e4f1d92fc2a2e8f1dd187e661cf52b13e4e51d4",
|
||||
"owner": "このチャットのユーザーの既存明示指示「mainの更新を明示的に許可します」「コミットすべき内容をコミットして。その上でpushして」に基づく継続許可。原P19-03の全条件レビュー合格と実C/M検証に対象を拘束し、新しいSHA指定の人間発言は主張しない。全ゲーム/他原成果の完了を意味しない。",
|
||||
"evidence": [
|
||||
{
|
||||
"id": 1,
|
||||
"task_id": "P19-03-TABLE",
|
||||
"kind": "validation",
|
||||
"commit_sha": "e0420d57a381a1644357f0590536e1d47c9bca9f",
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/239449693d9a4172a4feee317c184b6d-validation.json",
|
||||
"passed": 0
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"task_id": "P19-03-TABLE",
|
||||
"kind": "validation",
|
||||
"commit_sha": "e0420d57a381a1644357f0590536e1d47c9bca9f",
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/bf963f060c934169ae0ef366b28fcd3f-validation.json",
|
||||
"passed": 1
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"task_id": "P19-03-TABLE",
|
||||
"kind": "review",
|
||||
"commit_sha": "e0420d57a381a1644357f0590536e1d47c9bca9f",
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/d4e70e7f48f549b085692962f88531a8/result.json",
|
||||
"passed": 0
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"task_id": "P19-03-TABLE",
|
||||
"kind": "validation",
|
||||
"commit_sha": "806de25068bc423136063791afcea811d251ee1b",
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/406baca45e5f41c294ea45d380c945fc-validation.json",
|
||||
"passed": 1
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"task_id": "P19-03-TABLE",
|
||||
"kind": "review",
|
||||
"commit_sha": "806de25068bc423136063791afcea811d251ee1b",
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/38eaaacdb31b4c76bcf982987816a391/result.json",
|
||||
"passed": 1
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"task_id": "P19-03-TABLE",
|
||||
"kind": "integration",
|
||||
"commit_sha": "1875b032b7f6a8525fb6ccec0574e21769943c95",
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/be88ab416157401d97718dc80f68fd51-integration.json",
|
||||
"passed": 0
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"task_id": "P19-03-TABLE",
|
||||
"kind": "validation",
|
||||
"commit_sha": "903a2c566e73cebc874a6499410a1243bc190a63",
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/c3ed2fa3df3145fa97a037c574b6e228-validation.json",
|
||||
"passed": 1
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"task_id": "P19-03-TABLE",
|
||||
"kind": "root-preflight",
|
||||
"commit_sha": "7f9b63b0c281d57be4abec1c576e5abef273ca78",
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/66089140e92a48b2bc96ea67ca597b58-root-preflight.json",
|
||||
"passed": 1
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"task_id": "P19-03-TABLE",
|
||||
"kind": "review",
|
||||
"commit_sha": "903a2c566e73cebc874a6499410a1243bc190a63",
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/565d4f21c12b451da2d5a7dd462d099b/result.json",
|
||||
"passed": 1
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"task_id": "P19-03-TABLE",
|
||||
"kind": "integration",
|
||||
"commit_sha": "8e4f1d92fc2a2e8f1dd187e661cf52b13e4e51d4",
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/83e6d08d9ac245d6b35941ac165d3318-integration.json",
|
||||
"passed": 1
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"task_id": "P19-03-TABLE",
|
||||
"kind": "final",
|
||||
"commit_sha": "8e4f1d92fc2a2e8f1dd187e661cf52b13e4e51d4",
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/213aafebe6254110bf349c25b6036d92-final.json",
|
||||
"passed": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"from": "806de25068bc423136063791afcea811d251ee1b",
|
||||
"to": "903a2c566e73cebc874a6499410a1243bc190a63",
|
||||
"changed_top_level_keys": [
|
||||
"authority_snapshots"
|
||||
],
|
||||
"identical_top_level_keys": [
|
||||
"task_id",
|
||||
"schema_version",
|
||||
"identity_policy",
|
||||
"source_anchor",
|
||||
"common_rules",
|
||||
"cells",
|
||||
"catalog_evidence",
|
||||
"pending",
|
||||
"route_support",
|
||||
"acceptance",
|
||||
"accounting"
|
||||
],
|
||||
"current_keys": [
|
||||
"task_id",
|
||||
"schema_version",
|
||||
"identity_policy",
|
||||
"source_anchor",
|
||||
"common_rules",
|
||||
"cells",
|
||||
"authority_snapshots",
|
||||
"catalog_evidence",
|
||||
"pending",
|
||||
"route_support",
|
||||
"acceptance",
|
||||
"accounting"
|
||||
]
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"task_id": "P19-03-TABLE",
|
||||
"commit": "903a2c566e73cebc874a6499410a1243bc190a63",
|
||||
"status": "pass",
|
||||
"summary": "I re-reviewed the whole original P19-03 unit at 903a2c5, read-only. I did not edit or run anything.\n\n**Original acceptance (「7名×3ルートの到達表があり、未制作内容は欠損として残る。」)**\n- The acceptance text is identical to work_packages.json:9021.\n- I read BASELINE §6 (114–135) and §7 (136–161) directly. The 7 names in REACHABILITY_TABLE.md (アンリ/フィーネ/トマリ/アメリア/リズ/ミミ/サツキ) match lines 118–124 in order. Each cell cites its own character line (118…124).\n- The 21 cell IDs map to existing atomic records AR.heroine.<key>.route.{love,ntr,corruption}. I checked anri.route.love directly: B-7.1, entity key and original_name match.\n- Every cell has all 8 categories: entry events, state conditions, duel win/loss, route/selection effects, interruption/cancellation, save, history/marks, current reachability.\n- Common rules are kept separate from per-character content. All 23 common rules cite exact original line text plus the baseline hash, and the quoted text matches the BASELINE file.\n- Every per-character item is recorded as 欠損 / 原本未定義 / D08 pending, with a reason, an owner and natural_route_complete=false. The owners are P18-02, P19-01, P19-02, P20-02, P26-01 and P26-02, and they match those deliverables' titles and work in work_packages.\n- D05, D08, thresholds, rates and initial values all stay pending/null, with no invented numbers.\n\n**Checked against the actual game source**\n- data/characters/mvp_unique_characters.json contains only heroine_anri and rival_rai. None of the other six names appear anywhere under data/.\n- original_relationship_state.gd only validates and holds generic fields; it has no roster. So \"implemented\" is limited to that narrow storage, and \"partial\" to the affection/shield-max invariant, the snapshot container and the identity check.\n- There is no duel, history or pregnancy code anywhere in autoload/scripts/scenes. lust and netorare appear only in state validation, never in updates. The \"missing\" statuses are honest.\n- Legacy shield, route-lock and UI-label code is cited with blob OIDs and labelled legacy_not_original, never credited as an original route. Backend support is not called a completed natural route. Using atomic keys while leaving the six missing catalog IDs as explicit gaps is the honest choice and invents nothing.\n\n**Repair 2 (projection)**\n- PACKAGE_MUTABLE and UNIT_MUTABLE allow only progress, reference, evidence and time fields that already exist in BASE.\n- Every other field, including id/title/work/acceptance/depends_on/requirement_ids/decisions/owner_roles, is compared exactly against the BASE 8ca9263 projection. Type is preserved via json.dumps, so True does not compare equal to 1.\n- atomic_requirements.json, decisions.json and the selection record stay byte-exact against BASE.\n- test_every_register_definition_field changes or removes each distinct definition key, adds unknown keys, and alters list counts and order. D05 and D08 flipping to approved is rejected, and the real main 6e17cae and candidate 1875b03 registers are accepted as positive cases.\n- The fact comparison shows only authority_snapshots changed. I confirmed the 21 cells, common rules, statuses, owners and gaps are unchanged from the previously passed 806de25.\n\n**Scope and validation**\n- The diff touches only the 5 allowed files under execution/p19-03/.\n- All 3 registered checks ran on 903a2c5 and exited 0. p19-table binds actual_commit 903a2c5, 1368 selected files, file_equality true. p19-negative ran 16 tests, OK.\n- The Root non-formal preflight on S plus latest main (7f9b63b) also passed all 3 checks. It is not normal integration or final.\n- The earlier failed integration (1875b03) was recorded honestly and fixed without changing any original definition. No test was deleted or disabled.\n\n**Open items**\n- D08 and per-character content, P18–P20/P26 gameplay, and global Windows/game acceptance all stay open.\n- No credit before normal prepare-integration/final and the ledger update. Only then can the count move from 14/88 to 15/88.",
|
||||
"acceptance_ids": [
|
||||
"P19-03"
|
||||
],
|
||||
"findings": [
|
||||
{
|
||||
"severity": "low",
|
||||
"message": "test_actual_main_and_candidate_metadata names commits by abbreviated SHA (6e17cae, 1875b03). The test only works where those objects exist. That holds in the current repository, but full SHAs, or a clear explanation of the dependency, would make it more reproducible."
|
||||
},
|
||||
{
|
||||
"severity": "low",
|
||||
"message": "Three low notes from the previous review (806de25) are still deferred: (1) per-entry function-name markers for every legacy citation, (2) the label on the Repair 1 local actual_commit line, (3) aligning the snapshot_container range to function boundaries. This deferral is allowed. Item (2) is already addressed by the 「過去のローカル確認」 label."
|
||||
},
|
||||
{
|
||||
"severity": "low",
|
||||
"message": "Most data-level negative tests still compare the document against the same expected() canonical. The checker's hardcoded facts (statuses, owners) are therefore protected from tampering by self-comparison, not proven correct by the tests. I separately confirmed in the actual source and work_packages that the classifications and owners are correct."
|
||||
}
|
||||
]
|
||||
}
|
||||
+367
@@ -0,0 +1,367 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Read-only, stdlib P19-03 documentation validator; never accepts gameplay."""
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
OUT = 'docs/plans/original-completion-2026-10-02/execution/p19-03/'
|
||||
PLAN = 'docs/plans/original-completion-2026-10-02/'
|
||||
BASELINE = 'docs/traceability/original/BASELINE.txt'
|
||||
ANCHOR = '1b07b87d3736e777932315a4bdde8b70cbf9cb23'
|
||||
BASE = '8ca9263fee1ec4374d97c01fda82b95e1df6a977'
|
||||
BASE_HASH = '75e4bdbdeb379c9269553f0c776bdb9cc96e01f2d6aa5ca650d132c63a8aeb1a'
|
||||
SPEC_FILE_BYTES_SHA256 = '263a01b943d8056727335fb76977c010298e1c229077f8da76e48683ba2e89bb'
|
||||
# Proof: build/owner-handoff/p19-review-r01/SPEC_HASH_REPRESENTATIONS.json
|
||||
# Both hashes describe the same unchanged TASK_SPEC.json.
|
||||
RUNNER_CONTRACT_SPEC_SHA256 = '3af3d9b931edc5449796662ad69bb6f67c80b48827a86565b1952931db68dd15'
|
||||
PINS_HASH = '6c778226a4cc6d0b0d682500759e7d4229c926a27bd2e247b00b9c3e5f1a2fb0'
|
||||
ROUTES = {'love': '純愛', 'ntr': 'NTR', 'corruption': '堕落'}
|
||||
PEOPLE = [('anri', 'アンリ'), ('fine', 'フィーネ'), ('tomari', 'トマリ'),
|
||||
('amelia', 'アメリア'), ('liz', 'リズ'), ('mimi', 'ミミ'), ('satsuki', 'サツキ')]
|
||||
CATEGORIES = ('entry_required_events', 'state_conditions', 'duel_effects',
|
||||
'route_selection_effects', 'interruption_cancellation', 'save_handling',
|
||||
'history_marks', 'current_reachability')
|
||||
STATE = 'scripts/relationship/original_relationship_state.gd'
|
||||
SERVICE = 'scripts/relationship/relationship_service.gd'
|
||||
RUNTIME = 'autoload/simulation_runtime.gd'
|
||||
CATALOG = 'data/characters/mvp_unique_characters.json'
|
||||
|
||||
EVENT = 'scripts/events/event_service.gd'
|
||||
PREVIEW = 'scripts/relationship/placement_risk_preview_service.gd'
|
||||
LEGACY_REASON = 'P18-01 forbids one-to-one conversion; legacy numbers/daily limits are not approved originals.'
|
||||
LEGACY_RANGES = {
|
||||
'coassignment_attack': [(SERVICE,264,312),(RUNTIME,6850,6850),(EVENT,1039,1039),(PREVIEW,536,565),(PREVIEW,619,640)],
|
||||
'zero_break': [(SERVICE,264,312),(RUNTIME,6850,6850),(EVENT,1039,1039)],
|
||||
'love_actions': [(SERVICE,246,261)],
|
||||
'threshold_route_loss': [(SERVICE,315,340),(SERVICE,343,355),(RUNTIME,342,343),(EVENT,1047,1047)],
|
||||
'legacy_event_ui': [('scenes/main/main.gd',98,101)],
|
||||
}
|
||||
|
||||
|
||||
def validate_legacy(root, document):
|
||||
rules = {r['id']: r for r in document['common_rules']}
|
||||
for identity, ranges in LEGACY_RANGES.items():
|
||||
rule = rules[identity]
|
||||
require(rule['status'] == 'missing' and rule['legacy_classification'] == 'legacy_not_original',
|
||||
'legacy/original classification')
|
||||
require(rule['implementation'] == 'original conformance missing; see legacy_evidence'
|
||||
and rule['legacy_reason'] == LEGACY_REASON, 'unqualified legacy absence')
|
||||
entries = rule.get('legacy_evidence')
|
||||
require(type(entries) is list and len(entries) == len(ranges), 'missing legacy evidence')
|
||||
for entry, (path, start, end) in zip(entries, ranges):
|
||||
data = blob(root, ANCHOR, path)
|
||||
oid = subprocess.check_output(['git','rev-parse',ANCHOR+':'+path],cwd=root).decode().strip()
|
||||
require(entry == {'path':path,'anchor':ANCHOR,'git_blob_oid':oid,
|
||||
'sha256':sha(data),'lines':[start,end],
|
||||
'text':'\n'.join(data.decode().splitlines()[start-1:end])}, 'legacy text/blob/range')
|
||||
require(data == (root/path).read_bytes(), 'legacy current source mismatch')
|
||||
|
||||
|
||||
def sha(data):
|
||||
return hashlib.sha256(data).hexdigest()
|
||||
|
||||
|
||||
def require(value, message):
|
||||
if not value:
|
||||
raise ValueError(message)
|
||||
|
||||
|
||||
def decode(data):
|
||||
def unique(pairs):
|
||||
result = {}
|
||||
for k, v in pairs:
|
||||
require(k not in result, 'duplicate JSON key: ' + k)
|
||||
result[k] = v
|
||||
return result
|
||||
return json.loads(data, object_pairs_hook=unique,
|
||||
parse_constant=lambda s: (_ for _ in ()).throw(ValueError(s)))
|
||||
|
||||
|
||||
def blob(root, commit, path):
|
||||
return subprocess.check_output(['git', 'show', commit + ':' + path], cwd=root)
|
||||
|
||||
|
||||
def selection(root):
|
||||
paths = [p for folder in ('autoload', 'scripts', 'scenes', 'data', 'tests', 'assets', 'tools')
|
||||
for p in (root / folder).rglob('*')
|
||||
if p.is_file() and p.name != '.DS_Store' and '__pycache__' not in p.parts]
|
||||
paths += [root / p for p in ('project.godot', 'export_presets.cfg', 'Makefile', 'AGENTS.md')]
|
||||
require(all(not p.is_symlink() for p in paths), 'selected source aliases refused')
|
||||
return {p.relative_to(root).as_posix(): {'bytes': p.stat().st_size, 'sha256': sha(p.read_bytes())}
|
||||
for p in sorted(paths)}
|
||||
|
||||
|
||||
def binding(root):
|
||||
raw = lambda p: (root / p).read_bytes()
|
||||
require(sha(raw(OUT + 'TASK_SPEC.json')) == SPEC_FILE_BYTES_SHA256, 'immutable spec changed')
|
||||
spec = decode(raw(OUT + 'TASK_SPEC.json'))
|
||||
require(sha(raw(OUT + 'FROZEN_GAME_INPUT_PINS.json')) == spec['frozen_game_input_pins_sha256'] == PINS_HASH,
|
||||
'frozen pins SHA differs from immutable spec')
|
||||
pins = decode(raw(OUT + 'FROZEN_GAME_INPUT_PINS.json'))
|
||||
require(pins['audited_game_source_anchor_commit'] == spec['audit_source_anchor'] == ANCHOR, 'anchor identity')
|
||||
actual = selection(root)
|
||||
require(actual == pins['source_files'], 'full selected-source map: missing/new/changed file')
|
||||
for key in ('marker_contract', 'policy', 'engine'):
|
||||
require(sha(Path(pins[key + '_path']).read_bytes() if key == 'engine' else raw(pins[key + '_path']))
|
||||
== pins[key + '_sha256'], key + ' identity')
|
||||
require(sha(raw(BASELINE)) == pins['baseline_sha256'] == BASE_HASH, 'baseline hash')
|
||||
require(len(raw(BASELINE)) == pins['baseline_bytes'], 'baseline bytes')
|
||||
roster = ['tests/run_tests.gd'] + sorted(p.relative_to(root).as_posix()
|
||||
for p in (root / 'tests').rglob('test*.gd') if 'export' not in p.relative_to(root).parts
|
||||
and p.relative_to(root).as_posix() != 'tests/s0/test_kernel_and_save.gd')
|
||||
require(roster == pins['roster'], 'roster identity')
|
||||
require(sum(p.endswith('.gd') for p in actual) == pins['parse_files'], 'parse selection identity')
|
||||
# Audit evidence is bound to published blobs, never a future self-containing commit.
|
||||
for p in (STATE, SERVICE, RUNTIME, CATALOG):
|
||||
require(raw(p) == blob(root, ANCHOR, p), 'stale audited source: ' + p)
|
||||
return {'actual_commit': subprocess.check_output(['git', 'rev-parse', 'HEAD'], cwd=root).decode().strip(),
|
||||
'selected_files': len(actual), 'anchor': ANCHOR, 'file_equality': True,
|
||||
'native_evidence_reuse_accepted': False,
|
||||
'TASK_SPEC_file_bytes_sha256': SPEC_FILE_BYTES_SHA256,
|
||||
'Runner_git_show_stripped_UTF8_contract_spec_sha256': RUNNER_CONTRACT_SPEC_SHA256}
|
||||
|
||||
|
||||
# Exact key-level BASE -> 6e17cae/1875b03 diff; no prefix/wildcard exclusions.
|
||||
PACKAGE_MUTABLE = frozenset(("state", "legacy_state", "current_summary", "updated_at_jst"))
|
||||
UNIT_MUTABLE = frozenset((
|
||||
"state", "current_execution", "remaining_gaps", "updated_at_jst",
|
||||
"submitted_commit", "current_summary", "progress_summary", "evidence",
|
||||
# Normal final/source references: these names already occur in BASE units.
|
||||
"completed_at_jst", "implementation_commit", "integrated_commit",
|
||||
"integration_commit", "normal_integration_candidate",
|
||||
))
|
||||
|
||||
|
||||
def definition_projection(register):
|
||||
require(type(register) is list, "package register must be a list")
|
||||
projected = []
|
||||
for package in register:
|
||||
require(type(package) is dict, "package must be an object")
|
||||
record = {k: v for k, v in package.items() if k not in PACKAGE_MUTABLE}
|
||||
units = record.get("remaining_deliverables")
|
||||
require(type(units) is list, "deliverables must be a list")
|
||||
require(all(type(unit) is dict for unit in units), "unit must be an object")
|
||||
record["remaining_deliverables"] = [
|
||||
{k: v for k, v in unit.items() if k not in UNIT_MUTABLE} for unit in units]
|
||||
projected.append(record)
|
||||
return projected
|
||||
|
||||
|
||||
def validate_register(root, name, current):
|
||||
anchored = blob(root, BASE, PLAN + name)
|
||||
if name == "work_packages.json":
|
||||
# JSON serialization preserves types (True must not compare equal to 1).
|
||||
encode = lambda value: json.dumps(definition_projection(decode(value)),
|
||||
ensure_ascii=False, sort_keys=True)
|
||||
require(encode(current) == encode(anchored),
|
||||
"original definition changed: " + name)
|
||||
else:
|
||||
require(current == anchored, "original register changed: " + name)
|
||||
return anchored
|
||||
|
||||
|
||||
def expected(root):
|
||||
raw = lambda p: (root / p).read_bytes()
|
||||
require(sha(raw(BASELINE)) == BASE_HASH, 'baseline changed')
|
||||
anchored = {name: validate_register(root, name, raw(PLAN + name))
|
||||
for name in ('atomic_requirements.json', 'work_packages.json', 'decisions.json')}
|
||||
require(raw(OUT + 'ACTUAL_OPUS_NEXT_ORIGINAL_UNIT_SELECTION.json') ==
|
||||
blob(root, BASE, OUT + 'ACTUAL_OPUS_NEXT_ORIGINAL_UNIT_SELECTION.json'), 'selection record changed')
|
||||
lines = raw(BASELINE).decode().splitlines()
|
||||
def cite(start, end=None):
|
||||
end = end or start
|
||||
return {'path': BASELINE, 'lines': [start, end],
|
||||
'text': '\n'.join(lines[start - 1:end]), 'baseline_sha256': BASE_HASH}
|
||||
def evidence(path, start, end):
|
||||
data = blob(root, ANCHOR, path)
|
||||
require(data == raw(path), 'stale source ' + path)
|
||||
return {'path': path, 'sha256': sha(data), 'anchor': ANCHOR,
|
||||
'lines': [start, end], 'text': '\n'.join(data.decode().splitlines()[start - 1:end])}
|
||||
def item(identity, start, end, note, owner, status='missing', source=None):
|
||||
return {'id': identity, 'authority': cite(start, end), 'status': status,
|
||||
'implementation': source or 'original conformance missing', 'owner': owner,
|
||||
'observation': note, 'gap': None if status == 'implemented' else '欠損: ' + note}
|
||||
# Only narrow storage facts are implemented; simulation/route completion never follows.
|
||||
rules = [
|
||||
item('state_fields', 138, 143, '原本3値と盾の明示値の検証・保持のみ。初期値と更新方針は未定。',
|
||||
'P18-01', 'implemented', evidence(STATE, 4, 34)),
|
||||
item('affection_max_invariant', 140, 140, '入力時の最大値一致検証のみ。通常操作の回復・更新は欠損。',
|
||||
'P18-01', 'partial', evidence(STATE, 20, 30)),
|
||||
item('snapshot_container', 138, 143, '専用状態と旧値の分離保存・復元。人物別ルート進行保存を意味しない。',
|
||||
'P18-01', 'partial', evidence(SERVICE, 423, 479)),
|
||||
item('identity_registration', 138, 138, 'Runtimeは登録済み人物・相互対応を検証。既存カタログのヒロインはアンリのみ。通常ルート入口ではない。',
|
||||
'P19-01', 'partial', evidence(RUNTIME, 6791, 6812)),
|
||||
item('legacy_event_ui', 154, 157, '既存UIには汎用関係イベントの確認/保留ラベルがある。原本の行動・決闘選択・自然ルート到達は欠損。',
|
||||
'P19-01', 'partial', evidence('scenes/main/main.gd', 98, 101)),
|
||||
]
|
||||
clauses = [
|
||||
('defense_reduction', 141, 141, 'P18-02'), ('post_break_metric', 142, 143, 'P18-02'),
|
||||
('barrier_block', 143, 143, 'P18-02'), ('coassignment_attack', 145, 145, 'P18-02'),
|
||||
('zero_break', 146, 146, 'P18-02'), ('contact_after_break', 147, 147, 'P18-02'),
|
||||
('threshold_route_loss', 148, 148, 'P18-03'), ('duel_types', 150, 151, 'P19-01'),
|
||||
('duel_win', 152, 152, 'P19-01'), ('duel_loss', 153, 153, 'P19-01'),
|
||||
('love_actions', 155, 155, 'P19-01'), ('ntr_actions', 156, 156, 'P19-01'),
|
||||
('corruption_actions', 157, 157, 'P19-01'), ('history_fields', 159, 159, 'P19-02'),
|
||||
('history_cycle_parentage', 160, 160, 'P19-02'), ('portrait_marks', 161, 161, 'P26-02'),
|
||||
('route_skills', 132, 132, 'P20-01'), ('departure', 135, 135, 'P19-02')]
|
||||
for identity, start, end, owner in clauses:
|
||||
rules.append(item(identity, start, end,
|
||||
'原本の共通要求。専用原本モデルにはこの更新・表示の実装なし。旧汎用モデルの数値やルートを代用しない。', owner))
|
||||
for rule in rules:
|
||||
if rule['id'] in LEGACY_RANGES:
|
||||
rule.update(status='missing', implementation='original conformance missing; see legacy_evidence',
|
||||
legacy_classification='legacy_not_original', legacy_reason=LEGACY_REASON)
|
||||
rule['gap'] = '欠損: ' + rule['observation'] + ' ' + LEGACY_REASON
|
||||
rule['legacy_evidence'] = []
|
||||
for path, start, end in LEGACY_RANGES[rule['id']]:
|
||||
entry = evidence(path, start, end)
|
||||
entry['git_blob_oid'] = subprocess.check_output(
|
||||
['git','rev-parse',ANCHOR+':'+path],cwd=root).decode().strip()
|
||||
rule['legacy_evidence'].append(entry)
|
||||
# Read complete selected atomic records, not only their condition strings.
|
||||
atoms = decode(anchored['atomic_requirements.json'])['requirements']
|
||||
atoms = [x for x in atoms if set(x.get('source_group_ids', [])) & {'B-7.' + str(i) for i in range(1, 7)}]
|
||||
owners = {x['id'] for p in decode(anchored['work_packages.json']) for x in p.get('remaining_deliverables', [])}
|
||||
require(all(r['owner'] in owners for r in rules), 'unknown original owner')
|
||||
for key, name in PEOPLE:
|
||||
for route in ROUTES:
|
||||
require(any(x['id'] == 'AR.heroine.' + key + '.route.' + route and
|
||||
x['entity'] == {'kind': 'heroine', 'key': key, 'original_name': name} for x in atoms),
|
||||
'canonical atomic character/route missing')
|
||||
require(all(name in lines[117 + i] for i, (_, name) in enumerate(PEOPLE)), 'original character names')
|
||||
cells = []
|
||||
for i, (key, name) in enumerate(PEOPLE):
|
||||
for route, route_name in ROUTES.items():
|
||||
refs = {
|
||||
'entry_required_events': ['identity_registration', route + '_actions'],
|
||||
'state_conditions': ['state_fields', 'affection_max_invariant', 'defense_reduction',
|
||||
'post_break_metric', 'barrier_block', 'coassignment_attack', 'zero_break', 'contact_after_break'],
|
||||
'duel_effects': ['duel_types', 'duel_win', 'duel_loss'],
|
||||
'route_selection_effects': ['threshold_route_loss', route + '_actions', 'route_skills'],
|
||||
'interruption_cancellation': ['departure', 'threshold_route_loss', 'duel_loss'], 'save_handling': ['snapshot_container'],
|
||||
'history_marks': ['history_fields', 'history_cycle_parentage', 'portrait_marks'],
|
||||
'current_reachability': ['identity_registration', 'threshold_route_loss']}
|
||||
categories = {}
|
||||
for category in CATEGORIES:
|
||||
owner = {'entry_required_events': 'P26-01', 'state_conditions': 'P18-02',
|
||||
'duel_effects': 'P19-01', 'route_selection_effects': 'P26-02',
|
||||
'interruption_cancellation': 'P19-02', 'save_handling': 'P19-02',
|
||||
'history_marks': 'P19-02', 'current_reachability': 'P20-02'}[category]
|
||||
gap = item(key + '_' + route + '_' + category, 138, 161,
|
||||
'原本未定義/D08 pending: 人物固有のイベント列・条件・中断取消・進行保存・履歴と通常到達は未制作/未証明。共通要求から固有仕様を創作しない。', owner)
|
||||
gap['character_authority'] = cite(118 + i)
|
||||
categories[category] = {'common_rule_refs': refs[category], 'character_specific': gap}
|
||||
if category == 'interruption_cancellation':
|
||||
categories[category].update(route_termination_authorities=[cite(148),cite(153)],
|
||||
legacy_classification='legacy_not_original', legacy_reason=LEGACY_REASON,
|
||||
legacy_evidence=[e for r in rules if r['id']=='threshold_route_loss'
|
||||
for e in r['legacy_evidence'] if e['path']==SERVICE and e['lines']==[343,355]])
|
||||
|
||||
cells.append({'character_id': key, 'name': name, 'route_id': route, 'route': route_name,
|
||||
'natural_route_complete': False, 'categories': categories})
|
||||
return {'task_id': 'P19-03-TABLE', 'schema_version': 1,
|
||||
'identity_policy': '原本§6の名前とatomic entity.keyを監査IDに使用。実装IDを捏造しない。カタログにはheroine_anriのみ。OriginalRelationshipStateはsubject_idを保持し7名の列挙はしない。',
|
||||
'source_anchor': ANCHOR, 'common_rules': rules, 'cells': cells,
|
||||
'authority_snapshots': {PLAN + name: {
|
||||
'sha256': sha(data), 'anchored_base_commit': BASE,
|
||||
'records': definition_projection(decode(data)) if name == 'work_packages.json'
|
||||
else decode(data) if name == 'decisions.json' else atoms}
|
||||
for name, data in anchored.items()},
|
||||
'catalog_evidence': evidence(CATALOG, 1, 32),
|
||||
'pending': {'D05': 'pending', 'D08': 'pending', 'thresholds': None, 'rates': None, 'initial_values': None},
|
||||
'route_support': {r: {'UI': '欠損: 原本行動・3種決闘・原本3軸/盾の通常操作なし。既存汎用関係UIを原本ルートとしない。',
|
||||
'Runtime': 'partial: 原本明示状態の登録・identity検証のみ。共通更新と通常ルート到達は欠損。',
|
||||
'save': 'partial: 専用状態/旧値コンテナ保存あり。人物固有進行・中断再開は欠損。',
|
||||
'Windows': '未受入: global same-Windows acceptanceはopen。文書単位のnative GUI/Windows実行は適用外。',
|
||||
'evidence_refs': ['legacy_event_ui', 'identity_registration', 'snapshot_container', 'state_fields'],
|
||||
'missing_mechanisms': [x[0] for x in clauses]} for r in ROUTES.values()},
|
||||
'acceptance': '7名×3ルートの到達表があり、未制作内容は欠損として残る。',
|
||||
'accounting': '14/88 unchanged; formal Runner validation, independent whole-unit Opus review and normal integration/final required; no game acceptance'}
|
||||
|
||||
|
||||
def verify(candidate, canonical, root=None):
|
||||
require(type(candidate) is dict, 'document must be an object')
|
||||
if root is not None:
|
||||
validate_legacy(root, candidate)
|
||||
# Exact canonical equality also rejects additions, type coercion, invented numbers,
|
||||
# owner/status promotion and unsupported completion, including nested metadata.
|
||||
require(json.dumps(candidate, ensure_ascii=False, sort_keys=True) ==
|
||||
json.dumps(canonical, ensure_ascii=False, sort_keys=True), 'table differs from pinned canonical audit')
|
||||
|
||||
|
||||
def verify_records(candidate, canonical, markdown_bytes):
|
||||
verify(candidate, canonical)
|
||||
require(markdown_bytes == markdown(canonical).encode(), 'Markdown drift')
|
||||
|
||||
|
||||
def markdown(d):
|
||||
lines = ['# P19-03 到達表', '', d['acceptance'], '', d['identity_policy'], '',
|
||||
'共通原本ルールと人物固有欠損を分離する。implementedは狭い保持処理だけで、自然ルート完成ではない。', '',
|
||||
'|人物ID|原名|ルート|現在の到達性|', '|---|---|---|---|']
|
||||
for c in d['cells']:
|
||||
lines.append('|%s|%s|%s|欠損・通常到達未証明|' % (c['character_id'], c['name'], c['route']))
|
||||
lines += ['', '## 共通原本ルール', '']
|
||||
for r in d['common_rules']:
|
||||
lines += ['### ' + r['id'], '', r['status'] + ' / owner: ' + r['owner'], '',
|
||||
r['observation'], '', '原本 %s:%s–%s' % (BASELINE, *r['authority']['lines']), '',
|
||||
'```text', r['authority']['text'], '```', '',
|
||||
'実装証拠: ' + json.dumps(r['implementation'], ensure_ascii=False, sort_keys=True), '']
|
||||
if 'legacy_evidence' in r:
|
||||
lines += ['旧実装: ' + r['legacy_classification'] + ' / ' + r['legacy_reason'], '',
|
||||
'旧証拠 (git_blob_oid: Git blob OID; sha256: file-bytes SHA-256): ' +
|
||||
json.dumps(r['legacy_evidence'], ensure_ascii=False, sort_keys=True), '']
|
||||
for c in d['cells']:
|
||||
lines += ['## ' + c['character_id'] + ' / ' + c['name'] + ' / ' + c['route'], '']
|
||||
for category, record in c['categories'].items():
|
||||
g = record['character_specific']
|
||||
lines += ['- ' + category + ': 共通 [' + ', '.join(record['common_rule_refs']) +
|
||||
'] / missing / ' + g['gap'] + ' / owner: ' + g['owner'] +
|
||||
' / 原本 ' + str(g['authority']['lines']) + '・人物 ' + str(g['character_authority']['lines'])]
|
||||
if category == 'interruption_cancellation':
|
||||
lines += [' 原本中断参照: ' + json.dumps(record['route_termination_authorities'], ensure_ascii=False),
|
||||
' 旧確定ロック legacy_not_original: ' + json.dumps(record['legacy_evidence'], ensure_ascii=False)]
|
||||
lines.append('')
|
||||
lines += ['## ルート別適用性', '']
|
||||
for route, support in d['route_support'].items():
|
||||
lines += ['### ' + route, '']
|
||||
lines += ['- ' + k + ': ' + v for k, v in support.items() if isinstance(v, str)]
|
||||
lines += ['- 欠損機構: ' + ', '.join(support['missing_mechanisms']), '']
|
||||
lines += ['Authority snapshots: anchored_base_commit=' + BASE +
|
||||
'; JSON retains anchored blob SHA-256 and projected definition records.', '']
|
||||
lines += ['D05/D08、閾値・率・初期値はpending。完全な出典本文・SHA・原子要件全レコードはJSONに保持する。', '', d['accounting'], '']
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
def main():
|
||||
p = argparse.ArgumentParser(description=__doc__)
|
||||
p.add_argument('--project-root', type=Path, required=True)
|
||||
mode = p.add_mutually_exclusive_group(required=True)
|
||||
mode.add_argument('--check', action='store_true')
|
||||
mode.add_argument('--write', action='store_true')
|
||||
mode.add_argument('--source-binding-only', action='store_true')
|
||||
args = p.parse_args()
|
||||
try:
|
||||
root = args.project_root.resolve()
|
||||
result = binding(root)
|
||||
if not args.source_binding_only:
|
||||
canonical = expected(root)
|
||||
validate_legacy(root, canonical)
|
||||
if args.write:
|
||||
(root / OUT / 'REACHABILITY_TABLE.json').write_text(json.dumps(canonical, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')
|
||||
(root / OUT / 'REACHABILITY_TABLE.md').write_text(markdown(canonical), encoding='utf-8')
|
||||
else:
|
||||
validate_legacy(root, decode((root / OUT / 'REACHABILITY_TABLE.json').read_bytes()))
|
||||
verify_records(decode((root / OUT / 'REACHABILITY_TABLE.json').read_bytes()), canonical,
|
||||
(root / OUT / 'REACHABILITY_TABLE.md').read_bytes())
|
||||
print(json.dumps({'audit_integrity': 'pass', 'formal_acceptance': 'pending_runner_and_independent_review', **result}))
|
||||
return 0
|
||||
except (ValueError, OSError, KeyError, TypeError, subprocess.CalledProcessError) as e:
|
||||
print(json.dumps({'audit_integrity': 'fail', 'error': str(e)}))
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
+284
@@ -0,0 +1,284 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Meaningful in-memory controls; no product, Git or fixture writes."""
|
||||
import argparse
|
||||
import copy
|
||||
from pathlib import Path
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
import check_reachability_table as audit
|
||||
|
||||
ROOT = None
|
||||
|
||||
|
||||
class AuditTests(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.canonical = audit.expected(ROOT)
|
||||
|
||||
def reject(self, mutate):
|
||||
changed = copy.deepcopy(self.canonical)
|
||||
mutate(changed)
|
||||
with self.assertRaises(ValueError):
|
||||
audit.verify(changed, self.canonical)
|
||||
|
||||
def register_output(self, data):
|
||||
original = Path.read_bytes
|
||||
def read(path):
|
||||
return data if path == ROOT / audit.PLAN / "work_packages.json" else original(path)
|
||||
with patch.object(Path, "read_bytes", read):
|
||||
document = audit.expected(ROOT)
|
||||
import json
|
||||
self.assertEqual(json.dumps(document, ensure_ascii=False, indent=2) + "\n",
|
||||
(ROOT / audit.OUT / "REACHABILITY_TABLE.json").read_text())
|
||||
self.assertEqual(audit.markdown(document).encode(),
|
||||
(ROOT / audit.OUT / "REACHABILITY_TABLE.md").read_bytes())
|
||||
|
||||
def test_actual_main_and_candidate_metadata(self):
|
||||
for commit in ("6e17cae", "1875b03"):
|
||||
with self.subTest(commit=commit):
|
||||
self.register_output(audit.blob(ROOT, commit, audit.PLAN + "work_packages.json"))
|
||||
|
||||
def test_final_ledger_metadata(self):
|
||||
import json
|
||||
register = audit.decode(audit.blob(ROOT, audit.BASE, audit.PLAN + "work_packages.json"))
|
||||
package = next(p for p in register if p["id"] == "P19")
|
||||
unit = next(u for u in package["remaining_deliverables"] if u["id"] == "P19-03")
|
||||
package.update(state="completed", legacy_state="completed",
|
||||
current_summary="ledger completion", updated_at_jst="2026-10-17")
|
||||
unit.update({key: "synthetic final reference" for key in audit.UNIT_MUTABLE})
|
||||
unit["evidence"] = [{"path": "docs/final.json", "sha256_at_integration": "0" * 64}]
|
||||
unit["remaining_gaps"] = []
|
||||
self.register_output(json.dumps(register).encode())
|
||||
|
||||
def test_every_register_definition_field(self):
|
||||
import json
|
||||
base = audit.decode(audit.blob(ROOT, audit.BASE, audit.PLAN + "work_packages.json"))
|
||||
# Independently mutate/remove every package and unit definition field.
|
||||
# Compare full nested values; unknown additions fail at both record levels.
|
||||
def visit(value, path=(), level="packages"):
|
||||
if isinstance(value, list):
|
||||
yield path, "count"
|
||||
if len(value) > 1:
|
||||
yield path, "order"
|
||||
for i, child in enumerate(value):
|
||||
yield from visit(child, path + (i,),
|
||||
"package" if not path else "unit" if path[-1] == "remaining_deliverables" else "nested")
|
||||
elif isinstance(value, dict):
|
||||
yield path, "unknown"
|
||||
excluded = audit.PACKAGE_MUTABLE if level == "package" else audit.UNIT_MUTABLE if level == "unit" else ()
|
||||
for key, child in value.items():
|
||||
if key in excluded:
|
||||
continue
|
||||
yield path + (key,), "change"
|
||||
yield path + (key,), "remove"
|
||||
if key == "remaining_deliverables":
|
||||
yield from visit(child, path + (key,), "units")
|
||||
elif isinstance(child, list):
|
||||
yield path + (key,), "count"
|
||||
if len(child) > 1 and child[0] != child[1]:
|
||||
yield path + (key,), "order"
|
||||
|
||||
seen = set()
|
||||
anchored = audit.blob(ROOT, audit.BASE, audit.PLAN + "work_packages.json")
|
||||
for path, operation in visit(base):
|
||||
# Each distinct definition key/structural path once; repeated records
|
||||
# use the same schema, so do not pad by testing it 30/88 times.
|
||||
shape = tuple("*" if type(part) is int else part for part in path)
|
||||
if (shape, operation) in seen:
|
||||
continue
|
||||
seen.add((shape, operation))
|
||||
changed = copy.deepcopy(base)
|
||||
target = changed
|
||||
for key in path[:-1]:
|
||||
target = target[key]
|
||||
value = target[path[-1]] if path else changed
|
||||
if operation == "change":
|
||||
target[path[-1]] = {"altered_definition": True}
|
||||
elif operation == "remove":
|
||||
del target[path[-1]]
|
||||
elif operation == "unknown":
|
||||
value["unknown_metadata"] = "must fail"
|
||||
elif operation == "count":
|
||||
value.append({})
|
||||
else:
|
||||
value[0], value[1] = value[1], value[0]
|
||||
with self.subTest(path=path, operation=operation), patch.object(audit, 'blob', return_value=anchored), self.assertRaises(ValueError):
|
||||
audit.validate_register(ROOT, "work_packages.json", json.dumps(changed).encode())
|
||||
|
||||
def test_atomic_decision_and_selection_integrity(self):
|
||||
import json
|
||||
for name in ("atomic_requirements.json", "decisions.json"):
|
||||
data = audit.blob(ROOT, audit.BASE, audit.PLAN + name)
|
||||
with self.subTest(name=name), self.assertRaises(ValueError):
|
||||
audit.validate_register(ROOT, name, data + b" ")
|
||||
changed = audit.decode(data)
|
||||
if name == "atomic_requirements.json":
|
||||
changed["requirements"][0]["id"] = "changed_atomic_requirement"
|
||||
with self.assertRaises(ValueError):
|
||||
audit.validate_register(ROOT, name, json.dumps(changed).encode())
|
||||
decisions = audit.decode(audit.blob(ROOT, audit.BASE, audit.PLAN + "decisions.json"))
|
||||
def flip(value, identity):
|
||||
if isinstance(value, dict):
|
||||
if value.get("id") == identity:
|
||||
value["status"] = "approved"
|
||||
return True
|
||||
return any(flip(v, identity) for v in value.values())
|
||||
if isinstance(value, list):
|
||||
return any(flip(v, identity) for v in value)
|
||||
return False
|
||||
for identity in ("D05", "D08"):
|
||||
changed = copy.deepcopy(decisions)
|
||||
self.assertTrue(flip(changed, identity))
|
||||
with self.subTest(identity=identity), self.assertRaises(ValueError):
|
||||
audit.validate_register(ROOT, "decisions.json", json.dumps(changed).encode())
|
||||
original = Path.read_bytes
|
||||
target = ROOT / audit.OUT / "ACTUAL_OPUS_NEXT_ORIGINAL_UNIT_SELECTION.json"
|
||||
def corrupt(path):
|
||||
return original(path) + (b" " if path == target else b"")
|
||||
with patch.object(Path, "read_bytes", corrupt), self.assertRaises(ValueError):
|
||||
audit.expected(ROOT)
|
||||
|
||||
def test_valid_implemented_partial_missing(self):
|
||||
# All three legitimate status classes must survive serialization and the
|
||||
# exact same verifier used by --check, without status promotion.
|
||||
import json
|
||||
value = audit.decode(json.dumps(self.canonical))
|
||||
self.assertEqual({r['status'] for r in value['common_rules']}, {'implemented', 'partial', 'missing'})
|
||||
audit.verify(value, self.canonical)
|
||||
|
||||
def test_independent_legacy_source_evidence(self):
|
||||
import subprocess
|
||||
document = audit.decode((ROOT / audit.OUT / 'REACHABILITY_TABLE.json').read_bytes())
|
||||
audit.validate_legacy(ROOT, document)
|
||||
for rule in document['common_rules']:
|
||||
for entry in rule.get('legacy_evidence', []):
|
||||
data = subprocess.check_output(['git', 'show', audit.ANCHOR + ':' + entry['path']], cwd=ROOT)
|
||||
self.assertEqual(data, (ROOT / entry['path']).read_bytes())
|
||||
self.assertEqual(entry['git_blob_oid'], subprocess.check_output(
|
||||
['git','hash-object','--stdin'], input=data, cwd=ROOT).decode().strip())
|
||||
start, end = entry['lines']
|
||||
self.assertEqual(entry['text'], '\n'.join(data.decode().splitlines()[start-1:end]))
|
||||
rules = {r['id']: r for r in document['common_rules']}
|
||||
self.assertIn('func restore_shield', rules['love_actions']['legacy_evidence'][0]['text'])
|
||||
self.assertIn('shield_broken', rules['zero_break']['legacy_evidence'][0]['text'])
|
||||
self.assertIn('EXCLUSIVE_LOCKED', rules['threshold_route_loss']['legacy_evidence'][1]['text'])
|
||||
|
||||
def test_legacy_evidence_required_independently(self):
|
||||
for identity in audit.LEGACY_RANGES:
|
||||
for mutation in ('drop', 'empty', 'absence', 'blob', 'text'):
|
||||
changed = copy.deepcopy(self.canonical)
|
||||
rule = next(r for r in changed['common_rules'] if r['id'] == identity)
|
||||
if mutation == 'drop':
|
||||
rule.pop('legacy_evidence')
|
||||
elif mutation == 'empty':
|
||||
rule['legacy_evidence'] = []
|
||||
elif mutation == 'absence':
|
||||
rule['implementation'] = 'not implemented'
|
||||
else:
|
||||
rule['legacy_evidence'][0]['git_blob_oid' if mutation == 'blob' else 'text'] = 'stale'
|
||||
with self.subTest(identity=identity, mutation=mutation), self.assertRaises(ValueError):
|
||||
audit.validate_legacy(ROOT, changed)
|
||||
|
||||
def test_exact_cell_product(self):
|
||||
mutations = {
|
||||
'missing': lambda d: d['cells'].pop(),
|
||||
'duplicate': lambda d: d['cells'].append(copy.deepcopy(d['cells'][0])),
|
||||
'wrong_character': lambda d: d['cells'][0].update(character_id='unregistered'),
|
||||
'wrong_route': lambda d: d['cells'][0].update(route='unregistered'),
|
||||
}
|
||||
for name, mutate in mutations.items():
|
||||
with self.subTest(name=name):
|
||||
self.reject(mutate)
|
||||
|
||||
def test_categories_and_citations(self):
|
||||
self.reject(lambda d: d['cells'][0]['categories'].pop('save_handling'))
|
||||
self.reject(lambda d: d['common_rules'][0].pop('authority'))
|
||||
self.reject(lambda d: d['cells'][0]['categories']['state_conditions']['character_specific'].pop('character_authority'))
|
||||
|
||||
def test_stale_record_evidence(self):
|
||||
for field in ('text', 'baseline_sha256'):
|
||||
with self.subTest(field=field):
|
||||
self.reject(lambda d: d['common_rules'][0]['authority'].update({field: 'stale'}))
|
||||
for field in ('text', 'sha256', 'anchor'):
|
||||
with self.subTest(field=field):
|
||||
self.reject(lambda d: d['common_rules'][0]['implementation'].update({field: 'stale'}))
|
||||
|
||||
def test_real_source_and_baseline_changes(self):
|
||||
original = Path.read_bytes
|
||||
for target in (audit.BASELINE, audit.STATE):
|
||||
def corrupt(path):
|
||||
value = original(path)
|
||||
return value + b'\nchanged' if path == ROOT / target else value
|
||||
with self.subTest(target=target), patch.object(Path, 'read_bytes', corrupt):
|
||||
with self.assertRaises(ValueError):
|
||||
audit.expected(ROOT)
|
||||
actual_blob = audit.blob
|
||||
def corrupt_blob(root, commit, path):
|
||||
value = actual_blob(root, commit, path)
|
||||
return value + b'\nchanged' if path == audit.STATE else value
|
||||
with patch.object(audit, 'blob', side_effect=corrupt_blob):
|
||||
with self.assertRaises(ValueError):
|
||||
audit.expected(ROOT)
|
||||
|
||||
def test_no_invented_values_or_completion(self):
|
||||
self.reject(lambda d: d['pending'].update(thresholds=50))
|
||||
self.reject(lambda d: d['common_rules'][5].update(status='implemented'))
|
||||
self.reject(lambda d: d['cells'][0].update(natural_route_complete=True))
|
||||
self.reject(lambda d: d['cells'][0]['categories']['entry_required_events']['character_specific'].update(status='implemented', gap=None))
|
||||
|
||||
def test_owner_and_status(self):
|
||||
self.reject(lambda d: d['common_rules'][0].update(owner='P99-01'))
|
||||
self.reject(lambda d: d['common_rules'][0].update(owner='P19-02'))
|
||||
self.reject(lambda d: d['common_rules'][0].update(status='complete'))
|
||||
|
||||
def test_json_and_types(self):
|
||||
for data in ('{', '{"x":1,"x":2}', '{"x":NaN}'):
|
||||
with self.subTest(data=data), self.assertRaises(ValueError):
|
||||
audit.decode(data)
|
||||
for value in ([], None, 'table'):
|
||||
with self.subTest(value=value), self.assertRaises(ValueError):
|
||||
audit.verify(value, self.canonical)
|
||||
self.reject(lambda d: d.update(cells={}))
|
||||
self.reject(lambda d: d.update(schema_version=True))
|
||||
|
||||
def test_markdown_drift(self):
|
||||
expected = audit.markdown(self.canonical).encode()
|
||||
audit.verify_records(self.canonical, self.canonical,
|
||||
(ROOT / audit.OUT / 'REACHABILITY_TABLE.md').read_bytes())
|
||||
with self.assertRaises(ValueError):
|
||||
audit.verify_records(self.canonical, self.canonical, expected + b'\nchanged')
|
||||
|
||||
def test_full_frozen_map_and_identities(self):
|
||||
audit.binding(ROOT) # Valid frozen-map control; no native execution.
|
||||
actual_selection = audit.selection(ROOT)
|
||||
for kind in ('missing', 'new', 'changed'):
|
||||
changed = copy.deepcopy(actual_selection)
|
||||
key = next(iter(changed))
|
||||
if kind == 'missing':
|
||||
del changed[key]
|
||||
elif kind == 'new':
|
||||
changed['scripts/invented.gd'] = {'bytes': 0, 'sha256': '0' * 64}
|
||||
else:
|
||||
changed[key]['sha256'] = '0' * 64
|
||||
with self.subTest(kind=kind), patch.object(audit, 'selection', return_value=changed):
|
||||
with self.assertRaises(ValueError):
|
||||
audit.binding(ROOT)
|
||||
original = Path.read_bytes
|
||||
pins = audit.decode(original(ROOT / audit.OUT / 'FROZEN_GAME_INPUT_PINS.json'))
|
||||
targets = [ROOT / audit.OUT / 'FROZEN_GAME_INPUT_PINS.json', ROOT / pins['marker_contract_path'],
|
||||
ROOT / pins['policy_path'], Path(pins['engine_path'])]
|
||||
for target in targets:
|
||||
def corrupt(path):
|
||||
value = original(path)
|
||||
return value + b'\nchanged' if path == target else value
|
||||
with self.subTest(target=str(target)), patch.object(Path, 'read_bytes', corrupt):
|
||||
with self.assertRaises(ValueError):
|
||||
audit.binding(ROOT)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--project-root', type=Path, required=True)
|
||||
args, rest = parser.parse_known_args()
|
||||
ROOT = args.project_root.resolve()
|
||||
unittest.main(argv=[__file__] + rest)
|
||||
+7
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+5686
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,64 @@
|
||||
# P26-01 全必要内容の台帳 — 実装提出
|
||||
|
||||
対象: P26-01 / AC-P26-01。原作業「全章、7名の3ルート、全エンド、台詞、立ち絵、音声の必要枠と条件を確定する。」、原受入「原本で要求された未制作内容を欠損として記録し、架空の完成数を置かない。」を変更しない。
|
||||
|
||||
本提出は内容監査資料であり、原本全体は30パッケージ・88単位、正式完了15/88のまま、今回加算0。P26-01の自己受入は行わない。独立したwhole-unit Opusレビューが原受入を判定する。
|
||||
|
||||
## 作成した5成果物
|
||||
|
||||
|成果物|役割|
|
||||
|---|---|
|
||||
|CONTENT_LEDGER.json|原文引用、条件、状態、欠損、責任先、実ソースとSHAを持つ監査台帳|
|
||||
|CONTENT_LEDGER.md|JSONの全行と固定参照情報を欠落させない決定的な表示|
|
||||
|check_content_ledger.py|stdlibの読取専用検査、source binding、明示的な生成モード|
|
||||
|test_content_ledger.py|正例と、原本要求欠落・架空数・誤完成・出典改変等の負例|
|
||||
|IMPLEMENTATION_REPORT.md|原単位全体との対応と残存不足、本報告|
|
||||
|
||||
変更は契約の5 allowed_paths内だけ。TASK_SPEC、selection、frozen pins、原本、計画定義、決定、修正回数は変更しない。git書込み、他エージェント、Runner操作、ゲーム・素材編集、API/安全性/対象範囲変更は行わない。新規素材の導入はない。
|
||||
|
||||
## 原単位全体の対応
|
||||
|
||||
原本は `docs/traceability/original/BASELINE.txt`、SHA256 `75e4bdbdeb379c9269553f0c776bdb9cc96e01f2d6aa5ca650d132c63a8aeb1a`。各行は行番号、原文全文、ファイルSHAを保持する。
|
||||
|
||||
|要求|台帳ID/根拠|現状と不足の所有先|
|
||||
|---|---|---|
|
||||
|全章|chapters.all、原本8・26〜30・256行|メインストーリーの要求のみ。章名・章数・順序・場面一覧は未定義。仕様書の第1〜14章をシナリオ章に転用しない。D08|
|
||||
|7名×3ルート|route.anri/fine/tomari/amelia/liz/mimi/satsuki × love/ntr/corruption、118〜124・30・132・138〜161行|アンリ、フィーネ、トマリ、アメリア、リズ、ミミ、サツキと純愛/NTR/堕落の正確な対応。人物固有のイベント列、入口・分岐・終点・台詞・素材・履歴/保存・通常到達は欠損。P26-02 / D08|
|
||||
|全エンド|endings.all / endings.bad / endings.game_over、9・135・72行|全エンド集合、特定バッドエンド、赤字決算3回連続のゲームオーバーを区別。個別終点ID・本数は未定義。3ルートを3個の完成エンドに数えない。D08 / P26-02|
|
||||
|台詞|dialogue.all、155・230・256行、全route行の条件|会話/イベント/脚本の必要枠。台詞本文、話者一覧、行数、シーン列は未定義。UI文言や汎用関係イベントを完成脚本に数えない。P26-02 / D08|
|
||||
|立ち絵|portraits.all とP22人物利用枠、160〜161・230・235・242行|主/サブ、表情、衣装、破損、汚れ、刻印、妊婦外見、ルート別描き分け。必要枚数・共有方針は未定義。P26-03 / D09|
|
||||
|音声|voice.all とP22人物voice枠、252・257行|ボイス収録・実装が欠損。話者/台詞/クリップ数/担当未定義。BGM、UI音、汎用音はボイスの代用にしない。P26-03 / D09|
|
||||
|図鑑|encyclopedia.all、9行|対象集合、ID、解放条件、項目数は未定義。D08|
|
||||
|横断する必要内容|clause.*、原本27〜34・132・134〜135・138〜161・229〜230・234〜235・242〜246・252・255〜258行|原本共通ルール、世界設定、CG/差分/モブ、SDモーション、制作段階を保存。今回新規の物語・台詞・場面は制作しない。P26-02/03、P22制作系とD08/D09|
|
||||
|
||||
台帳の必要数・完成数はnull(未定義/未計数)。既知の7名×3ルートと、既存P22の614利用枠/用途群は、画像枚数、ボイス数、制作完了数、原子分母への換算をしない。未定義状態も欠損として明示する。状態語彙は produced / placeholder / code-drawing / partial / missing / undefined。完成を裏付ける証拠がないためproducedへの昇格はない。
|
||||
|
||||
## 版と実証拠
|
||||
|
||||
計画定義の基準は `379a1ba8fd25b5ad24226178a2492f91761dc31d`、ゲーム監査アンカーは `f4f85bc54c39361f9efcd16f67a17835559ca70c`。TASK_SPEC raw SHA256は `8026040345de6b7d06cfce40beac9150bfe9ad303d6b26c11bd94e66b1080b29`、stripしたUTF-8表現は `1fedc9ade42a04722846daa9ac8ec26f821fb4efbce8dbbb53e3e76e31f38d02`。両表現を区別する。selectionは基準コミットの同一バイトで固定する。
|
||||
|
||||
P19-03 REACHABILITY_TABLE.jsonは読取専用の既存監査でありP26の前身ではない。21セルの人物名・ルート名・natural_route_complete=falseを確認する。台帳にはそのセル参照とファイルSHAを保存する。実ソースのカタログ、OriginalRelationshipState、Runtime identity検査、relationship_serviceの保存コンテナ、PixelPeopleの汎用描画も直接参照し、正確な行範囲・本文・SHAを保持する。専用の明示状態検証/保存があることと、人物別ルートの内容制作・到達がないことを区別する。Runtimeの主人公ID `player` もこの証拠と全入力固定の対象。
|
||||
|
||||
P22-01は既存の360施設枠・176人物用途群・76その他用途群・2状態群を全て参照する。原レコードは型を保持して保存し、現在の表現先の実ファイルSHAを別に取得する。過去のSHAと現在のSHAが異なる場合も両方を残し、旧レコードを書き換えない。既存296mediaの全現物参照と、固定入力中の全assetsパス/SHAも記録する。汎用コード描画、仮素材、完成素材を混同しない。現物の存在だけで用途・差分の品質/権利受入済みとは判定しない。
|
||||
|
||||
P22-01の元artifactsパスは非追跡アーカイブの別名であり、その入力はRootの公開コミット `137639773c9017f9ee7733d78e37179b687f965c` の `accepted-p22-01-inputs/` からも読める。公開manifest SHA256 `90b5a69d5f364012edabe5a68b8c7613f5f5ca47bc189d435dd2e69b8dd8c915` と全10ファイルのサイズ/SHAで固定する。元パスがある場合は公開バイトと一致必須、ない場合は固定git objectを使う。レビュー用別名の設置や新規ファイル追加は本workerでは行わない。P22-03 production_backlog.jsonはアンカー固定された未受入の下書き参考のみで、制作数量・承認・完了の権威にしない。
|
||||
|
||||
## チェッカーと正式試験
|
||||
|
||||
`--check` は台帳・出典・固定入力・決定的Markdownを読取専用で検査する。`--source-binding-only` は同じ出典結合と台帳を確認し、Markdown表示の一致を要求しない。`--write` は固定原文・実ソースから指定JSON/Markdownの2ファイルだけを生成する。JSON重複キーと非有限数値も拒否する。
|
||||
|
||||
元の30/88のacceptance/work/dependency/requirement等は基準版の計画定義へfail closedで結合し、明示した既存の進捗メタデータキーだけを除いて比較する。work_packages全体をバイト固定しない。atomic_requirementsとdecisionsは型/値を変えず基準版へ結合する。台帳は閉じたスキーマ相当の完全一致、ID一意性、原要求/利用枠集合、正確な人物/ルート、null数量、owner/status/type、引用とSHAを検査する。期待値は提出台帳から生成せず、固定原文の明示的な条項範囲・固定P19/P22・実ソースから作る。
|
||||
|
||||
負例は章/ルート/各エンド/台詞/立ち絵/音声/図鑑/共通カテゴリ/利用枠の欠落、架空数、欠損の完成昇格、owner/status/type/追加キー/重複ID、人物誤同定、原文/原文SHA/実証拠SHA/アンカー改変、不正JSON/重複キー/非有限値、Markdown drift、計画定義改変、公開manifest改変、選択入力の欠落/追加/変更/型改変を含む。正例は提出資料、独立期待集合、元の入力集合、許容される進捗メタデータ変更。
|
||||
|
||||
正式試験はRunnerが実行する。本workerは `--check`、`--source-binding-only`、負例テストを実行しておらず、合格は報告しない。JSON/Markdownは生成処理だけを実行した。正式コマンドは契約の p26-ledger / p26-negative / p26-source-binding の3本をそのまま使用する。
|
||||
|
||||
全1368のselected game input、settings、assets、tests、tools、marker、policy、engine、roster、329parseとdefault player identityをチェッカーで固定入力マップへ照合する。固定pin SHA256は `6c778226a4cc6d0b0d682500759e7d4229c926a27bd2e247b00b9c3e5f1a2fb0`。追加/欠落/変更のいずれも拒否し、全選択入力をf4f85bcのgit blobにも照合する。docs helperはゲーム選択集合外。
|
||||
|
||||
既存nativeの184 suites / 21903 checks / 329 parse / 186 owned-endedは履歴としてのみ保存する。既存証拠のsource S `a7e3069b167511b3194242b3403fbcc35244a526` とC `65f07bf5eaa759a8e2e17c7bdbbbdbceb24ee373` への適用性は独立ゲートであり、本提出はnative再利用受入を主張しない。新規のnative full runは行わない。
|
||||
|
||||
## 残存不足と受入境界
|
||||
|
||||
D05の既存未解決事項、D08の章/ルート/全エンド/図鑑/必要内容範囲、D09の品質/量/担当/予算/権利は未解決のまま。D05の既存承認を撤回も拡張もしない。P26-02/03と上流の制作・ゲームプレイ・保存/移行・素材受入は未完。held gestures、same-Windows、global acceptanceも未受入。本監査に製品操作は追加されない。
|
||||
|
||||
whole-unit独立レビューが未定義の記録では原受入を満たさないと判断した場合は、正直に不合格/無加算とする。必要な通常prepare-integration、exact C/M、normal final、Rootの台帳更新/main pushはworker範囲外であり未実行。これらと独立受入が終わるまでは16/88へ進めない。
|
||||
@@ -0,0 +1,102 @@
|
||||
{
|
||||
"id": "P26-01-LEDGER",
|
||||
"original_plan_id": "P26-01",
|
||||
"title": "全必要内容の台帳",
|
||||
"original_work": "全章、7名の3ルート、全エンド、台詞、立ち絵、音声の必要枠と条件を確定する。",
|
||||
"original_acceptance": "原本で要求された未制作内容を欠損として記録し、架空の完成数を置かない。",
|
||||
"original_denominator": {
|
||||
"packages": 30,
|
||||
"units": 88,
|
||||
"completed_at_start": 15,
|
||||
"partial_credit": false
|
||||
},
|
||||
"whole_original_unit_review_required": true,
|
||||
"actual_opus_selection": "6b9bb7f7a8474689b4094efbfcde2eef",
|
||||
"audit_source_anchor": "f4f85bc54c39361f9efcd16f67a17835559ca70c",
|
||||
"scope": "Original documentation/audit unit only. Record content requirements, neutral abstract IDs, source traceability and missing/undefined production content. Do not author narrative, dialogue or intimate content or invent values. No game/asset code changes.",
|
||||
"authority": [
|
||||
{
|
||||
"path": "docs/traceability/original/BASELINE.txt",
|
||||
"sha256": "75e4bdbdeb379c9269553f0c776bdb9cc96e01f2d6aa5ca650d132c63a8aeb1a",
|
||||
"scope": "Read all applicable original clauses, including chapters,7characters,3routes,endings,dialogue,portraits,voice and encyclopedia. Exact original citations, no invented counts."
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/work_packages.json",
|
||||
"unit": "P26-01",
|
||||
"original_definition_must_remain_exact": true
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/atomic_requirements.json"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/decisions.json",
|
||||
"scope": "Only approved decisions apply; unresolved D08/D09 and other decisions remain explicit missing/undefined."
|
||||
}
|
||||
],
|
||||
"frozen_game_input_pins_sha256": "6c778226a4cc6d0b0d682500759e7d4229c926a27bd2e247b00b9c3e5f1a2fb0",
|
||||
"reusable_sources": [
|
||||
"docs/plans/original-completion-2026-10-02/execution/p19-03/REACHABILITY_TABLE.json",
|
||||
"artifacts/original-completion-2026-10-02/p22-01-usage-contract-candidate-r02/",
|
||||
"docs/plans/original-completion-2026-10-02/execution/p22-03/production_backlog.json"
|
||||
],
|
||||
"implementation_requirements": [
|
||||
"Produce CONTENT_LEDGER.json and deterministic CONTENT_LEDGER.md covering every original-required chapter/route/end/dialogue/portrait/voice/encyclopedia slot or explicit undefined scope.7originalcharacters crossed3originalroutes must retain exact identity. Enumerate original-defined end categories without inventing missing counts or scene lists.",
|
||||
"Each requirement has exact original citation text/line/hash, required condition, current evidence/status, explicit source or asset path+SHA at audit anchor or explicit missing, reason, and owning remaining original deliverable/decision. Distinguish produced versus placeholder/code drawing/partial/missing/undefined. An existing generic/backend asset never proves all original content produced.",
|
||||
"Reuse completed P19-03 route audit and P22-01 usage inventory with exact source pins. P22-03 backlog is draft/unaccepted reference only. Independently verify actual available content, do not just copy old statuses. Preserve known evidence and distinguish approved scope from unapproved candidate scope.",
|
||||
"All unproduced or undefined content remains missing with reason and ownership; no fabricated quantity, threshold, completion count or D05/D08/D09 approval. The audit does not complete content/gameplay/Windows/global acceptance.",
|
||||
"Implement stdlib checker check_content_ledger.py (--check read-only, --source-binding-only, optional --write) plus test_content_ledger.py under this docs directory only. Verify exact original full clause coverage; closed row/schema/unique IDs; source citation/pin integrity; truthful completion/unknown values and exact deterministic view. Do not use tautological generated facts as sole verification.",
|
||||
"Meaningful negative tests for omitted original chapter/route/ending/category, fabricated count, missing item falsely produced, invalid owner/status/type, stale original/source/hash, malformed JSON and Markdown drift, with valid controls. No test inflation or native game runs.",
|
||||
"Preserve immutable TASK_SPEC, selection and frozen pins. Anchor planning definitions to immutable base and keep all original30/88/acceptance/dependency definitions failclosed while allowing only explicit existing metadata progress fields; do not freeze entire mutable progress docs. Avoid prior P19 integration bug. All other source evidence exact and type-preserving.",
|
||||
"Prove complete frozen1368 game inputs/settings/assets/tests/tools/marker/policy/engine/roster/parse/default player identity. No omitted/new/changed selected input; docs helpers stay outside selected game set. Reuse native184/21903/329parse/186ended only when applicability independently proven at exactS/C. No new uncontrolled full run.",
|
||||
"Provide IMPLEMENTATION_REPORT.md mapping entire original unit to actual evidence and remaining gaps. Whole-unit independent Opus review must decide original acceptance; if pending scope prevents it, fail honestly with no credit. Normal prepare-integration/exactC-M/final then Root ledger/main push required before16/88."
|
||||
],
|
||||
"required_outputs": [
|
||||
"CONTENT_LEDGER.json",
|
||||
"CONTENT_LEDGER.md",
|
||||
"check_content_ledger.py",
|
||||
"test_content_ledger.py",
|
||||
"IMPLEMENTATION_REPORT.md"
|
||||
],
|
||||
"validations": {
|
||||
"p26-ledger": {
|
||||
"argv": [
|
||||
"{python}",
|
||||
"-B",
|
||||
"docs/plans/original-completion-2026-10-02/execution/p26-01/check_content_ledger.py",
|
||||
"--project-root",
|
||||
".",
|
||||
"--check"
|
||||
]
|
||||
},
|
||||
"p26-negative": {
|
||||
"argv": [
|
||||
"{python}",
|
||||
"-B",
|
||||
"docs/plans/original-completion-2026-10-02/execution/p26-01/test_content_ledger.py",
|
||||
"--project-root",
|
||||
"."
|
||||
]
|
||||
},
|
||||
"p26-source-binding": {
|
||||
"argv": [
|
||||
"{python}",
|
||||
"-B",
|
||||
"docs/plans/original-completion-2026-10-02/execution/p26-01/check_content_ledger.py",
|
||||
"--project-root",
|
||||
".",
|
||||
"--source-binding-only"
|
||||
]
|
||||
}
|
||||
},
|
||||
"pending_not_waived": [
|
||||
"P04 existing D05 questions",
|
||||
"D08/D09 unresolved scopes",
|
||||
"P26-02/03 and upstream production content",
|
||||
"held gestures and sameWindows acceptance"
|
||||
],
|
||||
"model_proposal": {
|
||||
"codex_model": "gpt-6.1-sol",
|
||||
"reason": "This is a documentation audit with a stdlib checker, following the proven P13-03/P19-03 pattern. P19-03 used Sol and closed with 2 repairs. It needs no game code, no native GUI and no new reasoning about game rules, so Astra's extra cost and usage isn't worth it."
|
||||
},
|
||||
"normal_OS_applicability": "Documentation audit introduces no product interaction. Existing route/save/UI support and missing requirements are audited; global and other-unit OS acceptance stays open."
|
||||
}
|
||||
@@ -0,0 +1,346 @@
|
||||
#!/usr/bin/env python3
|
||||
"""P26 documentation audit. Stdlib only; --check never writes or runs Godot."""
|
||||
import argparse
|
||||
from functools import lru_cache
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
OUT = 'docs/plans/original-completion-2026-10-02/execution/p26-01/'
|
||||
PLAN = 'docs/plans/original-completion-2026-10-02/'
|
||||
BASELINE = 'docs/traceability/original/BASELINE.txt'
|
||||
BASE = '379a1ba8fd25b5ad24226178a2492f91761dc31d'
|
||||
ANCHOR = 'f4f85bc54c39361f9efcd16f67a17835559ca70c'
|
||||
BASE_HASH = '75e4bdbdeb379c9269553f0c776bdb9cc96e01f2d6aa5ca650d132c63a8aeb1a'
|
||||
PINS_HASH = '6c778226a4cc6d0b0d682500759e7d4229c926a27bd2e247b00b9c3e5f1a2fb0'
|
||||
SPEC_HASH = '1fedc9ade42a04722846daa9ac8ec26f821fb4efbce8dbbb53e3e76e31f38d02'
|
||||
P22 = 'artifacts/original-completion-2026-10-02/p22-01-usage-contract-candidate-r02/'
|
||||
PUBLISHED = '137639773c9017f9ee7733d78e37179b687f965c'
|
||||
ARCHIVE = OUT + 'accepted-p22-01-inputs/'
|
||||
MANIFEST_HASH = '90b5a69d5f364012edabe5a68b8c7613f5f5ca47bc189d435dd2e69b8dd8c915'
|
||||
P19 = PLAN + 'execution/p19-03/REACHABILITY_TABLE.json'
|
||||
BACKLOG = PLAN + 'execution/p22-03/production_backlog.json'
|
||||
PEOPLE = [('anri', 'アンリ'), ('fine', 'フィーネ'), ('tomari', 'トマリ'),
|
||||
('amelia', 'アメリア'), ('liz', 'リズ'), ('mimi', 'ミミ'), ('satsuki', 'サツキ')]
|
||||
ROUTES = {'love': '純愛', 'ntr': 'NTR', 'corruption': '堕落'}
|
||||
STATUSES = {'produced', 'placeholder', 'code-drawing', 'partial', 'missing', 'undefined'}
|
||||
|
||||
|
||||
def require(ok, message):
|
||||
if not ok:
|
||||
raise ValueError(message)
|
||||
|
||||
|
||||
def sha(raw):
|
||||
return hashlib.sha256(raw).hexdigest()
|
||||
|
||||
|
||||
def decode(raw):
|
||||
def unique(pairs):
|
||||
result = {}
|
||||
for key, value in pairs:
|
||||
require(key not in result, 'duplicate JSON key: ' + key)
|
||||
result[key] = value
|
||||
return result
|
||||
return json.loads(raw, object_pairs_hook=unique,
|
||||
parse_constant=lambda s: (_ for _ in ()).throw(ValueError(s)))
|
||||
|
||||
|
||||
def encoded(value):
|
||||
return json.dumps(value, ensure_ascii=False, sort_keys=True, allow_nan=False)
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def blob(root, commit, path):
|
||||
return subprocess.check_output(['git', 'show', commit + ':' + path], cwd=root)
|
||||
|
||||
|
||||
PACKAGE_MUTABLE = {'state', 'legacy_state', 'current_summary', 'updated_at_jst'}
|
||||
UNIT_MUTABLE = {'state', 'current_execution', 'remaining_gaps', 'updated_at_jst',
|
||||
'submitted_commit', 'current_summary', 'progress_summary', 'evidence',
|
||||
'completed_at_jst', 'implementation_commit', 'integrated_commit',
|
||||
'integration_commit', 'normal_integration_candidate'}
|
||||
|
||||
|
||||
def projection(packages):
|
||||
require(type(packages) is list, 'package register type')
|
||||
result = []
|
||||
for package in packages:
|
||||
require(type(package) is dict, 'package type')
|
||||
row = {k: v for k, v in package.items() if k not in PACKAGE_MUTABLE}
|
||||
require(type(row.get('remaining_deliverables')) is list, 'deliverables type')
|
||||
row['remaining_deliverables'] = [{k: v for k, v in unit.items()
|
||||
if k not in UNIT_MUTABLE} for unit in row['remaining_deliverables']]
|
||||
result.append(row)
|
||||
return result
|
||||
|
||||
|
||||
def selection(root):
|
||||
paths = [p for folder in ('autoload', 'scripts', 'scenes', 'data', 'tests', 'assets', 'tools')
|
||||
for p in (root / folder).rglob('*') if p.is_file() and p.name != '.DS_Store'
|
||||
and '__pycache__' not in p.parts]
|
||||
paths += [root / p for p in ('project.godot', 'export_presets.cfg', 'Makefile', 'AGENTS.md')]
|
||||
require(all(not p.is_symlink() for p in paths), 'selected symlink')
|
||||
return {p.relative_to(root).as_posix(): {'bytes': p.stat().st_size,
|
||||
'sha256': sha(p.read_bytes())} for p in sorted(paths)}
|
||||
|
||||
|
||||
def binding(root):
|
||||
raw = lambda p: (root / p).read_bytes()
|
||||
spec_raw = raw(OUT + 'TASK_SPEC.json')
|
||||
require(sha(spec_raw) == '8026040345de6b7d06cfce40beac9150bfe9ad303d6b26c11bd94e66b1080b29', 'raw spec SHA')
|
||||
require(sha(spec_raw.decode().strip().encode()) == SPEC_HASH, 'immutable spec')
|
||||
require(spec_raw == blob(root, BASE, OUT + 'TASK_SPEC.json'), 'raw immutable spec')
|
||||
spec = decode(spec_raw)
|
||||
require(spec['audit_source_anchor'] == ANCHOR, 'audit anchor')
|
||||
require(sha(raw(OUT + 'FROZEN_GAME_INPUT_PINS.json')) == PINS_HASH ==
|
||||
spec['frozen_game_input_pins_sha256'], 'frozen pins')
|
||||
require(raw(OUT + 'ACTUAL_OPUS_NEXT_ORIGINAL_UNIT_SELECTION.json') ==
|
||||
blob(root, BASE, OUT + 'ACTUAL_OPUS_NEXT_ORIGINAL_UNIT_SELECTION.json'), 'selection')
|
||||
require(sha(raw(BASELINE)) == BASE_HASH, 'original source')
|
||||
for name in ('work_packages.json', 'atomic_requirements.json', 'decisions.json'):
|
||||
current, original = raw(PLAN + name), blob(root, BASE, PLAN + name)
|
||||
if name == 'work_packages.json':
|
||||
require(encoded(projection(decode(current))) == encoded(projection(decode(original))),
|
||||
'original definitions')
|
||||
else:
|
||||
require(current == original, 'original register: ' + name)
|
||||
pins = decode(raw(OUT + 'FROZEN_GAME_INPUT_PINS.json'))
|
||||
actual = selection(root)
|
||||
require(encoded(actual) == encoded(pins['source_files']), 'selected game set: missing/new/changed')
|
||||
require(len(actual) == 1368, 'selected game cardinality')
|
||||
for key in ('marker_contract', 'policy', 'engine'):
|
||||
path = Path(pins[key + '_path']) if key == 'engine' else root / pins[key + '_path']
|
||||
require(sha(path.read_bytes()) == pins[key + '_sha256'], key + ' identity')
|
||||
roster = ['tests/run_tests.gd'] + sorted(p.relative_to(root).as_posix()
|
||||
for p in (root / 'tests').rglob('test*.gd') if 'export' not in p.relative_to(root).parts
|
||||
and p.relative_to(root).as_posix() != 'tests/s0/test_kernel_and_save.gd')
|
||||
require(roster == pins['roster'], 'roster')
|
||||
require(sum(p.endswith('.gd') for p in actual) == pins['parse_files'] == 329, 'parse set')
|
||||
# Every selected file, including settings and default player identity, is bound
|
||||
# to both the immutable source map and the exact published game audit anchor.
|
||||
for path in actual:
|
||||
require(sha(blob(root, ANCHOR, path)) == actual[path]['sha256'], 'audit source: ' + path)
|
||||
return {'selected_files': len(actual), 'parse_files': 329,
|
||||
'source_anchor': ANCHOR, 'native_reuse_accepted': False,
|
||||
'native_reuse_reason': 'Exact game equality is checked; external native proof and exact S/C applicability remain independent review gates.'}
|
||||
|
||||
|
||||
def read_source(root, path):
|
||||
if path.startswith(P22):
|
||||
archived = blob(root, PUBLISHED, ARCHIVE + path[len(P22):])
|
||||
if (root / path).exists():
|
||||
require((root / path).read_bytes() == archived, 'P22 alias changed: ' + path)
|
||||
return archived
|
||||
return (root / path).read_bytes()
|
||||
|
||||
|
||||
def source(root, path):
|
||||
raw = read_source(root, path)
|
||||
anchor = PUBLISHED if path.startswith(P22) else ANCHOR
|
||||
archived_path = ARCHIVE + path[len(P22):] if path.startswith(P22) else path
|
||||
anchored = blob(root, anchor, archived_path)
|
||||
require(raw == anchored, 'stale evidence: ' + path)
|
||||
return {'path': path, 'sha256': sha(raw), 'bytes': len(raw),
|
||||
'anchor': anchor, 'anchor_path': archived_path}
|
||||
|
||||
|
||||
def excerpt(root, path, start, end):
|
||||
pin = source(root, path)
|
||||
return dict(pin, lines=[start, end], text='\n'.join(
|
||||
read_source(root, path).decode().splitlines()[start-1:end]))
|
||||
|
||||
|
||||
def expected(root):
|
||||
"""Independent original clauses plus pinned actual evidence, not ledger-derived facts."""
|
||||
lines = (root / BASELINE).read_text().splitlines()
|
||||
require(sha((root / BASELINE).read_bytes()) == BASE_HASH, 'baseline')
|
||||
manifest_raw = blob(root, PUBLISHED, ARCHIVE + 'ROOT_MATERIAL_PRESERVATION_MANIFEST.json')
|
||||
require(sha(manifest_raw) == MANIFEST_HASH, 'published P22 manifest')
|
||||
for entry in decode(manifest_raw)['files']:
|
||||
raw = read_source(root, entry['original_path'])
|
||||
require(len(raw) == entry['bytes'] and sha(raw) == entry['sha256'], 'published P22 file pin')
|
||||
def cite(start, end=None):
|
||||
end = end or start
|
||||
return {'path': BASELINE, 'lines': [start, end],
|
||||
'text': '\n'.join(lines[start-1:end]), 'sha256': BASE_HASH}
|
||||
rows = []
|
||||
def add(identity, kind, spans, condition, owner, status='undefined', evidence=None,
|
||||
reason='欠損: 個別ID・必要量・完成内容は原本未定義。D08/D09未決。', identity_data=None):
|
||||
rows.append({'id': identity, 'kind': kind, 'identity': identity_data,
|
||||
'citations': [cite(*span) for span in spans], 'required_condition': condition,
|
||||
'status': status, 'required_count': None, 'completed_count': None,
|
||||
'evidence': evidence or [], 'missing': 'original production content missing or undefined',
|
||||
'reason': reason, 'owner': owner})
|
||||
add('chapters.all', 'chapter', [(8,), (26,), (27,30), (256,)],
|
||||
'メインストーリー全章。原本の仕様書章番号をシナリオ章と混同しない。章名・章数・順序・場面一覧は未定義。', 'D08')
|
||||
add('endings.all', 'ending', [(9,), (135,)],
|
||||
'全エンドを要求。個別エンドID・本数・到達条件は未定義。', 'D08')
|
||||
add('endings.bad', 'ending', [(135,)],
|
||||
'特定バッドエンド確定時の敵/背景オブジェクト化。カテゴリのみ原本定義、対象人物/場面/数は未定義。', 'P26-02')
|
||||
add('endings.game_over', 'ending', [(72,)],
|
||||
'赤字決算3回連続のゲームオーバー。物語エンド数への換算不可。', 'P26-02', 'missing',
|
||||
[source(root, 'scripts/economy/economy_service.gd')],
|
||||
'欠損: 経済処理の既存コードは存在するが終点のシナリオ・画像・音声・全受入を証明しない。')
|
||||
add('encyclopedia.all', 'encyclopedia', [(9,)],
|
||||
'図鑑コンプ。対象集合・項目ID・解放条件・必要項目数は未定義。', 'D08')
|
||||
add('dialogue.all', 'dialogue', [(155,), (230,), (256,)],
|
||||
'会話/イベント用台詞とシナリオ。本文・話者・行数・場面単位は未定義。UI通知文を完成脚本に数えない。', 'P26-02')
|
||||
add('portraits.all', 'portrait', [(160,161), (230,), (235,), (242,)],
|
||||
'メイン/サブ人物の表情・衣装・破損・汚れ・刻印・妊婦外見・ルート別描き分け。差分枚数未定義。', 'P26-03', 'missing')
|
||||
add('voice.all', 'voice', [(252,), (257,)],
|
||||
'キャラクターボイスの収録・実装。話者/台詞/クリップ数/担当未定義。BGMやUI音は代用不可。', 'P26-03', 'missing')
|
||||
# All applicable full clauses are retained even where the original defines no finite scene list.
|
||||
for key, spans, condition in [
|
||||
('world', [(27,30)], '舞台・主人公・7人物の3運命を保つ。'),
|
||||
('scope', [(31,34)], '原本表現要求と今回の非露骨な監査範囲との差異を残す。'),
|
||||
('route_skills', [(132,), (134,135)], 'ルートによる技能・衣装補正・離脱条件。'),
|
||||
('route_rules', [(138,161)], '3軸/盾・侵食・3種決闘・プレイヤー行動・履歴/外見の全共通条件。'),
|
||||
('art', [(229,230), (234,235)], '原本のマップ/SD/立ち絵・モーションと描き分け。'),
|
||||
('cg', [(242,243)], '人物立ち絵およびルート別CG/差分/モブ汎用スチル。'),
|
||||
('motion', [(245,246)], '待機・歩行・作業・気絶・原本必須モーションと効果。'),
|
||||
('production', [(252,), (255,258)], '原本のシナリオ/素材量産/音声制作と受入は未完。')]:
|
||||
add('clause.' + key, 'category', spans, condition, 'P26-03', 'missing')
|
||||
table = decode((root / P19).read_bytes())
|
||||
table_pin = source(root, P19)
|
||||
cells = {(c['character_id'], c['route_id']): c for c in table['cells']}
|
||||
for i, (person, name) in enumerate(PEOPLE):
|
||||
require(name in lines[117+i], 'original identity')
|
||||
for route, route_name in ROUTES.items():
|
||||
cell = cells[(person, route)]
|
||||
require(cell['name'] == name and cell['route'] == route_name and
|
||||
cell['natural_route_complete'] is False, 'P19 route identity/status')
|
||||
add('route.' + person + '.' + route, 'route', [(118+i,), (30,), (132,), (138,161)],
|
||||
'人物固有の入口・イベント列・分岐・終点・台詞・立ち絵・音声・履歴/保存と通常到達。',
|
||||
'P26-02', 'missing', [dict(table_pin, cell=[person, route])],
|
||||
'欠損: P19共通モデル/保存の部分実装は人物別制作/到達ではない。人物固有条件・場面列はD08未決。',
|
||||
{'character_id': person, 'original_name': name, 'route_id': route, 'route_name': route_name})
|
||||
# Preserve every existing usage record (614 usage groups, never 614 finished assets).
|
||||
usage_inputs = ['facility_usage_slots.json', 'character_usage_slots.json',
|
||||
'other_usage_slots.json', 'state_usage_groups.json']
|
||||
usage_snapshots = {}
|
||||
for filename in usage_inputs:
|
||||
path = P22 + filename
|
||||
records = decode(read_source(root, path))
|
||||
usage_snapshots[path] = {'source': source(root, path), 'records': records}
|
||||
for record in records:
|
||||
anchors = record['source_anchors']
|
||||
for a in anchors:
|
||||
require(a['sha256'] == BASE_HASH and a['text'] == lines[a['line']-1], 'P22 citation')
|
||||
representations = []
|
||||
for rep in record.get('representations', []):
|
||||
pin = source(root, rep['path'])
|
||||
representations.append(dict(pin, historical_inventory=rep,
|
||||
current_bytes_equal_inventory=pin['sha256'] == rep['sha256']))
|
||||
kind = record.get('kind', 'usage')
|
||||
status = 'missing'
|
||||
if representations:
|
||||
status = 'code-drawing' if all(r['historical_inventory']['representation'] == 'code_drawn'
|
||||
for r in representations) else 'placeholder'
|
||||
slot_id = record.get('slot_id', record.get('group_id'))
|
||||
add('usage.' + slot_id, kind, [(a['line'],) for a in anchors],
|
||||
record['usage_condition'], 'P26-03', status, representations,
|
||||
'欠損: 利用枠/用途群。既存表現の現物SHAを再取得。汎用描画/仮素材は固有人物・必須差分の完成証明ではない。D09数量/品質/担当未決。',
|
||||
{'usage_source': path, 'slot_id': slot_id})
|
||||
references = {p: source(root, p) for p in [P19, BACKLOG] +
|
||||
[P22 + n for n in ['contract.json', 'source_pins.json', 'current_media_inventory.json']]}
|
||||
actual_support = [excerpt(root, 'data/characters/mvp_unique_characters.json', 1, 32),
|
||||
excerpt(root, 'scripts/relationship/original_relationship_state.gd', 4, 34),
|
||||
excerpt(root, 'autoload/simulation_runtime.gd', 6791, 6812),
|
||||
excerpt(root, 'scripts/relationship/relationship_service.gd', 423, 479),
|
||||
excerpt(root, 'scripts/ui/pixel_people.gd', 4, 18)]
|
||||
media = decode(read_source(root, P22 + 'current_media_inventory.json'))
|
||||
current_media = [dict(source(root, m['path']), historical_inventory=m) for m in media]
|
||||
pins = decode((root / OUT / 'FROZEN_GAME_INPUT_PINS.json').read_bytes())
|
||||
available_assets = {p: v for p, v in pins['source_files'].items() if p.startswith('assets/')}
|
||||
return {'task_id': 'P26-01-LEDGER', 'schema_version': 1, 'source_anchor': ANCHOR,
|
||||
'definition_base': BASE, 'rows': rows, 'usage_snapshots': usage_snapshots,
|
||||
'published_material': {'anchor': PUBLISHED, 'manifest_sha256': MANIFEST_HASH,
|
||||
'manifest_path': ARCHIVE + 'ROOT_MATERIAL_PRESERVATION_MANIFEST.json'},
|
||||
'references': references, 'P22_03_authority': 'draft/unaccepted reference only',
|
||||
'actual_support': actual_support,
|
||||
'support_interpretation': 'Explicit state/identity/container support only; generic pose has no original character-specific appearance. No finished chapter/dialogue/portrait/voice/encyclopedia inferred.',
|
||||
'current_media_reaudit': current_media,
|
||||
'available_asset_source_set': available_assets,
|
||||
'pending': {'D05': 'unresolved existing questions; existing approvals preserved',
|
||||
'D08': 'unresolved', 'D09': 'unresolved'},
|
||||
'accounting': {'packages': 30, 'units': 88, 'completed': 15, 'credit': 0,
|
||||
'partial_credit': False, 'whole_unit_accepted': False},
|
||||
'native_evidence': {'reuse_accepted': False, 'new_full_run': False,
|
||||
'historical_only': {'suites': 184, 'checks': 21903, 'parse': 329, 'owned_ended': 186},
|
||||
'reason': 'Runner must independently establish exact S/C applicability; no native result claimed here.'}}
|
||||
|
||||
|
||||
def verify(candidate, canonical):
|
||||
require(type(candidate) is dict, 'closed document object')
|
||||
require(type(candidate.get('rows')) is list, 'closed rows list')
|
||||
rows = candidate['rows']
|
||||
ids = [r['id'] for r in rows]
|
||||
require(len(ids) == len(set(ids)), 'duplicate row ID')
|
||||
require(set(ids) == {r['id'] for r in canonical['rows']}, 'original clause/slot coverage')
|
||||
for row in rows:
|
||||
require(row['status'] in STATUSES, 'invalid status')
|
||||
require(row['required_count'] is None and row['completed_count'] is None, 'invented quantity')
|
||||
require(row['status'] != 'produced', 'unsupported completion')
|
||||
require(row['owner'] in {'D08', 'P26-02', 'P26-03'}, 'invalid owner')
|
||||
require(row['citations'] and row['reason'] and row['missing'], 'missing traceability')
|
||||
require(encoded(candidate) == encoded(canonical), 'ledger differs from original/source-bound audit')
|
||||
|
||||
|
||||
def markdown(document):
|
||||
# A lossless deterministic human view, including exact citations and source hashes.
|
||||
lines = ['# P26-01 全必要内容の台帳', '',
|
||||
'15/88、今回加算0。未制作/未定義は欠損。利用枠数は完成数ではない。', '',
|
||||
'D05既存未解決事項・D08・D09は未解決。P22-03は未受入の参考資料。', '']
|
||||
for row in document['rows']:
|
||||
lines += ['## ' + row['id'], '', '- 種別: ' + row['kind'],
|
||||
'- 識別: ' + encoded(row['identity']),
|
||||
'- 状態: ' + row['status'], '- 所管: ' + row['owner'],
|
||||
'- 条件: ' + (row['required_condition'] if isinstance(row['required_condition'], str)
|
||||
else encoded(row['required_condition'])), '- 理由: ' + row['reason'],
|
||||
'- 必要数/完成数: 未定義 / 未計数', '- 欠損: ' + row['missing'], '']
|
||||
for c in row['citations']:
|
||||
lines += [f"原本 `{c['path']}:{c['lines'][0]}-{c['lines'][1]}` SHA256 `{c['sha256']}`", '',
|
||||
'```text', c['text'], '```', '']
|
||||
lines += ['証拠(空配列は明示的欠損):', '', '```json',
|
||||
json.dumps(row['evidence'], ensure_ascii=False, indent=2), '```', '']
|
||||
lines += ['## 固定参照・監査境界', '', '```json',
|
||||
json.dumps({k: v for k, v in document.items() if k != 'rows'}, ensure_ascii=False, indent=2), '```', '']
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
def check_view(raw, document):
|
||||
require(raw == markdown(document).encode(), 'Markdown drift')
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--project-root', type=Path, default=Path('.'))
|
||||
mode = parser.add_mutually_exclusive_group(required=True)
|
||||
mode.add_argument('--check', action='store_true')
|
||||
mode.add_argument('--source-binding-only', action='store_true')
|
||||
mode.add_argument('--write', action='store_true')
|
||||
args = parser.parse_args()
|
||||
root = args.project_root.resolve()
|
||||
try:
|
||||
result = binding(root)
|
||||
canonical = expected(root)
|
||||
if args.write:
|
||||
(root / OUT / 'CONTENT_LEDGER.json').write_text(json.dumps(canonical, ensure_ascii=False, indent=2) + '\n')
|
||||
(root / OUT / 'CONTENT_LEDGER.md').write_text(markdown(canonical))
|
||||
else:
|
||||
document = decode((root / OUT / 'CONTENT_LEDGER.json').read_bytes())
|
||||
verify(document, canonical)
|
||||
if args.check:
|
||||
check_view((root / OUT / 'CONTENT_LEDGER.md').read_bytes(), document)
|
||||
print(json.dumps({'documentation_check': 'pass', **result}, ensure_ascii=False))
|
||||
return 0
|
||||
except (ValueError, KeyError, TypeError, OSError, subprocess.CalledProcessError) as error:
|
||||
print('P26 audit rejected: ' + str(error), file=sys.stderr)
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Runner negative controls for P26; no fixture writes and no native execution."""
|
||||
import argparse
|
||||
import copy
|
||||
from pathlib import Path
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
import check_content_ledger as audit
|
||||
|
||||
|
||||
class LedgerTests(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.canonical = audit.expected(ROOT)
|
||||
cls.submitted = audit.decode((ROOT / audit.OUT / 'CONTENT_LEDGER.json').read_bytes())
|
||||
|
||||
def reject(self, mutate):
|
||||
value = copy.deepcopy(self.submitted)
|
||||
mutate(value)
|
||||
with self.assertRaises((ValueError, TypeError, KeyError)):
|
||||
audit.verify(value, self.canonical)
|
||||
|
||||
def test_valid_submitted_and_independent_source_control(self):
|
||||
audit.verify(self.submitted, self.canonical)
|
||||
audit.verify(copy.deepcopy(self.canonical), self.canonical)
|
||||
audit.check_view((ROOT / audit.OUT / 'CONTENT_LEDGER.md').read_bytes(), self.submitted)
|
||||
|
||||
def test_required_sets_are_independent_of_submitted_rows(self):
|
||||
ids = {r['id'] for r in self.canonical['rows']}
|
||||
self.assertTrue({'chapters.all', 'endings.all', 'endings.bad', 'endings.game_over',
|
||||
'dialogue.all', 'portraits.all', 'voice.all', 'encyclopedia.all'} <= ids)
|
||||
self.assertEqual({r['id'] for r in self.canonical['rows'] if r['kind'] == 'route'},
|
||||
{'route.' + p + '.' + r for p, _ in audit.PEOPLE for r in audit.ROUTES})
|
||||
|
||||
def test_omitted_original_categories_and_route(self):
|
||||
for identity in ['chapters.all', 'route.satsuki.corruption', 'endings.all',
|
||||
'endings.bad', 'endings.game_over', 'dialogue.all', 'voice.all',
|
||||
'portraits.all', 'encyclopedia.all', 'clause.route_rules']:
|
||||
with self.subTest(identity=identity):
|
||||
self.reject(lambda d: d.update(rows=[r for r in d['rows'] if r['id'] != identity]))
|
||||
|
||||
def test_missing_usage_slot(self):
|
||||
self.reject(lambda d: d['rows'].pop())
|
||||
|
||||
def test_fabricated_quantity_and_false_completion(self):
|
||||
self.reject(lambda d: d['rows'][0].update(required_count=8))
|
||||
self.reject(lambda d: d['rows'][0].update(completed_count=0))
|
||||
self.reject(lambda d: d['rows'][0].update(status='produced', missing=None))
|
||||
|
||||
def test_closed_schema_owner_status_type_and_duplicates(self):
|
||||
for field, value in [('owner', 'P99-99'), ('status', 'pass'), ('kind', 'invented'),
|
||||
('required_count', False), ('citations', []), ('extra', True)]:
|
||||
with self.subTest(field=field):
|
||||
self.reject(lambda d: d['rows'][0].update({field: value}))
|
||||
self.reject(lambda d: d['rows'].append(copy.deepcopy(d['rows'][0])))
|
||||
self.reject(lambda d: d.update(schema_version=True))
|
||||
|
||||
def test_exact_route_identity(self):
|
||||
self.reject(lambda d: next(r for r in d['rows'] if r['kind'] == 'route')
|
||||
['identity'].update(original_name='別人'))
|
||||
|
||||
def test_stale_original_and_source(self):
|
||||
self.reject(lambda d: d['rows'][0]['citations'][0].update(text='stale'))
|
||||
self.reject(lambda d: d['rows'][0]['citations'][0].update(sha256='0' * 64))
|
||||
self.reject(lambda d: d['references'][audit.P19].update(sha256='0' * 64))
|
||||
self.reject(lambda d: d.update(source_anchor='HEAD'))
|
||||
|
||||
def test_malformed_json_duplicate_keys_and_nonfinite(self):
|
||||
self.assertEqual(audit.decode('{"rows": []}'), {'rows': []})
|
||||
for raw in ['{', '{"x":1,"x":2}', '{"x":NaN}', '{"x":Infinity}']:
|
||||
with self.subTest(raw=raw), self.assertRaises(ValueError):
|
||||
audit.decode(raw)
|
||||
|
||||
def test_markdown_drift(self):
|
||||
view = audit.markdown(self.submitted).encode()
|
||||
audit.check_view(view, self.submitted)
|
||||
with self.assertRaises(ValueError):
|
||||
audit.check_view(view + b'\n', self.submitted)
|
||||
|
||||
def test_definition_projection_allows_only_progress(self):
|
||||
packages = audit.decode(audit.blob(ROOT, audit.BASE, audit.PLAN + 'work_packages.json'))
|
||||
changed = copy.deepcopy(packages)
|
||||
changed[0]['state'] = 'progress-only-control'
|
||||
changed[0]['remaining_deliverables'][0]['evidence'] = ['progress-only-control']
|
||||
self.assertEqual(audit.encoded(audit.projection(packages)), audit.encoded(audit.projection(changed)))
|
||||
for field in ['acceptance', 'work', 'depends_on', 'requirement_ids']:
|
||||
changed = copy.deepcopy(packages)
|
||||
changed[0][field] = 'mutated definition'
|
||||
self.assertNotEqual(audit.encoded(audit.projection(packages)), audit.encoded(audit.projection(changed)))
|
||||
|
||||
def test_published_source_changed_bytes_rejected(self):
|
||||
original = audit.blob
|
||||
def stale(root, anchor, path):
|
||||
raw = original(root, anchor, path)
|
||||
return raw + b' ' if path == audit.ARCHIVE + 'ROOT_MATERIAL_PRESERVATION_MANIFEST.json' else raw
|
||||
with patch.object(audit, 'blob', stale), self.assertRaises(ValueError):
|
||||
audit.expected(ROOT)
|
||||
|
||||
def test_selected_input_mutation_rejected(self):
|
||||
actual = audit.selection(ROOT)
|
||||
# Valid map control comes from frozen independent pins, not a second selection call.
|
||||
pins = audit.decode((ROOT / audit.OUT / 'FROZEN_GAME_INPUT_PINS.json').read_bytes())
|
||||
self.assertEqual(audit.encoded(actual), audit.encoded(pins['source_files']))
|
||||
for mode in ('missing', 'new', 'changed', 'wrong_type'):
|
||||
changed = copy.deepcopy(actual)
|
||||
key = 'project.godot'
|
||||
if mode == 'missing':
|
||||
del changed[key]
|
||||
elif mode == 'new':
|
||||
changed['data/unapproved.json'] = {'bytes': 0, 'sha256': '0' * 64}
|
||||
elif mode == 'changed':
|
||||
changed[key]['sha256'] = '0' * 64
|
||||
else:
|
||||
changed[key]['bytes'] = str(changed[key]['bytes'])
|
||||
with self.subTest(mode=mode), patch.object(audit, 'selection', return_value=changed), self.assertRaises(ValueError):
|
||||
audit.binding(ROOT)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--project-root', type=Path, default=Path('.'))
|
||||
args, remaining = parser.parse_known_args()
|
||||
ROOT = args.project_root.resolve()
|
||||
unittest.main(argv=[__file__] + remaining)
|
||||
@@ -244,7 +244,7 @@
|
||||
"facility_value_contracts_validation.json": "bf490a9ca585c48fc318e76c4a069ef244827d828d46e6415399f7710590dd16",
|
||||
"performance_audit.json": "0b630b15a392c3e0366f1362bfe4ddacb968f915f54549f82e4d6fa315384762",
|
||||
"progress_contract.json": "ccbdfce8c8365d5c13f59531955708834cce45acd0e136561c95295dfdb5df77",
|
||||
"progress_snapshot.json": "4a5e3a1ad7e69406bf3aef43333eda19c07337f1d76a8f5c68da74b6bded9fd1",
|
||||
"progress_snapshot.json": "332dd0b3ba2e58c6801fdebf0ce42b672f7085479b6c4842b109c4e921b09686",
|
||||
"progress_validator_guard_checks.json": "72ee513fcf1cad85c24bfd0a4b472f425f6acf117928ece0f6b41e29018da627",
|
||||
"progress_validator_guard_checks.r01.json": "14c26adffa5a1938241db4912e50ea54b660641ee6fee2e412d467dce14d0519",
|
||||
"requirement_coverage.json": "03b10e4da367579db502d0671a6e0dda36fd385111c6f1c0084acaff7605f593",
|
||||
@@ -254,6 +254,6 @@
|
||||
"validate_facility_value_contracts.py": "91640e2a76cd6cc9186f7b85c0bf379b24b6cac0d48962815235ee628e7ae43e",
|
||||
"validate_plan.py": "23678227d9b3c556f1bd903f4b5b3147c4a82ce5085e10055481026803451b80",
|
||||
"validator_update_checks.json": "f997d0f3de2cea29550840b1d5cb23647d64f81329de46758551e2b6c8fecc27",
|
||||
"work_packages.json": "0b472eaff8c208337cf2847c196add61415fbf22db2e7c298d2fc5c4ff38e5c0"
|
||||
"work_packages.json": "9cac178af50d3320287c64aa518f6ec704fc71139a481c858f45b707eaf9f8ad"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,8 +156,8 @@
|
||||
"planned": 1
|
||||
},
|
||||
"current_delivery_state_counts": {
|
||||
"completed": 14,
|
||||
"in_progress": 25,
|
||||
"completed": 15,
|
||||
"in_progress": 24,
|
||||
"planned": 49
|
||||
},
|
||||
"completed_current_deliveries": [
|
||||
@@ -9713,7 +9713,7 @@
|
||||
"execution": "the-tree-p06-01 Runner; recorded Claude decision, one Codex implementer",
|
||||
"current_gate_status": "not implemented or executed; formal completion not accepted"
|
||||
},
|
||||
"next_closure_plan_id": "P19-03",
|
||||
"next_closure_plan_id": "P04-01",
|
||||
"p24_03_formal_closure": "docs/plans/original-completion-2026-10-02/execution/p24-03-formal-closure-r01/closure.json",
|
||||
"new_engine_run_scope": "Supplemental positive metadata diagnostic r01 failed cleanup preparation/log isolation; r02 passed17checks unchanged source and entire default profile. No duplicated full game regression.",
|
||||
"current_closure_targets": {
|
||||
@@ -10478,30 +10478,48 @@
|
||||
"whole_original_acceptance": false
|
||||
},
|
||||
"current_p19_03_reachability": {
|
||||
"state": "whole_original_review_passed_integration_final_pending",
|
||||
"state": "completed",
|
||||
"spec": "docs/plans/original-completion-2026-10-02/execution/p19-03/TASK_SPEC.json",
|
||||
"actual_opus": "dc342e4d69154660bef7e688a70fd783",
|
||||
"original_unit_credit": 0,
|
||||
"original_unit_credit": 1,
|
||||
"source_anchor": "1b07b87d3736e777932315a4bdde8b70cbf9cb23",
|
||||
"P04_existing_questions": "preserved; no duplicate question or fake answer",
|
||||
"S": "806de25068bc423136063791afcea811d251ee1b",
|
||||
"S": "903a2c566e73cebc874a6499410a1243bc190a63",
|
||||
"actual_reviewer": {
|
||||
"id": "d4e70e7f48f549b085692962f88531a8",
|
||||
"status": "running",
|
||||
"pid": 30223,
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/d4e70e7f48f549b085692962f88531a8"
|
||||
"id": "565d4f21c12b451da2d5a7dd462d099b",
|
||||
"role": "reviewer",
|
||||
"status": "finished",
|
||||
"pid": 51196,
|
||||
"artifact": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p19-03-reachability/runs/565d4f21c12b451da2d5a7dd462d099b"
|
||||
},
|
||||
"current_status": "docs/plans/original-completion-2026-10-02/execution/p19-03/ROOT_CURRENT_ACCEPTANCE_STATUS.json",
|
||||
"whole_review": {
|
||||
"run_id": "38eaaacdb31b4c76bcf982987816a391",
|
||||
"run_id": "565d4f21c12b451da2d5a7dd462d099b",
|
||||
"status": "pass",
|
||||
"critical_high_medium": 0,
|
||||
"low": 3,
|
||||
"artifact": "ROOT_WHOLE_REVIEW_806DE25.json"
|
||||
"artifact": "ROOT_WHOLE_REVIEW_903A2C5.json"
|
||||
},
|
||||
"actual_repair_worker": {
|
||||
"id": "bf8a86e053044bfea0051253fefb2ec7",
|
||||
"status": "finished"
|
||||
}
|
||||
}
|
||||
},
|
||||
"nonformal_actual_main_preflight": {
|
||||
"passed": true,
|
||||
"source": "903a2c566e73cebc874a6499410a1243bc190a63",
|
||||
"preflight_commit": "7f9b63b0c281d57be4abec1c576e5abef273ca78",
|
||||
"main": "6e17cae5c9f0133fc3eb19e58572977f4151de7c",
|
||||
"normal_integration_or_final_satisfied": false,
|
||||
"artifact": "ROOT_ACTUAL_NONFORMAL_MAIN_PREFLIGHT_903A2C5.json"
|
||||
},
|
||||
"C": "8e4f1d92fc2a2e8f1dd187e661cf52b13e4e51d4",
|
||||
"M": "e7acd530c5d43313534d0b6ee23c915aba3cf70a",
|
||||
"normal_final": {
|
||||
"passed": true,
|
||||
"commit": "8e4f1d92fc2a2e8f1dd187e661cf52b13e4e51d4",
|
||||
"artifact": "ROOT_NORMAL_FINAL_C8E4F1D9.json"
|
||||
},
|
||||
"whole_game_acceptance": false
|
||||
},
|
||||
"next_closure_note": "P04-01 remains first upon existing D05 answers; actual Opus will select next independent original work without duplicate worker or invented values."
|
||||
}
|
||||
|
||||
@@ -8996,7 +8996,7 @@
|
||||
},
|
||||
"legacy_state": "planned",
|
||||
"state_scope": "package-level; completed means whole package accepted; partial implementation is not completion",
|
||||
"current_summary": "修正版806de25の登録3検証/12自己試験が実合格。実Opus38eaaが7名×3ルート21セル・全8カテゴリ・原本/全source/欠損と旧実装区分を全原条件再レビューしpass(重大/高/中0・低3)。通常integration/final・台帳確定前で原14/88に加算0。ゲーム1368入力は同一、旧全回帰証明を厳密再利用。",
|
||||
"current_summary": "P19-03分岐到達表の原成果を正式完了。P19-01/02のゲーム内行動・決闘・履歴等は未完。原P19-03を正式完了。S903a2c5→通常C8e4f1d9/Me7acd53、元受入7名×3ルート21セルと全8カテゴリ・23共通ルール・未制作欠損を実Opus565d全条件レビュー合格。登録3検証/16自己試験・実候補integration/final合格、レビュー済8文書と1368ゲーム入力の完全等値照合。原本/定義/未承認事項を保ち進捗メタだけ分離。原正式14→15/88(本件+1、部分点なし)。全ルート実装/完成素材/Windows等の全ゲーム完了は別未達。",
|
||||
"remaining_deliverables": [
|
||||
{
|
||||
"id": "P19-01",
|
||||
@@ -9019,7 +9019,7 @@
|
||||
"title": "分岐の到達性",
|
||||
"work": "人物ごとの3ルートに必要なイベント・条件・中断処理を列挙する。",
|
||||
"acceptance": "7名×3ルートの到達表があり、未制作内容は欠損として残る。",
|
||||
"state": "in_progress",
|
||||
"state": "completed",
|
||||
"evidence": [
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p19-03/TASK_SPEC.json",
|
||||
@@ -9028,19 +9028,21 @@
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p19-03/ROOT_CURRENT_ACCEPTANCE_STATUS.json",
|
||||
"sha256": "75dd5adc99eebd16703c5f5b4df12d3e4efdc24e702b24bb7daa1a71454417e6",
|
||||
"sha256": "02c474558fbd32e99ebb8069e5cfa3318048d8d7b72f12887e885bc37c294da2",
|
||||
"scope": "Actual registered3checks+selftests10 PASS; exact game-input reuse qualified; whole semantic review/integration/final pending, original credit0"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p19-03/ROOT_RUNNER_COMPLETED_TRACEABILITY.json",
|
||||
"sha256": "b433a6b52bb722fa8e9cdc2a161abbca71693f45926bb5c7bf1b00716d3d7f5a",
|
||||
"scope": "Whole original P19-03 acceptance, independent review, normal exactC/M integration/final, existing real authorization; originalcredit1 only; no gamecompletion"
|
||||
}
|
||||
],
|
||||
"current_summary": "修正版806de25の登録3検証/12自己試験が実合格。実Opus38eaaが7名×3ルート21セル・全8カテゴリ・原本/全source/欠損と旧実装区分を全原条件再レビューしpass(重大/高/中0・低3)。通常integration/final・台帳確定前で原14/88に加算0。ゲーム1368入力は同一、旧全回帰証明を厳密再利用。",
|
||||
"progress_summary": "初回実行パス未展開と実provider文脈上限の失敗を保持し、検査器実行前/推論前の障害のみを実行経路/全文ファイル参照で補正。提出版/全資料/受入条件/権限/課金に変更なし。人物固有未制作/D08/未定値は欠損。",
|
||||
"updated_at_jst": "2026-10-17T19:58:24.516684+09:00",
|
||||
"current_summary": "原P19-03を正式完了。S903a2c5→通常C8e4f1d9/Me7acd53、元受入7名×3ルート21セルと全8カテゴリ・23共通ルール・未制作欠損を実Opus565d全条件レビュー合格。登録3検証/16自己試験・実候補integration/final合格、レビュー済8文書と1368ゲーム入力の完全等値照合。原本/定義/未承認事項を保ち進捗メタだけ分離。原正式14→15/88(本件+1、部分点なし)。全ルート実装/完成素材/Windows等の全ゲーム完了は別未達。",
|
||||
"progress_summary": "原P19-03を正式完了。S903a2c5→通常C8e4f1d9/Me7acd53、元受入7名×3ルート21セルと全8カテゴリ・23共通ルール・未制作欠損を実Opus565d全条件レビュー合格。登録3検証/16自己試験・実候補integration/final合格、レビュー済8文書と1368ゲーム入力の完全等値照合。原本/定義/未承認事項を保ち進捗メタだけ分離。原正式14→15/88(本件+1、部分点なし)。全ルート実装/完成素材/Windows等の全ゲーム完了は別未達。",
|
||||
"updated_at_jst": "2026-10-17T20:29:39.555420+09:00",
|
||||
"current_execution": "docs/plans/original-completion-2026-10-02/execution/p19-03/ROOT_CURRENT_ACCEPTANCE_STATUS.json",
|
||||
"remaining_gaps": [
|
||||
"Normal actual integrationC/M and independent candidate source/input equality",
|
||||
"Normal final and existing exact real-owner main authorization, thenledger/push; no new humanSHA speech fabricated"
|
||||
],
|
||||
"submitted_commit": "806de25068bc423136063791afcea811d251ee1b"
|
||||
"remaining_gaps": [],
|
||||
"submitted_commit": "903a2c566e73cebc874a6499410a1243bc190a63"
|
||||
}
|
||||
],
|
||||
"estimate_person_days_historical_2026_09_29": [
|
||||
@@ -9061,7 +9063,7 @@
|
||||
],
|
||||
"cross_cutting_acceptance_scope": "Completion requirements only, not achieved results. Apply each to relevant slices; non-applicable views require a recorded reason.",
|
||||
"initial_revision_state": "planned",
|
||||
"updated_at_jst": "2026-10-17T19:39:39.105864+09:00"
|
||||
"updated_at_jst": "2026-10-17T20:29:39.555420+09:00"
|
||||
},
|
||||
{
|
||||
"id": "P20",
|
||||
|
||||
Reference in New Issue
Block a user