P13-03: 内容差異の記録
This commit is contained in:
@@ -25,7 +25,7 @@
|
|||||||
共有観測範囲(各施設の具体的検索結果は機械台帳に保持):
|
共有観測範囲(各施設の具体的検索結果は機械台帳に保持):
|
||||||
|
|
||||||
- normal_entry: adult_private_room is in the UI list and baseline catalog; black_market is expansion-only. No other original identity match. Static eligibility only; actual construction is unverified.
|
- normal_entry: adult_private_room is in the UI list and baseline catalog; black_market is expansion-only. No other original identity match. Static eligibility only; actual construction is unverified.
|
||||||
- runtime: Runtime loads baseline/infrastructure/rescue/original paths, not expansion paths at this load site. Generic services do not prove original special behavior.
|
- runtime: Runtime loads ORIGINAL_FACILITY_PATHS, including some files under the expansion directory. It does not load EXPANSION_FACILITY_PATHS or black_market. Generic services do not prove original special behavior.
|
||||||
- event_state: No facility-specific transition established by this search. Generic EventService is not a dedicated content catalog.
|
- event_state: No facility-specific transition established by this search. Generic EventService is not a dedicated content catalog.
|
||||||
- save: Generic snapshot plumbing is a technical lead only. Facility event round-trip and original semantics remain unverified.
|
- save: Generic snapshot plumbing is a technical lead only. Facility event round-trip and original semantics remain unverified.
|
||||||
- test: Selected generic suite sources searched; no formal suite run or dedicated original facility acceptance inferred.
|
- test: Selected generic suite sources searched; no formal suite run or dedicated original facility acceptance inferred.
|
||||||
@@ -228,7 +228,7 @@ event/overlay/history/story/voice/scene の内容ID・数量・受入はunknown
|
|||||||
- `docs/plans/original-completion-2026-10-02/asset_inventory_reaudit/facility_usage_slots.json` / current_checkout / SHA256 `56a031b6430aa9cb408f14b66efc5dd9a779841c0e7c19301945c49c12711491`
|
- `docs/plans/original-completion-2026-10-02/asset_inventory_reaudit/facility_usage_slots.json` / current_checkout / SHA256 `56a031b6430aa9cb408f14b66efc5dd9a779841c0e7c19301945c49c12711491`
|
||||||
- `docs/plans/original-completion-2026-10-02/asset_inventory_reaudit/inventory_summary.json` / current_checkout / SHA256 `298b37e65c41febe8a2ccdea10bd105ab7a606904f06b16c1659cda6214859b9`
|
- `docs/plans/original-completion-2026-10-02/asset_inventory_reaudit/inventory_summary.json` / current_checkout / SHA256 `298b37e65c41febe8a2ccdea10bd105ab7a606904f06b16c1659cda6214859b9`
|
||||||
- `docs/plans/original-completion-2026-10-02/decisions.json` / current_checkout / SHA256 `ad0673051b0fa601e525f05128e0b11e2dddd9d4bae6a3e0170bbf47da35efe9`
|
- `docs/plans/original-completion-2026-10-02/decisions.json` / current_checkout / SHA256 `ad0673051b0fa601e525f05128e0b11e2dddd9d4bae6a3e0170bbf47da35efe9`
|
||||||
- `autoload/simulation_runtime.gd` / current_checkout / SHA256 `d52a995ae715542bbc550f68d35889540658275d12e04ae0b21ac276f5843f39`
|
- `autoload/simulation_runtime.gd` / main_git_blob / SHA256 `4696df4a77feb465a5a3ba8b806569f7bcbe1d03c88289acfb78a3928f307d67`
|
||||||
- `data/facilities/adult_private_room.tres` / current_checkout / SHA256 `d8501586416b5c57a8b3b3b2afd1c0143428d8a4fa1df7112e995bd36649df6d`
|
- `data/facilities/adult_private_room.tres` / current_checkout / SHA256 `d8501586416b5c57a8b3b3b2afd1c0143428d8a4fa1df7112e995bd36649df6d`
|
||||||
- `data/facilities/cafeteria.tres` / current_checkout / SHA256 `86d540fe2d78b9dcdbe5a0af6e4a001f4cec54934636ed01deb25a943c79128a`
|
- `data/facilities/cafeteria.tres` / current_checkout / SHA256 `86d540fe2d78b9dcdbe5a0af6e4a001f4cec54934636ed01deb25a943c79128a`
|
||||||
- `data/facilities/expansion/black_market.tres` / current_checkout / SHA256 `c209d734c82487f6df4c03714618865d6a5f1d2cf991dc0056fe4bbad8f03a42`
|
- `data/facilities/expansion/black_market.tres` / current_checkout / SHA256 `c209d734c82487f6df4c03714618865d6a5f1d2cf991dc0056fe4bbad8f03a42`
|
||||||
@@ -266,7 +266,7 @@ event/overlay/history/story/voice/scene の内容ID・数量・受入はunknown
|
|||||||
- `data/facilities/standard_room.tres` / current_checkout / SHA256 `89f0a3a861d66afa4c1338ff1ec919685cf338b93b8da9a2387ce85e7e5bc336`
|
- `data/facilities/standard_room.tres` / current_checkout / SHA256 `89f0a3a861d66afa4c1338ff1ec919685cf338b93b8da9a2387ce85e7e5bc336`
|
||||||
- `data/facilities/tavern.tres` / current_checkout / SHA256 `eb494ae6ab0d1b9e88ae0a38944609702e43c81a370a29cfb030af9ae46f523c`
|
- `data/facilities/tavern.tres` / current_checkout / SHA256 `eb494ae6ab0d1b9e88ae0a38944609702e43c81a370a29cfb030af9ae46f523c`
|
||||||
- `data/facilities/warehouse.tres` / current_checkout / SHA256 `d0fcf0528da66da7b354ab5efaafe2483a7a76e05b324db255700ef73cdfc791`
|
- `data/facilities/warehouse.tres` / current_checkout / SHA256 `d0fcf0528da66da7b354ab5efaafe2483a7a76e05b324db255700ef73cdfc791`
|
||||||
- `scenes/main/main.gd` / current_checkout / SHA256 `a3d7d7ddd08a8df1f987806e60accf51792d728cf71c06e6b822f5a31d8ed3e3`
|
- `scenes/main/main.gd` / main_git_blob / SHA256 `92677e4ac57ed8d418a4a716bf0874cbbaea79cff893e5163c82ad1f75e7140a`
|
||||||
- `scripts/core/save_service.gd` / current_checkout / SHA256 `0c158d3e6ee693b89814bf232c954e4757c5ff91dc9df03bb322c3e593e73617`
|
- `scripts/core/save_service.gd` / current_checkout / SHA256 `0c158d3e6ee693b89814bf232c954e4757c5ff91dc9df03bb322c3e593e73617`
|
||||||
- `scripts/data/facility_catalog.gd` / current_checkout / SHA256 `7bb0c5085ddb361d384314cb219620d1483840942bc3f0f46dcb9dfa29d56e29`
|
- `scripts/data/facility_catalog.gd` / current_checkout / SHA256 `7bb0c5085ddb361d384314cb219620d1483840942bc3f0f46dcb9dfa29d56e29`
|
||||||
- `scripts/events/event_definition.gd` / current_checkout / SHA256 `4af68f2e5ec185a750d59aaa24c7cb63fe612cd6a785e7fd39af11f0b5ce74a2`
|
- `scripts/events/event_definition.gd` / current_checkout / SHA256 `4af68f2e5ec185a750d59aaa24c7cb63fe612cd6a785e7fd39af11f0b5ce74a2`
|
||||||
@@ -278,12 +278,10 @@ event/overlay/history/story/voice/scene の内容ID・数量・受入はunknown
|
|||||||
|
|
||||||
## 統合監査注記
|
## 統合監査注記
|
||||||
|
|
||||||
- Read-only integration audit: contract base e1a1651e15bbc9a0526ef31d0b2786feb20d8cd1 versus main 57131ec. This is a future refresh instruction, not a relabeling of any recorded source/game/asset hash.
|
- The two target sources are immutable main Git blobs at 57131ec616ba06a71d3d97eaea738f209f965349. Matches are re-searched from those bytes with main_git_blob provenance.
|
||||||
- autoload/simulation_runtime.gd adds preview_build_facility and extracts _build_facility_precheck shared by preview and execution. scenes/main/world_preview.gd routes previews through Runtime with a fallback and adds demolition mode. scenes/main/main.gd adds demolition confirmation/command handling, preview error messages and stricter interface-selection version checks.
|
- Read-only Git ancestry determines applicability: descendant HEAD requires working files equal to main blobs; non-descendant HEAD requires base blobs. Git errors reject. Report flags cannot select a mode.
|
||||||
- At normal integration Root must refresh normal_entry observations for original_facility_13, original_facility_14, original_facility_15, original_facility_16, original_facility_24, original_facility_25 and original_facility_26 against the integrated main.gd and preview path; refresh runtime observations against the integrated Runtime. Refresh event_state and save search evidence too because their Runtime source hash changes, even though these changed hunks do not establish dedicated original facility events or save round-trips. Recheck mapping/catalog/definitions without promoting missing identities or black_market eligibility.
|
- Other current-checkout checks remain strict; work packages remain frozen at the contract base. All unknown/unverified states and 30/88 accounting remain unchanged.
|
||||||
- The selected test sources in this ledger, facility catalog, event service and save service are unchanged between these commits. Added tests/transport/test_runtime_build_preview.gd and tests/ui/test_p08_normal_placement_ops.gd concern generic preview/placement/demolition; tests/ui/test_selection_departure.gd and tests/ui/fixtures/selection_cross_process.gd concern selection restoration. Root should assess their bounded relevance when refreshing each facility test observation; none accepts original content. Guest observation selection changes and P08 migration fixtures likewise provide no original facility content acceptance.
|
- Formal Runner validation and separate independent review remain external requirements; static observations confer no content completion credit.
|
||||||
- Minimal handling: retain this base-version evidence, explicitly re-search changed integrated source paths and rebuild affected technical observations, source pins and output receipt as a reviewed integration refresh; retain all unknown/unverified content states and the 30/88 denominator. Do not merely replace old hashes or claim old tests ran against new code. No rebase, overwrite or Git write is performed here.
|
|
||||||
- If P13 integrates first, P23 9a full tools map gains tools/check_p13_content_difference.py. P23 proof remains bound to its own version and requires future final source verification; this audit does not extend that proof.
|
|
||||||
|
|
||||||
## 検証・統合条件
|
## 検証・統合条件
|
||||||
|
|
||||||
|
|||||||
+4
@@ -1,3 +1,7 @@
|
|||||||
|
# Superseded historical repair instructions
|
||||||
|
|
||||||
|
The old repair-2 limit and 500000/450000-byte caps below are superseded by the current owner direction. Preserve required evidence without omissions or cap-driven compression. The prior failed invocation remains history, not current readiness. The immutable spec, scope and acceptance remain in force.
|
||||||
|
|
||||||
# P13-03 final bounded repair input (root context, not implementation)
|
# P13-03 final bounded repair input (root context, not implementation)
|
||||||
|
|
||||||
Original contract/spec/acceptance1 and repair cap2 remain unchanged. Repair1 used. Initial submitted7645c55149d3bebf3ed602cf3039b15b28fa376f records seven facilities,84slots,six non-facility categories. Root read-only diagnostic ran its --negative-checks: integrity pass,13 mutations rejected. This is not formal acceptance.
|
Original contract/spec/acceptance1 and repair cap2 remain unchanged. Repair1 used. Initial submitted7645c55149d3bebf3ed602cf3039b15b28fa376f records seven facilities,84slots,six non-facility categories. Root read-only diagnostic ran its --negative-checks: integrity pass,13 mutations rejected. This is not formal acceptance.
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -152,8 +152,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "autoload/simulation_runtime.gd",
|
"path": "autoload/simulation_runtime.gd",
|
||||||
"sha256": "d52a995ae715542bbc550f68d35889540658275d12e04ae0b21ac276f5843f39",
|
"sha256": "4696df4a77feb465a5a3ba8b806569f7bcbe1d03c88289acfb78a3928f307d67",
|
||||||
"applicability": "current_checkout",
|
"applicability": "main_git_blob",
|
||||||
|
"commit": "57131ec616ba06a71d3d97eaea738f209f965349",
|
||||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -380,8 +381,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "scenes/main/main.gd",
|
"path": "scenes/main/main.gd",
|
||||||
"sha256": "a3d7d7ddd08a8df1f987806e60accf51792d728cf71c06e6b822f5a31d8ed3e3",
|
"sha256": "92677e4ac57ed8d418a4a716bf0874cbbaea79cff893e5163c82ad1f75e7140a",
|
||||||
"applicability": "current_checkout",
|
"applicability": "main_git_blob",
|
||||||
|
"commit": "57131ec616ba06a71d3d97eaea738f209f965349",
|
||||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -434,28 +436,24 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"output_pins": {
|
"output_pins": {
|
||||||
"docs/plans/original-completion-2026-10-02/execution/p13-03/difference-ledger.json": "b7edd7fc8f5fa5602edc540a3eb8c4150b0268e7551c97a5c5ccc725ea5bb341",
|
"docs/plans/original-completion-2026-10-02/execution/p13-03/difference-ledger.json": "d9aa4725e191d9cef194b01695fe18c6c6ecdc5140c7dc0e72d9409dc1606630",
|
||||||
"docs/plans/original-completion-2026-10-02/execution/p13-03/DIFFERENCE_LEDGER.md": "e5964c169bae48a7ae937d8b6a5103ebc34f5f0860b69b18b0755d6f3b2a480a",
|
"docs/plans/original-completion-2026-10-02/execution/p13-03/DIFFERENCE_LEDGER.md": "1217a2356432cbf833e0baab443ee48a39776a3747e965e4fc3f914066959dcd",
|
||||||
"tools/check_p13_content_difference.py": "bf09c77441e821779a381b34b7ab97f754b38b7bc0f778b27c6fb2ebe29a75aa"
|
"tools/check_p13_content_difference.py": "7b29180c776218138bfe1bf23013102932d853481cff41e7d830f1f5cf5c4d26"
|
||||||
},
|
},
|
||||||
"status": "blocked",
|
"status": "ready_for_external_validation",
|
||||||
"formal_tests": "not_run",
|
"formal_tests": "external_runner_required",
|
||||||
"formal_claude_review": "not_run",
|
"formal_claude_review": "external_independent_review_required",
|
||||||
"worker_local_checks": {
|
"worker_history": [
|
||||||
"python3_B_integrity_and_mandatory_negatives": "pass",
|
"Earlier invocation failed because a literal python alias was unavailable; historical failure is not current readiness or formal acceptance."
|
||||||
"ast_parse": "pass",
|
],
|
||||||
"registered_argv": "blocked: python executable is unavailable in this worker environment",
|
"command": "{python} -B tools/check_p13_content_difference.py --verify-only",
|
||||||
"git_diff_check": "pass",
|
|
||||||
"acceptance": "not_claimed"
|
|
||||||
},
|
|
||||||
"command": "python -B tools/check_p13_content_difference.py --verify-only",
|
|
||||||
"purpose": "Verify record integrity and negative rejection only; not content acceptance.",
|
"purpose": "Verify record integrity and negative rejection only; not content acceptance.",
|
||||||
"source_applicability": "Exact IDs, source SHA256 and scopes are in difference-ledger.json. Work package frozen base Git blob and current checkout are separately identified.",
|
"source_applicability": "Exact IDs, source SHA256 and scopes are in difference-ledger.json. Work package base_git_blob, two main_git_blob sources and other current_checkout sources are separately identified.",
|
||||||
"required_before_integration": [
|
"required_before_integration": [
|
||||||
"Runner p13-difference pass",
|
"Runner p13-difference pass",
|
||||||
"separate formal Claude review pass"
|
"separate formal Claude review pass"
|
||||||
],
|
],
|
||||||
"worker_tests_run": true,
|
"record_readiness": "Canonical records prepared; formal validation and review are external.",
|
||||||
"test_applicability": {
|
"test_applicability": {
|
||||||
"runtime": "Not applicable to records-only changes; no game or platform acceptance.",
|
"runtime": "Not applicable to records-only changes; no game or platform acceptance.",
|
||||||
"native": "Not applicable to records-only changes; no game or platform acceptance.",
|
"native": "Not applicable to records-only changes; no game or platform acceptance.",
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ from pathlib import Path
|
|||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[1]
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
OUT = 'docs/plans/original-completion-2026-10-02/execution/p13-03/'
|
OUT = 'docs/plans/original-completion-2026-10-02/execution/p13-03/'
|
||||||
@@ -20,6 +21,8 @@ MAPPING = 'docs/plans/original-completion-2026-09-29/execution/original_facility
|
|||||||
SLOTS = PLAN + 'asset_inventory_reaudit/facility_usage_slots.json'
|
SLOTS = PLAN + 'asset_inventory_reaudit/facility_usage_slots.json'
|
||||||
SPEC = 'docs/spec/acceptance/P13-03.json'
|
SPEC = 'docs/spec/acceptance/P13-03.json'
|
||||||
BASE = 'e1a1651e15bbc9a0526ef31d0b2786feb20d8cd1'
|
BASE = 'e1a1651e15bbc9a0526ef31d0b2786feb20d8cd1'
|
||||||
|
MAIN = '57131ec616ba06a71d3d97eaea738f209f965349'
|
||||||
|
TARGET_PATHS = ('autoload/simulation_runtime.gd', 'scenes/main/main.gd')
|
||||||
SPEC_RAW = '917cf1504bbfc700e0da42b2db496b42486fe3c36c680f301f58cf34c95267b6'
|
SPEC_RAW = '917cf1504bbfc700e0da42b2db496b42486fe3c36c680f301f58cf34c95267b6'
|
||||||
SPEC_RUNNER = 'e1255835c1227e02bac42eb99b026b0fcbe69c272f9ed0b36199a2daf8d55c53'
|
SPEC_RUNNER = 'e1255835c1227e02bac42eb99b026b0fcbe69c272f9ed0b36199a2daf8d55c53'
|
||||||
VIEWS = ('normal_entry', 'runtime', 'event_state', 'save', 'test')
|
VIEWS = ('normal_entry', 'runtime', 'event_state', 'save', 'test')
|
||||||
@@ -33,12 +36,10 @@ CATEGORIES = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
INTEGRATION_NOTES = [
|
INTEGRATION_NOTES = [
|
||||||
'Read-only integration audit: contract base e1a1651e15bbc9a0526ef31d0b2786feb20d8cd1 versus main 57131ec. This is a future refresh instruction, not a relabeling of any recorded source/game/asset hash.',
|
'The two target sources are immutable main Git blobs at ' + MAIN + '. Matches are re-searched from those bytes with main_git_blob provenance.',
|
||||||
'autoload/simulation_runtime.gd adds preview_build_facility and extracts _build_facility_precheck shared by preview and execution. scenes/main/world_preview.gd routes previews through Runtime with a fallback and adds demolition mode. scenes/main/main.gd adds demolition confirmation/command handling, preview error messages and stricter interface-selection version checks.',
|
'Read-only Git ancestry determines applicability: descendant HEAD requires working files equal to main blobs; non-descendant HEAD requires base blobs. Git errors reject. Report flags cannot select a mode.',
|
||||||
'At normal integration Root must refresh normal_entry observations for original_facility_13, original_facility_14, original_facility_15, original_facility_16, original_facility_24, original_facility_25 and original_facility_26 against the integrated main.gd and preview path; refresh runtime observations against the integrated Runtime. Refresh event_state and save search evidence too because their Runtime source hash changes, even though these changed hunks do not establish dedicated original facility events or save round-trips. Recheck mapping/catalog/definitions without promoting missing identities or black_market eligibility.',
|
'Other current-checkout checks remain strict; work packages remain frozen at the contract base. All unknown/unverified states and 30/88 accounting remain unchanged.',
|
||||||
'The selected test sources in this ledger, facility catalog, event service and save service are unchanged between these commits. Added tests/transport/test_runtime_build_preview.gd and tests/ui/test_p08_normal_placement_ops.gd concern generic preview/placement/demolition; tests/ui/test_selection_departure.gd and tests/ui/fixtures/selection_cross_process.gd concern selection restoration. Root should assess their bounded relevance when refreshing each facility test observation; none accepts original content. Guest observation selection changes and P08 migration fixtures likewise provide no original facility content acceptance.',
|
'Formal Runner validation and separate independent review remain external requirements; static observations confer no content completion credit.',
|
||||||
'Minimal handling: retain this base-version evidence, explicitly re-search changed integrated source paths and rebuild affected technical observations, source pins and output receipt as a reviewed integration refresh; retain all unknown/unverified content states and the 30/88 denominator. Do not merely replace old hashes or claim old tests ran against new code. No rebase, overwrite or Git write is performed here.',
|
|
||||||
'If P13 integrates first, P23 9a full tools map gains tools/check_p13_content_difference.py. P23 proof remains bound to its own version and requires future final source verification; this audit does not extend that proof.',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -67,27 +68,59 @@ def load(path):
|
|||||||
return json.loads(raw(path), object_pairs_hook=unique)
|
return json.loads(raw(path), object_pairs_hook=unique)
|
||||||
|
|
||||||
|
|
||||||
|
def git_blob(commit, path):
|
||||||
|
return subprocess.check_output(['git', 'show', commit + ':' + path], cwd=ROOT)
|
||||||
|
|
||||||
|
|
||||||
|
def main_is_ancestor():
|
||||||
|
result = subprocess.run(['git', 'merge-base', '--is-ancestor', MAIN, 'HEAD'],
|
||||||
|
cwd=ROOT, capture_output=True)
|
||||||
|
if result.returncode not in (0, 1):
|
||||||
|
raise ValueError('Git ancestry check failed: ' + result.stderr.decode(errors='replace'))
|
||||||
|
return result.returncode == 0
|
||||||
|
|
||||||
|
|
||||||
|
def check_target_sources():
|
||||||
|
commit = MAIN if main_is_ancestor() else BASE
|
||||||
|
for path in TARGET_PATHS:
|
||||||
|
if raw(path) != git_blob(commit, path):
|
||||||
|
raise ValueError('stale working source: ' + path)
|
||||||
|
|
||||||
|
|
||||||
|
def source_bytes(path):
|
||||||
|
return git_blob(MAIN, path) if path in TARGET_PATHS else raw(path)
|
||||||
|
|
||||||
|
|
||||||
|
def provenance(path):
|
||||||
|
record = {'path': path, 'sha256': sha(source_bytes(path)),
|
||||||
|
'applicability': 'main_git_blob' if path in TARGET_PATHS else 'current_checkout'}
|
||||||
|
if path in TARGET_PATHS:
|
||||||
|
record['commit'] = MAIN
|
||||||
|
return record
|
||||||
|
|
||||||
|
|
||||||
def observation(paths, tokens, note):
|
def observation(paths, tokens, note):
|
||||||
"""Exact token matches are search observations, never accepted links."""
|
"""Exact token matches are search observations, never accepted links."""
|
||||||
evidence = []
|
evidence = []
|
||||||
for path in paths:
|
for path in paths:
|
||||||
lines = raw(path).decode('utf-8').splitlines()
|
lines = source_bytes(path).decode('utf-8').splitlines()
|
||||||
matches = [{'line': i + 1, 'text': line} for i, line in enumerate(lines)
|
matches = [{'line': i + 1, 'text': line} for i, line in enumerate(lines)
|
||||||
if any(token in line for token in tokens)]
|
if any(token in line for token in tokens)]
|
||||||
evidence.append({'path': path, 'sha256': sha(raw(path)),
|
evidence.append({**provenance(path),
|
||||||
'searched_tokens': tokens, 'matches': matches,
|
'searched_tokens': tokens, 'matches': matches,
|
||||||
'scope': 'Static search of this file only; no execution or acceptance.'})
|
'scope': 'Static search of this file only; no execution or acceptance.'})
|
||||||
return {'status': 'unverified', 'accepted': False, 'note': note, 'evidence': evidence}
|
return {'status': 'unverified', 'accepted': False, 'note': note, 'evidence': evidence}
|
||||||
|
|
||||||
|
|
||||||
def expected():
|
def expected():
|
||||||
|
check_target_sources()
|
||||||
if sha(raw(SPEC)) != SPEC_RAW or sha(raw(SPEC).decode().strip().encode()) != SPEC_RUNNER:
|
if sha(raw(SPEC)) != SPEC_RAW or sha(raw(SPEC).decode().strip().encode()) != SPEC_RUNNER:
|
||||||
raise ValueError('specification hash mismatch')
|
raise ValueError('specification hash mismatch')
|
||||||
spec = load(SPEC)
|
spec = load(SPEC)
|
||||||
sources = []
|
sources = []
|
||||||
for path, pin in spec['source_pins'].items():
|
for path, pin in spec['source_pins'].items():
|
||||||
if path == PLAN + 'work_packages.json':
|
if path == PLAN + 'work_packages.json':
|
||||||
frozen = subprocess.check_output(['git', 'show', BASE + ':' + path], cwd=ROOT)
|
frozen = git_blob(BASE, path)
|
||||||
if sha(frozen) != pin:
|
if sha(frozen) != pin:
|
||||||
raise ValueError('frozen work package pin mismatch')
|
raise ValueError('frozen work package pin mismatch')
|
||||||
sources.append({'path': path, 'sha256': pin, 'applicability': 'base_git_blob', 'commit': BASE})
|
sources.append({'path': path, 'sha256': pin, 'applicability': 'base_git_blob', 'commit': BASE})
|
||||||
@@ -139,7 +172,7 @@ def expected():
|
|||||||
'normal_entry': observation([entry, catalog], tokens,
|
'normal_entry': observation([entry, catalog], tokens,
|
||||||
'adult_private_room is in the UI list and baseline catalog; black_market is expansion-only. No other original identity match. Static eligibility only; actual construction is unverified.'),
|
'adult_private_room is in the UI list and baseline catalog; black_market is expansion-only. No other original identity match. Static eligibility only; actual construction is unverified.'),
|
||||||
'runtime': observation([runtime, catalog] + matching, tokens + ['FacilityCatalog.FACILITY_PATHS'],
|
'runtime': observation([runtime, catalog] + matching, tokens + ['FacilityCatalog.FACILITY_PATHS'],
|
||||||
'Runtime loads baseline/infrastructure/rescue/original paths, not expansion paths at this load site. Generic services do not prove original special behavior.'),
|
'Runtime loads ORIGINAL_FACILITY_PATHS, including some files under the expansion directory. It does not load EXPANSION_FACILITY_PATHS or black_market. Generic services do not prove original special behavior.'),
|
||||||
'event_state': observation([runtime, event], tokens,
|
'event_state': observation([runtime, event], tokens,
|
||||||
'No facility-specific transition established by this search. Generic EventService is not a dedicated content catalog.'),
|
'No facility-specific transition established by this search. Generic EventService is not a dedicated content catalog.'),
|
||||||
'save': observation([runtime, save], tokens + ['event_service.create_snapshot()', 'save_snapshot'],
|
'save': observation([runtime, save], tokens + ['event_service.create_snapshot()', 'save_snapshot'],
|
||||||
@@ -171,7 +204,7 @@ def expected():
|
|||||||
additional = sorted(set(search_paths + [entry, runtime, event, save, test,
|
additional = sorted(set(search_paths + [entry, runtime, event, save, test,
|
||||||
'tests/s2/test_facility_service.gd', 'tests/s4/test_runtime_relationship_events.gd',
|
'tests/s2/test_facility_service.gd', 'tests/s4/test_runtime_relationship_events.gd',
|
||||||
'scripts/events/event_definition.gd', 'scripts/ui/event_log_dialog.gd']))
|
'scripts/events/event_definition.gd', 'scripts/ui/event_log_dialog.gd']))
|
||||||
sources += [{'path': p, 'sha256': sha(raw(p)), 'applicability': 'current_checkout',
|
sources += [{**provenance(p),
|
||||||
'scope': 'Bounded static observation; no executed connection/content acceptance.'} for p in additional]
|
'scope': 'Bounded static observation; no executed connection/content acceptance.'} for p in additional]
|
||||||
return {'schema_version': 1, 'task_id': 'P13-03', 'acceptance_ids': ['P13-03'],
|
return {'schema_version': 1, 'task_id': 'P13-03', 'acceptance_ids': ['P13-03'],
|
||||||
'requirement_ids': spec['package_requirement_ids'], 'validation_ids': ['p13-difference'],
|
'requirement_ids': spec['package_requirement_ids'], 'validation_ids': ['p13-difference'],
|
||||||
@@ -231,7 +264,7 @@ def compact(document):
|
|||||||
if signature not in evidence_ids:
|
if signature not in evidence_ids:
|
||||||
identity = 'evidence_%04d' % (len(evidence) + 1)
|
identity = 'evidence_%04d' % (len(evidence) + 1)
|
||||||
evidence_ids[signature] = identity
|
evidence_ids[signature] = identity
|
||||||
provenance = {k: record[k] for k in ('path', 'sha256', 'scope')}
|
provenance = {k: v for k, v in record.items() if k not in ('searched_tokens', 'matches')}
|
||||||
evidence[identity] = {
|
evidence[identity] = {
|
||||||
'source_ref': context(provenance),
|
'source_ref': context(provenance),
|
||||||
'search_ref': context({'searched_tokens': record['searched_tokens']}),
|
'search_ref': context({'searched_tokens': record['searched_tokens']}),
|
||||||
@@ -270,9 +303,11 @@ def expand(document):
|
|||||||
return visit(document)
|
return visit(document)
|
||||||
|
|
||||||
|
|
||||||
def negative_checks(canonical):
|
def negative_checks(canonical, ledger_path=OUT + "difference-ledger.json"):
|
||||||
cases = {}
|
cases = {}
|
||||||
mutations = {
|
mutations = {
|
||||||
|
'tampered_ancestry_flag': lambda d: d.update(main_is_ancestor=False),
|
||||||
|
'tampered_report_flag': lambda d: d.update(source_mode='legacy_fallback'),
|
||||||
'facility_omission': lambda d: d['facilities'].pop(),
|
'facility_omission': lambda d: d['facilities'].pop(),
|
||||||
'slot_omission': lambda d: d['facilities'][0]['media_usage_slots'].pop(),
|
'slot_omission': lambda d: d['facilities'][0]['media_usage_slots'].pop(),
|
||||||
'stale_pin': lambda d: d['sources'][0].update(sha256='0' * 64),
|
'stale_pin': lambda d: d['sources'][0].update(sha256='0' * 64),
|
||||||
@@ -301,27 +336,91 @@ def negative_checks(canonical):
|
|||||||
cases[name] = 'rejected'
|
cases[name] = 'rejected'
|
||||||
else:
|
else:
|
||||||
raise ValueError('negative case was accepted: ' + name)
|
raise ValueError('negative case was accepted: ' + name)
|
||||||
|
# Inject source bytes and Git results only in memory; no product/Git writes.
|
||||||
|
real_raw, real_blob = raw, git_blob
|
||||||
|
snapshots = {(commit, path): real_blob(commit, path)
|
||||||
|
for commit in (BASE, MAIN) for path in TARGET_PATHS}
|
||||||
|
|
||||||
|
def rejected(name, operation):
|
||||||
|
try:
|
||||||
|
operation()
|
||||||
|
except (ValueError, OSError, subprocess.CalledProcessError):
|
||||||
|
cases[name] = 'rejected'
|
||||||
|
else:
|
||||||
|
raise ValueError('negative case was accepted: ' + name)
|
||||||
|
|
||||||
|
for descendant in (False, True):
|
||||||
|
commit = MAIN if descendant else BASE
|
||||||
|
label = 'merged' if descendant else 'frozen'
|
||||||
|
def working(path):
|
||||||
|
return snapshots[commit, path] if path in TARGET_PATHS else real_raw(path)
|
||||||
|
with patch(__name__ + '.main_is_ancestor', return_value=descendant):
|
||||||
|
with patch(__name__ + '.raw', side_effect=working):
|
||||||
|
verify(compact(expected()), canonical)
|
||||||
|
for target in TARGET_PATHS:
|
||||||
|
def corrupt(path):
|
||||||
|
data = working(path)
|
||||||
|
return data + b'\n# corrupted source' if path == target else data
|
||||||
|
with patch(__name__ + '.raw', side_effect=corrupt):
|
||||||
|
rejected(label + '_stale_' + target, expected)
|
||||||
|
other = BASE if descendant else MAIN
|
||||||
|
def wrong_version(path):
|
||||||
|
return snapshots[other, path] if path in TARGET_PATHS else real_raw(path)
|
||||||
|
with patch(__name__ + '.raw', side_effect=wrong_version):
|
||||||
|
rejected(label + '_wrong_snapshot', expected)
|
||||||
|
def corrupt_blob(version, path):
|
||||||
|
data = real_blob(version, path)
|
||||||
|
return data + b'\n# corrupted blob' if version == MAIN else data
|
||||||
|
with patch(__name__ + '.raw', side_effect=working), patch(__name__ + '.git_blob', side_effect=corrupt_blob):
|
||||||
|
rejected(label + '_corrupt_git_blob', lambda: verify(compact(expected()), canonical))
|
||||||
|
for result in (subprocess.CompletedProcess([], 2, b'', b'Git failure'),
|
||||||
|
subprocess.CompletedProcess([], -1, b'', b'interrupted')):
|
||||||
|
with patch.object(subprocess, 'run', return_value=result):
|
||||||
|
rejected('ancestry_git_error_' + str(result.returncode), expected)
|
||||||
|
with patch.object(subprocess, 'run', side_effect=OSError('Git unavailable')):
|
||||||
|
rejected('ancestry_git_unavailable', expected)
|
||||||
|
with patch(__name__ + '.git_blob', side_effect=subprocess.CalledProcessError(128, ['git', 'show'])):
|
||||||
|
rejected('blob_git_error', expected)
|
||||||
|
|
||||||
|
# Exercise the same read-only alternate input path used by the CLI.
|
||||||
|
alternate = OUT + 'in_memory_candidate.json'
|
||||||
|
ledger_bytes = real_raw(ledger_path)
|
||||||
|
def alternate_raw(path):
|
||||||
|
if path == alternate:
|
||||||
|
return ledger_bytes
|
||||||
|
if path == OUT + 'difference-ledger.json':
|
||||||
|
raise ValueError('default ledger must not be read for alternate input')
|
||||||
|
return real_raw(path)
|
||||||
|
with patch(__name__ + '.raw', side_effect=alternate_raw):
|
||||||
|
verify_records(alternate, canonical)
|
||||||
|
cases['alternate_ledger_valid'] = 'verified_read_only'
|
||||||
|
with patch(__name__ + '.raw', side_effect=lambda path: b'{}' if path == alternate else real_raw(path)):
|
||||||
|
rejected('alternate_ledger_corrupt', lambda: verify_records(alternate, canonical))
|
||||||
return cases
|
return cases
|
||||||
|
|
||||||
|
|
||||||
|
def verify_records(ledger_path, canonical):
|
||||||
|
verify(load(ledger_path), canonical)
|
||||||
|
if load(OUT + 'validation.json') != receipt_expected(ledger_path):
|
||||||
|
raise ValueError('receipt mismatch or false formal acceptance')
|
||||||
|
if raw(OUT + 'DIFFERENCE_LEDGER.md').decode() != readable(expand(canonical)):
|
||||||
|
raise ValueError('readable ledger differs from machine ledger')
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description=__doc__)
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
parser.add_argument('--ledger', default=OUT + 'difference-ledger.json')
|
parser.add_argument('--ledger', default=OUT + 'difference-ledger.json',
|
||||||
|
help='Read-only checkout-relative alternate ledger; must match canonical records and the registered receipt hash. No output is written.')
|
||||||
parser.add_argument('--negative-checks', action='store_true')
|
parser.add_argument('--negative-checks', action='store_true')
|
||||||
parser.add_argument('--verify-only', action='store_true',
|
parser.add_argument('--verify-only', action='store_true',
|
||||||
help='Read-only verification; negative checks are always mandatory.')
|
help='Read-only verification; negative checks are always mandatory.')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
try:
|
try:
|
||||||
canonical = compact(expected())
|
canonical = compact(expected())
|
||||||
verify(load(args.ledger), canonical)
|
verify_records(args.ledger, canonical)
|
||||||
receipt = load(OUT + 'validation.json')
|
|
||||||
if receipt != receipt_expected():
|
|
||||||
raise ValueError('receipt mismatch or false formal acceptance')
|
|
||||||
if raw(OUT + 'DIFFERENCE_LEDGER.md').decode() != readable(expand(canonical)):
|
|
||||||
raise ValueError('readable ledger differs from machine ledger')
|
|
||||||
result = {'record_integrity': 'pass', 'content_acceptance': 'not_claimed',
|
result = {'record_integrity': 'pass', 'content_acceptance': 'not_claimed',
|
||||||
'formal_review': 'external_runner_required'}
|
'formal_review': 'external_runner_required'}
|
||||||
result['negative_checks'] = negative_checks(canonical)
|
result['negative_checks'] = negative_checks(canonical, args.ledger)
|
||||||
print(json.dumps(result, ensure_ascii=False))
|
print(json.dumps(result, ensure_ascii=False))
|
||||||
return 0
|
return 0
|
||||||
except (ValueError, OSError, KeyError, TypeError, subprocess.CalledProcessError) as error:
|
except (ValueError, OSError, KeyError, TypeError, subprocess.CalledProcessError) as error:
|
||||||
@@ -329,28 +428,25 @@ def main():
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
def receipt_expected():
|
def receipt_expected(ledger_path=OUT + 'difference-ledger.json'):
|
||||||
ledger = expand(load(OUT + 'difference-ledger.json'))
|
ledger = expand(load(ledger_path))
|
||||||
return {'task_id': 'P13-03', 'acceptance_ids': ['P13-03'], 'validation_ids': ['p13-difference'],
|
return {'task_id': 'P13-03', 'acceptance_ids': ['P13-03'], 'validation_ids': ['p13-difference'],
|
||||||
'requirement_ids': ledger['requirement_ids'],
|
'requirement_ids': ledger['requirement_ids'],
|
||||||
'facility_ids': [f['original_id'] for f in ledger['facilities']],
|
'facility_ids': [f['original_id'] for f in ledger['facilities']],
|
||||||
'slot_ids': [s['slot_id'] for f in ledger['facilities'] for s in f['media_usage_slots']],
|
'slot_ids': [s['slot_id'] for f in ledger['facilities'] for s in f['media_usage_slots']],
|
||||||
'difference_ids': [n['difference_id'] for n in ledger['nonfacility_differences']],
|
'difference_ids': [n['difference_id'] for n in ledger['nonfacility_differences']],
|
||||||
'source_applicability_records': ledger['sources'],
|
'source_applicability_records': ledger['sources'],
|
||||||
'output_pins': {p: sha(raw(p)) for p in [OUT + 'difference-ledger.json',
|
'output_pins': {p: sha(raw(ledger_path if p == OUT + 'difference-ledger.json' else p)) for p in [OUT + 'difference-ledger.json',
|
||||||
OUT + 'DIFFERENCE_LEDGER.md', 'tools/check_p13_content_difference.py']},
|
OUT + 'DIFFERENCE_LEDGER.md', 'tools/check_p13_content_difference.py']},
|
||||||
'status': 'blocked', 'formal_tests': 'not_run', 'formal_claude_review': 'not_run',
|
'status': 'ready_for_external_validation',
|
||||||
'worker_local_checks': {
|
'formal_tests': 'external_runner_required',
|
||||||
'python3_B_integrity_and_mandatory_negatives': 'pass',
|
'formal_claude_review': 'external_independent_review_required',
|
||||||
'ast_parse': 'pass',
|
'worker_history': ['Earlier invocation failed because a literal python alias was unavailable; historical failure is not current readiness or formal acceptance.'],
|
||||||
'registered_argv': 'blocked: python executable is unavailable in this worker environment',
|
'command': '{python} -B tools/check_p13_content_difference.py --verify-only',
|
||||||
'git_diff_check': 'pass',
|
|
||||||
'acceptance': 'not_claimed'},
|
|
||||||
'command': 'python -B tools/check_p13_content_difference.py --verify-only',
|
|
||||||
'purpose': 'Verify record integrity and negative rejection only; not content acceptance.',
|
'purpose': 'Verify record integrity and negative rejection only; not content acceptance.',
|
||||||
'source_applicability': 'Exact IDs, source SHA256 and scopes are in difference-ledger.json. Work package frozen base Git blob and current checkout are separately identified.',
|
'source_applicability': 'Exact IDs, source SHA256 and scopes are in difference-ledger.json. Work package base_git_blob, two main_git_blob sources and other current_checkout sources are separately identified.',
|
||||||
'required_before_integration': ['Runner p13-difference pass', 'separate formal Claude review pass'],
|
'required_before_integration': ['Runner p13-difference pass', 'separate formal Claude review pass'],
|
||||||
'worker_tests_run': True,
|
'record_readiness': 'Canonical records prepared; formal validation and review are external.',
|
||||||
'test_applicability': {name: 'Not applicable to records-only changes; no game or platform acceptance.'
|
'test_applicability': {name: 'Not applicable to records-only changes; no game or platform acceptance.'
|
||||||
for name in ['runtime', 'native', 'Windows', 'engine', 'full_game_regression']}}
|
for name in ['runtime', 'native', 'Windows', 'engine', 'full_game_regression']}}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user