Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c6ccc5a6ab |
@@ -0,0 +1,19 @@
|
|||||||
|
# P22-02 素材契約(原成果未完了)
|
||||||
|
|
||||||
|
原30パッケージ/88成果・部分点なしを維持する。614 identityは360施設、176人物、2状態群、76その他であり、614画像ではない。495 candidate、119 missing、19 sourceを全て保持する。選定済完成資産は0。D08/D09の最終内容・数量はunknown。
|
||||||
|
|
||||||
|
asset-contracts.jsonは公開JSON共有参照(d/l/s/r)で、accepted_inputの全フィールドとcurrent契約の全フィールドを損失なく保持する。各identityの命名はid、候補名はcandidate_refの実path、形式と現raw SHAはcandidate_pool、historical適用性はcandidate_refs、creatorと不足は各契約にある。差替鎖は歴史的representation→現candidate→未選定replacement。missingをcode/file/fallbackで充足しない。最終の解像度・frame/layout・命名・差替参照は未確定として扱う。
|
||||||
|
|
||||||
|
Kenney Tiny Town/Tiny Dungeon/Interface Soundsのpublisher/member/license/manifest証拠はevidence_pinsの文書を完全再利用する。配布元URLとCC0記録はcandidate_poolおよび既存ライセンス証拠を参照。内部BGM合成recipeは内部由来であり、第三者CC0や最終聴感・権利受入へ昇格しない。自己制作・別許諾を排除しない。未知creator/rightsを推測しない。
|
||||||
|
|
||||||
|
checkerの通常0終了は記録整合性のみ。--require-readyは原条件未達なら2終了。READYには空でない完成資産、全exact useの選定・実利用・権利、未制作/開示不足の解消、必要な画面/聴感、Root静的検証と意味のあるnegative、独立Opusレビュー、統合・最終受入が必要。workerは正式試験も受入も主張しない。
|
||||||
|
|
||||||
|
## 次の製品変更提案(この実装では適用しない)
|
||||||
|
|
||||||
|
- scripts/ui/pixel_tower_art.gd、standard_room_art.gd、infirmary_room_art.gd: 各施設Lv1–3/表裏/外観内装のidから選定representationへ明示対応を追加。共有atlasや専用一部装飾を全施設に流用して完成扱いしない。最小差分は選定されたidの参照と該当描画分岐のみ。実画面で各対応と未制作開示を確認する。
|
||||||
|
- scripts/ui/pixel_people.gd: character条件ごとの選定と必要variant参照を明示し、2状態群は状態表現として接続する。数量は承認されるまでunknown。該当人物・状態の画面確認が必要。
|
||||||
|
- assets/themes/japanese_fantasy/visual-theme-v1.tres、scenes/main/world_preview.gd、scenes/main/main.gd: 世界/skin候補のcreator/rightsを解決してから選定素材への参照のみ差替。サイズ、alpha、atlas region、nearest/mipmapと全参照整合を確認し実表示で確認する。
|
||||||
|
- scripts/ui/paired_bgm.gdと2 candidate WAV: internal-origin-observationsのrecipeとbyte証拠を保持し、creator/権利の承認と両contextの聴感を取得してから最終選定。UI4音もpublisher証拠だけで最終聴感を代用しない。
|
||||||
|
- missing_candidateの119 identityは各契約のsource_anchors/usage_conditionを制作依頼に渡し、Kenney適合候補を先に確認する。最小asset/reference差分は選定後にのみ確定できる。未確定の絵や数量を捏造しない。
|
||||||
|
|
||||||
|
Runnerの検証対象: 全614 coverage、全decoded semantic hash、raw input/source/evidence pins、historical適用性、PNG寸法、参照・source omission、duplicate、cycle/bad index/key/type、unknown rights/false finished、数量変更。negativeはledgerの該当値の改変・削除、source/寸法・reference変更を含める。完全packetを500000 bytes未満で確認し、欠落・切捨てで縮小しない。その後に必要な製品実装・usability・独立レビュー・統合・finalを行う。
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Root context: fixed spec hash representation
|
||||||
|
|
||||||
|
This is coordination input, not a spec change or acceptance.
|
||||||
|
|
||||||
|
{
|
||||||
|
"task": "P22-02",
|
||||||
|
"base_commit": "10c62e1fa7b71576598583f434824b59816d4705",
|
||||||
|
"spec_ref": "docs/spec/acceptance/P22-02.json",
|
||||||
|
"contract_spec_sha256": "f252de3c5cff7ebfa62322ae2f2df09fb80a44bc59eb286b76d4acb4c12ca875",
|
||||||
|
"raw_spec_sha256": "c26c0b12cf7e7a7c46e671acde2e00762904732c1cd6381a53836e3d7b3f9824",
|
||||||
|
"runner_strip_spec_sha256": "f252de3c5cff7ebfa62322ae2f2df09fb80a44bc59eb286b76d4acb4c12ca875",
|
||||||
|
"raw_worktree_equals_base_git_blob": true,
|
||||||
|
"spec_changed": false,
|
||||||
|
"contract_changed": false,
|
||||||
|
"root_normalized_hash_verification_passed": true,
|
||||||
|
"reason": "Runner git helper uses stdout.strip(), then UTF8; source_pins and accepted input raw SHA remain raw bytes, not stripped"
|
||||||
|
}
|
||||||
|
|
||||||
|
Compare contract spec via git show base:spec, stdout.strip(), encode UTF8 and SHA256. Raw spec includes terminal newline and has a different raw-byte SHA. This is expected. It is not permission to edit/normalize any file. For source_pins and accepted input, use the full raw bytes as before. Read accepted input only with targeted Python. Do not block for a terminal newline difference when the Runner hash and exact base raw blob are both proven equal. Preserve all original conditions and current unmade gaps.
|
||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,75 @@
|
|||||||
|
"""Build only the authorized ledger, preserving complete JSON fields."""
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[5]
|
||||||
|
HERE = Path(__file__).resolve().parent
|
||||||
|
INPUT = 'docs/spec/inputs/P22-02-accepted-usage.json'
|
||||||
|
CURRENT = 'docs/plans/original-completion-2026-10-02/checkpoints/p22-02-slot-contract-r02/all-slot-current-candidate-contracts.json'
|
||||||
|
EVIDENCE = 'docs/plans/original-completion-2026-10-02/checkpoints/p22-02-current-contract-r01'
|
||||||
|
|
||||||
|
def build():
|
||||||
|
keys, strings, pool = [], [], []
|
||||||
|
key_ids, string_ids, object_ids = {}, {}, {}
|
||||||
|
def key_id(key):
|
||||||
|
if key not in key_ids:
|
||||||
|
key_ids[key] = len(keys)
|
||||||
|
keys.append(key)
|
||||||
|
return key_ids[key]
|
||||||
|
def encode(value):
|
||||||
|
if isinstance(value, str):
|
||||||
|
if value not in string_ids:
|
||||||
|
string_ids[value] = len(strings)
|
||||||
|
strings.append(value)
|
||||||
|
return ['s', string_ids[value]]
|
||||||
|
if isinstance(value, (dict, list)):
|
||||||
|
signature = json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(',', ':'))
|
||||||
|
if signature in object_ids:
|
||||||
|
return ['r', object_ids[signature]]
|
||||||
|
if isinstance(value, dict):
|
||||||
|
node = ['d']
|
||||||
|
for key, item in value.items():
|
||||||
|
node.extend([key_id(key), encode(item)])
|
||||||
|
else:
|
||||||
|
node = ['l'] + [encode(item) for item in value]
|
||||||
|
index = len(pool)
|
||||||
|
pool.append(node)
|
||||||
|
object_ids[signature] = index
|
||||||
|
return ['r', index]
|
||||||
|
return value
|
||||||
|
pins = {}
|
||||||
|
for path in [ROOT / CURRENT, *sorted((ROOT / EVIDENCE).iterdir())]:
|
||||||
|
if path.is_file():
|
||||||
|
pins[str(path.relative_to(ROOT))] = hashlib.sha256(path.read_bytes()).hexdigest()
|
||||||
|
ledger = {
|
||||||
|
'accepted_input': json.loads((ROOT / INPUT).read_text()),
|
||||||
|
'current': json.loads((ROOT / CURRENT).read_text()),
|
||||||
|
'evidence_pins': pins,
|
||||||
|
'original_conditions': {
|
||||||
|
'all_exact_uses_selected_and_usable': False,
|
||||||
|
'all_creator_and_rights_evidence_accepted': False,
|
||||||
|
'all_naming_resolution_layout_replacement_references_accepted': False,
|
||||||
|
'all_mandatory_unmade_and_disclosure_gaps_resolved': False,
|
||||||
|
'applicable_display_and_hearing_evidence': False,
|
||||||
|
'independent_opus_review': False,
|
||||||
|
'root_static_and_meaningful_negative_validation': False,
|
||||||
|
'integration_and_final_original_30_88_acceptance': False,
|
||||||
|
},
|
||||||
|
'selection_contract': {
|
||||||
|
'selected_assets': [],
|
||||||
|
'candidate_names': 'Exact candidate_pool path names; no rename or final assignment',
|
||||||
|
'replacement_chain': 'Accepted historical representation -> current candidate_ref (prior applicability retained) -> selected replacement UNKNOWN',
|
||||||
|
'format': 'candidate_pool observed_format for physical media; representation_kind and exact raw source for code. Final per-use format/layout UNKNOWN.',
|
||||||
|
'rights': 'candidate_pool rights_provenance and complete pinned publisher/license/manifest evidence; internal recipe is origin only, not final rights or hearing acceptance',
|
||||||
|
'quantity': 'D08/D09 UNKNOWN. 2 state groups are not images. Never infer final file/frame/variant counts from 614 identities.',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
files = encode(ledger)
|
||||||
|
packet = {'keys': keys, 'strings': strings, 'pool': pool, 'files': files, 'encoding': 'd=flat key-id/value; l=list; s=string index; r=complete object/list index'}
|
||||||
|
raw = json.dumps(packet, ensure_ascii=False, separators=(',', ':')).encode() + b'\n'
|
||||||
|
(HERE / 'asset-contracts.json').write_bytes(raw)
|
||||||
|
print(json.dumps({'ledger_bytes': len(raw), 'formal_tests': 'not_run'}))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
build()
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"task_id": "P22-02",
|
||||||
|
"formal_tests": "not_run; Runner owns execution",
|
||||||
|
"original_unit_ready": false,
|
||||||
|
"acceptance_claimed": false,
|
||||||
|
"spec_comparison": "UTF8 decode.strip.encode SHA only for contract spec",
|
||||||
|
"spec_sha256": "f252de3c5cff7ebfa62322ae2f2df09fb80a44bc59eb286b76d4acb4c12ca875",
|
||||||
|
"spec_raw_sha256": "c26c0b12cf7e7a7c46e671acde2e00762904732c1cd6381a53836e3d7b3f9824",
|
||||||
|
"accepted_input_raw_sha256": "45fa52acf0c8bd4dd58c3b40b681cb92066f05d617df157fc18370a5e8816281",
|
||||||
|
"ledger_bytes": 453678,
|
||||||
|
"packet_bytes_before_this_validation_metadata": 472408,
|
||||||
|
"syntax_ast_parse": "passed; not formal validation",
|
||||||
|
"complete_packet_limit": 500000,
|
||||||
|
"runner_required": ["exact static validation", "meaningful negatives", "packet byte total", "applicable display and hearing", "independent Opus review", "integration and final original acceptance"],
|
||||||
|
"expected_exit_codes": {"record_integrity_if_valid": 0, "require_ready_with_current_unmet_conditions": 2, "integrity_error": 1},
|
||||||
|
"original_incomplete": ["614 exact uses lack completed selected usable assets; 495 candidates and 119 missing are not completion", "final per-use naming/resolution/frame/layout/replacement references", "creator and rights gaps including 20 media; internal BGM origin is not final approval", "mandatory unmade/disclosure gaps; D08/D09 content and quantities unknown", "applicable display/hearing evidence", "Root static validation and meaningful negatives", "independent Opus review", "integration and final original 30 packages/88 delivery units acceptance"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Read-only P22 record integrity; exit 2 for unmet original readiness."""
|
||||||
|
import argparse
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
OUT = 'docs/plans/original-completion-2026-10-02/execution/p22-02/'
|
||||||
|
INPUT = 'docs/spec/inputs/P22-02-accepted-usage.json'
|
||||||
|
CURRENT = 'docs/plans/original-completion-2026-10-02/checkpoints/p22-02-slot-contract-r02/all-slot-current-candidate-contracts.json'
|
||||||
|
SPEC_SHA = 'f252de3c5cff7ebfa62322ae2f2df09fb80a44bc59eb286b76d4acb4c12ca875'
|
||||||
|
INPUT_SHA = '45fa52acf0c8bd4dd58c3b40b681cb92066f05d617df157fc18370a5e8816281'
|
||||||
|
|
||||||
|
def need(ok, message):
|
||||||
|
if not ok:
|
||||||
|
raise ValueError(message)
|
||||||
|
|
||||||
|
def sha(raw):
|
||||||
|
return hashlib.sha256(raw).hexdigest()
|
||||||
|
|
||||||
|
def semantic(value):
|
||||||
|
return sha(json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(',', ':')).encode())
|
||||||
|
|
||||||
|
def pairs(items):
|
||||||
|
result = {}
|
||||||
|
for key, value in items:
|
||||||
|
need(key not in result, 'duplicate JSON key: ' + key)
|
||||||
|
result[key] = value
|
||||||
|
return result
|
||||||
|
|
||||||
|
def read(path):
|
||||||
|
return json.loads((ROOT / path).read_text(), object_pairs_hook=pairs)
|
||||||
|
|
||||||
|
def decode(doc, node=None):
|
||||||
|
need(type(doc) is dict and all(type(doc.get(k)) is list for k in ('keys', 'strings', 'pool')), 'wrong codec tables')
|
||||||
|
need(all(type(k) is str for k in doc['keys']) and len(set(doc['keys'])) == len(doc['keys']), 'duplicate/wrong key table')
|
||||||
|
active = set()
|
||||||
|
def index(values, i):
|
||||||
|
need(type(i) is int and 0 <= i < len(values), 'bad reference index')
|
||||||
|
return values[i]
|
||||||
|
def walk(n):
|
||||||
|
if not isinstance(n, list):
|
||||||
|
need(n is None or type(n) in (str, int, float, bool), 'wrong scalar type')
|
||||||
|
return n
|
||||||
|
need(bool(n) and type(n[0]) is str, 'wrong node type')
|
||||||
|
tag = n[0]
|
||||||
|
if tag == 'l':
|
||||||
|
return [walk(x) for x in n[1:]]
|
||||||
|
if tag == 'd':
|
||||||
|
need(len(n) % 2 == 1, 'malformed flat dictionary')
|
||||||
|
result = {}
|
||||||
|
for i in range(1, len(n), 2):
|
||||||
|
key = index(doc['keys'], n[i])
|
||||||
|
need(type(key) is str and key not in result, 'duplicate or invalid decoded key')
|
||||||
|
result[key] = walk(n[i + 1])
|
||||||
|
return result
|
||||||
|
need(tag in ('s', 'r') and len(n) == 2, 'unknown node')
|
||||||
|
if tag == 's':
|
||||||
|
value = index(doc['strings'], n[1])
|
||||||
|
need(type(value) is str, 'wrong shared string type')
|
||||||
|
return value
|
||||||
|
i = n[1]
|
||||||
|
value = index(doc['pool'], i)
|
||||||
|
need(i not in active and isinstance(value, list) and value[0] in ('d', 'l'), 'cycle or wrong shared object type')
|
||||||
|
active.add(i)
|
||||||
|
result = walk(value)
|
||||||
|
active.remove(i)
|
||||||
|
return result
|
||||||
|
result = walk(doc['files'] if node is None else node)
|
||||||
|
for i in range(len(doc['pool'])):
|
||||||
|
walk(['r', i])
|
||||||
|
return result
|
||||||
|
|
||||||
|
def check(path):
|
||||||
|
spec = (ROOT / 'docs/spec/acceptance/P22-02.json').read_bytes()
|
||||||
|
need(sha(spec.decode().strip().encode()) == SPEC_SHA, 'contract spec SHA mismatch')
|
||||||
|
need(sha((ROOT / INPUT).read_bytes()) == INPUT_SHA, 'accepted input raw SHA mismatch')
|
||||||
|
accepted = read(INPUT)
|
||||||
|
original = decode(accepted)
|
||||||
|
records = {}
|
||||||
|
for name, rows in original.items():
|
||||||
|
need(type(rows) is list, 'decoded file must be a list')
|
||||||
|
pin = accepted['source_files'][name]
|
||||||
|
need(len(rows) == pin['records'] and semantic(rows) == pin['semantic_sha256'], 'decoded semantic file mismatch: ' + name)
|
||||||
|
for row in rows:
|
||||||
|
identity = row.get('slot_id', row.get('group_id'))
|
||||||
|
need(type(identity) is str and identity not in records, 'duplicate or invalid identity')
|
||||||
|
records[identity] = (name, row)
|
||||||
|
need(len(records) == 614, 'accepted identity coverage')
|
||||||
|
packed = read(path)
|
||||||
|
ledger = decode(packed)
|
||||||
|
need(ledger['accepted_input'] == accepted, 'lossless accepted input mismatch')
|
||||||
|
current = read(CURRENT)
|
||||||
|
need(ledger['current'] == current, 'current contract fields changed/omitted or false promotion')
|
||||||
|
evidence_dir = ROOT / 'docs/plans/original-completion-2026-10-02/checkpoints/p22-02-current-contract-r01'
|
||||||
|
expected_evidence = {CURRENT} | {str(p.relative_to(ROOT)) for p in evidence_dir.iterdir() if p.is_file()}
|
||||||
|
need(set(ledger['evidence_pins']) == expected_evidence, 'evidence omission/extra')
|
||||||
|
selection = ledger['selection_contract']
|
||||||
|
need(selection['selected_assets'] == [], 'unsupported selected asset promotion')
|
||||||
|
need('D08/D09 UNKNOWN' in selection['quantity'] and '2 state groups are not images' in selection['quantity'], 'invented quantities/state image promotion')
|
||||||
|
condition_keys = {'all_exact_uses_selected_and_usable', 'all_creator_and_rights_evidence_accepted', 'all_naming_resolution_layout_replacement_references_accepted', 'all_mandatory_unmade_and_disclosure_gaps_resolved', 'applicable_display_and_hearing_evidence', 'independent_opus_review', 'root_static_and_meaningful_negative_validation', 'integration_and_final_original_30_88_acceptance'}
|
||||||
|
need(set(ledger['original_conditions']) == condition_keys and all(v is False for v in ledger['original_conditions'].values()), 'unsupported original evidence promotion')
|
||||||
|
for evidence, digest in ledger['evidence_pins'].items():
|
||||||
|
need(sha((ROOT / evidence).read_bytes()) == digest, 'evidence raw SHA mismatch: ' + evidence)
|
||||||
|
seen = set()
|
||||||
|
used = set()
|
||||||
|
for contract in current['contracts']:
|
||||||
|
identity = contract['id']
|
||||||
|
need(identity in records and identity not in seen, 'contract identity coverage/duplicate')
|
||||||
|
seen.add(identity)
|
||||||
|
name, record = records[identity]
|
||||||
|
need(contract['source_file'] == name and semantic(record) == contract['accepted_record_semantic_sha256'], 'accepted record mismatch')
|
||||||
|
for anchor in contract['source_anchors']:
|
||||||
|
raw = (ROOT / anchor['path']).read_bytes()
|
||||||
|
need(sha(raw) == anchor['sha256'], 'anchor raw SHA')
|
||||||
|
need(raw.decode().splitlines()[anchor['line'] - 1] == anchor['text'], 'anchor line/reference mismatch')
|
||||||
|
for ref in contract['candidate_refs']:
|
||||||
|
source = ref['candidate_ref']
|
||||||
|
need(source in current['candidate_pool'], 'omitted candidate source')
|
||||||
|
used.add(source)
|
||||||
|
actual = current['candidate_pool'][source]['current_raw_sha256']
|
||||||
|
need(ref['prior_source_still_equal'] == (ref['prior_raw_sha256'] == actual), 'historical applicability mismatch')
|
||||||
|
need(seen == set(records), 'omitted identities')
|
||||||
|
need(used == set(current['candidate_pool']) and len(used) == 19, 'source coverage')
|
||||||
|
for source, fact in current['candidate_pool'].items():
|
||||||
|
raw = (ROOT / source).read_bytes()
|
||||||
|
need(sha(raw) == fact['current_raw_sha256'], 'current source raw SHA: ' + source)
|
||||||
|
fmt = fact['observed_format']
|
||||||
|
if source.endswith('.png'):
|
||||||
|
need(raw[:8] == b'\x89PNG\r\n\x1a\n', 'PNG signature')
|
||||||
|
width, height = struct.unpack('>II', raw[16:24])
|
||||||
|
need((width, height) == (fmt['png_width'], fmt['png_height']), 'dimension mismatch')
|
||||||
|
pending = [c['id'] for c in current['contracts'] if not c['original_asset_completion'] or c['missing_conditions'] or c['finished_asset'] is None]
|
||||||
|
# Nonvacuous: all accepted uses plus external original acceptance conditions.
|
||||||
|
ready = bool(seen) and not pending and all(ledger['original_conditions'].values())
|
||||||
|
return {'record_integrity': True, 'original_unit_ready': ready, 'pending_identity_count': len(pending), 'original_conditions': ledger['original_conditions'], 'acceptance_claimed': False}
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('--ledger', default=OUT + 'asset-contracts.json')
|
||||||
|
parser.add_argument('--require-ready', action='store_true')
|
||||||
|
args = parser.parse_args()
|
||||||
|
try:
|
||||||
|
result = check(args.ledger)
|
||||||
|
print(json.dumps(result, ensure_ascii=False, sort_keys=True))
|
||||||
|
return 2 if args.require_ready and not result['original_unit_ready'] else 0
|
||||||
|
except (ValueError, KeyError, TypeError, IndexError, OSError, RecursionError) as exc:
|
||||||
|
print(json.dumps({'record_integrity': False, 'error': str(exc), 'acceptance_claimed': False}))
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main())
|
||||||
Reference in New Issue
Block a user