From 16207d353ae4a2bb180793325cba9aec9ef68d66 Mon Sep 17 00:00:00 2001 From: Agent Control Runner Date: Fri, 16 Oct 2026 06:46:41 +0900 Subject: [PATCH] =?UTF-8?q?P04-01:=20=E5=90=8C=E6=99=82=E7=99=BA=E7=94=9F?= =?UTF-8?q?=E3=81=AE=E6=9B=B4=E6=96=B0=E8=A6=8F=E7=B4=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../execution/p04-01/REPAIR21_STATUS.md | 95 ++++++++++++++++++ .../p04-01/bulk_reader_equivalence.py | 98 +++++++++++++++++++ tools/check_p04_order_evidence.py | 45 ++++++++- 3 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 docs/plans/original-completion-2026-10-02/execution/p04-01/REPAIR21_STATUS.md create mode 100644 docs/plans/original-completion-2026-10-02/execution/p04-01/bulk_reader_equivalence.py diff --git a/docs/plans/original-completion-2026-10-02/execution/p04-01/REPAIR21_STATUS.md b/docs/plans/original-completion-2026-10-02/execution/p04-01/REPAIR21_STATUS.md new file mode 100644 index 0000000..3673190 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p04-01/REPAIR21_STATUS.md @@ -0,0 +1,95 @@ +# Repair21 — source submission; tests NOTRUN + +P04-01 source-only performance repair. Changes are restricted to the checker, +the new `bulk_reader_equivalence.py` fixture, and this status file. No Git +command, test, fixture, collector, Runner, native/Godot run, agent, commit, +branch or integration operation was executed by the worker. + +`read_blobs` validates full lowercase 40-hex OIDs before starting a process, +deduplicates/sorts them, and uses one `git cat-file --batch` process per nonempty +request. Empty requests start no process. `check_output` inherits stderr and +raises for nonzero exit status just like `git_bytes`. The separately injectable +byte parser verifies ordered OIDs, blob type, decimal size, exact framing and +complete output consumption. There is deliberately no blob cache, so no object +can be reused across `_GIT_ENV` namespaces. The two bulk call sites preserve +selected-path sorted manifests and every actual-file byte/mode comparison. + +No existing require message or assertion was removed. The `NATIVE_RUNS` through +`verify_native` region, commit-type checks, ancestry, merge-tree isolation, +status/untracked/symlink/module checks, schema/encoder, six existing suites and +role case IDs were not edited. Checker self-blob reads remain unchanged. + +The fixture source covers binary NUL/CR/LF/trailing LF, empty and large blobs, +unicode `ls-tree -z` path resolution, duplicates, empty input, malformed/short +OIDs, missing objects, tree/commit objects, invalid/truncated/oversized/garbage +responses, process failure, one-process sorted input, and private object +visibility inside versus outside and across isolated namespaces. It has not run. + +Static validation: `ast.parse` and in-memory `compile(..., 'exec')` completed for +the checker and new fixture. Neither module was imported or executed. This is +syntax validation only. Tests: **NOTRUN**. Runtime equivalence and completion +within the registered 180 seconds remain for Root to measure. + +The existing schema2 index at B/p04-evidence/index.json was read as data, along +with the existing builder and role fixture. Its registered/execution/tested +roles remain deb1bcb/9767b0a/5f6bc11 and original_credit remains 13/88. +The existing index and r20 collection are untouched. No new generation is +needed if Root confirms the recomputed payload is identical. If generation is +needed, use a new explicit destination, never overwrite existing evidence. +Original P04-01 remains incomplete; criteria and nativeWindows pending status +are unchanged. No original credit or acceptance is claimed. + +## Root execution order — all NOTRUN + +Use the clean new auto-submitted checkout, whose SHA is assigned after this +source submission. Do not use the registered base SHA as the new submission. + +```sh +export B=/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build +export E=docs/plans/original-completion-2026-10-02/execution/p04-01 +export BUILD_OUTPUT_DIR="$B" +export PYTHONDONTWRITEBYTECODE=1 +python3 "$E/bulk_reader_equivalence.py" +python3 "$E/checker_negative_fixtures.py" +python3 "$E/checker_applicability_fixtures.py" --native-bundle "$B/audit-support/native-first-current" +python3 "$E/checker_native_fixtures.py" "$B/audit-support/native-first-current" +python3 "$E/checker_series_fixtures.py" --build "$B" +python3 "$E/checker_encoder_fixtures.py" +python3 "$E/checker_join_fixtures.py" --build "$B" +python3 "$E/checker_role_fixtures.py" --build "$B" --evidence "$B/p04-evidence" +``` + +Next run the registered validation on the **new auto-submitted SHA**, retaining +its existing 180-second timeout and actual timed receipt. The supplied formal +API call is exactly: + +```python +runner.validate("P04-01") +``` + +The external Runner launcher/configuration is not present in the supplied task +context; use Root's already registered invocation, without substituting an +invented CLI, changing timeout, or treating direct checker timing as registered +validation. Record actual SHA, elapsed time and exit status from that invocation. + +Then run direct real-candidate controls from actual clean submitted, merged and +final checkouts, preserving the formal review/integration state machine: + +```sh +python3 tools/check_p04_order_evidence.py --verify-only +python3 "$P04_MERGED_CHECKOUT/tools/check_p04_order_evidence.py" --verify-only +python3 "$P04_FINAL_CHECKOUT/tools/check_p04_order_evidence.py" --verify-only +``` + +After required formal validation/review and exact final-source binding, run the +full178 product regression once, using a fresh output destination: + +```sh +python3 "$P04_FINAL_CHECKOUT/tools/run_all_tests.py" \ + --project-root "$P04_FINAL_CHECKOUT" --output "$B/p04-final-product-full-r21" +``` + +Do not regenerate raw collections, overwrite index/r20 evidence, alter existing +case semantics, or run an additional native/full suite to compensate for a +timeout. Any unrelated improvement is deferred. Pending Root execution is not +a worker specification gap and does not change this submission's scope. diff --git a/docs/plans/original-completion-2026-10-02/execution/p04-01/bulk_reader_equivalence.py b/docs/plans/original-completion-2026-10-02/execution/p04-01/bulk_reader_equivalence.py new file mode 100644 index 0000000..badf819 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p04-01/bulk_reader_equivalence.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +"""Root-only disposable repository controls; never original acceptance evidence.""" +import importlib.util +import os +from pathlib import Path +import subprocess +import sys +import tempfile +from unittest.mock import patch + +sys.dont_write_bytecode = True +ROOT = Path(__file__).resolve().parents[5] + + +def rejected(operation): + try: + operation() + except (ValueError, subprocess.CalledProcessError): + return + raise AssertionError('invalid input/response accepted') + + +def run(): + spec = importlib.util.spec_from_file_location('bulk_gate', ROOT / 'tools/check_p04_order_evidence.py') + gate = importlib.util.module_from_spec(spec) + spec.loader.exec_module(gate) + with tempfile.TemporaryDirectory(prefix='p04-bulk-fixture-') as temporary: + base = Path(temporary) + repo = base / 'repo' + repo.mkdir() + gate.ROOT = repo + env = gate.git_environment() + env.update(GIT_AUTHOR_NAME='fixture', GIT_AUTHOR_EMAIL='fixture@invalid', + GIT_COMMITTER_NAME='fixture', GIT_COMMITTER_EMAIL='fixture@invalid') + + def git(*args, data=None): + return subprocess.check_output(['git', '-c', 'core.hooksPath=/dev/null', *args], + input=data, cwd=repo, env=env) + + git('init', '--quiet') + payloads = [b'\x00binary\r\nline\n', b'', bytes(range(256)) * 32768] + oids = [git('hash-object', '-w', '--stdin', data=data).decode().strip() for data in payloads] + name = '日本語の木.dat' + (repo / name).write_bytes(payloads[0]) + git('add', '--', name) + git('commit', '--quiet', '-m', 'fixture') + entries = gate.tree_entries('HEAD') # ls-tree -z resolves the unicode path. + assert entries[name][1] == oids[0] + expected = {oid: git('cat-file', 'blob', oid) for oid in oids} + original_output = subprocess.check_output + with patch.object(gate.subprocess, 'check_output', wraps=original_output) as process: + assert gate.read_blobs(reversed(oids + [oids[0]])) == expected + assert process.call_count == 1 + assert process.call_args.kwargs['input'] == ('\n'.join(sorted(set(oids))) + '\n').encode() + with patch.object(gate.subprocess, 'check_output', side_effect=AssertionError('process started')): + assert gate.read_blobs([]) == {} + for invalid in ('abc', 'g' * 40, 'a' * 39, 'a' * 41, 'HEAD', oids[0] + '\n', None): + rejected(lambda: gate.read_blobs([invalid])) + for oid in ('0' * 40, git('rev-parse', 'HEAD').decode().strip(), + git('rev-parse', 'HEAD^{tree}').decode().strip()): + rejected(lambda: gate.read_blobs([oid])) + + oid = oids[0] + header = oid.encode() + b' blob ' + valid = header + b'3\na\x00\n\n' + assert gate.parse_blob_batch(valid, [oid]) == {oid: b'a\x00\n'} + bad = [b'', header + b'3', header + b'3\na', valid[:-1], + header + b'999\na\n', header + b'1\nabc\n', valid + b'garbage', + oid.encode() + b' missing\n', oid.encode() + b' ambiguous\n', + header + b'-1\n', header + b'x\n', header + b'1.0\n', + b'f' * 40 + b' blob 0\n\n', oid.encode() + b' tree 0\n\n'] + for response in bad: + rejected(lambda: gate.parse_blob_batch(response, [oid])) + with patch.object(gate.subprocess, 'check_output', return_value=response): + rejected(lambda: gate.read_blobs([oid])) + rejected(lambda: gate.parse_blob_batch(valid + valid, [oid])) + rejected(lambda: gate.parse_blob_batch(valid, [oid, oids[1]])) + with patch.object(gate.subprocess, 'check_output', + side_effect=subprocess.CalledProcessError(7, ['git'])): + rejected(lambda: gate.read_blobs([oid])) + + with patch.dict(os.environ, BUILD_OUTPUT_DIR=str(base)): + with gate.isolated_objects(): + private_data = b'isolated-only unique payload\x00\n' + private = subprocess.check_output( + ['git', 'hash-object', '-w', '--stdin'], input=private_data, + cwd=repo, env=gate._GIT_ENV).decode().strip() + assert gate.read_blobs([private]) == {private: private_data} + rejected(lambda: gate.read_blobs([private])) + with gate.isolated_objects(): + rejected(lambda: gate.read_blobs([private])) + assert gate.read_blobs(oids) == expected + assert gate._GIT_ENV is None + print('bulk reader equivalence controls completed') + + +if __name__ == '__main__': + run() diff --git a/tools/check_p04_order_evidence.py b/tools/check_p04_order_evidence.py index 1c676bd..a93525b 100644 --- a/tools/check_p04_order_evidence.py +++ b/tools/check_p04_order_evidence.py @@ -141,6 +141,44 @@ def git_bytes(*args): return subprocess.check_output(['git', '--no-replace-objects', *args], cwd=ROOT, env=env) +def parse_blob_batch(stdout, oids): + """Decode length-framed output without splitting binary payloads into lines.""" + result = {} + offset = 0 + for oid in oids: + end = stdout.find(b'\n', offset) + require(end >= 0, 'truncated blob batch header') + header = stdout[offset:end].split(b' ') + require(len(header) == 3 and header[0] == oid.encode('ascii') + and header[1] == b'blob' and re.fullmatch(rb'[0-9]+', header[2]) is not None, + 'invalid blob batch header: ' + oid) + size = int(header[2]) + start = end + 1 + end = start + size + require(end < len(stdout) and stdout[end:end + 1] == b'\n', + 'truncated blob batch payload or missing LF: ' + oid) + result[oid] = stdout[start:end] + offset = end + 1 + require(offset == len(stdout), 'extra blob batch output') + return result + + +def read_blobs(oids): + """One process per request; no cache can cross object namespaces.""" + requested = list(oids) + require(all(isinstance(oid, str) and re.fullmatch('[0-9a-f]{40}', oid) is not None + for oid in requested), 'invalid full blob OID') + requested = sorted(set(requested)) + if not requested: + return {} + env = _GIT_ENV if _GIT_ENV is not None else git_environment() + # Inherit stderr and raise on nonzero status, exactly as git_bytes does. + stdout = subprocess.check_output(['git', '--no-replace-objects', 'cat-file', '--batch'], + input=('\n'.join(requested) + '\n').encode('ascii'), + cwd=ROOT, env=env) + return parse_blob_batch(stdout, requested) + + def git_environment(): env = {k: v for k, v in os.environ.items() if not k.startswith('GIT_')} env.update(GIT_OPTIONAL_LOCKS='0', GIT_NO_REPLACE_OBJECTS='1', GIT_CONFIG_NOSYSTEM='1', @@ -197,9 +235,11 @@ def allowed_path(path): def product_manifest(entries): result = {} + blobs = read_blobs(oid for path, (_, oid) in entries.items() + if selected_path(path) and path != CHECKER_PATH) for path, (_, oid) in sorted(entries.items()): if selected_path(path) and path != CHECKER_PATH: - data = git_bytes('cat-file', 'blob', oid) + data = blobs[oid] result[path] = {'bytes': len(data), 'sha256': hashlib.sha256(data).hexdigest()} return result @@ -337,9 +377,10 @@ def actual_checkout(): require(not git_bytes('status', '--porcelain=v1', '--untracked-files=all', '--ignore-submodules=none'), 'checkout is not clean') require(not git_bytes('ls-files', '--others', '-z'), 'untracked/ignored substitution') + blobs = read_blobs(oid for _, oid in entries.values()) for path, (mode, oid) in entries.items(): actual = safe(ROOT, path) - require(actual.read_bytes() == git_bytes('cat-file', 'blob', oid), 'HEAD/tree/FS bytes: ' + path) + require(actual.read_bytes() == blobs[oid], 'HEAD/tree/FS bytes: ' + path) require(('100755' if actual.stat().st_mode & 0o111 else '100644') == mode, 'HEAD/tree/FS mode: ' + path) # Also reject untracked directory symlinks, including ones ignored by Git.