From bce0ca6c094f67c38f443e3fdb552c26e88923d4 Mon Sep 17 00:00:00 2001 From: magnaprog <132261408+magnaprog@users.noreply.github.com> Date: Wed, 17 Jun 2026 21:32:36 -0700 Subject: [PATCH 1/4] fix: harden paper evidence contracts --- PERFORMANCE.md | 8 ++ docs/evaluation-contracts.md | 3 + paper/README.md | 18 +++- paper/main.tex | 4 +- poetry.lock | 16 +-- pyproject.toml | 1 + quantcortex/backtest/conformance.py | 81 +++++++++++++-- quantcortex/data/local_csv.py | 23 ++++- requirements/test.lock | 6 ++ schemas/canonical_target_tape.schema.json | 3 +- scripts/release_paper_artifacts.sh | 120 ++++++++++++++++++++-- scripts/run_paper_experiments.py | 72 ++++++++++++- tests/test_backtest_conformance.py | 92 +++++++++++++++++ tests/test_local_csv.py | 25 +++++ tests/test_paper_artifacts.py | 28 ++++- tests/test_paper_experiments.py | 84 ++++++++++++++- tests/test_repository_data_policy.py | 23 +++++ 17 files changed, 569 insertions(+), 38 deletions(-) diff --git a/PERFORMANCE.md b/PERFORMANCE.md index 92b4fa8..dae4ff1 100644 --- a/PERFORMANCE.md +++ b/PERFORMANCE.md @@ -135,6 +135,14 @@ The fixed paper experiment is stricter than the general report: it accepts no missing price rows, performs no forward fill, and requires at least 274 signal warm-up sessions before the evaluation window. +`scripts/release_paper_artifacts.sh` is intentionally bound to the reviewed +input digest. When release-critical paths are unchanged, it regenerates from the +recorded source commit and timestamp. Changed experiment, report, or paper source +requires an explicit `QUANTCORTEX_GENERATED_AT` and regenerates from current +`HEAD`. The wrapper fails rather than labeling a different matrix with the +reviewed provider provenance. A new panel requires a new, explicitly reviewed +experiment configuration and source record. + For an explicitly requested live download: ```bash diff --git a/docs/evaluation-contracts.md b/docs/evaluation-contracts.md index 2dddbca..0976685 100644 --- a/docs/evaluation-contracts.md +++ b/docs/evaluation-contracts.md @@ -39,6 +39,9 @@ the complete symbol set and gross limit: `target_tape_to_payload` and `target_tape_from_payload` implement that envelope; `schemas/canonical_target_tape.schema.json` specifies it for other engines. +The paper experiment round-trips each variant through this boundary before +backtesting and publishes canonical payload hashes in +`paper/results/target_tape_hashes.json`. The evaluation contract also records post-overlay exposure rules and the paper-trading order-state policy: persist intent before submission, block diff --git a/paper/README.md b/paper/README.md index a982b1e..027c735 100644 --- a/paper/README.md +++ b/paper/README.md @@ -38,11 +38,16 @@ scripts/release_paper_artifacts.sh \ ``` The input must contain `QQQ`, `VGT`, `GLD`, `TLT`, `SPY`, `VIG`, and `SHV` and -must match the SHA-256 digest in `results/manifest.json` for exact -reproduction. The wrapper requires committed tracked source, regenerates the -reviewed `docs/img/` gallery and paper experiment in a detached clean worktree -with the input mounted outside it, verifies the recorded source commit and clean -start state, then copies reviewed artifacts back. The +must match the SHA-256 digest in `results/manifest.json`; the release wrapper +rejects another matrix rather than attaching the reviewed provenance to it. It +uses the recorded source commit and timestamp when all release-critical paths +are unchanged, so the final artifact commit can reproduce without timestamp-only +drift. Changed experiment, report, or paper source must set +`QUANTCORTEX_GENERATED_AT` explicitly; that creates a release from current +`HEAD`. The wrapper requires committed tracked source, regenerates the reviewed +`docs/img/` gallery and paper experiment in a detached clean worktree with the +input mounted outside it, verifies the recorded source commit and clean start +state, then copies reviewed artifacts back. The fixed experiment requires complete rows, performs no forward fill, and rejects fewer than 274 pre-evaluation sessions. Raw provider data is not committed. Aggregate tables, generated LaTeX values, figures, the explicit experiment @@ -58,6 +63,9 @@ and 63-session sensitivity results. `sharpe_uncertainty.csv` directly resamples the conventional sample Sharpe statistic. `comparator_diagnostics.csv` records the causal target-exposure comparator after its own costs, while `evaluation_contract.json` records the machine-readable semantics. +`target_tape_hashes.json` records the canonical payload hash, decision count, +record count, and symbol set for every audited strategy variant without +publishing the underlying provider matrix. The primary accounting path is the event-driven engine. It holds explicit adjusted-close pseudo-shares between rebalances, sizes targets against post-cost diff --git a/paper/main.tex b/paper/main.tex index 28740c0..c818483 100644 --- a/paper/main.tex +++ b/paper/main.tex @@ -319,7 +319,9 @@ \subsection{Reference implementation and order-state controls} versions, dependency lock, input SHA-256, experiment design, source-tree hashes, and the hash of every published table and figure. A versioned JSON contract and canonical long-form target-tape schema make the engine boundary machine -readable; deterministic fixtures exercise it without using the empirical price +readable. The fixed experiment round-trips every strategy decision stream +through the versioned payload boundary and records a canonical payload hash; +deterministic fixtures test the same boundary without using the empirical price matrix. The empirical sections below exercise the research and backtest contracts. Order-state controls are verified by deterministic tests: paper-trading state is written atomically as a versioned diff --git a/poetry.lock b/poetry.lock index ac8e3df..f74eeaf 100644 --- a/poetry.lock +++ b/poetry.lock @@ -464,7 +464,7 @@ version = "26.1.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] +groups = ["main", "dev", "test"] files = [ {file = "attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309"}, {file = "attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32"}, @@ -2484,7 +2484,7 @@ version = "4.26.0" description = "An implementation of JSON Schema validation for Python" optional = false python-versions = ">=3.10" -groups = ["dev"] +groups = ["dev", "test"] files = [ {file = "jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce"}, {file = "jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326"}, @@ -2515,7 +2515,7 @@ version = "2025.9.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = false python-versions = ">=3.9" -groups = ["dev"] +groups = ["dev", "test"] files = [ {file = "jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe"}, {file = "jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d"}, @@ -5652,7 +5652,7 @@ version = "0.37.0" description = "JSON Referencing + Python" optional = false python-versions = ">=3.10" -groups = ["dev"] +groups = ["dev", "test"] files = [ {file = "referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231"}, {file = "referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8"}, @@ -5882,7 +5882,7 @@ version = "2026.5.1" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.11" -groups = ["dev"] +groups = ["dev", "test"] files = [ {file = "rpds_py-2026.5.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3397a5ed7174dc2786bb214030232fc36fe8e5584fec43a9952cc542b1a12036"}, {file = "rpds_py-2026.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:99ab6ba7bfa2cb0f96a04e3652355bf04e3f51aceb1e943b8541dab7ba4828cc"}, @@ -6846,12 +6846,12 @@ version = "4.15.0" description = "Backported and Experimental Type Hints for Python 3.9+" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] +groups = ["main", "dev", "test"] files = [ {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, ] -markers = {main = "python_version < \"3.14\" and (extra == \"brokers\" or extra == \"all\" or extra == \"nlp\" or extra == \"rl\" or extra == \"providers\" or extra == \"storage\") or extra == \"rl\" or extra == \"all\" or extra == \"nlp\" or extra == \"brokers\" or extra == \"providers\" or extra == \"storage\""} +markers = {main = "python_version < \"3.14\" and (extra == \"brokers\" or extra == \"all\" or extra == \"nlp\" or extra == \"rl\" or extra == \"providers\" or extra == \"storage\") or extra == \"rl\" or extra == \"all\" or extra == \"nlp\" or extra == \"brokers\" or extra == \"providers\" or extra == \"storage\"", test = "python_version < \"3.13\""} [[package]] name = "typing-inspection" @@ -7264,4 +7264,4 @@ storage = ["psycopg2-binary", "redis", "sqlalchemy"] [metadata] lock-version = "2.1" python-versions = ">=3.11,<3.15" -content-hash = "fdf69ed71f0e77bc4e134fd0c617b6ad4ecb2bc28e3b34547f8513519bcbf3ed" +content-hash = "ce7cef2e61d6975f34107c519d29ea046adf86a5a073b95268394ed2bc55e59b" diff --git a/pyproject.toml b/pyproject.toml index 72c7f96..11e1c9a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,6 +86,7 @@ packages = [ poetry-plugin-export = ">=1.10,<1.11" [tool.poetry.group.test.dependencies] +jsonschema = ">=4.20,<5" packaging = ">=24" pytest = ">=8.0" pytest-cov = ">=4.1" diff --git a/quantcortex/backtest/conformance.py b/quantcortex/backtest/conformance.py index 1d36a1c..f051958 100644 --- a/quantcortex/backtest/conformance.py +++ b/quantcortex/backtest/conformance.py @@ -8,7 +8,9 @@ from __future__ import annotations +import re from collections.abc import Mapping, Sequence +from datetime import datetime import numpy as np import pandas as pd @@ -19,6 +21,43 @@ "target_weight", ) TARGET_TAPE_SCHEMA_VERSION = 1 +_RFC3339_TIMESTAMP = re.compile( + r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$" +) + + +def _validated_payload_timestamp(value: object) -> str: + """Validate the RFC 3339 subset emitted by the canonical serializer.""" + if not isinstance(value, str): + raise TypeError( + "target-tape decision_timestamp must be an RFC 3339 string" + ) + if _RFC3339_TIMESTAMP.fullmatch(value) is None: + raise ValueError( + "target-tape decision_timestamp must be an RFC 3339 date-time" + ) + candidate = value[:-1] + "+00:00" if value.endswith("Z") else value + try: + parsed = datetime.fromisoformat(candidate) + except ValueError as exc: + raise ValueError( + "target-tape decision_timestamp must be an RFC 3339 date-time" + ) from exc + if parsed.tzinfo is None or parsed.utcoffset() is None: + raise ValueError( + "target-tape decision_timestamp must include a UTC offset" + ) + return value + + +def _validated_payload_number(value: object, *, name: str) -> float: + """Accept only JSON number primitives, excluding booleans and strings.""" + if type(value) not in (int, float): + raise TypeError(f"{name} must be a JSON number") + parsed = float(value) + if not np.isfinite(parsed): + raise ValueError(f"{name} must be finite") + return parsed def _validated_max_gross(value: object) -> float: @@ -88,7 +127,7 @@ def validate_target_tape( raise ValueError("target_weight values must be finite") if (weights < -1e-12).any(): raise ValueError("target_weight values must be long-only") - normalized.loc[normalized["target_weight"].abs() < 1e-15, "target_weight"] = 0.0 + normalized.loc[normalized["target_weight"] < 0.0, "target_weight"] = 0.0 duplicate = normalized.duplicated( subset=["decision_timestamp", "symbol"], @@ -154,7 +193,12 @@ def target_tape_to_weights( ) weights.columns.name = None weights.index.name = None - return weights.sort_index().sort_index(axis=1) + column_order = ( + sorted(normalized["symbol"].unique()) + if expected_symbols is None + else [symbol.strip() for symbol in expected_symbols] + ) + return weights.sort_index().reindex(columns=column_order) def weights_to_target_tape( @@ -234,11 +278,16 @@ def target_tape_from_payload(payload: Mapping[str, object]) -> pd.DataFrame: "target-tape payload keys must be exactly " + ", ".join(sorted(required_keys)) ) - if payload["schema_version"] != TARGET_TAPE_SCHEMA_VERSION: + schema_version = payload["schema_version"] + if type(schema_version) is not int: + raise TypeError("target-tape schema_version must be an integer") + if schema_version != TARGET_TAPE_SCHEMA_VERSION: raise ValueError("unsupported target-tape schema version") symbols = payload["symbols"] if not isinstance(symbols, list): raise TypeError("target-tape symbols must be a list") + if any(not isinstance(symbol, str) for symbol in symbols): + raise TypeError("target-tape symbols must contain strings") records = payload["records"] if not isinstance(records, list) or not records: raise ValueError("target-tape records must be a non-empty list") @@ -249,10 +298,30 @@ def target_tape_from_payload(payload: Mapping[str, object]) -> pd.DataFrame: "target-tape record keys must be exactly " + ", ".join(TARGET_TAPE_COLUMNS) ) - tape = pd.DataFrame(records, columns=TARGET_TAPE_COLUMNS) + normalized_records = [] + for record in records: + timestamp = _validated_payload_timestamp(record["decision_timestamp"]) + symbol = record["symbol"] + if not isinstance(symbol, str): + raise TypeError("target-tape record symbol must be a string") + target_weight = _validated_payload_number( + record["target_weight"], + name="target-tape target_weight", + ) + normalized_records.append( + { + "decision_timestamp": timestamp, + "symbol": symbol, + "target_weight": target_weight, + } + ) + max_gross = _validated_payload_number( + payload["max_gross"], + name="target-tape max_gross", + ) return validate_target_tape( - tape, - max_gross=_validated_max_gross(payload["max_gross"]), + pd.DataFrame(normalized_records, columns=TARGET_TAPE_COLUMNS), + max_gross=_validated_max_gross(max_gross), expected_symbols=symbols, ) diff --git a/quantcortex/data/local_csv.py b/quantcortex/data/local_csv.py index bb6084c..58c8a63 100644 --- a/quantcortex/data/local_csv.py +++ b/quantcortex/data/local_csv.py @@ -95,12 +95,16 @@ def load_price_matrix( start: str | None = None, end: str | None = None, max_ffill: int | None = 5, + *, + require_complete: bool = False, ) -> pd.DataFrame: """Load a wide adjusted-close CSV indexed by a required ``date`` column. Missing prices are forward-filled for at most ``max_ffill`` rows. Set it to ``None`` to disable filling; unlimited filling is intentionally unsupported - because it can keep stale or delisted assets alive indefinitely. + because it can keep stale or delisted assets alive indefinitely. When + ``require_complete`` is true, any missing value that remains in the requested + date window raises instead of silently removing that row. """ resolved, frame = _read_dated_csv(path) frame.columns = [str(column).strip() for column in frame.columns] @@ -126,6 +130,8 @@ def load_price_matrix( frame = _numeric(frame, resolved) if (frame <= 0).any(axis=None): raise LocalDataError(f"prices must be strictly positive in {resolved}") + if not isinstance(require_complete, bool): + raise LocalDataError("require_complete must be a boolean") if max_ffill is not None: if ( @@ -135,7 +141,20 @@ def load_price_matrix( ): raise LocalDataError("max_ffill must be a non-negative integer or None") frame = frame.ffill(limit=int(max_ffill)) if max_ffill > 0 else frame - frame = _slice(frame, start, end).dropna(how="any") + frame = _slice(frame, start, end) + if require_complete and frame.isna().any(axis=None): + missing = frame.isna().stack() + locations = [ + f"{timestamp.date().isoformat()}:{symbol}" + for (timestamp, symbol), is_missing in missing.items() + if is_missing + ] + preview = ", ".join(locations[:3]) + raise LocalDataError( + "price matrix contains missing required observations" + + (f"; first missing values: {preview}" if preview else "") + ) + frame = frame.dropna(how="any") if frame.empty: raise LocalDataError("no complete price rows remain after forward-filling") return frame diff --git a/requirements/test.lock b/requirements/test.lock index 0d7d335..b4038b1 100644 --- a/requirements/test.lock +++ b/requirements/test.lock @@ -1,3 +1,4 @@ +attrs==26.1.0 ; python_version >= "3.11" and python_version < "3.15" colorama==0.4.6 ; python_version >= "3.11" and python_version < "3.15" and (platform_system == "Windows" or sys_platform == "win32") contourpy==1.3.3 ; python_version >= "3.11" and python_version < "3.15" coverage==7.14.1 ; python_version >= "3.11" and python_version < "3.15" @@ -5,6 +6,8 @@ cycler==0.12.1 ; python_version >= "3.11" and python_version < "3.15" fonttools==4.63.0 ; python_version >= "3.11" and python_version < "3.15" iniconfig==2.3.0 ; python_version >= "3.11" and python_version < "3.15" joblib==1.5.3 ; python_version >= "3.11" and python_version < "3.15" +jsonschema-specifications==2025.9.1 ; python_version >= "3.11" and python_version < "3.15" +jsonschema==4.26.0 ; python_version >= "3.11" and python_version < "3.15" kiwisolver==1.5.0 ; python_version >= "3.11" and python_version < "3.15" matplotlib==3.11.0 ; python_version >= "3.11" and python_version < "3.15" narwhals==2.22.1 ; python_version >= "3.11" and python_version < "3.15" @@ -19,9 +22,12 @@ pyparsing==3.3.2 ; python_version >= "3.11" and python_version < "3.15" pytest-cov==7.1.0 ; python_version >= "3.11" and python_version < "3.15" pytest==9.1.0 ; python_version >= "3.11" and python_version < "3.15" python-dateutil==2.9.0.post0 ; python_version >= "3.11" and python_version < "3.15" +referencing==0.37.0 ; python_version >= "3.11" and python_version < "3.15" +rpds-py==2026.5.1 ; python_version >= "3.11" and python_version < "3.15" ruff==0.15.17 ; python_version >= "3.11" and python_version < "3.15" scikit-learn==1.9.0 ; python_version >= "3.11" and python_version < "3.15" scipy==1.17.1 ; python_version >= "3.11" and python_version < "3.15" six==1.17.0 ; python_version >= "3.11" and python_version < "3.15" threadpoolctl==3.6.0 ; python_version >= "3.11" and python_version < "3.15" +typing-extensions==4.15.0 ; python_version >= "3.11" and python_version < "3.14" tzdata==2025.3 ; python_version >= "3.11" and python_version < "3.15" and (sys_platform == "win32" or sys_platform == "emscripten") diff --git a/schemas/canonical_target_tape.schema.json b/schemas/canonical_target_tape.schema.json index 03ec18d..7015949 100644 --- a/schemas/canonical_target_tape.schema.json +++ b/schemas/canonical_target_tape.schema.json @@ -37,7 +37,8 @@ "properties": { "decision_timestamp": { "type": "string", - "format": "date-time" + "format": "date-time", + "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$" }, "symbol": { "type": "string", diff --git a/scripts/release_paper_artifacts.sh b/scripts/release_paper_artifacts.sh index 7ca4b2f..5815000 100755 --- a/scripts/release_paper_artifacts.sh +++ b/scripts/release_paper_artifacts.sh @@ -26,8 +26,92 @@ if [[ ! -f "${prices_csv}" ]]; then exit 1 fi -source_commit="$(git -C "${repo_root}" rev-parse HEAD)" -generated_at="${QUANTCORTEX_GENERATED_AT:-$(date -u '+%Y-%m-%dT%H:%M:%SZ')}" +reviewed_manifest="${repo_root}/paper/results/manifest.json" +if [[ ! -f "${reviewed_manifest}" ]]; then + printf '%s\n' \ + "reviewed paper manifest not found: ${reviewed_manifest}" >&2 + exit 1 +fi +expected_input_digest="$( + "${python_bin}" -c \ + 'import json, sys; print(json.load(open(sys.argv[1]))["source"]["input_sha256"])' \ + "${reviewed_manifest}" +)" +actual_input_digest="$( + "${python_bin}" -c \ + 'import hashlib, pathlib, sys; print(hashlib.sha256(pathlib.Path(sys.argv[1]).read_bytes()).hexdigest())' \ + "${prices_csv}" +)" +if [[ "${actual_input_digest}" != "${expected_input_digest}" ]]; then + printf '%s\n' \ + "price matrix digest does not match the reviewed experiment" \ + "expected: ${expected_input_digest}" \ + "actual: ${actual_input_digest}" >&2 + exit 1 +fi +case "${prices_csv}" in + "${repo_root}"/*) + relative_prices="${prices_csv#${repo_root}/}" + if git -C "${repo_root}" ls-files --error-unmatch -- "${relative_prices}" \ + >/dev/null 2>&1; then + printf '%s\n' \ + "reviewed raw price input must not be tracked by Git: ${relative_prices}" >&2 + exit 1 + else + tracking_status=$? + if [[ "${tracking_status}" -ne 1 ]]; then + printf '%s\n' \ + "could not determine whether the raw price input is tracked" >&2 + exit 1 + fi + fi + ;; +esac + +current_commit="$(git -C "${repo_root}" rev-parse HEAD)" +reviewed_source_commit="$( + "${python_bin}" -c \ + 'import json, sys; print(json.load(open(sys.argv[1]))["generator"]["git"]["source_commit"])' \ + "${reviewed_manifest}" +)" +reviewed_generated_at="$( + "${python_bin}" -c \ + 'import json, sys; print(json.load(open(sys.argv[1]))["generated_at"])' \ + "${reviewed_manifest}" +)" +if [[ -n "${QUANTCORTEX_GENERATED_AT:-}" ]]; then + source_commit="${current_commit}" + generated_at="${QUANTCORTEX_GENERATED_AT}" +else + if ! git -C "${repo_root}" cat-file -e "${reviewed_source_commit}^{commit}" \ + >/dev/null 2>&1; then + printf '%s\n' "reviewed source commit is unavailable" >&2 + exit 1 + fi + release_source_paths=( + quantcortex + schemas + pyproject.toml + poetry.lock + scripts/build_paper.sh + scripts/generate_report.py + scripts/run_paper_experiments.py + paper/main.tex + paper/anonymous.tex + paper/checklist.tex + paper/references.bib + paper/neurips_2026.sty + ) + if ! git -C "${repo_root}" diff --quiet \ + "${reviewed_source_commit}" "${current_commit}" -- \ + "${release_source_paths[@]}"; then + printf '%s\n' \ + "QUANTCORTEX_GENERATED_AT is required for changed release source" >&2 + exit 1 + fi + source_commit="${reviewed_source_commit}" + generated_at="${reviewed_generated_at}" +fi source_date_epoch="${SOURCE_DATE_EPOCH:-$(git -C "${repo_root}" show -s --format=%ct "${source_commit}")}" temporary_root="$(mktemp -d "${TMPDIR:-/tmp}/quantcortex-paper-release.XXXXXX")" source_worktree="${temporary_root}/source" @@ -44,10 +128,26 @@ trap cleanup EXIT git -C "${repo_root}" worktree add --detach "${source_worktree}" "${source_commit}" \ >/dev/null -permission="Owner-supplied local input; publication of derived aggregate " -permission+="results authorized by the repository owner; provider terms not " -permission+="independently verified" -adjustment="yfinance adjusted close with auto_adjust=False" +provider="$( + "${python_bin}" -c \ + 'import json, sys; print(json.load(open(sys.argv[1]))["source"]["provider"])' \ + "${reviewed_manifest}" +)" +permission="$( + "${python_bin}" -c \ + 'import json, sys; print(json.load(open(sys.argv[1]))["source"]["permission_basis"])' \ + "${reviewed_manifest}" +)" +retrieved_at="$( + "${python_bin}" -c \ + 'import json, sys; print(json.load(open(sys.argv[1]))["source"]["retrieved_at"])' \ + "${reviewed_manifest}" +)" +adjustment="$( + "${python_bin}" -c \ + 'import json, sys; print(json.load(open(sys.argv[1]))["source"]["adjustment_method"])' \ + "${reviewed_manifest}" +)" ( cd "${source_worktree}" @@ -58,9 +158,9 @@ adjustment="yfinance adjusted close with auto_adjust=False" --cash-proxy-symbol SHV \ --output-dir "${generated_output}" \ --bootstrap-replications 5000 \ - --data-provider "Yahoo Finance via yfinance 1.4.1" \ + --data-provider "${provider}" \ --permission-basis "${permission}" \ - --retrieved-at 2026-06-16 \ + --retrieved-at "${retrieved_at}" \ --adjustment-method "${adjustment}" \ --generated-at "${generated_at}" \ --require-clean-source @@ -76,9 +176,9 @@ adjustment="yfinance adjusted close with auto_adjust=False" --imgdir "${performance_output}/img" \ --report-out "${performance_output}/report.md" \ --manifest-out "${performance_output}/img/performance_manifest.json" \ - --data-provider "Yahoo Finance via yfinance 1.4.1" \ + --data-provider "${provider}" \ --permission-basis "${permission}" \ - --retrieved-at 2026-06-16 \ + --retrieved-at "${retrieved_at}" \ --adjustment-method "${adjustment}" \ --generated-at "${generated_at}" \ --require-clean-source \ diff --git a/scripts/run_paper_experiments.py b/scripts/run_paper_experiments.py index d9f9c89..89166bf 100644 --- a/scripts/run_paper_experiments.py +++ b/scripts/run_paper_experiments.py @@ -25,6 +25,12 @@ logging.getLogger("hmmlearn").setLevel(logging.ERROR) os.environ.setdefault("LOKY_MAX_CPU_COUNT", "1") +from quantcortex.backtest.conformance import ( + target_tape_from_payload, + target_tape_to_payload, + target_tape_to_weights, + weights_to_target_tape, +) from quantcortex.backtest.costs.transaction_costs import TransactionCostModel from quantcortex.backtest.engines.event_driven import EventDrivenBacktest from quantcortex.backtest.engines.vectorized import BacktestResult, VectorizedBacktest @@ -78,7 +84,7 @@ PRIMARY_BOOTSTRAP_BLOCK_LENGTH = 21 BOOTSTRAP_SEED = 42 PAPER_MAX_FORWARD_FILL = 0 -PROVENANCE_SCHEMA_VERSION = 4 +PROVENANCE_SCHEMA_VERSION = 5 EVALUATION_CONTRACT_SCHEMA_VERSION = 1 TARGET_TAPE_SCHEMA_VERSION = 1 TARGET_EXPOSURE_COMPARATOR_SYMBOL = "equal_initial_weight_basket" @@ -152,6 +158,32 @@ def _git_metadata(repo_root: Path) -> dict[str, str | bool]: } +def _git_path_is_tracked(repo_root: Path, path: Path) -> bool: + """Return whether ``path`` is tracked in the source repository.""" + try: + relative = path.resolve().relative_to(repo_root.resolve()).as_posix() + except ValueError: + return False + try: + result = subprocess.run( + ["git", "ls-files", "--error-unmatch", "--", relative], + cwd=repo_root, + check=False, + capture_output=True, + text=True, + ) + except OSError as exc: + raise RuntimeError("could not determine whether paper input is tracked") from exc + if result.returncode == 0: + return True + if result.returncode == 1: + return False + detail = result.stderr.strip() or f"git exited with status {result.returncode}" + raise RuntimeError( + f"could not determine whether paper input is tracked: {detail}" + ) + + def _sha256(path: Path) -> str: digest = hashlib.sha256() with path.open("rb") as handle: @@ -1756,6 +1788,7 @@ def run_experiments( evaluation_end, ) strategy_weights: dict[str, pd.DataFrame] = {} + target_tape_metadata: dict[str, dict[str, object]] = {} ablation_rows: list[dict[str, float | str]] = [] variant_series: dict[str, dict[str, pd.Series]] = {} gross_active_by_variant: dict[str, pd.Series] = {} @@ -1776,8 +1809,28 @@ def run_experiments( ) for variant, strategy in strategies.items(): - weights = strategy.generate_weights(prices, weekly) + raw_weights = strategy.generate_weights(prices, weekly) + target_tape = weights_to_target_tape(raw_weights, max_gross=1.0) + target_payload = target_tape_to_payload( + target_tape, + max_gross=1.0, + expected_symbols=list(prices.columns), + ) + validated_tape = target_tape_from_payload(target_payload) + weights = target_tape_to_weights( + validated_tape, + max_gross=1.0, + expected_symbols=list(prices.columns), + ) strategy_weights[variant] = weights + target_tape_metadata[variant] = { + "schema_version": TARGET_TAPE_SCHEMA_VERSION, + "decision_count": int(weights.shape[0]), + "record_count": int(len(target_tape)), + "symbols": list(target_payload["symbols"]), + "max_gross": 1.0, + "canonical_payload_sha256": _json_sha256(target_payload), + } result = _engine_result( weights, prices, @@ -2088,6 +2141,7 @@ def protocol_row( "evaluation_index": evaluation_index, "warmup_sessions": available_warmup_sessions, "required_warmup_sessions": required_warmup_sessions, + "target_tape_metadata": target_tape_metadata, "accounting": pd.DataFrame(accounting_rows), "ablation": ablation, "ablation_uncertainty": ablation_uncertainty, @@ -2160,12 +2214,16 @@ def main(argv: list[str]) -> int: raise ValueError(f"dependency lock is missing: {dependency_lock_path}") source = args.prices_csv.expanduser().resolve() + raw_input_committed = _git_path_is_tracked(repo_root, source) + if raw_input_committed: + raise RuntimeError("paper price input must not be tracked by Git") input_digest = sha256_file(source) symbols = UNIVERSE + [args.cash_proxy_symbol] prices_with_cash = load_price_matrix( source, symbols=symbols, max_ffill=PAPER_MAX_FORWARD_FILL, + require_complete=True, ) prices = prices_with_cash.loc[:, UNIVERSE] cash_returns = prices_with_cash[args.cash_proxy_symbol].pct_change( @@ -2233,6 +2291,10 @@ def main(argv: list[str]) -> int: path=results_dir / "generated_values.tex", ), _write_json(contract, results_dir / "evaluation_contract.json"), + _write_json( + experiment["target_tape_metadata"], + results_dir / "target_tape_hashes.json", + ), ] uncertainty_path = results_dir / "uncertainty.json" artifacts.append(_write_json(experiment["uncertainty"], uncertainty_path)) @@ -2286,7 +2348,7 @@ def main(argv: list[str]) -> int: "source": { "file_name": source.name, "input_sha256": input_digest, - "raw_input_committed": False, + "raw_input_committed": raw_input_committed, "symbols": symbols, "cash_proxy": args.cash_proxy_symbol, "provider": args.data_provider, @@ -2414,6 +2476,10 @@ def main(argv: list[str]) -> int: "schema_version": EVALUATION_CONTRACT_SCHEMA_VERSION, "canonical_sha256": _json_sha256(contract), }, + "decision_streams": { + "path": "results/target_tape_hashes.json", + "variants": experiment["target_tape_metadata"], + }, "artifacts": { str(path.relative_to(output_dir)): _sha256(path) for path in sorted(artifacts) diff --git a/tests/test_backtest_conformance.py b/tests/test_backtest_conformance.py index f55b0a3..2c3d20e 100644 --- a/tests/test_backtest_conformance.py +++ b/tests/test_backtest_conformance.py @@ -1,10 +1,13 @@ from __future__ import annotations +import copy import json from pathlib import Path +import numpy as np import pandas as pd import pytest +from jsonschema import Draft202012Validator, FormatChecker from quantcortex.backtest.conformance import ( TARGET_TAPE_COLUMNS, @@ -88,6 +91,81 @@ def test_canonical_target_tape_payload_rejects_unknown_fields(): target_tape_from_payload(payload) +def test_target_tape_to_weights_preserves_declared_symbol_order(): + weights = target_tape_to_weights( + _fixture_tape(), + expected_symbols=["B", "A"], + ) + + assert list(weights.columns) == ["B", "A"] + + +def test_target_tape_long_only_tolerance_preserves_positive_weights_only(): + tape = _fixture_tape() + tape.loc[0, "target_weight"] = 5e-16 + tape.loc[1, "target_weight"] = -5e-13 + + normalized = validate_target_tape(tape, expected_symbols=["A", "B"]) + + assert normalized.loc[0, "target_weight"] == 5e-16 + assert normalized.loc[1, "target_weight"] == 0.0 + payload = target_tape_to_payload(normalized, expected_symbols=["A", "B"]) + roundtrip = target_tape_to_weights( + target_tape_from_payload(payload), + expected_symbols=["A", "B"], + ) + assert roundtrip.iloc[0].to_dict() == {"A": 5e-16, "B": 0.0} + + tape.loc[1, "target_weight"] = -2e-12 + with pytest.raises(ValueError, match="long-only"): + validate_target_tape(tape, expected_symbols=["A", "B"]) + + +@pytest.mark.parametrize( + ("path", "value", "error", "message"), + [ + (("schema_version",), True, TypeError, "schema_version must be an integer"), + (("max_gross",), "1.0", TypeError, "max_gross must be a JSON number"), + ( + ("records", 0, "decision_timestamp"), + "2024-01-01", + ValueError, + "must be an RFC 3339 date-time", + ), + ( + ("records", 0, "decision_timestamp"), + 1_704_067_200, + TypeError, + "must be an RFC 3339 string", + ), + ( + ("records", 0, "target_weight"), + "1.0", + TypeError, + "target_weight must be a JSON number", + ), + ( + ("records", 0, "target_weight"), + np.float64(1.0), + TypeError, + "target_weight must be a JSON number", + ), + ], +) +def test_canonical_target_tape_payload_enforces_published_json_types( + path, value, error, message +): + payload = target_tape_to_payload(_fixture_tape(), expected_symbols=["A", "B"]) + mutated = copy.deepcopy(payload) + cursor = mutated + for key in path[:-1]: + cursor = cursor[key] + cursor[path[-1]] = value + + with pytest.raises(error, match=message): + target_tape_from_payload(mutated) + + def test_conformance_fixture_has_hand_computable_next_bar_returns(): weights = target_tape_to_weights( _fixture_tape(), @@ -136,3 +214,17 @@ def test_committed_contract_schemas_are_versioned_and_specific(): assert contract_schema["properties"]["target_tape"][ "additionalProperties" ] is False + + target_validator = Draft202012Validator( + target_schema, + format_checker=FormatChecker(), + ) + target_validator.validate( + target_tape_to_payload(_fixture_tape(), expected_symbols=["A", "B"]) + ) + contract_validator = Draft202012Validator(contract_schema) + contract_validator.validate( + json.loads( + (REPO_ROOT / "paper" / "results" / "evaluation_contract.json").read_text() + ) + ) diff --git a/tests/test_local_csv.py b/tests/test_local_csv.py index 920f2cb..c060709 100644 --- a/tests/test_local_csv.py +++ b/tests/test_local_csv.py @@ -70,6 +70,31 @@ def test_load_price_matrix_rejects_missing_symbol(tmp_path): load_price_matrix(path, max_ffill=True) with pytest.raises(LocalDataError, match="valid timestamp"): load_price_matrix(path, start="not-a-date") + with pytest.raises(LocalDataError, match="must be a boolean"): + load_price_matrix(path, require_complete=1) + + +def test_load_price_matrix_can_fail_closed_on_incomplete_rows(tmp_path): + path = tmp_path / "prices.csv" + pd.DataFrame( + { + "date": ["2024-01-01", "2024-01-02", "2024-01-03"], + "AAA": [10.0, None, 12.0], + "BBB": [20.0, 21.0, 22.0], + } + ).to_csv(path, index=False) + + permissive = load_price_matrix(path, max_ffill=0) + assert permissive.index.tolist() == [ + pd.Timestamp("2024-01-01"), + pd.Timestamp("2024-01-03"), + ] + + with pytest.raises( + LocalDataError, + match=r"missing required observations.*2024-01-02:AAA", + ): + load_price_matrix(path, max_ffill=0, require_complete=True) def test_load_price_matrix_rejects_duplicate_csv_headers(tmp_path): diff --git a/tests/test_paper_artifacts.py b/tests/test_paper_artifacts.py index 7f186d7..1978de0 100644 --- a/tests/test_paper_artifacts.py +++ b/tests/test_paper_artifacts.py @@ -22,7 +22,7 @@ def test_paper_artifacts_match_manifest_and_generator(): manifest = json.loads( (PAPER_ROOT / "results" / "manifest.json").read_text(encoding="utf-8") ) - assert manifest["schema_version"] == 4 + assert manifest["schema_version"] == 5 source = manifest["source"] assert source["raw_input_committed"] is False @@ -157,6 +157,7 @@ def test_paper_artifacts_match_manifest_and_generator(): assert "results/ablation_uncertainty.csv" in artifacts assert "results/comparator_diagnostics.csv" in artifacts assert "results/evaluation_contract.json" in artifacts + assert "results/target_tape_hashes.json" in artifacts assert "results/return_decomposition.csv" in artifacts assert "results/sharpe_uncertainty.csv" in artifacts assert "results/protocol_switches.csv" in artifacts @@ -167,6 +168,18 @@ def test_paper_artifacts_match_manifest_and_generator(): assert artifact.is_file(), relative_path assert _sha256(artifact) == expected_digest, relative_path + target_tape_path = PAPER_ROOT / manifest["decision_streams"]["path"] + target_tapes = json.loads(target_tape_path.read_text(encoding="utf-8")) + assert target_tapes == manifest["decision_streams"]["variants"] + assert set(target_tapes) == {"full", "no_regime", "no_vol_scaler", "signal_only"} + for metadata in target_tapes.values(): + assert metadata["symbols"] == sorted(metadata["symbols"]) + assert metadata["record_count"] == ( + metadata["decision_count"] * len(metadata["symbols"]) + ) + assert len(metadata["canonical_payload_sha256"]) == 64 + int(metadata["canonical_payload_sha256"], 16) + with (PAPER_ROOT / "results" / "protocol_switches.csv").open( encoding="utf-8", newline="", @@ -231,6 +244,9 @@ def test_paper_artifacts_match_manifest_and_generator(): def test_paper_source_and_reviewed_pdf_are_published(): main = (PAPER_ROOT / "main.tex").read_text(encoding="utf-8") + release_script = (REPO_ROOT / "scripts" / "release_paper_artifacts.sh").read_text( + encoding="utf-8" + ) assert "\\usepackage[preprint]{neurips_2026}" in main assert "\\usepackage{orcidlink}" in main @@ -243,6 +259,16 @@ def test_paper_source_and_reviewed_pdf_are_published(): assert "\\PaperInputDigest" in main assert "{bootstrap_robustness.pdf}" in main assert "target-exposure comparator" in main + assert "actual_input_digest" in release_script + assert "expected_input_digest" in release_script + assert "ls-files --error-unmatch" in release_script + assert "reviewed_generated_at" in release_script + assert "reviewed_source_commit" in release_script + assert "release_source_paths" in release_script + assert "QUANTCORTEX_GENERATED_AT is required for changed release source" in ( + release_script + ) + assert '--data-provider "${provider}"' in release_script anonymous_source = (PAPER_ROOT / "anonymous.tex").read_text(encoding="ascii") assert "\\def\\quantcortexanonymous{1}" in anonymous_source diff --git a/tests/test_paper_experiments.py b/tests/test_paper_experiments.py index 9fd88ee..0d4b7df 100644 --- a/tests/test_paper_experiments.py +++ b/tests/test_paper_experiments.py @@ -4,6 +4,7 @@ import json import subprocess from pathlib import Path +from types import SimpleNamespace import numpy as np import pandas as pd @@ -20,6 +21,7 @@ _cagr, _costed_target_exposure_comparator, _git_metadata, + _git_path_is_tracked, _max_drawdown, _save_figures, _tex_number, @@ -385,6 +387,33 @@ def test_git_metadata_captures_cleanliness_before_writes(tmp_path): assert dirty["worktree_clean_at_start"] is False +def test_git_path_tracking_is_measured_from_the_source_repository(tmp_path): + subprocess.run(["git", "init", "-q"], cwd=tmp_path, check=True) + tracked = tmp_path / "tracked.csv" + untracked = tmp_path / "untracked.csv" + outside = tmp_path.parent / f"{tmp_path.name}-outside.csv" + tracked.write_text("date,A\n2024-01-01,1\n", encoding="ascii") + untracked.write_text("date,A\n2024-01-01,1\n", encoding="ascii") + outside.write_text("date,A\n2024-01-01,1\n", encoding="ascii") + subprocess.run(["git", "add", "tracked.csv"], cwd=tmp_path, check=True) + + assert _git_path_is_tracked(tmp_path, tracked) is True + assert _git_path_is_tracked(tmp_path, untracked) is False + assert _git_path_is_tracked(tmp_path, outside) is False + + +def test_git_path_tracking_fails_closed_on_git_errors(monkeypatch, tmp_path): + candidate = tmp_path / "prices.csv" + candidate.write_text("date,A\n2024-01-01,1\n", encoding="ascii") + monkeypatch.setattr( + "scripts.run_paper_experiments.subprocess.run", + lambda *args, **kwargs: SimpleNamespace(returncode=128, stderr="fatal"), + ) + + with pytest.raises(RuntimeError, match="could not determine"): + _git_path_is_tracked(tmp_path, candidate) + + def test_paper_cli_requires_clean_source_before_reading_input(monkeypatch, tmp_path): monkeypatch.setattr( "scripts.run_paper_experiments._git_metadata", @@ -412,6 +441,36 @@ def test_paper_cli_requires_clean_source_before_reading_input(monkeypatch, tmp_p ) +def test_paper_cli_rejects_a_git_tracked_price_input(monkeypatch): + monkeypatch.setattr( + "scripts.run_paper_experiments._git_metadata", + lambda _repo_root: { + "source_commit": "0" * 40, + "worktree_clean_at_start": True, + }, + ) + tracked_fixture = ( + Path(__file__).resolve().parent / "fixtures" / "conformance" / "prices.csv" + ) + + with pytest.raises(RuntimeError, match="must not be tracked by Git"): + paper_main( + [ + "run_paper_experiments.py", + "--prices-csv", + str(tracked_fixture), + "--data-provider", + "test provider", + "--permission-basis", + "test permission", + "--retrieved-at", + "2026-06-16", + "--adjustment-method", + "test adjustment", + ] + ) + + def test_paper_cli_writes_a_complete_test_only_artifact_set(monkeypatch, tmp_path): warmup = pd.bdate_range(end="2017-12-29", periods=300) first_period = pd.bdate_range("2018-01-02", periods=40) @@ -442,6 +501,16 @@ def test_paper_cli_writes_a_complete_test_only_artifact_set(monkeypatch, tmp_pat "scripts.run_paper_experiments._threadpool_environment", lambda: [{"user_api": "test", "num_threads": 1}], ) + from scripts import run_paper_experiments as paper_experiments + + parsed_payloads = [] + original_parser = paper_experiments.target_tape_from_payload + + def recording_parser(payload): + parsed_payloads.append(payload) + return original_parser(payload) + + monkeypatch.setattr(paper_experiments, "target_tape_from_payload", recording_parser) assert ( paper_main( @@ -476,7 +545,7 @@ def test_paper_cli_writes_a_complete_test_only_artifact_set(monkeypatch, tmp_pat manifest = json.loads( (output_dir / "results" / "manifest.json").read_text(encoding="utf-8") ) - assert manifest["schema_version"] == 4 + assert manifest["schema_version"] == 5 assert manifest["generated_at"] == "2026-06-16T00:00:00Z" assert manifest["generator"]["git"] == { "source_commit": "1" * 40, @@ -485,11 +554,24 @@ def test_paper_cli_writes_a_complete_test_only_artifact_set(monkeypatch, tmp_pat assert manifest["source"]["raw_input_committed"] is False assert manifest["source"]["provider"] == "deterministic synthetic test fixture" assert "results/evaluation_contract.json" in manifest["artifacts"] + assert "results/target_tape_hashes.json" in manifest["artifacts"] assert "results/sharpe_uncertainty.csv" in manifest["artifacts"] assert "figures/accounting_summary.pdf" in manifest["artifacts"] for relative_path in manifest["artifacts"]: assert (output_dir / relative_path).is_file(), relative_path + target_tapes = manifest["decision_streams"]["variants"] + assert set(target_tapes) == {"full", "no_regime", "no_vol_scaler", "signal_only"} + assert all(metadata["schema_version"] == 1 for metadata in target_tapes.values()) + assert all(metadata["decision_count"] > 0 for metadata in target_tapes.values()) + assert all(metadata["symbols"] == sorted(metadata["symbols"]) for metadata in target_tapes.values()) + assert all( + metadata["record_count"] + == metadata["decision_count"] * len(metadata["symbols"]) + for metadata in target_tapes.values() + ) + assert len(parsed_payloads) == 4 + def test_evaluation_contract_separates_attribution_and_tradable_comparator(): contract = evaluation_contract("SHV") diff --git a/tests/test_repository_data_policy.py b/tests/test_repository_data_policy.py index 66345ba..017039a 100644 --- a/tests/test_repository_data_policy.py +++ b/tests/test_repository_data_policy.py @@ -4,6 +4,7 @@ import hashlib import json import re +import subprocess from pathlib import Path REPO_ROOT = Path(__file__).resolve().parent.parent @@ -42,6 +43,28 @@ def test_redistributed_market_data_is_absent(): present = [path for path in FORBIDDEN_MARKET_DATA if (REPO_ROOT / path).exists()] assert not present, f"redistributed market-data snapshots reappeared: {present}" + tracked = subprocess.run( + ["git", "ls-files"], + cwd=REPO_ROOT, + check=True, + capture_output=True, + text=True, + ).stdout.splitlines() + assert [path for path in tracked if path.startswith("local_data/")] == [ + "local_data/README.md" + ] + + raw_columns = {"date", "QQQ", "VGT", "GLD", "TLT", "SPY", "VIG", "SHV"} + leaked = [] + for relative_path in tracked: + if not relative_path.endswith(".csv"): + continue + with (REPO_ROOT / relative_path).open(encoding="utf-8", newline="") as handle: + header = set(next(csv.reader(handle), [])) + if raw_columns <= header: + leaked.append(relative_path) + assert not leaked, f"tracked raw paper price matrices detected: {leaked}" + def test_published_performance_charts_match_manifest_and_readme(): image_dir = REPO_ROOT / "docs" / "img" From 0ab7b57889bf890b59cf42553aacaa8d8cb6811f Mon Sep 17 00:00:00 2001 From: magnaprog <132261408+magnaprog@users.noreply.github.com> Date: Wed, 17 Jun 2026 21:37:52 -0700 Subject: [PATCH 2/4] docs: regenerate audited paper artifacts --- docs/img/performance_manifest.json | 14 +-- paper/build_manifest.json | 10 +- paper/quantcortex_audit_anonymous.pdf | Bin 333047 -> 333196 bytes paper/quantcortex_audit_anonymous.sha256 | 2 +- paper/quantcortex_audit_neurips2026.pdf | Bin 335015 -> 335134 bytes paper/quantcortex_audit_neurips2026.sha256 | 2 +- ...antcortex_audit_neurips2026.sources.sha256 | 4 +- paper/results/generated_values.tex | 2 +- paper/results/manifest.json | 92 +++++++++++++++--- paper/results/target_tape_hashes.json | 62 ++++++++++++ 10 files changed, 158 insertions(+), 30 deletions(-) create mode 100644 paper/results/target_tape_hashes.json diff --git a/docs/img/performance_manifest.json b/docs/img/performance_manifest.json index 753997e..4b0d32a 100644 --- a/docs/img/performance_manifest.json +++ b/docs/img/performance_manifest.json @@ -1,19 +1,19 @@ { "schema_version": 4, - "generated_at": "2026-06-16T22:00:41Z", + "generated_at": "2026-06-18T04:32:48Z", "generator": { "path": "scripts/generate_report.py", "script_sha256": "b536aa7fc5e4fe7df6c7ff28c0992629a489869eaec46486db7aff1cb946099b", "git": { - "source_commit": "d185c44928af865882c4d830066432dc97eb9972", + "source_commit": "bce0ca6c094f67c38f443e3fdb552c26e88923d4", "worktree_clean_at_start": true }, "source_tree": { - "sha256": "a72c2fcd825bb15a2879a3b33d63487a34348b837ff733b7c1ee9d0232ed19cb", + "sha256": "bad09f5c067dd16f556bdff8789fd6d33ff70a9860d856cb66e080f7b063c4bc", "file_count": 107, "files": { - "poetry.lock": "fa8904674c2b24f3141acae607fd0a49d97125bc109c18def9fccbb2256c8de0", - "pyproject.toml": "175abd743d38f6b6c1cc8ae42471d62d83c86beb245d93fea231c666f51b2643", + "poetry.lock": "bf5c536966be29e3cafa807c954b49aa1a097bad1bbed2cc676eeec50c5881b4", + "pyproject.toml": "55ee8092718433e41c5bf2bb7d400fc9501096a207c9dc6b330c40b2ed7d8311", "quantcortex/__init__.py": "14bf1ebdacd054c3738e4704d33da6709a39206463df8b8ced5376da342c4036", "quantcortex/alpha/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "quantcortex/alpha/factors/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", @@ -37,7 +37,7 @@ "quantcortex/alpha/validation/alphalens_report.py": "8463289117add78a576e37a5b99a539be5c808fca86100e26deb29e8060aa60d", "quantcortex/alpha/validation/factor_decay.py": "9e6e049165f014db2122d9ed57415e45e48142b475dfb7221247d447d9a50397", "quantcortex/backtest/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - "quantcortex/backtest/conformance.py": "e169cc67cac9eb56d8da4e4a0da1e257bb6cb8d1745baca681f50fab6c62fc57", + "quantcortex/backtest/conformance.py": "3a37ec8fe8a28bcd1ac5b3ae30214ea490c8480fb9912f405b9b83d398272121", "quantcortex/backtest/costs/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "quantcortex/backtest/costs/transaction_costs.py": "48200419f37004c58df6f89041e31516d9ad98f66c22f75d11a0b9342474d5c7", "quantcortex/backtest/engines/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", @@ -58,7 +58,7 @@ "quantcortex/backtest/validation/multiple_testing.py": "6b68f6f150dcc8fb90213dcf769307454c0c506e99666a533d5d07ae3ccb0b5d", "quantcortex/backtest/validation/survivorship_check.py": "5b772bd6b40ffe44f590ec0ddb00b7e3dc61a1aba9cae8831227325f4f53beff", "quantcortex/data/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - "quantcortex/data/local_csv.py": "30c11c3200530810b3345f8e29fdf966f35671e30c94fc5bb1b2db656e6df79b", + "quantcortex/data/local_csv.py": "6e5f3d24b1477ce122a1e80899e841fffd6d857034189f7d8605705f52c6839c", "quantcortex/data/processors/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "quantcortex/data/processors/adjustments.py": "ae2d4d0362e3484b89b5a5c57a7fd6320973b208ee0cd5a6be9a3f29d2544e2c", "quantcortex/data/processors/calendar.py": "e591bccc3e7f632501b068e7abec1ece182d0ef930589381776fe89158d1df51", diff --git a/paper/build_manifest.json b/paper/build_manifest.json index d766ab7..4c5674a 100644 --- a/paper/build_manifest.json +++ b/paper/build_manifest.json @@ -1,18 +1,18 @@ { "anonymous_pdf": { "path": "quantcortex_audit_anonymous.pdf", - "sha256": "1ee5d885f03316f70c06dd0c9a7e2cd18ef352f83a7045077925c1f767bf20f9" + "sha256": "e5e73d3418d320c53e5f1e0f7338103ce8647bb990b586e1f4a8c28a8e88153b" }, "pdf": { "path": "quantcortex_audit_neurips2026.pdf", - "sha256": "d43a4c75a1b49b3d2c5e703128e5208be60688e8b1d3bd20c51a3ebbb29e6ede" + "sha256": "56d6cc012ad6b180c0397ed81c8902535838b712c56a6f889a311568eecb3f42" }, "schema_version": 1, - "source_commit": "d185c44928af865882c4d830066432dc97eb9972", - "source_date_epoch": 1781647230, + "source_commit": "bce0ca6c094f67c38f443e3fdb552c26e88923d4", + "source_date_epoch": 1781757156, "source_manifest": { "path": "quantcortex_audit_neurips2026.sources.sha256", - "sha256": "11096197aee3ed3a6b5505788756789b5deeddee140d3a204c4ed6ac4349b919" + "sha256": "787035d389f9712575b59e4de1225e1e1e8678aa4a90ade47ec7b420a368d949" }, "tectonic_bundle": { "name": "default_bundle_v33.tar", diff --git a/paper/quantcortex_audit_anonymous.pdf b/paper/quantcortex_audit_anonymous.pdf index 17f5422c10c072de79da07793bac3165dc5c46b5..ff598c542d1b4ad80e289b5157dac52ce66cb09b 100644 GIT binary patch delta 49543 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 diff --git a/paper/quantcortex_audit_anonymous.sha256 b/paper/quantcortex_audit_anonymous.sha256 index 00aedb3..64eaec5 100644 --- a/paper/quantcortex_audit_anonymous.sha256 +++ b/paper/quantcortex_audit_anonymous.sha256 @@ -1 +1 @@ -1ee5d885f03316f70c06dd0c9a7e2cd18ef352f83a7045077925c1f767bf20f9 quantcortex_audit_anonymous.pdf +e5e73d3418d320c53e5f1e0f7338103ce8647bb990b586e1f4a8c28a8e88153b quantcortex_audit_anonymous.pdf diff --git a/paper/quantcortex_audit_neurips2026.pdf b/paper/quantcortex_audit_neurips2026.pdf index 65143691984c7a0702bdd7d10dcace32de6c2d05..b0b32fb0deb5cbc9923a4589155c542fe05483db 100644 GIT binary patch delta 17308 zcmaf(LwBGJl!T*>ZQHidv2AqHv2DJw(Xnl-W83Q3w(VrT+0AYib?Pqa2h@E|mA0Yh zw4>MgdI21Qg0RjmPNs&oupVnux|@j`&GEpD0gL_aLIgbM9|((Ofzb#ws?>HTdWv%1 z38W1Yw=fiQZb}~Q>csc$>t%~SqE0;jq{fTsQ>}&bZWm9kuU0==Q8KZ=BVtnU81AS` zfy_-%U!<3B_pk4;+iT5QuAaB*4G`8u?FLWZ9zfYLi8jAcp4%;D8w%Jwk+=G(U0y$_rV*%Xkov2F&F z0)_C0f!8bS*H_={3C2C}~kuhWiPg7v1fqYyC3q z8mO1Y$%g}Ee`bp9Iw>bmjdSm0hhE0T2>}=-X0*0X6 zmUPHpCB)OE)HyxNn87kQpxL90Y!@!1*nBAB!A#F%AjBuKK(}o)4J3x*Xa8aU=8R>f zP?J$iRJAWzEP6g$rzRM}(TA!#QBWPAJ{fntfD0K&&lS2u6F;vZ7K({hj%bB>FK0eQ zf0xyR{%b5x50zyB^%??|1*1uF4^YpOEp0)JGhx#vN;uL&Hnrn zxi&P~h)*T;LlV~KbNwUyw5B?T*;Or_XfjLw-pnI(@oKEu)ZzT=uWmfl?yt>@tpvoe z{Ix8f+E^s`=g+V?Dz+PJLL#Ivs!``Y^H*c%0W}6v8fTg#Rf7%IM3b7x##cFX(_Q%@vvbx3Je1%Zc zDJaydw^R27!%tK>eyV9QUF@JD`(x&RQgL???*BW_G=j6iMoUzfN=QwzM}PGOGlEKh zJ*&oCs{6+q;q#M+_8%xB+s8WdtvIZ(?SM2w8!Qy%vz=!x?EVFo5P+SB<;Umg6LYW# zGSht-`0k=5deY~WWhRA5-Dm(C^x#aleI>zE<*M6HMO|0>f%hdHq-EFUXR4R+t4QZ# zs1*g4LD^F08TmB&-81>O0$$WWBergGUqeU%b4eSzuw&ut^2Xx^7``+X#M%>)C_LYJ zELUzp;_B9Q4s&d&Silg(QBb2R_fhN7+fIE@rK94w7WH32^;P)ebfJYVp%?p@n>?H~ znh!oEUz|z9%7!>1^OSxxCIQ#g+7ZKrq*f#=V*h(J2s5G+@bt89QOEl}`HM9}+x&JC zJ2Z4yh`G$auRweVDYq=8+FS3M+_t4m3YBct75q4tP7({N+HliJ!~+i29AE zo76;hB^J43vhJObtpGu(;$>Bu(!t76ks!D5PW9!rq1n+D*3?nq%w5QIqqDn}Bbea^ z(r3*6a|JC9deja2r9e;@nGk+-C$8B*)f3jO61g5%ZM8$413o(`Xl@AsgiZ5I8Vsl1 ztO}OpM{r5-0}$2+D;n~*BUYOY=&)nrTi2*7k;+r|Jhi%%fjP2#L0}z^VYzs|sMV9D zVtM$y&{<3!7!u2$3795~I8UIis7wyl!ZVp63B0()kX3Lp&>`CUrU$~b2uq&nvq;4YlA zgY#VD9P;-KY#gJ7+HkO`1Wzu_V)Pr0+`&O+ zuGXfYx4`$`Lo* zAQ(>ZwDm7>e1TMrmhge-R^pV(J7#UyEuq)G1SEkKs+;oHKlaZ=y)+9mnab0q_uRth zbTpIB@vnrEH_jZhYm3X90%A7o=ri(&)TE>buC=`1G!UijUzpZg->Gc6ro+}Sh6scv zB7{ZJCh&7RU6UrCgvid3z$_Zt?Vd{8)7kAMh8k>Q@hg=oQ@`k5MV;=yTi&_3VEm$o zYYN^*e(Kmiz6m$_`0-NCvo%6|D(`!oDv8?Ud*~8ii8{Op7QMyOk9y4AZgy#GtJPdt zsVEEDoy(6Nxv+Kb1-eoWIa3Bwo0?PdE_+B1uFuJM+l2=5#`skIF{&R#f;&GMIBO9E8qL zL0gw`qQ*69*U51FpX)L?{vt{ps!UzqBjS>2d-wTtwl>YE0#50|PA_fY43wv9gn#uf=iU(ohNEwe=n%Z1E70R*^u&B*k`L$Wx#6u2 z+d5`7q3&um3CYFMG$(>pDv+Nj6^#V`85=!tcugX2FrS($4fRm;-QnmQ39MEh2g6n@ z(cs{7A=BCbtNds%D6|JuQf1AoiTa*mysX{HAmnSdn|VnXgkNI!k;}j zw9d<*@jr{mro1E^Eg6Y%jxAm=$1YIa;l{y1i!JQ{JF-rg8-&4{J#raSO02;e@@bSr zj}FrroCkzKL|tJD$L2h@aRx0J2=vs8UPR^0rWQpM6N$^v@_8NC;v#kcIRQgY;;}Vu19oL zbqiN{R@@LG4HT**1Ft_0i>*bTy$YS1Cgj5dJQ4o7K|K@x`4?1BvJ(a%T9L5I^w;e( z5rrhpke>eaS46mTus%1+L3j6N_w(ISdu_1Gm@UO^^raJlPzYvz z-E+!C5t$}iQ9!P}r8v(ejtgl$4wx5z;Bg;QXN9m~5o0kE3aba13VMh)mjv^zidB0A zew?lJ2l&)i@JE;Er0{>bSewV=jyB3ogDVXz>OpJ}q|OrN;ErT+AG7bsf{gNBy|&{n z6O5U; z(Ya&BNzr-TG8wmG+5XXwD3d9nEh`|m6w+pRiX7_TXMYt6QI2~9C8|$9y8-a)!0izm9?pAFR&z72KXVv4XF7$ zLgWV2Lu+p{&24m76&dwGv4*`tMANPY@f9c15JW`%^=8IXlEKNz$BvxXo24AuQf}m( zib$x4U~5}yPk-{#P5(@GUkSgqhiP)-o;KF-5h-9zoCn6(T~cFB@mG5Q9$m+gScy|d zg`(cSCN7Uo@EU*J#w3KTG5tgzwl{uIq70JQjbtOV*>2OxLZ1P7JPJn`u-R&jpFD=1 z<6BxHw$%wZGPC|DXshf`v6bKP-9K6zkz1Z{j0!V@S13gXM<3z@K?C# zqB3R^ey4xH5ha$y`ifZ@W288vW*xH)&#j zI6DwsF`NS0`FIRhgdBKKK~DH^u+i13;1?^(@Acr1$u^t8jwTnForOULm3{#t5H`n5 z8w^Ph8!wIkGu*W(1mZp4V|*hUP|QBS<8rgDYw?vjdQjSDP&12@YVw%(`vohQSgmn4 zLa!e0Q!MWhf%O)O<|bbozQcVyAbg$7`4H`k6|-7|j@8*#}F8)vP%V=Bcl7i14C zFKxf!Jz2TgZZ7}it*RqN!gUxqvz5pVL8rF*(nm78D=*V&E@7i>uORGngoiOisw3+N z(UunqKFK35Pl1RQ$6B7DVTJ7jQ?&wt&FUh$~k{r*a@ z#cl~w*3O#fOCcZjbc`T#nb;1WEY3>>e;rykEgPp3ThcCiu1qX$=+69WmqE%Hmq=Ud zidO5|(@34|W*U0oNcC#9H|K&XFL#J%ycH(>?SSU#G=Amu72Gz6 zDPAT30+Hat#4G6dFT*&?+uuuSaKESg+P?EF!tA#&I$BKNUuVo;+&}5VYhlMCKpaq% zZd7kg)*1H_7E-h1ol3A-R@%bO-0$!kg2vacb6*N?dcxh@zh2TGe$9mB0?H$|W zRR!sEAWPO&KJ#eVry}p|?Et%af2X-(9L3(b5VeND)?TzQV|T2C&TQeM1z5jFy17$u z6_?_&r`B`z}@+?&lSC9(1P8 zw<*9gA7r8$8$$Hg#{mI|12T7C5VxY`(cBenzhHVwM?I<6$7j011u*T7oC)9KXswrr zbiY9D+PnH9tkrzuVvsN#V);A5!|KbQzVfOXE*iUmxUSSYs;{hM>(|s!@X2|G^SNK4 zVYrjFu=`|&n##weYLB}gl^M$s0?pv2E*4m!{tO;_sdM7qguRd!7n}9_z9NfaP38Q_ ztwlW<{>xcrYOlxJ7JeyW$g2sk-b)C8>Z+Yq~mF3&u5ni~?JyH4Y>C+Srh&vZ*$a~gK?X0a| z^7*Z|S>|{NcYAMyv}Kw)B46MOxdu(%_y6jO3Y>iWq}GMk=x6~txKh60PZayv`=G?? zGbupn5mdMoZj^t1rP^*bA*jS@zUzZcDhwdojjYyAJVObsq3!nOY$FN()m$uN$o^@N zWbTKmH-`mjmsNVp;XA)WG>`Se4p%~1g#2S8DU3L@GCp?eM4orM)6;pN$|vkxKS-t)tfD>Zt<|y}C|ywg*0D`jA-HeV?b!u{zNa4~CVwhKe;l!8gw*vG@|LdOw9u z3oF!APt03a@aAHlEL^_d6G|oU*iNOrXL@unu` zW3QV1`ThD(Y&$Vi-Gq<*0ZLy;em|Pu;|kIb z->hSHsxwO?FgIsOLetvV;WolvG1_$Qu_*%YNEir2wCAle4~WL-d>E(_P(U7J+&COs zj`Ne;Dy{x)s*b1#=!XX!yVzQ;^7{if^Pk#COfS$g2-ktcx4(8x1T;if)r+rkS)gYZ zpA~b}nl$lYB5$=5J%&(@8_GWZ`!%Ly6sRg(<*NdYpjDrj zb)d7+P=AAx@%j-4{n^D<>@)eEZU?jSA-@y5^H`nw#Oo5ii}!S_4_8~bu(W!atJ))5 z5jKgT0XNs(Dd5;V_Lxt<&h3Zr#Y+I%8$dKh_H;lJ2leN*Z~M7PG{*$dRpe_^P>O6K zd3zZ3#nt_Vd`Kwh`~>QURgW$DZH)P^k=jN_bW?*ofr3)!*qsF;F(j`Lt6K|wt+T4S zg5Lr5oVS{162gSTbRcGuIJ^9D;se1xpg-q8lro8Wi3)Pn7$EZV5VHEvI-sZ!6M;`z z!X{*Btujl)zu!-nNZt5XRru0N)!JY@b`(b-GVPes-xZ$w>3Q|(q}}5QC*WbgOZI?{}(&dc1)itw5N2FUX(wzx7jKn%jnRuk1FJExs9q=-WQu3|@aU1P6cOLc1% zrXiLh8k9Q1>; z@-hHNO#D>b92R{e1I_uN@SCOGpMJCF^DNgNg=gZYgH%++$dhevH(*8`AF{3?d&0Hh zZaVN0LF#{5ZJc*2A0(BaLU7LEag60F8(YJ*G2%a%@gsY;e7;CsUt$fh!DBC7 zb>jG+cRk5jxO?nRji5LJdg(lrn7(L#t`-3(KCHmF)S4}FC0JJ5kr`o}NAY}(PyK#I zB|EI4lWPMv0`jmwg+T2%B;F9*Xn7ZZz#RxK!_E>l63&m0h_3qMH^V;^=Uo!+u)fv8 zq{j6|k-{qsiZ5UJ2R@^+G(=#Ro_m(4b(82j=|5SYp>ZNXcTg0`y>US=#`UN(4OYuH zpyh7JNa^)ikkH3Pnx!l4G%OIA*wOea1;-Brk6s#>A)082#sTU2T$5!`foL)=kkOwm zAngHq!=lXP4ABINigYr6dwuPPjRIBWJ?%7>?Fzz~;WpV}MHtgS6c6;vwpO4jPzl)v5xMhoNKK zp$g!Tm38O3+9*JLaUnoqH)eUXkCd$f->4zl>+%{XCB%Uc*zI_736NPj@Kz ze&e<}xI1{>L1AX&4dX14bLko3GB%X6>m+65iN5~$0A$KxbhPwD*v4#3QCswaXt+@( zWJ0NmS43@LQ*SC?j@wBSB`RrA;gP|M%UMA6Uk>D%kfH|I56AI2)1qdHXR70oFIa2_ zAX7^E+1HWMBLDU_L6F~1fNDX_hKXpwI;v^zsQ$$tVgjQS6HFoSP>NL0VN~*=4K|X* z$Mk^a1!NPxx4Q90278xkNqh)?J84>k!mM=d;Ue;0b^dnmS(T&}(vhZv1mYQ{z{iRaJ;Hq=;2N{Pe z)|!gqOs-~SpfX@EH{{U;?5=}AIZ+9-vdf)QyjaZ~ADG!=XTv008m>j;_J0{aw}`?k z06|bS0ZV$Sp)~V`xTBXmcF2aDiXV9ak=4tS7@mlmHZF|DL+i4ZHW-iPHK2Ynt=XZ+ zwDa%h70BYcv42uAod}k#gu+CKDt!NZOWvCoN=C01f#0^9N%qUwvt-o|LPurSK^JtcS_Nbm#KQJ2OZT- z`AAYk)#9ilVKB0X>!JRUnnJPfK)YwK|7jDw}fejC{jY3|XTtcBvRU)XKm zkbiN~K?#gZ3_`c?2%~~l$Ra%Ngj@E*N@UkUwNJ^_7uyK4or@u^4BxlYSDtCAt+cFdT{A-hmCmBucY@xhSfx zF}M#BDZ4y7II~Jv#66=y3P~HviEBN$ltIFF(MAqMzzhSetT>+#sta!~ePzm_ZepYx z-{uB$j#a;_VQhP;q5Th28^jA?2cSCerZ2BP4oHHzC{5rX9rT|qV5v6@2?J%9cQCTp z-+9#^FB4}ZAxV`131@g3%|}D6SWm2hh{6tF#eEc2XlylEBc?^@KV%m~pj5Dve8Avy zlx0m#0uv*>peJEmCFO=++oKVQ3J9aEj;5F6Cp038b42d_+-g@j(Y=pZ0em8)k(ElX z+a+SJ4tYNich6-c#!Sc(OE*x1|R`F<*l?W3JZAefih3Rv_gb=|L z!@sqgtNMT1UqXX!b{?eTlqewyg*-V8pc4$O|JW)`JheVVP+^g@F;{(ryGQtHd*esd zx`J9gh{~E`J0*jy<~tLq2ed`P{6+jvKDReOB2b1$+-Q2tE^ff5#zF~@x>HKe>x}8@ z_B`@Myb)#{5oJlK&1}n2O>9Sm`I*=PdCNZ{2$qu8;TaSX1KgpuK{$0Q%1Z;}2m3WT+g=jH& z=qnZIM8yvoecs-EoA_t{`yP`rw*I<(09eB#e=hj6_5L+B*lEG(%C5^AXQKnIlu_!5 zT_;fV%Z}vs!hC`S%X@!EgoYlhqr)8aDwN%Y>_rmuN0>he$?Tp&yzP)`ZaiN?G3=v1 zoX~E?s`Efh-Io^90S)i<@p}^}6r3^~VVv(g!gf{t4kKF;bfdoau(qyXwDbqo4msT6 z_lLh*`}%5+r}Yko2$K+4+Kmz;MH^H(W2Zz1Q0n4kR+ykiAH=L?nx?0oEou5lu&WM4 zvn+%Fl$PyssK$x~IRjB-X3opSQgtPWNi>qzIwD@rH?<5S8cW~1n3gg%?G8ZC8%|_9 zri&kfPI~8EC8fBn=Y_Ou<^7218_Luf+x34x#-PTGu*M9~mc|S)p`SoFW$*O^4N;6Y z-?SVm-)WaEFHU$c#UOe)+#iJvgY8BwrDhBYu4Tf^9WX6=O!FDW))!wAOc=kRf}|*w z1xIoSeEa@tqK?I+X{j&KbMchDb?T>9h~uT-i|anXFn=HY`FrF%pKai-NAsKi z!iFNDRpI8mrBP#Qs%+EZZEF6IR(AXZhjKa1=269LuKK@g6R5X219H`bGUB93T_;$% zYcjF@Vh56xX|_jKHVfB9j|-e2*v+x!%J zbI2};oNpMH0jSX(wJDMxbei{D-4$o1lRmBN_WSIn7uK=~(l1h92p3E;Mobmn2(4q| zO26QBqF5E2mG2M@7{npv`pBdSKfNp85IiMe|2Cy!&V|4f$lk9~r*zGQ1rYurf1d(( z+DpYsLu5YEM*XC-pe0+pY!L>nt9kOSt|HSKOZqJ?3WVy{ZeX!->Jqjr`8ICSc;ACZ z>x0YP$YM0Lvmp8##F&*zt4U^Sa9N@0L%%$b`#e?HN1u7@MLW6U{wb*07aNt~ha{i! zftO0a2T31ct-ikoW1V3mAtGj-0w>kxj{!odSh37pv0K|AR)x|ZyeHd3>hEO+xquV1~#{`?Vm(o+=15@SRWaU*u?3h8tx>Zy$(atA5gzj&)>OOuJrUowZ4 z1PWQVENCscrhetMPTWjg-UF`J}>j%q^>kv!K{|QRKmMDkVwWn-&W?oI z2>RnIe0YAIozWDNjJNWF#UIB7bkHHL4bVU!zUVFGiGF*Ts|~R=6;~m&uM0BVEY*lP zvk|K1+XqQkblYLwLzAkRW3=129K#MNX(+pgEirY>!SMXzmXq(v1(Up@N1 znQ$O|-b{E}up}`b-w_dAQT**l1X-a`kkiK5N!+xDn_9B@3ujwd-g!s-6!hW=^S~T? zn{XR6kA;hG%Uu%$DN8Pm=3hsOGS@gY{HB~qA+la5C|c9?v9qfmnf~G8%}UCIPWGY+ zt1qo2#_XEtCisAsi^Y|Qa81%Q0nipt;mS_YuhIJV*K27{ArMpCsL1FF2)Clrkd`Od z)SU7Q254}({=8IpJi@Js66(ko8f!`qFP3BVoN3Zl2@4-6P^!z2<%uX9SS7gJJTJ`v zV?N*LWiZ19!%Di15Wzi(H(?v|sy{X`cq}4b=(^HHr*gq{=LeZ{Mr+4g1kj{k-ue|U zgX~2&694eygvRMsE}pWTPp;8gzsUV0KxbYuhUgPI|Km&`!AhB14C1RRQ!UcJj-V-w zy42l<*OKGSoKkhh-Xgz^dsOYFLSXeqN+mSW4(~UN{fGb}E#Pe_{xLluLY%cWLsXwl zjrn^4weu(nhUAWWA`vw>3}7X%>GdjJR)tYcwk6AGP`6GFJp9MsR%7kC$(c_5Pb{f` zK0^*;(KWe9rMbFh!c|{=xxp&xfIK9*74pC}C%b?-y(FG$D0F>l7P36wK?+62#~u8* zFjm?6dReVs9w_uqI%S+#)P zLcUc5+zsH^2}#jF-m!hn6%j28FHJ26xcsHg;f_&=O?3C`#cgtgn%IkWzM@y%EuS*u ztN9I#j?Fy1GafuF?+M#IRY#6wWgdTgU9FyL>uR~xK#OMoHtRsHCz&@NlXl@n7Euf) zc68i@U?{+{-};ULbU%9qj_tP^{b}(qLg#CYyZ`I>@9CfA$3sl~xQI?08Pr|M`^eGQ zkWerwfk>g2jfYs*TuT#Bi4@PPhYOV5lwH%JB3XHbmN^jMB*hXQ+YN!wSq5e z+)8pKd$@?8fM5ylzO+W{GMoW zA$da--DA@LTIoF?)0q&ZJVX|v*cHyIrcW!EKA&qgRB>ZyK?;lLD-s~Hy4H%LQU~@J z{J@2GB-GF?wPzs-ClkQ76--(Ox>(hSl1FzP znm{|whTbt?3iERfq_AXuBS80W^X{LIA{#`Vvnfr$Upn+W2z`UMY_gE_7f;?=@EeKe zhk6Z5b2_hSM82l=ouFAV>Z}{A+U{+9a?*B+*4l#_?QBOaOj*FkM*4R?J3`-oQ$Fx1 z97*dJx4t~mAwhYh2Z5Sl+pi5obO-i~G8orHKGQ=T@B>`-6FLm-y+F~SteF<~d)x5N z^Hy)QlEF4yapM6xWwtbbVudKuGuK(m(+mOY8*1|m{w7>)*4ieH>~4dLq&Uy6SJ=P% z>L){Z7~g{pdSt>#bAZsk=8|=wVU^U@cMy;J<$Y ztjzzH&TnQ}+v7<#g!bebun;wJ-#C=i&O=3kbPq!+C^Xb_Y5VU$MdHd%$`qv(H9UR2 z-FHrPkgqq0C|rP~@TBHkot>RkoV8T&VX7-Hi(jfJXZ8tSsg(3mgM6jYf1J=f`lMXY-f~|q1u2TF+K9=gf%B4yel*-}*Kqu>h zrKbr&4@WMiYkmP}Mb#miIh?Gz{6om0fx06RwUu!`K&cX|Xe$$Pm|Lo%sZ1W+e~RJj z7^N}1MwPYui=&6vsybRV&jW2<>+ z-eyVW#C0+Gg!3bX*#D+de}iD@rV+uQPK^WsZ>0$gkxih=-75`RZy0?p>TGGJ*>$rkcnuV*V+ZfF zbMo5H;8vBHE~{D&7!IO%gKlI2y<7S+ak?vrsb3@LhG&k4>VR6?2|Izh>?E5G2bFRS z$^(Xo8X&o7r$(ouL8jxCN!8em*5hOIqTuq*Pnf<2iDMKP#abRLu}$eHXX<+tdSZrn zQoUA#rWtN9#Xqag&_0yCL05~LP!==EIE8(p;VbAgs?Tw=`6WWQo<<%zl)RdInL6Yyk6RQPD({7R-!^lz;t7wl9yt5 zN{Uxir9&k)nS7dN)cYu zC{VPki=I*AL3tTFddE;Wki5)R_|;Zbv}is&0MTVT=zZ$0O5vNo#U|WZF$DFfX-bmC zmCmJrJ~W9khoV0HUiEaZo+yv1C(s&@4 zhaS);XlVQvJO&1`a+?OCZudS*I$jt|e~SK);P!^xN|EdMqZc855(+^COrX0-`7a_w zK0vc)A({6yUDul#vS&^oJ7*9nQt8Uzs&Zog^4V>GRatL-NL#(4>60V&wH!d(Z>x=C zWuzLo6)zdgZnkF%je2sC6|bXkvmHR1$g*Ir-c%t;#%IZ})|aBPj(3-%-CG=UQKZ@b zX}7Y2zc%Z#BIvBr{gwd=RI$ob)5iVmbr^nzgO<{4JT>CYu#*QrCs_)rXZJ)2j1Tr7 z77o7-2a()|Y4Mwa1n>nOSupdE4kT(;^BkqGux(n?3TUQ$SoETgqi!v_vlBQHLF4c} z^5F0K<*BugH9=)E?5O==FacjtP(9{;;=I0)m54D16xUImaS~WS`9;cfJbZme3E|~t zGp$-CFNQL31`P}Z+zX#ynt(8p}Mtx+GrPZ4Vg-P zDIrR?3ie(koQ|-ThG}+_{q3A@GAI1+F`c~@q9A`o4+PGI;=C{px*Kd62G)+!U{{+l zRJ#GRSM{SVJX{GNSTM<+98P?72^8I7THpQ1 zSZ`#&A&iK&6otBlK4H$D-=&AM%4I&DKIL#T4qMB9-0w+6^8)lG~f5!@emy;Fb4wP4}zDm^d3<77SR8IN;bvZpK#ln z9=`OMX#@qpXyjx0ndz%Ipq+(tE)$~R1!=Te_Mq1~(91p~9fGA3_Cu^|JmhiR;cK$= z=*P;;FMWKx1Ugp+q|wROk>ec#Ra@ARPpC1%b>~4w5f!jvg$J{5=mSXbeF6@-zhG%V zR3#(K31s_+CGB%Tpt?&6`iMy)QNeQ$wY^`St_J~gn8m#6GuwBk=DCdQrnuT{@SXFg zxh>cPg1GM%5F^dxA+b8Rp;VGwF1mFU#5RE;WNbTFAUxj8`kWf zL5V_+)lDxh4QzNA__weQ;{G&pRQ+i-v63{Q^9&4#T0c>wHI5?V&6hKwPf#p8g)ngp zeLMlzIsH8&gl85#_C!r)ra@LHTRi3som&Ad6W$^+^BM2t0%_*#$uVkfV zhD-OXGO5=ndyhutbo5^XcYb!0T3bHic*<5fnNWs6g>5c;G`b09#MENWYj=P4?3x1W z-e32XrE$Q^wfSZ3KyIx864kw=VhL7h7Z%n)BhSQy-pyFzX~$QgjwNH9-t@fE8k{yM zvz4HT!JoS%uZmyGaZ;Ek0tEV9HY4W8Q3Yq8#?Fscpf}uJ{5%~NZQflLOu&(*d?!e( zN~rqP>GOblPqZS|v5YnAL%tB;*Kt;j zzdi{49h6XlnyQKNJ9GtJYWL)vH=(KjU&MP!?tQWayAZtC6*V()X5sbAEZwF2tD)EN zR34{#?qp`)@3=8M9PhWY^sC4IhaC80TfcWuKh>AVcOH084o|+~_S`kL-ZNnJ-JUR4 zL2<3;!S7F5!^y|dA`O2EVnKFgayuifm=WNg+(W7HRRF>HYqmG@)V(&xSE!RVBN=;B zz9mO3m;B|`gk2ycZ!05Dl1UTQf!Bol)oIJVK?}*tz68jPrrAnhb(frQk2p-c{(fpP z7rOrI)gqQ)^)O2FO-DK8gbiGP%bHX?QzSr7=@45({5uUZ)f2dZj&q_#=|FxPT!sW? zX_7H{2s(N13lp|^Lt#nb54?la6S}Vaz_SXdHuKER-n{@!(ib?Uj*j!EO;bp<>5^3< z2q=4071UI@UQ>H!&?eSD1Y5;QtSI8gHWEfnghWa0=e?K=<+wsv+5p=^6CU4m zjklq@%Y85T<$L$2YyEwqzL62=aSN@5hll#Md*3dvp6b&-N|!^2t5rkxm1j@C_}aJJ zS82=3Rd51WH5A6GVd)UsNqgfT_mq$2#TzLH7GvwQ|acv&UxRTD6~dm z!N(%8AV~e^IT+2PsCOoR4E;tt7xrUDw+<*i%bK^vVeC^4Ho7$f-;*t|~WnY*M9oAv0KY261 z@pJ^bAOZbj&(n+D$ptZfQ#`*at&43x##qR0yH<4@z;`Xiy2S&!<$5K`DJCB4IjJ}G zh$nC^AR6ZwJMqp!J^6>!h>$g`b zO_Is@k4xdIcjbm3)X*QJp@YK49=n<=3IY}oFhCo|9h+47H_8swEY(xjWbc4K(bg*y z;>VoCbh3-Lw{CkEAMaP8Z6Vi>^>+dYi?(Z*rbF@3K4F%;Eo1NFcUD{2)($v`Le!74 z=$?*fdncUj55c-qvakMFXNW(I8`{&DiAm2^DRa~a(Z^8tF`83X+;HPD2v&&4Qh2T~ zBfwF0mW}0&{C%4tR>h{c_uq)-w?w>QE#K@=mZGM!@JHK46nV)|7WS40$-f4fhS9f$ zq46u}(FNDQ2CSJZwokL=1oH@ShMztMc@JyA4&e^T+J}ZAqOHM_^$h$Ly#Im!MmNDn z)sAHB2m>H*z*!fe_ebmg5N7~G?mW|@0&#Hm0W!fO-3;`?HEP%SBSz>{~u7avHSbLcSX`Z~GR{NTFz(nv+4@eG_ zW=CJ%z1z8qddlu1t&4nuqT{P(+#?e}kwYAkfk{(GNb>#W4cJW%Jj?vU^)7bVL)ti2 zc!H$ZJA$^wtrX;+w*D_*!m_u*y#+Mf*24(TUul8Dl_Z>K za3r+ReSiDTkZ>T;Q?YyvmP^gi9N3TNT$F{Ec7T&rN`mg9tf=%kKHzR3nu9Z0KLsH& zs9zQ~H$Y)&c@=-FL`&QP?b8T;0U`&iJW0xKi! zLIR#qVLc2;!semWgAEBYKk13vgJcI`U#K=ap}wg^14&x1UccvDnl0Q_?#A#b2~ac_ z7XQ(*immZr*rnw#`Q}?{0Qp;&BJ-N=^z81l%kNb@*IIx~k;cn8Z;xF>m!C)S={uK_ zhDMT!(^tAi8n3l&TR(dx_xly>JpKNqJy$D`12M(@_%b$3L*LF8z1hO8^fh)BPz^vIu7r1S1<#y^^ z^TM{78WwDmZDR#o`9~aSWLR{St&5;!x>-iI-sbgEKIgt&*jhB7Uzt3Wr@ZWJ$|cIIEHl2#hy0QJFjvk)4v|> z(vUMJm}zq-K5kqDuGSW}$k~0`&NyurY+FS)LlOV8YP$gh*YlRMrR(6-?%Jf4Hgqa+ zezzl$Wto?)F+$dN7li?2%n0HOJeKhsQz+rG9(dA# zNN2n9yENCl6bvMHIoZ+zk;r!xWF3?AA6ACl;3uz7UKL-$Q zf=I|ZZy%d8NI#f*hF2ea9H&DIuLlp|5V2NxmZS7&5yOVohD-;ef&yq6^au6KJND16 zuRd6n`as#mj#5kdBmy=_Qd7QL#DO`A*W{G* zp`trWUCZB%mth|Qg`(1Fi5G>ygMt`>m9A~6lYw~c{{i+p4X&xB2I0pUGz6qO?_O#a z<_`uDP7Y3HQyxPO6CP7DLr!KRLt`^z6B82-BMvimRx?gRLH_?QkqU?PLlbaU!q7w? zxfOWF6i2ShL$CMu$0%A+s&|h@VAmMj>LC4XpNAr=R`>f_nM4L%{(|9b@PwR_l9DZb zt_(OpLQ714F_>Jx7WlYNXX_DgpYZK?7My6PLL#z}{i>_Ti(3{ur`91i)S79gH<&=B zdW%1LtS4#9iy?HGg{llU{QT_^hC(m9AE?Sfg+;W8oDxAYPCFhvz>WS?vfEyZW9~nRL zG>t?WKXY#n*d=EV<8VwlY-BjYEicpW=pEevKlQ-LO$)a5@k`w!{xX_?3^ggSBjncLhDty8rR@jTqkyZ<;<+-e{L^Q=VJkG zz>Um&N3pjZ)c#NCzeHV#n{YF3!ELxz>;o@#)TfNPLcJY#;7;6wyKxs5iCtRxM8#r1 z&U2srNpDT|VhQfU{bGL?==S^?tUU*~;#F$%Js!cscu?$DW!ia2>~~e&vF}D}asth2 zc~tDb^EE#vp0IP?PEYtMe@#xI`GQX48SzB))1w#Ay!mB#Ry-Si(W9l}DN1(FR#c#g zd1uP;oOp`MH9s$&D}&t5tFf9~6wkFk-Q@aPO)Aj*E|}IK$A%b*jjAfqSqBi*Xn3#=TgA`*1&+75E??;_EhFL@6G@V|W73;we0hX4NXg zb6Ad-@d8%hZ8U3|S&MFPMf1(xMYF=#;^SYe|CFkVla}JHLKCtz@fBy{ajmO~GkK@h ze&Q6oc02d%f78TYoRS1LIT^1>b#YFuag)+4O#;LzJLx9puWJ%0PWf9mxj0ypAaN>Q zxXG;yO=^g9yTVN#urSDc@NwGI*I_xDjQPJ$ArO;u8{MS^oovNp`cBejEiK3N|n`3MC~)PeuxvEQPxO delta 17190 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

6!DA+Yyg%$+tx9^rW`qGnV_~-P3I+fDA_`*R6ds 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 Date: Thu, 18 Jun 2026 15:06:28 -0700 Subject: [PATCH 3/4] fix: align target tape wire contract --- docs/evaluation-contracts.md | 11 +- poetry.lock | 30 ++-- pyproject.toml | 2 +- quantcortex/backtest/conformance.py | 54 ++++++-- requirements/test.lock | 13 +- schemas/canonical_target_tape.schema.json | 14 +- scripts/release_paper_artifacts.sh | 1 + scripts/run_paper_experiments.py | 1 + tests/test_backtest_conformance.py | 162 ++++++++++++++++++++-- tests/test_paper_artifacts.py | 3 + 10 files changed, 243 insertions(+), 48 deletions(-) diff --git a/docs/evaluation-contracts.md b/docs/evaluation-contracts.md index 0976685..9df5725 100644 --- a/docs/evaluation-contracts.md +++ b/docs/evaluation-contracts.md @@ -37,10 +37,13 @@ the complete symbol set and gross limit: } ``` -`target_tape_to_payload` and `target_tape_from_payload` implement that envelope; -`schemas/canonical_target_tape.schema.json` specifies it for other engines. -The paper experiment round-trips each variant through this boundary before -backtesting and publishes canonical payload hashes in +`target_tape_to_payload` and `target_tape_from_payload` implement that envelope. +`schemas/canonical_target_tape.schema.json` specifies its serialized structure +and primitive constraints for other engines. Runtime validation additionally +enforces cross-record portfolio invariants: no duplicate timestamp-symbol rows, +the declared symbol universe at every decision, and the per-decision gross +limit. The paper experiment round-trips each variant through this boundary +before backtesting and publishes canonical payload hashes in `paper/results/target_tape_hashes.json`. The evaluation contract also records post-overlay exposure rules and the diff --git a/poetry.lock b/poetry.lock index f74eeaf..b0cc87e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -403,7 +403,7 @@ version = "1.4.0" description = "Better dates & times for Python" optional = false python-versions = ">=3.8" -groups = ["dev"] +groups = ["dev", "test"] files = [ {file = "arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205"}, {file = "arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7"}, @@ -1632,7 +1632,7 @@ version = "1.5.1" description = "Validates fully-qualified domain names against RFC 1123, so that they are acceptable to modern bowsers" optional = false python-versions = ">=2.7, !=3.0, !=3.1, !=3.2, !=3.3, !=3.4, <4" -groups = ["dev"] +groups = ["dev", "test"] files = [ {file = "fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014"}, {file = "fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f"}, @@ -2262,7 +2262,7 @@ version = "3.18" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] +groups = ["main", "dev", "test"] files = [ {file = "idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2"}, {file = "idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848"}, @@ -2395,7 +2395,7 @@ version = "20.11.0" description = "Operations with ISO 8601 durations" optional = false python-versions = ">=3.7" -groups = ["dev"] +groups = ["dev", "test"] files = [ {file = "isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042"}, {file = "isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9"}, @@ -2472,7 +2472,7 @@ version = "3.1.1" description = "Identify specific nodes in a JSON document (RFC 6901) " optional = false python-versions = ">=3.10" -groups = ["dev"] +groups = ["dev", "test"] files = [ {file = "jsonpointer-3.1.1-py3-none-any.whl", hash = "sha256:8ff8b95779d071ba472cf5bc913028df06031797532f08a7d5b602d8b2a488ca"}, {file = "jsonpointer-3.1.1.tar.gz", hash = "sha256:0b801c7db33a904024f6004d526dcc53bbb8a4a0f4e32bfd10beadf60adf1900"}, @@ -2930,7 +2930,7 @@ version = "1.3.1" description = "a modern parsing library" optional = false python-versions = ">=3.8" -groups = ["dev"] +groups = ["dev", "test"] files = [ {file = "lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12"}, {file = "lark-1.3.1.tar.gz", hash = "sha256:b426a7a6d6d53189d318f2b6236ab5d6429eaf09259f1ca33eb716eed10d2905"}, @@ -5370,7 +5370,7 @@ version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["main", "dev"] +groups = ["main", "dev", "test"] files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, @@ -5817,7 +5817,7 @@ version = "0.1.4" description = "A pure python RFC3339 validator" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -groups = ["dev"] +groups = ["dev", "test"] files = [ {file = "rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa"}, {file = "rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b"}, @@ -5832,7 +5832,7 @@ version = "0.1.1" description = "Pure python rfc3986 validator" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -groups = ["dev"] +groups = ["dev", "test"] files = [ {file = "rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9"}, {file = "rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055"}, @@ -5844,7 +5844,7 @@ version = "1.1.0" description = "Helper functions to syntactically validate strings according to RFC 3987." optional = false python-versions = ">=3.9" -groups = ["dev"] +groups = ["dev", "test"] files = [ {file = "rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f"}, {file = "rfc3987_syntax-1.1.0.tar.gz", hash = "sha256:717a62cbf33cffdd16dfa3a497d81ce48a660ea691b1ddd7be710c22f00b4a0d"}, @@ -6280,7 +6280,7 @@ version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["main", "dev"] +groups = ["main", "dev", "test"] files = [ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, @@ -6875,7 +6875,7 @@ version = "2025.3" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" -groups = ["main", "dev"] +groups = ["main", "dev", "test"] files = [ {file = "tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1"}, {file = "tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7"}, @@ -6888,7 +6888,7 @@ version = "1.3.0" description = "RFC 6570 URI Template Processor" optional = false python-versions = ">=3.7" -groups = ["dev"] +groups = ["dev", "test"] files = [ {file = "uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7"}, {file = "uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363"}, @@ -6934,7 +6934,7 @@ version = "25.10.0" description = "A library for working with the color formats defined by HTML and CSS." optional = false python-versions = ">=3.10" -groups = ["dev"] +groups = ["dev", "test"] files = [ {file = "webcolors-25.10.0-py3-none-any.whl", hash = "sha256:032c727334856fc0b968f63daa252a1ac93d33db2f5267756623c210e57a4f1d"}, {file = "webcolors-25.10.0.tar.gz", hash = "sha256:62abae86504f66d0f6364c2a8520de4a0c47b80c03fc3a5f1815fedbef7c19bf"}, @@ -7264,4 +7264,4 @@ storage = ["psycopg2-binary", "redis", "sqlalchemy"] [metadata] lock-version = "2.1" python-versions = ">=3.11,<3.15" -content-hash = "ce7cef2e61d6975f34107c519d29ea046adf86a5a073b95268394ed2bc55e59b" +content-hash = "20db487a78d05dfdbc61f18045e883b20a6a82fc2a028ed30bd7902bf816f6ff" diff --git a/pyproject.toml b/pyproject.toml index 11e1c9a..c67df2e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,7 +86,7 @@ packages = [ poetry-plugin-export = ">=1.10,<1.11" [tool.poetry.group.test.dependencies] -jsonschema = ">=4.20,<5" +jsonschema = { version = ">=4.20,<5", extras = ["format-nongpl"] } packaging = ">=24" pytest = ">=8.0" pytest-cov = ">=4.1" diff --git a/quantcortex/backtest/conformance.py b/quantcortex/backtest/conformance.py index f051958..898e48c 100644 --- a/quantcortex/backtest/conformance.py +++ b/quantcortex/backtest/conformance.py @@ -22,7 +22,8 @@ ) TARGET_TAPE_SCHEMA_VERSION = 1 _RFC3339_TIMESTAMP = re.compile( - r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$" + r"^\d{4}-\d{2}-\d{2}T(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d" + r"(?:\.\d+)?(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$" ) @@ -54,12 +55,37 @@ def _validated_payload_number(value: object, *, name: str) -> float: """Accept only JSON number primitives, excluding booleans and strings.""" if type(value) not in (int, float): raise TypeError(f"{name} must be a JSON number") - parsed = float(value) + try: + parsed = float(value) + except OverflowError as exc: + raise ValueError(f"{name} must be finite binary64") from exc if not np.isfinite(parsed): - raise ValueError(f"{name} must be finite") + raise ValueError(f"{name} must be finite binary64") return parsed +def _validated_payload_schema_version(value: object) -> int: + """Normalize JSON numbers that represent an integral schema version.""" + parsed = _validated_payload_number(value, name="target-tape schema_version") + if not parsed.is_integer(): + raise TypeError("target-tape schema_version must be an integer") + version = int(parsed) + if version != TARGET_TAPE_SCHEMA_VERSION: + raise ValueError("unsupported target-tape schema version") + return version + + +def _validated_payload_symbol(value: object, *, name: str) -> str: + """Validate a canonical wire symbol without silently normalizing it.""" + if not isinstance(value, str): + raise TypeError(f"{name} must be a string") + if not value or value != value.strip() or "\r" in value or "\n" in value: + raise ValueError( + f"{name} must be non-empty with no outer whitespace or line breaks" + ) + return value + + def _validated_max_gross(value: object) -> float: if isinstance(value, (bool, np.bool_)): raise TypeError("max_gross must be a finite positive number") @@ -100,6 +126,7 @@ def validate_target_tape( try: timestamps = pd.to_datetime( normalized["decision_timestamp"], + format="mixed", utc=True, errors="raise", ) @@ -278,16 +305,14 @@ def target_tape_from_payload(payload: Mapping[str, object]) -> pd.DataFrame: "target-tape payload keys must be exactly " + ", ".join(sorted(required_keys)) ) - schema_version = payload["schema_version"] - if type(schema_version) is not int: - raise TypeError("target-tape schema_version must be an integer") - if schema_version != TARGET_TAPE_SCHEMA_VERSION: - raise ValueError("unsupported target-tape schema version") + _validated_payload_schema_version(payload["schema_version"]) symbols = payload["symbols"] if not isinstance(symbols, list): raise TypeError("target-tape symbols must be a list") - if any(not isinstance(symbol, str) for symbol in symbols): - raise TypeError("target-tape symbols must contain strings") + symbols = [ + _validated_payload_symbol(symbol, name="target-tape symbol") + for symbol in symbols + ] records = payload["records"] if not isinstance(records, list) or not records: raise ValueError("target-tape records must be a non-empty list") @@ -301,13 +326,16 @@ def target_tape_from_payload(payload: Mapping[str, object]) -> pd.DataFrame: normalized_records = [] for record in records: timestamp = _validated_payload_timestamp(record["decision_timestamp"]) - symbol = record["symbol"] - if not isinstance(symbol, str): - raise TypeError("target-tape record symbol must be a string") + symbol = _validated_payload_symbol( + record["symbol"], + name="target-tape record symbol", + ) target_weight = _validated_payload_number( record["target_weight"], name="target-tape target_weight", ) + if target_weight < 0.0: + raise ValueError("target-tape target_weight must be non-negative") normalized_records.append( { "decision_timestamp": timestamp, diff --git a/requirements/test.lock b/requirements/test.lock index b4038b1..0f53e4f 100644 --- a/requirements/test.lock +++ b/requirements/test.lock @@ -1,14 +1,20 @@ +arrow==1.4.0 ; python_version >= "3.11" and python_version < "3.15" attrs==26.1.0 ; python_version >= "3.11" and python_version < "3.15" colorama==0.4.6 ; python_version >= "3.11" and python_version < "3.15" and (platform_system == "Windows" or sys_platform == "win32") contourpy==1.3.3 ; python_version >= "3.11" and python_version < "3.15" coverage==7.14.1 ; python_version >= "3.11" and python_version < "3.15" cycler==0.12.1 ; python_version >= "3.11" and python_version < "3.15" fonttools==4.63.0 ; python_version >= "3.11" and python_version < "3.15" +fqdn==1.5.1 ; python_version >= "3.11" and python_version < "3.15" +idna==3.18 ; python_version >= "3.11" and python_version < "3.15" iniconfig==2.3.0 ; python_version >= "3.11" and python_version < "3.15" +isoduration==20.11.0 ; python_version >= "3.11" and python_version < "3.15" joblib==1.5.3 ; python_version >= "3.11" and python_version < "3.15" +jsonpointer==3.1.1 ; python_version >= "3.11" and python_version < "3.15" jsonschema-specifications==2025.9.1 ; python_version >= "3.11" and python_version < "3.15" jsonschema==4.26.0 ; python_version >= "3.11" and python_version < "3.15" kiwisolver==1.5.0 ; python_version >= "3.11" and python_version < "3.15" +lark==1.3.1 ; python_version >= "3.11" and python_version < "3.15" matplotlib==3.11.0 ; python_version >= "3.11" and python_version < "3.15" narwhals==2.22.1 ; python_version >= "3.11" and python_version < "3.15" numpy==2.4.6 ; python_version >= "3.11" and python_version < "3.15" @@ -23,6 +29,9 @@ pytest-cov==7.1.0 ; python_version >= "3.11" and python_version < "3.15" pytest==9.1.0 ; python_version >= "3.11" and python_version < "3.15" python-dateutil==2.9.0.post0 ; python_version >= "3.11" and python_version < "3.15" referencing==0.37.0 ; python_version >= "3.11" and python_version < "3.15" +rfc3339-validator==0.1.4 ; python_version >= "3.11" and python_version < "3.15" +rfc3986-validator==0.1.1 ; python_version >= "3.11" and python_version < "3.15" +rfc3987-syntax==1.1.0 ; python_version >= "3.11" and python_version < "3.15" rpds-py==2026.5.1 ; python_version >= "3.11" and python_version < "3.15" ruff==0.15.17 ; python_version >= "3.11" and python_version < "3.15" scikit-learn==1.9.0 ; python_version >= "3.11" and python_version < "3.15" @@ -30,4 +39,6 @@ scipy==1.17.1 ; python_version >= "3.11" and python_version < "3.15" six==1.17.0 ; python_version >= "3.11" and python_version < "3.15" threadpoolctl==3.6.0 ; python_version >= "3.11" and python_version < "3.15" typing-extensions==4.15.0 ; python_version >= "3.11" and python_version < "3.14" -tzdata==2025.3 ; python_version >= "3.11" and python_version < "3.15" and (sys_platform == "win32" or sys_platform == "emscripten") +tzdata==2025.3 ; python_version >= "3.11" and python_version < "3.15" +uri-template==1.3.0 ; python_version >= "3.11" and python_version < "3.15" +webcolors==25.10.0 ; python_version >= "3.11" and python_version < "3.15" diff --git a/schemas/canonical_target_tape.schema.json b/schemas/canonical_target_tape.schema.json index 7015949..2c01426 100644 --- a/schemas/canonical_target_tape.schema.json +++ b/schemas/canonical_target_tape.schema.json @@ -7,6 +7,7 @@ "required": ["schema_version", "symbols", "max_gross", "records"], "properties": { "schema_version": { + "type": "integer", "const": 1 }, "symbols": { @@ -16,12 +17,13 @@ "items": { "type": "string", "minLength": 1, - "pattern": ".*\\S.*" + "pattern": "^(?:\\S|\\S.*\\S)$" } }, "max_gross": { "type": "number", - "exclusiveMinimum": 0.0 + "exclusiveMinimum": 0.0, + "maximum": 1.7976931348623157e308 }, "records": { "type": "array", @@ -38,15 +40,17 @@ "decision_timestamp": { "type": "string", "format": "date-time", - "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$" + "pattern": "^\\d{4}-\\d{2}-\\d{2}T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|[+-](?:[01]\\d|2[0-3]):[0-5]\\d)$" }, "symbol": { "type": "string", - "minLength": 1 + "minLength": 1, + "pattern": "^(?:\\S|\\S.*\\S)$" }, "target_weight": { "type": "number", - "minimum": 0.0 + "minimum": 0.0, + "maximum": 1.7976931348623157e308 } } } diff --git a/scripts/release_paper_artifacts.sh b/scripts/release_paper_artifacts.sh index 5815000..f2f8a96 100755 --- a/scripts/release_paper_artifacts.sh +++ b/scripts/release_paper_artifacts.sh @@ -95,6 +95,7 @@ else poetry.lock scripts/build_paper.sh scripts/generate_report.py + scripts/release_paper_artifacts.sh scripts/run_paper_experiments.py paper/main.tex paper/anonymous.tex diff --git a/scripts/run_paper_experiments.py b/scripts/run_paper_experiments.py index 89166bf..9ef0870 100644 --- a/scripts/run_paper_experiments.py +++ b/scripts/run_paper_experiments.py @@ -96,6 +96,7 @@ "net_excess_over_cash": "Net excess over cash", } SOURCE_TREE_FIXED_FILES = ( + "scripts/release_paper_artifacts.sh", "scripts/run_paper_experiments.py", "schemas/canonical_target_tape.schema.json", "schemas/evaluation_contract.schema.json", diff --git a/tests/test_backtest_conformance.py b/tests/test_backtest_conformance.py index 2c3d20e..68f1374 100644 --- a/tests/test_backtest_conformance.py +++ b/tests/test_backtest_conformance.py @@ -29,6 +29,89 @@ def _fixture_tape() -> pd.DataFrame: return pd.read_csv(FIXTURE_ROOT / "target_tape.csv") +def _target_tape_schema_validator() -> Draft202012Validator: + schema = json.loads( + (REPO_ROOT / "schemas" / "canonical_target_tape.schema.json").read_text() + ) + return Draft202012Validator(schema, format_checker=FormatChecker()) + + +def _wire_case_payload(case: str) -> dict[str, object]: + payload = copy.deepcopy( + target_tape_to_payload(_fixture_tape(), expected_symbols=["A", "B"]) + ) + records = payload["records"] + assert isinstance(records, list) + + if case == "valid": + return payload + if case == "integral_float_schema_version": + payload["schema_version"] = 1.0 + elif case == "boolean_schema_version": + payload["schema_version"] = True + elif case == "nonintegral_schema_version": + payload["schema_version"] = 1.5 + elif case == "unsupported_schema_version": + payload["schema_version"] = 2 + elif case == "string_max_gross": + payload["max_gross"] = "1.0" + elif case == "negative_target_weight": + records[0]["target_weight"] = -5e-13 + elif case == "oversized_binary64_number": + oversized = 10**1000 + payload["max_gross"] = oversized + records[0]["target_weight"] = oversized + elif case == "maximum_binary64_number": + maximum = float.fromhex("0x1.fffffffffffffp+1023") + payload["max_gross"] = maximum + records[0]["target_weight"] = maximum + elif case in { + "date_only_timestamp", + "lowercase_timestamp", + "year_zero_timestamp", + "invalid_calendar_date", + "fractional_timestamp", + "maximum_offset_timestamp", + "local_hour_24", + "local_minute_60", + "local_second_60", + "offset_hour_24", + "offset_minute_60", + }: + replacements = { + "date_only_timestamp": "2024-01-01", + "lowercase_timestamp": "2024-01-01t00:00:00z", + "year_zero_timestamp": "0000-01-01T00:00:00Z", + "invalid_calendar_date": "2023-02-29T00:00:00Z", + "fractional_timestamp": "2024-01-01T00:00:00.123456789Z", + "maximum_offset_timestamp": "2024-01-01T00:00:00+23:59", + "local_hour_24": "2024-01-01T24:00:00Z", + "local_minute_60": "2024-01-01T00:60:00Z", + "local_second_60": "2024-01-01T00:00:60Z", + "offset_hour_24": "2024-01-01T00:00:00+24:00", + "offset_minute_60": "2024-01-01T00:00:00+00:60", + } + original = records[0]["decision_timestamp"] + for record in records: + if record["decision_timestamp"] == original: + record["decision_timestamp"] = replacements[case] + elif case in {"blank_symbol", "outer_whitespace_symbol"}: + replacement = " " if case == "blank_symbol" else " A" + symbols = payload["symbols"] + assert isinstance(symbols, list) + symbols[0] = replacement + for record in records: + if record["symbol"] == "A": + record["symbol"] = replacement + elif case == "unknown_payload_field": + payload["unexpected"] = True + elif case == "unknown_record_field": + records[0]["unexpected"] = True + else: # pragma: no cover - protects the test table itself + raise AssertionError(f"unknown wire test case: {case}") + return payload + + def test_canonical_target_tape_round_trips(): tape = validate_target_tape(_fixture_tape(), expected_symbols=["A", "B"]) weights = target_tape_to_weights(tape, expected_symbols=["A", "B"]) @@ -54,6 +137,73 @@ def test_canonical_target_tape_json_payload_round_trips(): pd.testing.assert_frame_equal(restored, tape) +@pytest.mark.parametrize( + ("case", "accepted"), + [ + ("valid", True), + ("integral_float_schema_version", True), + ("boolean_schema_version", False), + ("nonintegral_schema_version", False), + ("unsupported_schema_version", False), + ("string_max_gross", False), + ("negative_target_weight", False), + ("oversized_binary64_number", False), + ("maximum_binary64_number", True), + ("date_only_timestamp", False), + ("lowercase_timestamp", False), + ("year_zero_timestamp", False), + ("invalid_calendar_date", False), + ("fractional_timestamp", True), + ("maximum_offset_timestamp", True), + ("local_hour_24", False), + ("local_minute_60", False), + ("local_second_60", False), + ("offset_hour_24", False), + ("offset_minute_60", False), + ("blank_symbol", False), + ("outer_whitespace_symbol", False), + ("unknown_payload_field", False), + ("unknown_record_field", False), + ], +) +def test_target_tape_schema_and_runtime_align_on_wire_constraints(case, accepted): + """Keep primitive wire validation aligned without duplicating semantics.""" + payload = _wire_case_payload(case) + schema_accepts = not list(_target_tape_schema_validator().iter_errors(payload)) + try: + target_tape_from_payload(payload) + except (TypeError, ValueError): + runtime_accepts = False + else: + runtime_accepts = True + + assert schema_accepts is accepted + assert runtime_accepts is accepted + + +def test_canonical_target_tape_payload_survives_strict_json_round_trip(): + tape = validate_target_tape(_fixture_tape(), expected_symbols=["A", "B"]) + payload = target_tape_to_payload(tape, expected_symbols=["A", "B"]) + encoded = json.dumps(payload, allow_nan=False, sort_keys=True) + decoded = json.loads(encoded) + + _target_tape_schema_validator().validate(decoded) + restored = target_tape_from_payload(decoded) + + pd.testing.assert_frame_equal(restored, tape) + + +@pytest.mark.parametrize("value", [float("nan"), float("inf"), float("-inf")]) +def test_canonical_target_tape_payload_rejects_nonfinite_json_numbers(value): + payload = target_tape_to_payload(_fixture_tape(), expected_symbols=["A", "B"]) + payload["records"][0]["target_weight"] = value + + with pytest.raises(ValueError, match="must be finite binary64"): + target_tape_from_payload(payload) + with pytest.raises(ValueError, match="Out of range float values"): + json.dumps(payload, allow_nan=False) + + @pytest.mark.parametrize( ("mutator", "message"), [ @@ -124,7 +274,7 @@ def test_target_tape_long_only_tolerance_preserves_positive_weights_only(): @pytest.mark.parametrize( ("path", "value", "error", "message"), [ - (("schema_version",), True, TypeError, "schema_version must be an integer"), + (("schema_version",), True, TypeError, "schema_version must be a JSON number"), (("max_gross",), "1.0", TypeError, "max_gross must be a JSON number"), ( ("records", 0, "decision_timestamp"), @@ -187,9 +337,7 @@ def test_conformance_fixture_has_hand_computable_next_bar_returns(): def test_committed_contract_schemas_are_versioned_and_specific(): - target_schema = json.loads( - (REPO_ROOT / "schemas" / "canonical_target_tape.schema.json").read_text() - ) + target_schema = _target_tape_schema_validator().schema contract_schema = json.loads( (REPO_ROOT / "schemas" / "evaluation_contract.schema.json").read_text() ) @@ -215,11 +363,7 @@ def test_committed_contract_schemas_are_versioned_and_specific(): "additionalProperties" ] is False - target_validator = Draft202012Validator( - target_schema, - format_checker=FormatChecker(), - ) - target_validator.validate( + _target_tape_schema_validator().validate( target_tape_to_payload(_fixture_tape(), expected_symbols=["A", "B"]) ) contract_validator = Draft202012Validator(contract_schema) diff --git a/tests/test_paper_artifacts.py b/tests/test_paper_artifacts.py index 1978de0..ba0523b 100644 --- a/tests/test_paper_artifacts.py +++ b/tests/test_paper_artifacts.py @@ -51,6 +51,7 @@ def test_paper_artifacts_match_manifest_and_generator(): source_commit, "--", "quantcortex", + "scripts/release_paper_artifacts.sh", "scripts/run_paper_experiments.py", "schemas", "pyproject.toml", @@ -64,6 +65,7 @@ def test_paper_artifacts_match_manifest_and_generator(): assert dependency_lock["sha256"] == _sha256(REPO_ROOT / "poetry.lock") assert generator["threadpools"] source_tree = generator["source_tree"] + assert "scripts/release_paper_artifacts.sh" in source_tree["files"] assert source_tree == source_tree_manifest( REPO_ROOT, list(source_tree["files"]), @@ -265,6 +267,7 @@ def test_paper_source_and_reviewed_pdf_are_published(): assert "reviewed_generated_at" in release_script assert "reviewed_source_commit" in release_script assert "release_source_paths" in release_script + assert "scripts/release_paper_artifacts.sh" in release_script assert "QUANTCORTEX_GENERATED_AT is required for changed release source" in ( release_script ) From 9fda3da04733d439ef5451b3d8dfd63d4d000a09 Mon Sep 17 00:00:00 2001 From: magnaprog <132261408+magnaprog@users.noreply.github.com> Date: Thu, 18 Jun 2026 15:11:54 -0700 Subject: [PATCH 4/4] docs: refresh audited paper artifacts --- docs/img/performance_manifest.json | 12 ++++----- paper/build_manifest.json | 10 +++---- paper/quantcortex_audit_anonymous.pdf | Bin 333196 -> 333030 bytes paper/quantcortex_audit_anonymous.sha256 | 2 +- paper/quantcortex_audit_neurips2026.pdf | Bin 335134 -> 334976 bytes paper/quantcortex_audit_neurips2026.sha256 | 2 +- ...antcortex_audit_neurips2026.sources.sha256 | 2 +- paper/results/generated_values.tex | 2 +- paper/results/manifest.json | 25 +++++++++--------- 9 files changed, 28 insertions(+), 27 deletions(-) diff --git a/docs/img/performance_manifest.json b/docs/img/performance_manifest.json index 4b0d32a..96b3c53 100644 --- a/docs/img/performance_manifest.json +++ b/docs/img/performance_manifest.json @@ -1,19 +1,19 @@ { "schema_version": 4, - "generated_at": "2026-06-18T04:32:48Z", + "generated_at": "2026-06-18T22:06:35Z", "generator": { "path": "scripts/generate_report.py", "script_sha256": "b536aa7fc5e4fe7df6c7ff28c0992629a489869eaec46486db7aff1cb946099b", "git": { - "source_commit": "bce0ca6c094f67c38f443e3fdb552c26e88923d4", + "source_commit": "ef6e7e3414aed0ae9b77d50748a22823529486af", "worktree_clean_at_start": true }, "source_tree": { - "sha256": "bad09f5c067dd16f556bdff8789fd6d33ff70a9860d856cb66e080f7b063c4bc", + "sha256": "f964d653b5e645e1efe97889e8acb43fbb0c2c8ddeb0835803f07c299abff5a0", "file_count": 107, "files": { - "poetry.lock": "bf5c536966be29e3cafa807c954b49aa1a097bad1bbed2cc676eeec50c5881b4", - "pyproject.toml": "55ee8092718433e41c5bf2bb7d400fc9501096a207c9dc6b330c40b2ed7d8311", + "poetry.lock": "abce2cd132651851d81034dea085d7dbfbe5e44321f2e13997db69f46d7f080b", + "pyproject.toml": "eaeeb454c28bf7f6d9e530002bb7e88624b56b6c3e1fcb71e6414045cb9c42a0", "quantcortex/__init__.py": "14bf1ebdacd054c3738e4704d33da6709a39206463df8b8ced5376da342c4036", "quantcortex/alpha/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "quantcortex/alpha/factors/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", @@ -37,7 +37,7 @@ "quantcortex/alpha/validation/alphalens_report.py": "8463289117add78a576e37a5b99a539be5c808fca86100e26deb29e8060aa60d", "quantcortex/alpha/validation/factor_decay.py": "9e6e049165f014db2122d9ed57415e45e48142b475dfb7221247d447d9a50397", "quantcortex/backtest/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - "quantcortex/backtest/conformance.py": "3a37ec8fe8a28bcd1ac5b3ae30214ea490c8480fb9912f405b9b83d398272121", + "quantcortex/backtest/conformance.py": "22f9b18101f0d9adcae98297e395c1ab6a90b18e411f24e7456f1d166b7df9b5", "quantcortex/backtest/costs/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "quantcortex/backtest/costs/transaction_costs.py": "48200419f37004c58df6f89041e31516d9ad98f66c22f75d11a0b9342474d5c7", "quantcortex/backtest/engines/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", diff --git a/paper/build_manifest.json b/paper/build_manifest.json index 4c5674a..c1b1f14 100644 --- a/paper/build_manifest.json +++ b/paper/build_manifest.json @@ -1,18 +1,18 @@ { "anonymous_pdf": { "path": "quantcortex_audit_anonymous.pdf", - "sha256": "e5e73d3418d320c53e5f1e0f7338103ce8647bb990b586e1f4a8c28a8e88153b" + "sha256": "3bf902d420224032fa11492ddb4f8d3b636972f4a3d7740e4b7aef4bbf8484ff" }, "pdf": { "path": "quantcortex_audit_neurips2026.pdf", - "sha256": "56d6cc012ad6b180c0397ed81c8902535838b712c56a6f889a311568eecb3f42" + "sha256": "59fcd30467d449984118d746417d810757d32fbceb72af25d0d4a84a65203000" }, "schema_version": 1, - "source_commit": "bce0ca6c094f67c38f443e3fdb552c26e88923d4", - "source_date_epoch": 1781757156, + "source_commit": "ef6e7e3414aed0ae9b77d50748a22823529486af", + "source_date_epoch": 1781820388, "source_manifest": { "path": "quantcortex_audit_neurips2026.sources.sha256", - "sha256": "787035d389f9712575b59e4de1225e1e1e8678aa4a90ade47ec7b420a368d949" + "sha256": "ffd76bc58b7b0dd3499cb934a33abd613477478b3fb1fadabb16d5b47b5cbbde" }, "tectonic_bundle": { "name": "default_bundle_v33.tar", diff --git a/paper/quantcortex_audit_anonymous.pdf b/paper/quantcortex_audit_anonymous.pdf index ff598c542d1b4ad80e289b5157dac52ce66cb09b..c0d530ed80c614ffe1e246f91a79e49bba515675 100644 GIT binary patch delta 9043 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 diff --git a/paper/quantcortex_audit_anonymous.sha256 b/paper/quantcortex_audit_anonymous.sha256 index 64eaec5..2a0a59c 100644 --- a/paper/quantcortex_audit_anonymous.sha256 +++ b/paper/quantcortex_audit_anonymous.sha256 @@ -1 +1 @@ -e5e73d3418d320c53e5f1e0f7338103ce8647bb990b586e1f4a8c28a8e88153b quantcortex_audit_anonymous.pdf +3bf902d420224032fa11492ddb4f8d3b636972f4a3d7740e4b7aef4bbf8484ff quantcortex_audit_anonymous.pdf diff --git a/paper/quantcortex_audit_neurips2026.pdf b/paper/quantcortex_audit_neurips2026.pdf index b0b32fb0deb5cbc9923a4589155c542fe05483db..0ad1de7ed5475ef898c4bdebc4c5046efb017caa 100644 GIT binary patch delta 9669 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 HMNdWwnIjYI delta 9822 zcmV-kCZXAYxfGtd6o7;Qv;scc0XLUF+X5SZh$g`A^eG>Wdppid5{-;cxTZ z=ku$@*(T9$RBZk8f{ ziL~1q7QQw&#`o9JhfcM|b!sW<=$3mgwChc?)&0$~j)tH|^({9(ECqBach~Xz`D9fW zFIQ<^M!)R#o!;qwRHGSsUcef6!!6VEjQwE8>!CBl^1oOAJnU>GlDJOr>$kI3&CRIY zX!_05WPtVSj{c3LG!EVmf+MOMl?3ef+)MT2+Wls7YYmSen{tQ}+GEQ?*@(y1u zMFvd4BS{|pd#m~lc}EJgwU-vrg$bfd^Vuktz0rq(9*`va%>#1cmlv20Fy>hj{VQlH zBh~G@I?_Is_YBUs6lU`0cJhF-7S7c(|n9=Fzgv)w6s^8<`t15EHs6}7rC4uD^c zW~WJ1N1awTY7<@v`1B-v_Ns4;>UiRea(5b#qORja$Vxm0B+YybNRk`?na47%^X~#O z&odz(ATrGZB3F4O{w(sc+_&?^s;XmA)QFuQBJZJXKSrKNW0-cN_kcTpKLJ*WxXyD? zRF9D+(kd2pDsw*xCk)Pw-oaT*QA9&KHD+x(Gu|;RwR%*hbEo{ZiqoX3aPG2-%Z!$R zzN@W2)-q}aqPtPE|2MkVR*f?z%&hQ{zeG~Sbtdxp09<3uespJc>Obw(UfWOlEB+he zP#5p-P97o!Qi;$EI_TtoL^_*QMOFiRF4*|R65NAL;PmE(?OMr_+?6NCpdKb7xGIlE z(kH8ewz)Io=!q5b1F@oO=3>Wek6sg=iU*Kyv1*vwz_6Y>zEEnhH>1^>5=@=JQiD+7 zftuLi;0Tt%u>CZ;!;3Sm_FGAgb}()gg@nwH7D+RhN{XS@X9`DuqcYxTDrq;(U|TYl z-yZIb1~TKI%Z-4;axfVW==5Iaw3||Hmq|1<4-&Hh1^$S})6+CAWfmhk ztL!m=8FT@}aF4lvRt+HRz^6Hk`uNeWg>7X;QXX%xgJIpLR*mXxKdn3C0GUsA;4tASLipN?ScaxDqKMsgi82={!DxRyTD(?N0UP z8m@~!yP-eHwV8;eOfq@TwOLY!h{K{#u$oIbiKD~W9qrxgr)gOCW*Pz)l<|o| z8t9Q^Gs$|f=U-p-q#)G2?pqWmbQ*U&0MT<3x*OGh6G`~`!cXmkZ$sRZkUSZNk6WwN z=`-uh+A3@KOh6qJFxF!P!9VMea~(!9CZDAMeOpScLc-e(S3wfizPTH>o_jEstm-tk zP2U>kt#(o!YWgB4Kg+rde#RK}4FE|!duc`d&ci|=oZ8PHv7IOuVAK-4=8Fj-@;J+r z5`>3;G9<3RdZpJ>2~m}8Bbu^RYn6iK(mc7YYkA!^nJCgkl%gz}Ocm92m84R(t**;; zURBq!YK!C~g_XDl(X45Nwf8{#!{~KbQuYX+Bp=yZ>@PBc<1|_m2 zyWj6OiHt)GNhnNzbhId*IE_w@lXrf=8ntl;%i@f4?krQ`sm*3Pu3&%2$ zH`dDslO^}r<aG6}&fxde9<4Wj2 zd!$LQJd<%gm(YIf7wut#mTFr=+L(8-a1Wa_96{e?Xh2ALraka*9)Xj$yw26_&tj_7H*8TUc+*2BjDgdLTEUJ z!@V+8A5ii|2;t_A-sl-Bl>3ykvU;3s&qD|!sF|oKR4UNBuL-Du{M?!Up)?J_H8}PI%^62)_;$gdBE>#U5A;2*#%=!G z4is=Sny3kNlRIVQS_9-7H0Uc8S>l32#hlN#ck^wCyz97oro_1#MPtJ&Q8So;NFYv& zBI^6Yo|)bG=A8F^&wGxHvbU#y zWHQZDA~wym)#3NKI3-+FjR z@ij$srowNoA}}f@UY)Lu-=>ICZB_(-&JCKY2v(;{H@7Kfsa1+-Wo%T!7KM6?B1{>s zShsdr=vqZU=<0PLYkxKO|0MhLGFYuij7pGlbC~NA#i;Bw@=PhM3Dk4cM9Pg~sYw(^ zO{Siw+^H9+Ur;Ynew078lv+kDrvj)I)EiVFwVDc{)=+DyFlrsOo{FG&J4!}>*;CW0 zNUD?ihb-NWw=0!1@;v!%`*8b<_CGin9KNMP=u3{X91Tn&^ToKpaTlFvry{2>oy(m6 z>JmMEBDS~!eo=-a@QZSM=R@vjd{=CYIzBdLzq;pW*Zv;l8kF{3bGl57|86?ho^H%U z8Ys#t$tR!u)6ad!_HuwCM%$8q-HbY*x~ZZLfAXE5dsU+jpqgG*l#K^sTq2$HriHU4LJsm0YiJ{M#i2AP&Mhg}I5)C1VP{Txb{?dEGkKM1W^@XU zbvM*8-_P-K%vM2MoEdiWxQaG*gN3)9nIpKJ8+qG`wO00~n0%b;bTmP`QVA(qM6~qK z<>AYg?)UqCKM403>@@QhnTS{gar&M2t33PMrUQjW#D3P=*=XURzGQb{bGmfGqbUP1;JU%{b*+li4CBX5tKv>vfW zTG=_2n1z>e(4RQC=*S6k&pEir-0~hIG;#KS#}BdgRD4_JUL^gmv$eI8ho;hs(#rjN z2cR05t0$G4dB`r^5}TmXsCUNiTvM7=4hal3*rU%ilzhVZ70 zBfEB0H-M4Zr)}0Ewk9Pxd+Yo=Z(uvjesv$qc~`MZN})r4!1D#Svv)9mM|o$5EeS1N z$6>kG145&DuztgiViTVE<%c(+1)59h3QLMh@*t04do|4|X0xfa``qUKIb;f%N?gg? zqy#$$j3D+JwtxI7cHw=>xkW2O{r%Tm`SSfsr-z0vtXYg)>(azNL3YA=T9S2^cw-b^ zGEDDi%zz?)V3eTE;5RvDfcEfVXlqBff+j5CeMkV15GEg#hY#s`8j)_K?TaJ#`?2e- z8x~7VwV@K~nI{qxaF`@9Yp@kJNP+#eBrkssZmxLWzvXhv<&z*VpDY-bk{$o*qSp|- zg5_HpN*VT=U-}zsz=!d8=!qxe$qyfXjy&-pEHx-U+S7S+Iz*D? zAq2fjTpqnFaWifIqb7b7(D!XMxE-+7z-Eh$5~fn;qiC_5{z>j+HXV5|sv-#(BA?|! zSf1TMTp#`l+o5xCti8KS0#OYa$IvY?>6AT|A+h=O?V1HV(-Z!`E5ZEAb>D#0x|5cO^`aZMPtz5Sl3-I&Y;s|xvMn5#*}lH> zc!;lyZB1s_X;e{eUJ|H5Rj;mp&t}+5`B7R`1Vk{u#nfudN?+>YJp^}s`V_kob-p`Q zyBK!*l8tZ*q#0(Y(pNMUSaOa6GjjdLi`(E49t}CScl4rgokLDY!SI zHm*l(E%nyMW9QGGICiG*_@?#z-wEcT{i9|gc18ZnOOGGr;mE<>b2_GfpT39f;di!a z@>Cjy z(l&Q~DYkHCZF^#(R-2fA*se93+uO}(^!(tl+Is(EZR}NZnK9hB+P?cv>lfosx@>oGb2O&b;F<15XoD(4jiI&{nwTFyU7}An6<6-;lAgv2@{PNpNLK;? zWy!A>W@c?mPT5jcV{$LwpK8OhD&A8169`5GY(p3NO$AJmb_0j0OfIqK`-eT!w3$S$f6?br`5?Bw_+^ z7!4g6fCCcvptiK@Fc=5CGwK@@0EnYXA)44SK9qhg;la%xfBaUP!S6hSaAsKcPoc*G`t#L5Wd|O_qx70v z8$PvGykW3h4hGm)gM+{h=7tqlX|IK7t&-4uxUcfzzAlIH;%WuFA%kcXhug{HHA17n zO0?m{q&xE{%#!)5!|*)%SqB1?AT?8a&`NJbI4 zNTcILHjbyD*ikqEu6$t?BIRRvkaJ|UUt(tg*$K07oZQ1o*Jy0?*vI)U=3Q9yVsH%g%k$ySg{2nBV}H$m>cv2RWi zzEGnT0VRkCEy`aKVpj&e%g=(MU4nmKj<-a>=jCThx{7hR^rhM4tD{Wrb;*e%YuVNf zdX}=e7&x318b0lXW2`K)&1C=IUZup%cHi&}t(3$5*Yc(tKA|nwdaufgwGr)~ZIbGl z-l)5N&S1#3w(lz1S_T`&D4*w7mV1K?L}Ne6A%o+_wt#0VN2w z5V=uX&f$L`M0Y$p#Tx-Rk+6A@i_rR3yFS}f5YKKKG{6Rwr#x5^Sd_B zZpwu!HViqJeLHzwnOK*Z5$0@Ve9Aww*Zg zZP*i~Eb^F}<%w<=&Yk3Jahu@{K4IizJjxzYTjt1*OY=0_c?jol_B;%WCLFrSyXi0) z#nXFxYPKh$1yW{Xa^^~1-8_%R$434i`!e{xp#wdDYKirMS5p4E`=cjYf`7Fv_k-M18@CZGQ z?y|f!M_I@)nM^_gXV-^lO5gw+CnJ)M!}Nh9(}-l>6Ouj5qlkapK|KH_`4*8hek5u1 z4Z8QpHrXM4@{a71eR4n!$$%V@V{$@H$r(8(7vv)e$t@X@5rG-VJ$WE8`49O*#$-aK zBq1~MmCQ*>GO{4w$anHce!R9?;DNRs`x?kKGgz_doBZIsGz`CH7{aj(XfIjczS_SW zT)pXok=%w^y3T(!>&i7PnWjsgX(P#v6nk3?Nner1*4bQTUH2fLaEn-N>$ zquL#ZOa3&+`Lx^ncu^zoG`e4`gULHPj^azl354S~OgCa0$Tq*>LFqT#ui~oL{N`?q zj)5zYa00C~oQ}xXMUq9i3pM)HY`jP}IM?6NJn7(JR&9SWg<=lOHBP4RcoOHWuZt+f z+EB#{-;+J?#19o;{B!Azm*9_|$Y*jzZs+0fOO#omi*_#dliij4okKCY9oyN;n|!+4 z1w742G##PR(fvFG^`daN$Rd*Dm&GWK=204_uH(1aPDe8iYG&-q<_!QwOncKbUfw(Q z?2D>BpZ|Y(zIS@~=5R1brU|1~oN+i`w`RYyH8ZxfW@xUgne#?#R;Iz4@kF;JpcJo# ztxT(`HJhq6cQwVISYh;a5spcif!*a+cLEl63ucthxR{Q>ONPlj`bXiv1@W%IKhGzY z!C%s~tbn>!L043Nes^(kyz^#fFxY2wonYCSV2FQFCBepD5zOGmB^ZMITk01qYhJLd zsY5e-iLr$VAJqLJYm$|{UeelL|0SHw!jj}X2Ia(TTcR#4E6B+Ma4{)Z$Pj-A{R#-( zF&9l>~#4(3d)Fz+4g?OYw$<@7q_>O~yN@4%oYN+>%yWD7=ADw3Ar#23J2dmFkoBW+7LrLgoWpk4p5V3Zow?Cs z-c`%4Fg)PimsVn}3sZMaWR;V8?(Wl;P`i6@^5N_VS6h#?lD-rtx``9`zPkvr_+@`k zos(KB-be$2UxWxqFfggG355f$qi%O>gDSSBJ^VV>esXz!et2L*Q3JB<#bU2%+`b?} z82q&YhkrWY6=*qah`kPGt|pywZv5#-ErM3EE4f1HL+|~;!DpEJ-KU12Ao;VOtbN^N zc|KU4-J5*)nT6Ihd}7M-Lf%*Pnc!E)P}9C&gK) ze6*NVyDVn5g9CpBqRvLktGO4i=U#rWVgzhvNyyRhpm%zV4r12n5HA)F{03H_h)~36 z_=2Gx4|pxK!f%YwTtuK&e0|E(*T-$DN}>)4FRA`2bldCSk=@7 zt5<=(xn}05(JeX(UiU@iZqDYHDiXU_{iD6J;(Tmc3ldVjR6(NAg^PkjfWMwwD@aHo zYI}NqNPT)atfj_)6^2!H!Kr^OxCuccZXJpAHxc=ZrKSGW`-9$YAyCjxq<%3XRU?rK zhy*v$ATJQhORuuGx){fEKc!FEHj5|LgfvHKBG zisoW>?OP(q^xn#n$e=M5RJg5b+*a9I#ajx!sYdt<)j_u){lONZ%P%p6J^{m3e!nz( zYpoKv5#k(6q@&gM`tjWzR1&7}gVt-Fm-OKW2Tlzif7SV426sB*mqEb<6PJh<1sXy& zH8wD1Ibk(qIb~*HHZWpgV`gJyWMnmBHD)w2W;S6yJT^5pFl9MmHDozuW??okVqs%u zV`OAxHDWbpG%{v3VVC3<1y_G}P!(4c$MHS;7DW)SpcJuyfEA?JP_cK64K!B7-n$}T zZ=exNRIp(0Q6WkcP3$e|#ONd@CMGkP(Wrmq4-=D__+QN1?>+qUnKQpVcguad_dd(A ztPdY-Oa8E`ppVx?>nK_zVOY<$EMLnKC;E}*^|2wjpp71M&6jr_Ub>DQ#@I7lB@vU+%;#{i3ZH7{$8>&9 zJ%S!H&m(aZj>a)K7Bg`iW--eABICs>3D+}E;LPW#XW|r`j1zywI^9q^Cy7;&(yaBIuGZI-D$HX3%IKQ4;!m_j@XL}-OlVWnk>WRxI*llD9u-jo%=%TRk#}0 z;96WKc7El|tml7jFH+}Y0dByJ%zQ_&w;j~}Pw2lyU5J}-Gj73cxK-=}FLl(XjJiU- z9e3bP+=IJu7Z!{n&lc}VPcRo$`gMr(2c&1!j6?7#ChKPH~AbKXu*_$q%*PNDgNPU9KzMD)|67tp-< zWq4LR8-CHFrQ#_{cF$H+pow{B%JH0dipw=WFP(+W|f$TlW;QH7>ZLc93!v+Ho_?MU^K?yN?e7jaSg6T2hGmD4qKpEAJQ-h z6LA(+!MfND6L1Ai$5z+_&CcEw<8UOl#&}$aEzy4$Q*jY4#%x@IIhc#p&=13~9@fW( z7>SLsANpe(Y>Vx%J*HqsG&^Q>?2KKoEB43kH~`I_6@UYA5Dvy6I23zgFAT&W?2Ub} zFV4W3I2-3+4V;Vfa6X#7&+KcXa5UD$sW=Vua49asHUH0?*DU#$O>s*01A z;;upyvNiD)XX0_KtBEstr`CSr6ufpj_w0Yu#9y3}1UESuuSs=rPOWj1(kx8^#3?)J zCg-nf5-3jjTQ|8lSd$=eDqgtBtqe_Sh;zHbO&;WGQd69Vm3LK3oNwB>M;~9%q_#Lu z-nhy4p_&AX^R%a%{P0YZI^sO@XkAyFpM$jy5$E^!T8E1BSDMzT;^VtX>u`*~2I3~; z*Glt77=_Uoi%qdPw#0Z$z$9#qZLvLez)s>55@T8a1BXd=vzJ#K1s@7FFf|G#B}Gq0 E3htpjfB*mh diff --git a/paper/quantcortex_audit_neurips2026.sha256 b/paper/quantcortex_audit_neurips2026.sha256 index 24b0609..4f8efdd 100644 --- a/paper/quantcortex_audit_neurips2026.sha256 +++ b/paper/quantcortex_audit_neurips2026.sha256 @@ -1 +1 @@ -56d6cc012ad6b180c0397ed81c8902535838b712c56a6f889a311568eecb3f42 quantcortex_audit_neurips2026.pdf +59fcd30467d449984118d746417d810757d32fbceb72af25d0d4a84a65203000 quantcortex_audit_neurips2026.pdf diff --git a/paper/quantcortex_audit_neurips2026.sources.sha256 b/paper/quantcortex_audit_neurips2026.sources.sha256 index b5ce6e9..0752c99 100644 --- a/paper/quantcortex_audit_neurips2026.sources.sha256 +++ b/paper/quantcortex_audit_neurips2026.sources.sha256 @@ -3,7 +3,7 @@ 4bb1dc333bc0b23fb706bc5755b2cef765a2757284798d6ed9d090d530b47f6e checklist.tex c0c907c664fe2629306b7c07973747b44dc1c04f9ead03ffd292719374e1f531 references.bib 0c1ad36961fcd9198dcc2558cf2793e1df39973bde8264fd701f5e7970672757 neurips_2026.sty -89cd92d665460e351d5fbd9b86ea86027cf515efd8584f6434fab1ea91bb6601 results/generated_values.tex +98611c031c54382859488367dc1f5474a283014e3db2867f8210dab49ac85f25 results/generated_values.tex 83aea7fe6e6a97b55f8fe4b00218ae11972902947ed058d8281d40cb1d6e6f3c figures/accounting_summary.pdf a2a0284f9c0687ba6ff52b4a8077189d7a2ba21b63e5e77c4287639b6bbc23b4 figures/audit_protocol.pdf de3901b50dba906bc418660a4de8983ad311a0d4ed12b946e4d12b104435e4e2 figures/bootstrap_robustness.pdf diff --git a/paper/results/generated_values.tex b/paper/results/generated_values.tex index ca2a958..cc34141 100644 --- a/paper/results/generated_values.tex +++ b/paper/results/generated_values.tex @@ -4,7 +4,7 @@ \newcommand{\PaperRequiredWarmupSessions}{274} \newcommand{\PaperBootstrapReplications}{5,000} \newcommand{\PaperInputDigest}{efb384a62157e56a0cd8065abf45c1ed07d90ec26c681e5d54d74fe4cb9c55e1} -\newcommand{\PaperSourceTreeDigest}{81187dc1c7daba3fac350f992fdc4163017176c4a68f80322dde97b588f28d60} +\newcommand{\PaperSourceTreeDigest}{044c219b82295b187b92a7044757289faf91757d276206fe6abdec5d52252e60} \newcommand{\PaperNetCAGR}{1.40\%} \newcommand{\PaperGrossCAGR}{3.17\%} \newcommand{\PaperCashCAGR}{2.50\%} diff --git a/paper/results/manifest.json b/paper/results/manifest.json index 0ef53cf..d6a84df 100644 --- a/paper/results/manifest.json +++ b/paper/results/manifest.json @@ -20,7 +20,7 @@ "results/cost_sensitivity.csv": "25b9969cf8ecdabd19e7761ad2973252c9f5b9f994b6dc147595a2a112c24d88", "results/engine_comparison.csv": "ea0322dcd2aa4a1eb3b5996045c3a4b2ed25a85684a578ee788b013b99b643cd", "results/evaluation_contract.json": "77ee05ce64622ef9ba1bfbd7dae85c4f6fd44f07db0b21feaf6b3e0e418673e7", - "results/generated_values.tex": "89cd92d665460e351d5fbd9b86ea86027cf515efd8584f6434fab1ea91bb6601", + "results/generated_values.tex": "98611c031c54382859488367dc1f5474a283014e3db2867f8210dab49ac85f25", "results/protocol_switches.csv": "20d5a0dc37e07a20c1f2772c8e9940ff6464ef1da98692edd5fdb06531bc2393", "results/return_decomposition.csv": "53a84aa9b91c92f0037e48dc09154807cbf003ccf0038f39da8406108bf709cc", "results/sharpe_uncertainty.csv": "aead873ced9b25c76c6944aa6e3ba0901ade65c784fa5cb8cc10ad1c6c01f136", @@ -240,14 +240,14 @@ "path": "results/evaluation_contract.json", "schema_version": 1 }, - "generated_at": "2026-06-18T04:32:48Z", + "generated_at": "2026-06-18T22:06:35Z", "generator": { "dependency_lock": { "path": "poetry.lock", - "sha256": "bf5c536966be29e3cafa807c954b49aa1a097bad1bbed2cc676eeec50c5881b4" + "sha256": "abce2cd132651851d81034dea085d7dbfbe5e44321f2e13997db69f46d7f080b" }, "git": { - "source_commit": "bce0ca6c094f67c38f443e3fdb552c26e88923d4", + "source_commit": "ef6e7e3414aed0ae9b77d50748a22823529486af", "worktree_clean_at_start": true }, "packages": { @@ -261,12 +261,12 @@ "path": "scripts/run_paper_experiments.py", "platform": "macOS-26.4-arm64-arm-64bit-Mach-O", "python": "3.14.4", - "script_sha256": "00ded585aaf5ca39254c84d1fa289e487b995fc439a1cebd7838f3b21060516c", + "script_sha256": "922bf3c414e0eadca5c13ee831528347dd83a0cd174efbdf15a987b511845de5", "source_tree": { - "file_count": 109, + "file_count": 110, "files": { - "poetry.lock": "bf5c536966be29e3cafa807c954b49aa1a097bad1bbed2cc676eeec50c5881b4", - "pyproject.toml": "55ee8092718433e41c5bf2bb7d400fc9501096a207c9dc6b330c40b2ed7d8311", + "poetry.lock": "abce2cd132651851d81034dea085d7dbfbe5e44321f2e13997db69f46d7f080b", + "pyproject.toml": "eaeeb454c28bf7f6d9e530002bb7e88624b56b6c3e1fcb71e6414045cb9c42a0", "quantcortex/__init__.py": "14bf1ebdacd054c3738e4704d33da6709a39206463df8b8ced5376da342c4036", "quantcortex/alpha/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "quantcortex/alpha/factors/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", @@ -290,7 +290,7 @@ "quantcortex/alpha/validation/alphalens_report.py": "8463289117add78a576e37a5b99a539be5c808fca86100e26deb29e8060aa60d", "quantcortex/alpha/validation/factor_decay.py": "9e6e049165f014db2122d9ed57415e45e48142b475dfb7221247d447d9a50397", "quantcortex/backtest/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - "quantcortex/backtest/conformance.py": "3a37ec8fe8a28bcd1ac5b3ae30214ea490c8480fb9912f405b9b83d398272121", + "quantcortex/backtest/conformance.py": "22f9b18101f0d9adcae98297e395c1ab6a90b18e411f24e7456f1d166b7df9b5", "quantcortex/backtest/costs/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "quantcortex/backtest/costs/transaction_costs.py": "48200419f37004c58df6f89041e31516d9ad98f66c22f75d11a0b9342474d5c7", "quantcortex/backtest/engines/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", @@ -371,11 +371,12 @@ "quantcortex/timing/kama.py": "ffb848ba93041af1e04f2b7896ea7a8f33ac7e5e3e53db1e44f53af111829eda", "quantcortex/timing/tsmom.py": "c78ac313268091f45e0e589067f12e07e8a340fa243b8fae2853778ef4ba8ea9", "quantcortex/timing/vix_scaler.py": "a3667424e5573fb289e63c26c69da6a68d6c943742359f0466d29b25c56e3686", - "schemas/canonical_target_tape.schema.json": "5751ed1dac67def67fa2bcc53c856b3a52e3329b75cffb9726d90a17bac40965", + "schemas/canonical_target_tape.schema.json": "4f1c0bf6d5360305d2982adea78de3f61c4bc1ebae9207cb2ba2bd4379b43d44", "schemas/evaluation_contract.schema.json": "970f24f587e669925306625d12c5a84dffd03ff5b222a59905849b2fa222784f", - "scripts/run_paper_experiments.py": "00ded585aaf5ca39254c84d1fa289e487b995fc439a1cebd7838f3b21060516c" + "scripts/release_paper_artifacts.sh": "cf3de9434ab3991598e0c8d1d2c9346fde425fdf1eb792a6941fede0c66342e9", + "scripts/run_paper_experiments.py": "922bf3c414e0eadca5c13ee831528347dd83a0cd174efbdf15a987b511845de5" }, - "sha256": "81187dc1c7daba3fac350f992fdc4163017176c4a68f80322dde97b588f28d60" + "sha256": "044c219b82295b187b92a7044757289faf91757d276206fe6abdec5d52252e60" }, "threadpools": [ {