From 06457c4d53a5d89b0271752c18d7091526928939 Mon Sep 17 00:00:00 2001 From: clover caruso Date: Mon, 7 Sep 2026 19:45:52 -0700 Subject: [PATCH] test: provide an isolated public library regression lane Run workspace tests, doctests, Clippy, consumer builds and Python regression tests through one command with per-stage logs and explicit completion status. Exclude private input/exporter overrides and document the separate native lab lane. Validated from versioned inputs alone: 171 Rust tests, six doctests, 117 Python regressions and all build/lint checks. Verify missing-tool failure and refusal to overwrite retained results. Assisted-by: gpt-6-astra --- tools/TESTING.md | 57 +++++++++++++++++++++++++++++++++++++++ tools/check_public.py | 62 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 tools/TESTING.md create mode 100644 tools/check_public.py diff --git a/tools/TESTING.md b/tools/TESTING.md new file mode 100644 index 0000000000000000000000000000000000000000..90be63e2462e80ffc6de0fe3462c38b7dfbadaf2 --- /dev/null +++ b/tools/TESTING.md @@ -0,0 +1,57 @@ +# Library regression lanes + +## Public fixtures + +From a checkout with Rust and Python 3 plus Pillow installed: + +```sh +python3 tools/check_public.py /absolute/path/to/new-results +``` + +The command runs formatting, all workspace features/targets, doctests, Clippy, +diagnostic/example builds, and Python regression tests. Each stage has its own +log; `results.json` records executed commands, elapsed times and exit statuses. +Only a completed run receives `status: passed`. Existing result directories are +refused. This lane clears inherited `ONESTORE_*` overrides and uses this +checkout's binaries so personal captures or external exporters cannot silently +replace public inputs. + +Repeat the same command in a fresh checkout containing only versioned files to +verify clean-checkout compatibility. Fixture symlinks must remain symlinks; their +targets are versioned in this repository. Neither `corpus/private`, ignored +`evidence`, existing `target` outputs, credentials nor running virtual machines +are required. Cargo's normal dependency cache may be reused. + +Rust explicitly reports ignored lab tests and fixture generators. Those cases +are **not** part of a successful public run. The Python suite tests native/lab +harness logic using retained synthetic captures and mocks; it does not claim a +new execution of OneNote or a real server interruption. + +## Private and native verification + +Private notebooks stay outside versioned fixtures. Materialize a copy before +editing and retain source hashes; never point an authoring harness at an original +notebook. Live acceptance uses explicitly owned disposable targets and preserves +the run's commands, inputs, outputs and teardown evidence. + +| Boundary | Entry point | Acceptance evidence | +| --- | --- | --- | +| Native authoring and cold reopen | `native_runner.py --help` | Independent OneNote capture; exact expected page count when known; owned clone teardown | +| Mixed native/Rust/offline writers | `native_collaboration.py --help` | Recorded intents, durable receipts, independent server state and cold native comparison | +| SMB directory pagination | `test_smb_directory.py --help` | Caller-owned Linux VM, native filesystem oracle, interrupted-page rejection | +| SMB publication and payload interruptions | Ignored tests in `onestore-smb` | Explicit `ONESTORE_SMB_*` lab inputs, retained protocol traces and independent recovery checks | +| Retained cache migration | Ignored `migrate_retained_cache_copy` test | New destination, unchanged source, images, intent IDs, attempts and receipts | + +To compare an additional **already captured** notebook hierarchy without running +OneNote: + +```sh +PYTHONPATH=tools ONESTORE_NOTEBOOK_NATIVE=/absolute/path/to/capture \ + python3 -m unittest test_notebook_discovery +``` + +The capture contains `notebook/` and `read/hierarchy.xml`. This comparison is a +separate private lane and must retain its own log. A missing capture, unavailable +lab, compilation-only iOS result or ignored test never establishes live native +compatibility. Process exit, server/VM interruption and physical storage loss +remain distinct fault models. diff --git a/tools/check_public.py b/tools/check_public.py new file mode 100644 index 0000000000000000000000000000000000000000..179de351d3f93260fa8dc8042d94c3bcd07bb656 --- /dev/null +++ b/tools/check_public.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +"""Run the public library regression lane and retain each command's output.""" +import argparse +from datetime import datetime, timezone +import json +import os +from pathlib import Path +import subprocess +import sys +import time + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('output', type=Path, help='New directory for logs and results') + args = parser.parse_args() + root = Path(__file__).resolve().parent.parent + output = args.output.resolve() + output.mkdir(parents=True, exist_ok=False) + environment = {key: value for key, value in os.environ.items() + if not key.startswith('ONESTORE_')} + environment['PYTHONPATH'] = str(root / 'tools') + environment['CARGO_TARGET_DIR'] = str(root / 'target') + commands = [ + ('python-dependencies', [sys.executable, '-c', 'import PIL']), + ('format', ['cargo', 'fmt', '--all', '--check']), + ('rust', ['cargo', 'test', '--locked', '--workspace', '--all-features', '--all-targets']), + ('doctests', ['cargo', 'test', '--locked', '--workspace', '--all-features', '--doc']), + ('clippy', ['cargo', 'clippy', '--locked', '--workspace', '--all-features', '--all-targets', '--', '-D', 'warnings']), + ('tools', ['cargo', 'build', '--locked', '--workspace', '--all-features', '--examples', '--bins']), + ('python', [sys.executable, '-m', 'unittest', 'discover', '-s', 'tools', '-p', 'test_*.py', '-v']), + ] + manifest = {'lane': 'public', 'root': str(root), 'status': 'running', + 'started': datetime.now(timezone.utc).isoformat(), 'stages': []} + result_path = output / 'results.json' + result_path.write_text(json.dumps(manifest, indent=2) + '\n') + for name, command in commands: + print(name, flush=True) + started = time.monotonic() + log = output / (name + '.log') + with log.open('w') as stream: + try: + status = subprocess.run(command, cwd=root, env=environment, + stdout=stream, stderr=subprocess.STDOUT).returncode + except OSError as error: + stream.write(str(error) + '\n') + status = None + manifest['stages'].append({'name': name, 'command': command, + 'exit': status, 'seconds': time.monotonic() - started, + 'log': log.name}) + if status != 0: + manifest['status'] = 'failed' + result_path.write_text(json.dumps(manifest, indent=2) + '\n') + if status != 0: + raise SystemExit(f'{name} failed: {log}') + manifest['status'] = 'passed' + result_path.write_text(json.dumps(manifest, indent=2) + '\n') + print(result_path) + + +if __name__ == '__main__': + main() -- 2.54.0