Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions docs/research/research-package-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,31 @@ explicit head sha); there is no `external` pin for bytes that are not a Git
object here. For such an input, record its source and a byte-equality check in
the verifier and explain the gap in the README.

Shared Git source readers ignore local replacement refs, including a custom
`GIT_REPLACE_REF_BASE` namespace. Otherwise Git can report the original blob ID
while returning a replacement's bytes, allowing locally generated pins to fail
in a clean checkout. The generator, metadata validator, HEAD input inventory,
committed-byte preflight and package exporter use the stored objects. Replacement
refs are left intact; the policy applies only to these Git subprocesses and does
not change the caller's environment or verifier subprocesses. This authenticates
source bytes, not publication ancestry or mathematical claims; the optional
source-history preflight below remains separate.

Regression controls use temporary Git repositories with blob and commit
replacements, the legacy batch fallback, newline paths, a custom replacement
namespace, forged live pins and an exported payload:

```sh
python3 -W error -B -m unittest discover -s tests -p 'test_research_git_replacements.py' -v
```

This extends the immutable-object policy of Nick Petalas's
[source-history preflight (PR3304)](https://github.com/CrocSwap/integer-mult-bounds/pull/3304)
to the shared source readers. The runner and scaffold retain Douglas Colkitt's
attribution, and the exporter retains Tekalign's. Added regression coverage and
reader policy prepared for roger-sato with substantial OpenAI Codex assistance;
Apache-2.0.

`original_card` in `TASK.json` must equal the full pinned catalogue card object.
Hand authors can print the exact object instead of copying it by hand:

Expand Down
14 changes: 14 additions & 0 deletions research/isolated-descendant-bytecode/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,20 @@ pins are in [SOURCES.json](SOURCES.json). Canonical scientific base is
runner is provenance; the manifest also declares the evolving live runner and
regressions for replay selection.

The `research_package.py` source row is historical provenance: `verify.py`
loads that helper from the exact base-commit Git blob and checks its original
SHA256 before copying it into the differential fixture. Its base, blob and
SHA256 are unchanged. The original manifest is retained at commit
`20ecf2891d80b5acf18d980b2164fb44ea7faa90` (blob
`5e2d5560769ca754175472d123829a8586bb4ddc`). Classifying this row as a live
byte pin incorrectly prevented compatible changes to the current helper.
`VERIFY.json` still declares the current helper as an input for replay
selection, and its unchanged third command runs the eight current-helper
bytecode regressions. The sixteen-run historical differential, all three
registered commands, verifier and `RESULT.json` are retained unchanged.
This metadata correction was prepared for roger-sato with substantial OpenAI
Codex assistance; Arham Tahir's original work and source credit are retained.

```sh
python3.12 -B scripts/research_package.py --package research/isolated-descendant-bytecode --check-only
python3.12 -B scripts/research_package.py --package research/isolated-descendant-bytecode
Expand Down
2 changes: 1 addition & 1 deletion research/isolated-descendant-bytecode/SOURCES.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
},
{
"path": "scripts/research_package.py",
"usage": "input",
"usage": "provenance",
"git_blob": "404823640a4506cc363d5e999b724553a41a39a2",
"sha256": "8e1fe8bebe7f045c82a672a103ed87a35cd9dfdbab5848b97969350449d0c8b4"
},
Expand Down
16 changes: 12 additions & 4 deletions scripts/research_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,16 @@ def relative_file(root, name):
return result


def git_source_env():
# Replacement refs can pair an original object ID with different bytes.
# Pins and HEAD inventories must describe the stored objects even when the
# caller has configured a replacement namespace or an inherited override.
return {**os.environ, "GIT_NO_REPLACE_OBJECTS": "1"}


def git(root, *args):
return subprocess.run(["git", *args], cwd=root, capture_output=True, check=True).stdout
return subprocess.run(["git", *args], cwd=root, env=git_source_env(),
capture_output=True, check=True).stdout


def tracked_input_paths(root):
Expand All @@ -74,7 +82,7 @@ def tracked_input_paths(root):
preserves Git filenames containing whitespace, including CR and LF.
"""
raw = subprocess.run(
["git", "ls-tree", "-r", "--name-only", "-z", "HEAD"], cwd=root,
["git", "ls-tree", "-r", "--name-only", "-z", "HEAD"], cwd=root, env=git_source_env(),
capture_output=True, check=True, timeout=30).stdout
return frozenset(name.decode("utf-8") for name in raw.split(b"\0") if name)

Expand All @@ -92,7 +100,7 @@ def git_source_rows(root, base, names):
Newline paths and non-blob objects retain the legacy Git-show semantics.
The caller must close this generator if source validation fails mid-stream.
"""
with subprocess.Popen(["git", "cat-file", "--batch"], cwd=root,
with subprocess.Popen(["git", "cat-file", "--batch"], cwd=root, env=git_source_env(),
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE) as process:
try:
Expand Down Expand Up @@ -135,7 +143,7 @@ def _git_blob_batch(root, specs, nul):
argv = ["git", "cat-file", "--batch"] + (["-z"] if nul else [])
# Usage diagnostics from the unsupported-option probe are expected. Avoid
# a second pipe that could block while we consume the framed stdout reply.
with subprocess.Popen(argv, cwd=root, stdin=subprocess.PIPE,
with subprocess.Popen(argv, cwd=root, env=git_source_env(), stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) as process:
try:
for index, spec in enumerate(specs):
Expand Down
149 changes: 149 additions & 0 deletions tests/test_research_descendant_source_roles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
"""Historical helper authentication and current-helper replay remain separate.

Arham Tahir's source-bound differential and registered commands are unchanged.
Prepared for roger-sato with substantial OpenAI Codex assistance. Apache-2.0.
"""
import copy
import json
import os
from pathlib import Path
import shutil
import subprocess
import sys
import tempfile
import unittest

ROOT = Path(__file__).resolve().parents[1]
ORIGINAL = '20ecf2891d80b5acf18d980b2164fb44ea7faa90'
PACKAGE = 'research/isolated-descendant-bytecode'
HELPER = 'scripts/research_package.py'


def git(root, *args):
return subprocess.check_output(['git', '--no-replace-objects', *args], cwd=root,
stderr=subprocess.PIPE, timeout=30)


class DescendantSourceRoleTests(unittest.TestCase):
def setUp(self):
temporary = tempfile.TemporaryDirectory()
self.addCleanup(temporary.cleanup)
self.root = Path(temporary.name)
self.original = json.loads(git(ROOT, 'show', ORIGINAL + ':' + PACKAGE + '/SOURCES.json'))
self.manifest = json.loads((ROOT / PACKAGE / 'VERIFY.json').read_bytes())
names = set(self.manifest['inputs']) | {
PACKAGE + '/' + name for name in
('SOURCES.json', 'VERIFY.json', 'TASK.json', 'README.md', 'verify.py', 'RESULT.json')}
for name in names:
target = self.root / name
target.parent.mkdir(parents=True, exist_ok=True)
shutil.copyfile(ROOT / name, target)
git(self.root, 'init', '-q')
objects = Path(git(ROOT, 'rev-parse', '--git-path', 'objects').decode().strip())
if not objects.is_absolute():
objects = ROOT / objects
(self.root / '.git/objects/info/alternates').write_text(str(objects.resolve()) + '\n')
git(self.root, 'config', 'user.name', 'Fixture')
git(self.root, 'config', 'user.email', 'fixture@example.invalid')
git(self.root, 'config', 'core.autocrlf', 'false')
self.commit()

def commit(self):
git(self.root, 'add', '.')
git(self.root, 'commit', '-qm', 'fixture')

def write_sources(self, value):
(self.root / PACKAGE / 'SOURCES.json').write_text(json.dumps(value), encoding='utf-8')

def cli(self, script='research_package.py', arguments=None):
if arguments is None:
arguments = ['--package', PACKAGE, '--check-only']
flags = ['-O'] if sys.flags.optimize else []
return subprocess.run([sys.executable, *flags, '-B', str(self.root / 'scripts' / script),
*arguments], cwd=self.root, capture_output=True, text=True, timeout=60)

def test_only_source_role_changes_and_frozen_evidence_is_retained(self):
expected = copy.deepcopy(self.original)
row = next(row for row in expected['files'] if row['path'] == HELPER)
self.assertEqual(row['usage'], 'input')
row['usage'] = 'provenance'
self.assertEqual(json.loads((ROOT / PACKAGE / 'SOURCES.json').read_bytes()), expected)
for name in ('VERIFY.json', 'TASK.json', 'verify.py', 'RESULT.json'):
with self.subTest(name=name):
self.assertEqual((ROOT / PACKAGE / name).read_bytes(),
git(ROOT, 'show', ORIGINAL + ':' + PACKAGE + '/' + name))
self.assertIn(HELPER, self.manifest['inputs'])
self.assertEqual(len(self.manifest['commands']), 3)

def test_original_gate_rejects_but_correct_role_accepts_current_helper(self):
# The same harmless change demonstrates the old gate on any successor.
helper = self.root / HELPER
helper.write_bytes(helper.read_bytes() + b'\n# compatible fixture comment\n')
migrated = json.loads((self.root / PACKAGE / 'SOURCES.json').read_bytes())
self.write_sources(self.original)
before = self.cli()
self.assertNotEqual(before.returncode, 0)
self.assertIn('working source drift: ' + HELPER, before.stderr)
self.write_sources(migrated)
after = self.cli()
self.assertEqual(after.returncode, 0, after.stderr)
self.assertIn('PASS_PACKAGE_METADATA_AND_PINS', after.stdout)

def test_historical_blob_and_hash_corruption_still_rejects(self):
sources = json.loads((self.root / PACKAGE / 'SOURCES.json').read_bytes())
for field, value, message in (
('git_blob', '0' * 40, 'source blob provenance mismatch'),
('sha256', '0' * 64, 'source SHA256 provenance mismatch')):
with self.subTest(field=field):
corrupted = copy.deepcopy(sources)
next(row for row in corrupted['files'] if row['path'] == HELPER)[field] = value
self.write_sources(corrupted)
result = self.cli()
self.assertNotEqual(result.returncode, 0)
self.assertIn(message + ': ' + HELPER, result.stderr)
self.assertNotIn('PASS_PACKAGE', result.stdout)

def test_unrelated_live_input_drift_still_rejects(self):
name = 'scripts/check_research_commit.py'
path = self.root / name
path.write_bytes(path.read_bytes() + b'\n# unpinned fixture change\n')
result = self.cli()
self.assertNotEqual(result.returncode, 0)
self.assertIn('working source drift: ' + name, result.stderr)

def test_current_helper_remains_a_planner_and_publication_input(self):
base = git(self.root, 'rev-parse', 'HEAD').decode().strip()
helper = self.root / HELPER
helper.write_bytes(helper.read_bytes() + b'\n# current input change\n')
result = self.cli('check_research_commit.py', ['--package', PACKAGE])
self.assertNotEqual(result.returncode, 0)
self.assertIn('working/commit bytes differ: ' + HELPER, result.stderr)
self.commit()
explanation = self.root / 'plan.json'
result = self.cli(arguments=['--changed-since', base, '--explain-plan', str(explanation)])
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual(json.loads(result.stdout), {'include': [{'package': PACKAGE}]})
selected = json.loads(explanation.read_bytes())['selected']
self.assertEqual(selected[0]['causes']['declared_inputs'], [HELPER])

def test_broken_live_cache_isolation_fails_the_unchanged_registered_command(self):
helper = self.root / HELPER
source = helper.read_bytes()
protected = b'run_command(isolated_python_argv(argv, cache), cwd, timeout)'
self.assertEqual(source.count(protected), 1)
helper.write_bytes(source.replace(protected, b'run_command(argv, cwd, timeout)'))
command = self.manifest['commands'][2]
argv = [sys.executable if value == '{python}' else value.replace('{package}', PACKAGE)
for value in command['argv']]
env = os.environ.copy()
env.pop('PYTHONOPTIMIZE', None)
result = subprocess.run(argv, cwd=self.root, env=env, capture_output=True, text=True,
timeout=command['timeout_seconds'])
self.assertNotEqual(result.returncode, 0)
self.assertIn('Ran 8 tests', result.stderr)
self.assertIn('UNVERIFIED_BYTECODE_SENTINEL', result.stderr)
self.assertIn('FAILED', result.stderr)


if __name__ == '__main__':
unittest.main()
Loading