From 75de146098de6a1fe81245f9c345ba8f9ba9f8a3 Mon Sep 17 00:00:00 2001 From: cloudQuant Date: Sun, 20 Sep 2026 10:05:56 +0800 Subject: [PATCH 1/2] build: stabilize quality gates for 0.5.1 --- .github/workflows/ci.yml | 27 ++++++++++ .github/workflows/publish.yml | 27 ++++++++++ .pre-commit-config.yaml | 17 +----- CHANGELOG.md | 22 +++++++- CITATION.cff | 2 +- README.md | 11 ++-- THIRD_PARTY_NOTICES.md | 2 +- ...-09-20-cq-2026-09-quality-stabilization.md | 54 +++++++++++++++++++ docs/upstream-provenance.md | 7 +++ mkdocs.yml | 1 + mkdocs_docs/development/changelog.md | 9 ++-- mkdocs_docs/development/releases/0.5.1.md | 35 ++++++++++++ mkdocs_docs/index.md | 5 +- pyproject.toml | 2 +- scripts/snapshot_public_api.py | 2 +- tests/packaging/test_release_candidate.py | 5 +- tests/packaging/test_release_consistency.py | 1 + tests/packaging/test_wheel_contents.py | 2 + tests/quality/test_0042_r2_planned_api.py | 15 ++++++ .../test_snapshot_public_api_source.py | 47 ++++++++++++++++ 20 files changed, 259 insertions(+), 34 deletions(-) create mode 100644 docs/plans/2026-09-20-cq-2026-09-quality-stabilization.md create mode 100644 mkdocs_docs/development/releases/0.5.1.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 49259a0b..6ec5620b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -507,6 +507,33 @@ jobs: - name: Build sdist and wheel run: python -m build + - name: Compare static root API with wheel + run: | + # This schema-v2 source scan does not import optional dependencies. + python - <<'PY' + from pathlib import Path + import subprocess + import sys + + wheels = sorted(Path("dist").glob("fincore-*.whl")) + if len(wheels) != 1: + raise SystemExit(f"expected exactly one fincore wheel in dist/, found {len(wheels)}") + subprocess.run( + [ + sys.executable, + "scripts/snapshot_public_api.py", + "--source-root", + ".", + "--wheel", + str(wheels[0]), + "--surface", + "fincore", + "--compare", + ], + check=True, + ) + PY + - name: Check dist run: twine check dist/* diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b8d10d43..9e8ed64f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -118,6 +118,33 @@ jobs: - name: Verify candidate digest run: python scripts/check_release_candidate.py --dist dist/ --manifest dist/release-manifest.json + - name: Compare static root API with candidate wheel + run: | + # This schema-v2 source scan does not import optional dependencies. + python - <<'PY' + from pathlib import Path + import subprocess + import sys + + wheels = sorted(Path("dist").glob("fincore-*.whl")) + if len(wheels) != 1: + raise SystemExit(f"expected exactly one fincore wheel in dist/, found {len(wheels)}") + subprocess.run( + [ + sys.executable, + "scripts/snapshot_public_api.py", + "--source-root", + ".", + "--wheel", + str(wheels[0]), + "--surface", + "fincore", + "--compare", + ], + check=True, + ) + PY + - name: Verify release consistency run: python scripts/check_release_consistency.py --dist dist/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 65781b64..383a1f97 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -36,20 +36,7 @@ repos: entry: mypy args: - --ignore-missing-imports - - fincore/core - - fincore/constants - - fincore/metrics - - fincore/plugin - - fincore/data - - fincore/optimization - - fincore/attribution - - fincore/report - - fincore/risk - - fincore/simulation - - fincore/utils - - fincore/viz - - fincore/empyrical.py - - fincore/tearsheets - - fincore/pyfolio.py + - fincore language: system + pass_filenames: false files: ^fincore/ diff --git a/CHANGELOG.md b/CHANGELOG.md index fe2ce062..40b7782e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,29 @@ # Changelog -All notable changes to Fincore are documented here. This changelog reports version **0.5.1.dev0**, the current development version; **0.5.0** is the latest release. +All notable changes to Fincore are documented here. This changelog reports version **0.5.1**, the current release; **0.5.0** is the preceding breaking unified-core release. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and version labels follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [0.5.1] - 2026-09-20 + +### Fixed + +- **Quality gates** — repaired the MyPy pre-commit hook so it checks the + current `fincore` package rather than paths removed by the 0.5 cutover. +- **Reproducible packaging contracts** — excluded pytest's repository-local + temporary staging directory from clean-source copies used by wheel and sdist + contract tests. +- **Static root contract** — made the source-only public-API scanner recognise + the explicitly exported `fincore.__version__` value, allowing the source and + built wheel root namespaces to be compared without importing optional + dependencies. + +### Changed + +- Release validation now treats the frozen 0.4 API snapshot as historical + compatibility evidence and validates the 0.5 root namespace through the + schema-v2 static contract instead. No public API or runtime behavior changed. ## [0.5.0] - 2026-09-01 diff --git a/CITATION.cff b/CITATION.cff index 2006af3c..97365c4a 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -6,7 +6,7 @@ authors: email: "yunjinqi@gmail.com" repository-code: "https://github.com/cloudQuant/fincore" license: MIT -version: 0.4.0.dev0 +version: 0.5.1 keywords: - quantitative-finance - performance-analytics diff --git a/README.md b/README.md index 0264d4f4..71e81449 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # fincore | Quantitative Performance & Risk Analytics

- Version 0.5.0 + Version 0.5.1 Status: Beta Python 3.11+ MIT License @@ -22,10 +22,11 @@ Pyfolio, and Alphalens, but rebuilds them as one low-coupling core rather than three package-shaped APIs. The public contract is organized by domain and each capability has one canonical implementation path. -Version **0.5.0** is a deliberately breaking release. It does **not** -provide `fincore.empyrical`, `fincore.pyfolio`, `fincore.alphalens`, flat root -metric functions, compatibility aliases, or façade classes. Update imports to -the focused domain modules described in the [migration guide](docs/MIGRATION.md). +Version **0.5.1** is a quality-maintenance release that preserves the +deliberately breaking 0.5.0 public contract. It does **not** provide +`fincore.empyrical`, `fincore.pyfolio`, `fincore.alphalens`, flat root metric +functions, compatibility aliases, or façade classes. Update imports to the +focused domain modules described in the [migration guide](docs/MIGRATION.md). | Domain | Use it for | Canonical examples | | --- | --- | --- | diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index 8ca85977..c5499bb7 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -31,7 +31,7 @@ Do not hand-edit the JSON block without updating the paired evidence in "schema_version": 2, "project": { "name": "fincore", - "version": "0.5.1.dev0", + "version": "0.5.1", "license": "MIT" }, "empyrical": { diff --git a/docs/plans/2026-09-20-cq-2026-09-quality-stabilization.md b/docs/plans/2026-09-20-cq-2026-09-quality-stabilization.md new file mode 100644 index 00000000..7053e0cd --- /dev/null +++ b/docs/plans/2026-09-20-cq-2026-09-quality-stabilization.md @@ -0,0 +1,54 @@ +# CQ-2026-09 质量稳态迭代计划 + +## 目标与边界 + +| 字段 | 结论 | +| --- | --- | +| 候选基线 | `master@2354bb5` 的隔离工作树;不使用原工作区的未提交治理改动。 | +| 目标 | 修复失效的本地质量门、隔离测试构建输入、建立 0.5 根命名空间的静态契约检查,并让发布流水线验证这些证据。 | +| 不变性 | 不修改 `fincore/` 运行时代码、数值结果、异常语义、公开 API、依赖解析或性能目标。 | +| 发布目标 | `0.5.1`(补丁版本);不重新解释 0.5.0 的破坏性 API 决策。 | +| 非目标 | 兼容层恢复、旧 0.4 API fixture 重写、清理原工作区的忽略工件、改变用户拥有的未提交文件。 | + +## 已验证的发现 + +| ID | 发现 | 状态 | 处置 | +| --- | --- | --- | --- | +| CQ-01 | pre-commit 的 MyPy 参数仍指向已删除目录,hook 退出而不是检查当前包。 | `PASS`(独立复验) | 改为一次 `mypy --ignore-missing-imports fincore`,关闭文件名自动追加。 | +| CQ-02 | 打包合同测试复制源码时会纳入仓库内 `.pytest_tmp`,可能造成递归复制/竞态。 | `PASS`(独立复验) | 两个 staging ignore 列表加入该目录,并有断言。 | +| CQ-03 | `check_quality_snapshot.py --allow-snapshot-output-commit` 在干净候选基线通过。 | `PASS` | 把它作为候选证据,不把输出型快照提交误判为陈旧。 | +| CQ-04 | `public-api-0.4.0.dev0.json` 是原子切换前的 schema-v1 历史投影;它与 0.5 源码不同是预期结果。 | `EXPECTED_HISTORICAL` | 不覆盖、不删除;发布门改用 0.5 的 schema-v2 源码/轮子契约。 | +| CQ-05 | schema-v2 扫描根包时遗漏 `__all__` 明确导出的动态 `__version__` 赋值。 | `PASS`(独立复验) | 静态解析器与回归用例已修复;不接触包运行时代码。 | +| CQ-06 | 隔离 Ruff 扫描有 37 个 C901 热点、5 个 F401 和 6 个 E402。 | `DEFERRED` | 生产源码重构必须先取得缺失的项目开发规范与逐模块行为基线。 | +| CQ-07 | `AGENTS.md` 引用的 `.joyincode/rules/backend.md`、`frontend.md` 在候选基线不存在。 | `BLOCKED` | 在规则恢复或项目负责人明确 waiver 前,不进行 `fincore/` 源码重构。 | + +## 实施编排 + +| 阶段 | 修改范围 | 验收证据 | 状态 | +| --- | --- | --- | --- | +| Q1:本地类型门 | `.pre-commit-config.yaml` | `pre-commit run mypy --all-files` 为 0 | `PASS` | +| Q2:构建输入隔离 | 两个 `tests/packaging/` 文件 | 在仓库外 `--basetemp` 的 20 个打包合同用例通过 | `PASS` | +| Q3:根 API 静态契约 | `scripts/snapshot_public_api.py`、质量/契约测试 | 当前源根和 wheel 根快照均可生成,源/轮一致 | `PASS`(本地) | +| Q4:CI/CD 绑定 | `ci.yml`、`publish.yml` 的最小必要门 | tag 版本、静态契约、构建候选和已有 release 证据均 fail-closed | `PASS`(本地;远端待运行) | +| Q5:在线文档与版本 | `pyproject.toml`、CHANGELOG、MkDocs、README、release note | `0.5.1` 一致且 `mkdocs build --strict` 通过 | `PASS`(本地;部署待运行) | +| Q6:发布验收 | 候选 commit、tag、GitHub CI/Docs/Publish 运行、PyPI 项目页 | 所有本地与远端门 `PASS`;否则明确 `NO-GO` | `PENDING` | + +## 不变性与验收矩阵 + +| 用例 | 命令/证据 | 通过条件 | +| --- | --- | --- | +| AC-01 | `conda run -n base … python -m pre_commit run mypy --all-files` | hook 实际检查 `fincore` 且 exit 0。 | +| AC-02 | `pytest tests/packaging/test_release_consistency.py tests/packaging/test_wheel_contents.py --basetemp ` | staging source 不含 `.pytest_tmp`;全部节点通过。 | +| AC-03 | `snapshot_public_api.py --source-root . --surface fincore` | 仅语法扫描即可产出 schema-v2 根契约;不导入可选依赖。 | +| AC-04 | 构建后的 `--source-root . --wheel --surface fincore --compare` | 源码与候选 wheel 的根公开契约逐字一致。 | +| AC-05 | `pytest -m 'not integration_online' --basetemp ` | 非在线回归完整通过;网络型检查单独报告。 | +| AC-06 | `python -m mkdocs build --strict`、release consistency、twine、wheel-consumer | 文档与可发布工件一致。 | +| AC-07 | tag 的 GitHub CI、Docs 与 Publish-to-PyPI 运行;PyPI `0.5.1` 元数据 | 远端证据全部成功后才宣布发布。 | + +## 风险控制与放行条件 + +1. `public-api-0.4.0.dev0.json` 仅保留为历史发现输入;不能用“更新 fixture”掩盖 0.5 公共契约变化。 +2. Q3 只允许测试工具和合同文件变化;任何 `fincore/` 源码差异立即停止并重新评审。 +3. Q4 不复制已有的完整 CI;只增加当前缺失且能从候选工件验证的 fail-closed 门。 +4. Q6 之前必须有干净候选提交、精确 tag/版本一致性、完整 CI 与文档构建成功。PyPI trusted publishing 失败时状态为 `NO-GO`,不得声称已发布。 +5. CQ-06/CQ-07 未关闭前,本迭代不把“降低复杂度”作为已完成成果;它们将作为后续、规则齐全且逐模块基线完备的源码重构迭代。 diff --git a/docs/upstream-provenance.md b/docs/upstream-provenance.md index bc60d0f1..80911825 100644 --- a/docs/upstream-provenance.md +++ b/docs/upstream-provenance.md @@ -107,3 +107,10 @@ That review has not occurred in this task. The distributed NOTICE and Apache license copy preserve observed attribution and terms. Pending review does not block CI/CD, but it also does not create a release-approval claim or legal conclusion. + +## 2026-09-20 Release-identity refresh + +Only the Fincore product version advances from the development identifier +`0.5.1.dev0` to stable `0.5.1`. Upstream commit identifiers, content digests, +observed license information, and all `pending-human-review` statuses remain +unchanged. This identity update is not a legal approval or review. diff --git a/mkdocs.yml b/mkdocs.yml index fbaf0d68..8d133e74 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -95,5 +95,6 @@ nav: - Development Guide: development/guide.md - API Stability: development/api-stability.md - Changelog: development/changelog.md + - Release notes 0.5.1: development/releases/0.5.1.md - Release notes 0.5.0: development/releases/0.5.0.md - Ecosystem: ecosystem.md diff --git a/mkdocs_docs/development/changelog.md b/mkdocs_docs/development/changelog.md index 43b995d0..f0937703 100644 --- a/mkdocs_docs/development/changelog.md +++ b/mkdocs_docs/development/changelog.md @@ -3,7 +3,8 @@ The authoritative changelog is maintained in [`CHANGELOG.md`](https://github.com/cloudQuant/fincore/blob/master/CHANGELOG.md). -The current release is **0.5.0**, a breaking unified-core release. It removes -legacy package façades and documents the canonical domain paths required by -new integrations. See the [0.5.0 release notes](releases/0.5.0.md) for the -upgrade boundary and installation guidance. +The current release is **0.5.1**, a quality-maintenance update that preserves +the 0.5 unified-core API. It makes local, packaging, and source-to-wheel +contract checks reproducible without changing the public namespace. See the +[0.5.1 release notes](releases/0.5.1.md) for the verification changes and the +[0.5.0 release notes](releases/0.5.0.md) for the breaking upgrade boundary. diff --git a/mkdocs_docs/development/releases/0.5.1.md b/mkdocs_docs/development/releases/0.5.1.md new file mode 100644 index 00000000..1e035ae2 --- /dev/null +++ b/mkdocs_docs/development/releases/0.5.1.md @@ -0,0 +1,35 @@ +# fincore 0.5.1 + +Released 2026-09-20. + +fincore 0.5.1 is a quality-maintenance release. It preserves the canonical, +breaking 0.5 public API introduced in 0.5.0: no legacy Empyrical, Pyfolio, or +Alphalens façades, flat root metric functions, compatibility aliases, or +stateful compatibility registries are restored. + +## Quality and release verification + +- The MyPy pre-commit hook checks the current package tree instead of removed + pre-0.5 directories. +- Packaging contract tests isolate pytest's temporary staging output, so a + local test run cannot accidentally alter the source copy used to construct a + wheel or sdist. +- The static API scanner now validates the explicitly exported root version + value without importing optional dependencies. Release validation compares + that source root contract with the built wheel. + +These are verification and developer-experience changes only. Financial +calculations, errors, dependencies, and the public namespace are unchanged. + +## Install + +```bash +pip install "fincore==0.5.1" +``` + +Python 3.11 or newer is required. Install only the capability extras needed by +your workflow, for example `fincore[visualization]`, `fincore[factor-analysis]`, +`fincore[report-pdf]`, or `fincore[report-xlsx]`. + +If upgrading from a pre-0.5 integration, read the +[0.5 migration guide](../../getting-started/migration.md) first. diff --git a/mkdocs_docs/index.md b/mkdocs_docs/index.md index 3be53013..25ecc0ad 100644 --- a/mkdocs_docs/index.md +++ b/mkdocs_docs/index.md @@ -1,8 +1,9 @@ # fincore 0.5 fincore is a unified Python platform for quantitative performance, portfolio, -factor, attribution, and risk analysis. Version **0.5.0** reorganises -those capabilities into focused canonical domains. +factor, attribution, and risk analysis. Version **0.5.0** reorganised those +capabilities into focused canonical domains; **0.5.1** preserves that public +contract while improving release-quality verification. This is a breaking release: upstream-shaped Empyrical, Pyfolio, and Alphalens facades, root-level metric calls, and compatibility extras are retired. Import diff --git a/pyproject.toml b/pyproject.toml index db923c43..7ddd9357 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "fincore" -version = "0.5.1.dev0" +version = "0.5.1" description = "Quantitative performance and risk analytics for Python" readme = "README.md" license = "MIT" diff --git a/scripts/snapshot_public_api.py b/scripts/snapshot_public_api.py index 7c283c4f..326cd8ad 100644 --- a/scripts/snapshot_public_api.py +++ b/scripts/snapshot_public_api.py @@ -551,7 +551,7 @@ def bindings(self, module_path: str) -> dict[str, _Binding]: if isinstance(node, (ast.Assign, ast.AnnAssign)): targets = node.targets if isinstance(node, ast.Assign) else [node.target] for target in targets: - if isinstance(target, ast.Name) and not target.id.startswith("_"): + if isinstance(target, ast.Name): bindings.setdefault(target.id, _Binding("direct", _ResolvedExport("value", None))) bindings.update(self._dynamic_bindings(module_path, tree, source)) self._bindings[module_path] = bindings diff --git a/tests/packaging/test_release_candidate.py b/tests/packaging/test_release_candidate.py index 5ae37814..ef729b75 100644 --- a/tests/packaging/test_release_candidate.py +++ b/tests/packaging/test_release_candidate.py @@ -14,8 +14,9 @@ import pytest -def test_pyproject_version_is_current_development_release() -> None: - assert _pyproject_version() == "0.5.1.dev0" +def test_pyproject_version_is_current_stable_release() -> None: + """The project metadata targets the current stable release.""" + assert _pyproject_version() == "0.5.1" def test_sha256_is_deterministic(tmp_path: Path) -> None: diff --git a/tests/packaging/test_release_consistency.py b/tests/packaging/test_release_consistency.py index 2c4711db..cb64fc4e 100644 --- a/tests/packaging/test_release_consistency.py +++ b/tests/packaging/test_release_consistency.py @@ -24,6 +24,7 @@ "dist", "__pycache__", ".pytest_cache", + ".pytest_tmp", ".mypy_cache", ".ruff_cache", ".hypothesis", diff --git a/tests/packaging/test_wheel_contents.py b/tests/packaging/test_wheel_contents.py index b5d70e67..f280ebd2 100644 --- a/tests/packaging/test_wheel_contents.py +++ b/tests/packaging/test_wheel_contents.py @@ -49,6 +49,7 @@ "dist", "__pycache__", ".pytest_cache", + ".pytest_tmp", ".mypy_cache", ".ruff_cache", ".hypothesis", @@ -179,6 +180,7 @@ def test_build_source_staging_excludes_generated_outputs(tmp_path: Path) -> None assert not (source / "build").exists() assert not (source / "dist").exists() + assert not (source / ".pytest_tmp").exists() # --------------------------------------------------------------------------- diff --git a/tests/quality/test_0042_r2_planned_api.py b/tests/quality/test_0042_r2_planned_api.py index 8d685cf9..4eb14e72 100644 --- a/tests/quality/test_0042_r2_planned_api.py +++ b/tests/quality/test_0042_r2_planned_api.py @@ -12,6 +12,8 @@ import os from pathlib import Path +from scripts.snapshot_public_api import build_static_snapshot + REPOSITORY_ROOT = Path(os.environ.get("FINCORE_0042R2_SOURCE_ROOT", Path(__file__).parents[2])).resolve() FIXTURES = REPOSITORY_ROOT / "tests" / "parity" / "fixtures" PLANNED_API = FIXTURES / "planned-api-0.5.0.json" @@ -75,6 +77,19 @@ def test_root_shape_is_namespace_only_without_flat_callables() -> None: assert root["rule"].strip() +def test_actual_source_root_matches_planned_root_shape() -> None: + planned = _load_planned() + actual = build_static_snapshot(source_root=REPOSITORY_ROOT, surfaces=("fincore",))["surfaces"]["fincore"] + + allowed_symbols = set(planned["root_shape"]["allowed_symbols"]) + assert set(actual["public_symbols"]) == allowed_symbols + + entries = actual["entries"] + assert entries["__version__"]["kind"] == "value" + namespace_symbols = allowed_symbols - {"__version__", "errors"} + assert all(entries[name]["kind"] == "module" for name in namespace_symbols) + + def test_target_namespaces_are_disjoint_from_removed_surfaces() -> None: planned = _load_planned() namespaces = planned["target_namespaces"] diff --git a/tests/quality/test_snapshot_public_api_source.py b/tests/quality/test_snapshot_public_api_source.py index 4fdd4ba1..b53c420b 100644 --- a/tests/quality/test_snapshot_public_api_source.py +++ b/tests/quality/test_snapshot_public_api_source.py @@ -176,6 +176,53 @@ def test_static_snapshot_does_not_import_optional_or_heavy_dependencies(tmp_path assert '"available"' in result.stdout +def test_static_snapshot_resolves_explicitly_exported_value_from_call(tmp_path: Path) -> None: + """A statically exported private assignment is included without executing it.""" + + source_root = tmp_path / "source" + _write_package(source_root, '__all__ = ["__version__"]\n__version__ = resolve_version()\n') + output = tmp_path / "snapshot.json" + + result = _run_snapshot( + "--source-root", + str(source_root), + "--surface", + "fincore", + "--output", + str(output), + cwd=tmp_path, + ) + + assert result.returncode == 0, result.stderr + snapshot = json.loads(output.read_text(encoding="utf-8")) + assert snapshot["schema_version"] == 2 + assert snapshot["surfaces"]["fincore"]["entries"]["__version__"] == { + "kind": "value", + "public_path": "fincore.__version__", + } + + +def test_repository_fincore_surface_is_statically_resolvable(tmp_path: Path) -> None: + """The real root namespace can be scanned without importing its dependencies.""" + + source_root = _snapshot_script().parent.parent + output = tmp_path / "fincore-snapshot.json" + + result = _run_snapshot( + "--source-root", + str(source_root), + "--surface", + "fincore", + "--output", + str(output), + cwd=tmp_path, + ) + + assert result.returncode == 0, result.stderr + snapshot = json.loads(output.read_text(encoding="utf-8")) + assert snapshot["surfaces"]["fincore"]["entries"]["__version__"]["kind"] == "value" + + def test_selected_empty_public_surface_fails_closed(tmp_path: Path) -> None: """An explicitly selected surface cannot disappear behind an empty export list.""" From cbe496935d3eb7aa60e3c06587591d9256374ef1 Mon Sep 17 00:00:00 2001 From: cloudQuant Date: Sun, 20 Sep 2026 10:21:05 +0800 Subject: [PATCH 2/2] docs(quality): refresh 0.5.1 baseline --- docs/quality/current-baseline.json | 94 +++++++++++++++--------------- docs/quality/current-baseline.md | 16 ++--- 2 files changed, 56 insertions(+), 54 deletions(-) diff --git a/docs/quality/current-baseline.json b/docs/quality/current-baseline.json index 1383f808..b80672ca 100644 --- a/docs/quality/current-baseline.json +++ b/docs/quality/current-baseline.json @@ -3,7 +3,7 @@ "docs/quality/current-baseline.json", "docs/quality/current-baseline.md" ], - "copy_manifest_sha256": "f44c243bb0503a3cfb68649037d5283e2582608ec1070a21ce5e611c24f18706", + "copy_manifest_sha256": "aae6ff55dde15aa706dcb6f49ba30a15b0d5519f8f6c3ed2eecb15187c4316ff", "environment": { "matplotlib": "3.10.9", "numpy": "1.26.4", @@ -11,7 +11,7 @@ "python": "3.11.8 | packaged by conda-forge | (main, Feb 16 2024, 20:49:36) [Clang 16.0.6 ]", "scipy": "1.17.1" }, - "generated_at": "2026-09-01T14:00:47.471138+00:00", + "generated_at": "2026-09-20T02:06:36.731364+00:00", "non_serial_counts_match": true, "outcome": "pass", "runs": [ @@ -28,14 +28,14 @@ "-m", "not slow and not integration" ], - "discovered": 1854, - "duration_seconds": 104.972, + "discovered": 1857, + "duration_seconds": 204.036, "integrity_ok": true, "label": "trusted-baseline", - "output_tail": "...... [ 64%]\ntests/test_metrics/test_perf_stats_more_coverage.py . [ 64%]\ntests/test_metrics/test_positions_metrics.py ............. [ 64%]\ntests/test_metrics/test_ratios_additional.py ................... [ 65%]\ntests/test_metrics/test_ratios_complete.py ............................. [ 67%]\n....................... [ 68%]\ntests/test_metrics/test_ratios_line_417.py ... [ 68%]\ntests/test_metrics/test_remaining_missing_coverage.py .................. [ 69%]\n [ 69%]\ntests/test_metrics/test_risk_complete.py ............................... [ 71%]\n..... [ 71%]\ntests/test_metrics/test_risk_more_coverage.py ......... [ 72%]\ntests/test_metrics/test_rolling_additional.py ............... [ 73%]\ntests/test_metrics/test_rolling_detailed.py ....... [ 73%]\ntests/test_metrics/test_round_trips_agg.py ..... [ 73%]\ntests/test_metrics/test_round_trips_extract.py ......... [ 74%]\ntests/test_metrics/test_round_trips_groupby.py .... [ 74%]\ntests/test_metrics/test_round_trips_stats.py ...... [ 74%]\ntests/test_metrics/test_stats_additional.py ................. [ 75%]\ntests/test_metrics/test_stats_hurst_coverage.py .... [ 75%]\ntests/test_metrics/test_stats_missing_lines.py ...... [ 76%]\ntests/test_metrics/test_stats_unreachable.py ... [ 76%]\ntests/test_metrics/test_timing_additional.py ....... [ 76%]\ntests/test_metrics/test_transactions_edge_cases.py ... [ 76%]\ntests/test_optimization/risk_parity_coverage/test_budget_validation.py . [ 77%]\n..... [ 77%]\ntests/test_optimization/risk_parity_coverage/test_custom_budget.py .. [ 77%]\ntests/test_optimization/risk_parity_coverage/test_edge_cases.py ....... [ 77%]\ntests/test_optimization/risk_parity_coverage/test_objective_function.py . [ 77%]\n... [ 77%]\ntests/test_optimization/risk_parity_coverage/test_output_structure.py .. [ 78%]\n... [ 78%]\ntests/test_optimization/test_edge_cases.py .......... [ 78%]\ntests/test_optimization/test_efficient_frontier.py ........ [ 79%]\ntests/test_optimization/test_frontier_full_coverage.py .............. [ 79%]\ntests/test_optimization/test_frontier_missing_coverage.py ... [ 80%]\ntests/test_optimization/test_objectives_full_coverage.py ............... [ 80%]\n..... [ 81%]\ntests/test_optimization/test_optimization.py ........................... [ 82%]\n............... [ 83%]\ntests/test_optimization/test_optimize.py ........... [ 84%]\ntests/test_optimization/test_risk_parity.py ............. [ 84%]\ntests/test_optimization/test_risk_parity_full_coverage.py .............. [ 85%]\n.......... [ 86%]\ntests/test_optimization/test_utils_full_coverage.py ............ [ 86%]\ntests/test_risk/evt/test_evt_cvar.py .............. [ 87%]\ntests/test_risk/evt/test_evt_nan.py ..... [ 87%]\ntests/test_risk/evt/test_evt_var.py ........... [ 88%]\ntests/test_risk/evt/test_extreme_risk.py .... [ 88%]\ntests/test_risk/evt/test_gev_fit.py .. [ 88%]\ntests/test_risk/evt/test_gpd_fit.py .......... [ 89%]\ntests/test_risk/evt/test_hill_estimator.py ......... [ 89%]\ntests/test_risk/risk_models/test_garch.py ............ [ 90%]\ntests/test_risk/test_backtesting.py .............. [ 91%]\ntests/test_risk/test_evt_remaining_coverage.py ...... [ 91%]\ntests/test_risk/test_garch_detailed.py ............................ [ 92%]\ntests/test_risk/test_models.py ........................ [ 94%]\ntests/test_simulation/test_base.py ..... [ 94%]\ntests/test_simulation/test_bootstrap.py ................ [ 95%]\ntests/test_simulation/test_monte_carlo.py ............. [ 96%]\ntests/test_simulation/test_paths.py ............... [ 96%]\ntests/test_simulation/test_scenarios.py ........... [ 97%]\ntests/test_viz/test_bokeh_coverage.py ......... [ 97%]\ntests/test_viz/test_html_backend.py ..... [ 98%]\ntests/test_viz/test_interactive/test_interactive.py .................... [ 99%]\n [ 99%]\ntests/test_viz/test_matplotlib_backend.py .. [ 99%]\ntests/test_viz/test_plotly_coverage.py ........... [100%]\n\n=============================== warnings summary ===============================\ntests/numerical/test_factor_multihorizon_preparation.py::test_prepares_each_horizon_without_discarding_short_horizon_rows\n /private/var/folders/7d/hnmknylj1w91h3cvq6mh3thm0000gn/T/fincore-quality-baseline-rujjt3zf/run-01-trusted-baseline/fincore/factor_analysis/portfolio.py:188: UserWarning: 'freq' not set, using business day calendar\n return positions(weights, period)\n\n-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html\n==== 1838 passed, 15 skipped, 1 deselected, 1 warning in 100.82s (0:01:40) =====\n", - "passed": 1838, + "output_tail": "...... [ 64%]\ntests/test_metrics/test_perf_stats_more_coverage.py . [ 64%]\ntests/test_metrics/test_positions_metrics.py ............. [ 64%]\ntests/test_metrics/test_ratios_additional.py ................... [ 66%]\ntests/test_metrics/test_ratios_complete.py ............................. [ 67%]\n....................... [ 68%]\ntests/test_metrics/test_ratios_line_417.py ... [ 68%]\ntests/test_metrics/test_remaining_missing_coverage.py .................. [ 69%]\n [ 69%]\ntests/test_metrics/test_risk_complete.py ............................... [ 71%]\n..... [ 71%]\ntests/test_metrics/test_risk_more_coverage.py ......... [ 72%]\ntests/test_metrics/test_rolling_additional.py ............... [ 73%]\ntests/test_metrics/test_rolling_detailed.py ....... [ 73%]\ntests/test_metrics/test_round_trips_agg.py ..... [ 73%]\ntests/test_metrics/test_round_trips_extract.py ......... [ 74%]\ntests/test_metrics/test_round_trips_groupby.py .... [ 74%]\ntests/test_metrics/test_round_trips_stats.py ...... [ 74%]\ntests/test_metrics/test_stats_additional.py ................. [ 75%]\ntests/test_metrics/test_stats_hurst_coverage.py .... [ 75%]\ntests/test_metrics/test_stats_missing_lines.py ...... [ 76%]\ntests/test_metrics/test_stats_unreachable.py ... [ 76%]\ntests/test_metrics/test_timing_additional.py ....... [ 76%]\ntests/test_metrics/test_transactions_edge_cases.py ... [ 76%]\ntests/test_optimization/risk_parity_coverage/test_budget_validation.py . [ 77%]\n..... [ 77%]\ntests/test_optimization/risk_parity_coverage/test_custom_budget.py .. [ 77%]\ntests/test_optimization/risk_parity_coverage/test_edge_cases.py ....... [ 77%]\ntests/test_optimization/risk_parity_coverage/test_objective_function.py . [ 77%]\n... [ 78%]\ntests/test_optimization/risk_parity_coverage/test_output_structure.py .. [ 78%]\n... [ 78%]\ntests/test_optimization/test_edge_cases.py .......... [ 78%]\ntests/test_optimization/test_efficient_frontier.py ........ [ 79%]\ntests/test_optimization/test_frontier_full_coverage.py .............. [ 80%]\ntests/test_optimization/test_frontier_missing_coverage.py ... [ 80%]\ntests/test_optimization/test_objectives_full_coverage.py ............... [ 80%]\n..... [ 81%]\ntests/test_optimization/test_optimization.py ........................... [ 82%]\n............... [ 83%]\ntests/test_optimization/test_optimize.py ........... [ 84%]\ntests/test_optimization/test_risk_parity.py ............. [ 84%]\ntests/test_optimization/test_risk_parity_full_coverage.py .............. [ 85%]\n.......... [ 86%]\ntests/test_optimization/test_utils_full_coverage.py ............ [ 86%]\ntests/test_risk/evt/test_evt_cvar.py .............. [ 87%]\ntests/test_risk/evt/test_evt_nan.py ..... [ 87%]\ntests/test_risk/evt/test_evt_var.py ........... [ 88%]\ntests/test_risk/evt/test_extreme_risk.py .... [ 88%]\ntests/test_risk/evt/test_gev_fit.py .. [ 88%]\ntests/test_risk/evt/test_gpd_fit.py .......... [ 89%]\ntests/test_risk/evt/test_hill_estimator.py ......... [ 89%]\ntests/test_risk/risk_models/test_garch.py ............ [ 90%]\ntests/test_risk/test_backtesting.py .............. [ 91%]\ntests/test_risk/test_evt_remaining_coverage.py ...... [ 91%]\ntests/test_risk/test_garch_detailed.py ............................ [ 92%]\ntests/test_risk/test_models.py ........................ [ 94%]\ntests/test_simulation/test_base.py ..... [ 94%]\ntests/test_simulation/test_bootstrap.py ................ [ 95%]\ntests/test_simulation/test_monte_carlo.py ............. [ 96%]\ntests/test_simulation/test_paths.py ............... [ 96%]\ntests/test_simulation/test_scenarios.py ........... [ 97%]\ntests/test_viz/test_bokeh_coverage.py ......... [ 97%]\ntests/test_viz/test_html_backend.py ..... [ 98%]\ntests/test_viz/test_interactive/test_interactive.py .................... [ 99%]\n [ 99%]\ntests/test_viz/test_matplotlib_backend.py .. [ 99%]\ntests/test_viz/test_plotly_coverage.py ........... [100%]\n\n=============================== warnings summary ===============================\ntests/numerical/test_factor_multihorizon_preparation.py::test_prepares_each_horizon_without_discarding_short_horizon_rows\n /private/var/folders/7d/hnmknylj1w91h3cvq6mh3thm0000gn/T/fincore-quality-baseline-32293h70/run-01-trusted-baseline/fincore/factor_analysis/portfolio.py:188: UserWarning: 'freq' not set, using business day calendar\n return positions(weights, period)\n\n-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html\n==== 1841 passed, 15 skipped, 1 deselected, 1 warning in 199.39s (0:03:19) =====\n", + "passed": 1841, "returncode": 0, - "selected": 1853, + "selected": 1856, "selector": "not slow and not integration", "skipped": 15, "warnings": 1, @@ -59,11 +59,11 @@ "-m", "serial" ], - "discovered": 1854, - "duration_seconds": 6.476, + "discovered": 1857, + "duration_seconds": 9.555, "integrity_ok": true, "label": "serial", - "output_tail": "============================= test session starts ==============================\nplatform darwin -- Python 3.11.8, pytest-8.4.2, pluggy-1.6.0\nbenchmark: 5.1.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)\nrootdir: /private/var/folders/7d/hnmknylj1w91h3cvq6mh3thm0000gn/T/fincore-quality-baseline-rujjt3zf/run-02-serial\nconfigfile: pyproject.toml\ntestpaths: tests\nplugins: asyncio-0.24.0, cov-6.0.0, Faker-37.5.3, anyio-4.11.0, flask-1.3.0, doctestplus-1.6.0, html-4.1.1, xdist-3.8.0, time-machine-2.16.0, timeout-2.4.0, metadata-3.1.1, rerunfailures-14.0, playwright-0.7.0, mock-3.14.1, ordering-0.6, sugar-1.1.1, benchmark-5.1.0, allure-pytest-2.15.2, langsmith-0.4.38, base-url-2.1.0, dash-2.18.2, picked-0.5.1, hypothesis-6.148.5, requests-mock-1.12.1\nasyncio: mode=Mode.STRICT, default_loop_scope=None\ncollected 1854 items / 1851 deselected / 3 selected\n\ntests/test_metrics/test_alpha_beta_line_543_596.py .. [ 66%]\ntests/test_metrics/test_alpha_beta_missing_coverage.py . [100%]\n\n====================== 3 passed, 1851 deselected in 3.93s ======================\n", + "output_tail": "============================= test session starts ==============================\nplatform darwin -- Python 3.11.8, pytest-8.4.2, pluggy-1.6.0\nbenchmark: 5.1.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)\nrootdir: /private/var/folders/7d/hnmknylj1w91h3cvq6mh3thm0000gn/T/fincore-quality-baseline-32293h70/run-02-serial\nconfigfile: pyproject.toml\ntestpaths: tests\nplugins: asyncio-0.24.0, cov-6.0.0, Faker-37.5.3, anyio-4.11.0, flask-1.3.0, doctestplus-1.6.0, html-4.1.1, xdist-3.8.0, time-machine-2.16.0, timeout-2.4.0, metadata-3.1.1, rerunfailures-14.0, playwright-0.7.0, mock-3.14.1, ordering-0.6, sugar-1.1.1, benchmark-5.1.0, allure-pytest-2.15.2, langsmith-0.4.38, base-url-2.1.0, dash-2.18.2, picked-0.5.1, hypothesis-6.148.5, requests-mock-1.12.1\nasyncio: mode=Mode.STRICT, default_loop_scope=None\ncollected 1857 items / 1854 deselected / 3 selected\n\ntests/test_metrics/test_alpha_beta_line_543_596.py .. [ 66%]\ntests/test_metrics/test_alpha_beta_missing_coverage.py . [100%]\n\n====================== 3 passed, 1854 deselected in 6.08s ======================\n", "passed": 3, "returncode": 0, "selected": 3, @@ -90,14 +90,14 @@ "-m", "not serial and not slow and not integration" ], - "discovered": 1854, - "duration_seconds": 103.155, + "discovered": 1857, + "duration_seconds": 215.449, "integrity_ok": true, "label": "non-serial-single", - "output_tail": "..... [ 64%]\ntests/test_metrics/test_perf_stats_more_coverage.py . [ 64%]\ntests/test_metrics/test_positions_metrics.py ............. [ 64%]\ntests/test_metrics/test_ratios_additional.py ................... [ 65%]\ntests/test_metrics/test_ratios_complete.py ............................. [ 67%]\n....................... [ 68%]\ntests/test_metrics/test_ratios_line_417.py ... [ 68%]\ntests/test_metrics/test_remaining_missing_coverage.py .................. [ 69%]\n [ 69%]\ntests/test_metrics/test_risk_complete.py ............................... [ 71%]\n..... [ 71%]\ntests/test_metrics/test_risk_more_coverage.py ......... [ 72%]\ntests/test_metrics/test_rolling_additional.py ............... [ 73%]\ntests/test_metrics/test_rolling_detailed.py ....... [ 73%]\ntests/test_metrics/test_round_trips_agg.py ..... [ 73%]\ntests/test_metrics/test_round_trips_extract.py ......... [ 74%]\ntests/test_metrics/test_round_trips_groupby.py .... [ 74%]\ntests/test_metrics/test_round_trips_stats.py ...... [ 74%]\ntests/test_metrics/test_stats_additional.py ................. [ 75%]\ntests/test_metrics/test_stats_hurst_coverage.py .... [ 75%]\ntests/test_metrics/test_stats_missing_lines.py ...... [ 76%]\ntests/test_metrics/test_stats_unreachable.py ... [ 76%]\ntests/test_metrics/test_timing_additional.py ....... [ 76%]\ntests/test_metrics/test_transactions_edge_cases.py ... [ 76%]\ntests/test_optimization/risk_parity_coverage/test_budget_validation.py . [ 76%]\n..... [ 77%]\ntests/test_optimization/risk_parity_coverage/test_custom_budget.py .. [ 77%]\ntests/test_optimization/risk_parity_coverage/test_edge_cases.py ....... [ 77%]\ntests/test_optimization/risk_parity_coverage/test_objective_function.py . [ 77%]\n... [ 77%]\ntests/test_optimization/risk_parity_coverage/test_output_structure.py .. [ 78%]\n... [ 78%]\ntests/test_optimization/test_edge_cases.py .......... [ 78%]\ntests/test_optimization/test_efficient_frontier.py ........ [ 79%]\ntests/test_optimization/test_frontier_full_coverage.py .............. [ 79%]\ntests/test_optimization/test_frontier_missing_coverage.py ... [ 80%]\ntests/test_optimization/test_objectives_full_coverage.py ............... [ 80%]\n..... [ 81%]\ntests/test_optimization/test_optimization.py ........................... [ 82%]\n............... [ 83%]\ntests/test_optimization/test_optimize.py ........... [ 84%]\ntests/test_optimization/test_risk_parity.py ............. [ 84%]\ntests/test_optimization/test_risk_parity_full_coverage.py .............. [ 85%]\n.......... [ 86%]\ntests/test_optimization/test_utils_full_coverage.py ............ [ 86%]\ntests/test_risk/evt/test_evt_cvar.py .............. [ 87%]\ntests/test_risk/evt/test_evt_nan.py ..... [ 87%]\ntests/test_risk/evt/test_evt_var.py ........... [ 88%]\ntests/test_risk/evt/test_extreme_risk.py .... [ 88%]\ntests/test_risk/evt/test_gev_fit.py .. [ 88%]\ntests/test_risk/evt/test_gpd_fit.py .......... [ 89%]\ntests/test_risk/evt/test_hill_estimator.py ......... [ 89%]\ntests/test_risk/risk_models/test_garch.py ............ [ 90%]\ntests/test_risk/test_backtesting.py .............. [ 91%]\ntests/test_risk/test_evt_remaining_coverage.py ...... [ 91%]\ntests/test_risk/test_garch_detailed.py ............................ [ 92%]\ntests/test_risk/test_models.py ........................ [ 94%]\ntests/test_simulation/test_base.py ..... [ 94%]\ntests/test_simulation/test_bootstrap.py ................ [ 95%]\ntests/test_simulation/test_monte_carlo.py ............. [ 96%]\ntests/test_simulation/test_paths.py ............... [ 96%]\ntests/test_simulation/test_scenarios.py ........... [ 97%]\ntests/test_viz/test_bokeh_coverage.py ......... [ 97%]\ntests/test_viz/test_html_backend.py ..... [ 98%]\ntests/test_viz/test_interactive/test_interactive.py .................... [ 99%]\n [ 99%]\ntests/test_viz/test_matplotlib_backend.py .. [ 99%]\ntests/test_viz/test_plotly_coverage.py ........... [100%]\n\n=============================== warnings summary ===============================\ntests/numerical/test_factor_multihorizon_preparation.py::test_prepares_each_horizon_without_discarding_short_horizon_rows\n /private/var/folders/7d/hnmknylj1w91h3cvq6mh3thm0000gn/T/fincore-quality-baseline-rujjt3zf/run-03-non-serial-single/fincore/factor_analysis/portfolio.py:188: UserWarning: 'freq' not set, using business day calendar\n return positions(weights, period)\n\n-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html\n===== 1835 passed, 15 skipped, 4 deselected, 1 warning in 99.12s (0:01:39) =====\n", - "passed": 1835, + "output_tail": "..... [ 64%]\ntests/test_metrics/test_perf_stats_more_coverage.py . [ 64%]\ntests/test_metrics/test_positions_metrics.py ............. [ 64%]\ntests/test_metrics/test_ratios_additional.py ................... [ 65%]\ntests/test_metrics/test_ratios_complete.py ............................. [ 67%]\n....................... [ 68%]\ntests/test_metrics/test_ratios_line_417.py ... [ 68%]\ntests/test_metrics/test_remaining_missing_coverage.py .................. [ 69%]\n [ 69%]\ntests/test_metrics/test_risk_complete.py ............................... [ 71%]\n..... [ 71%]\ntests/test_metrics/test_risk_more_coverage.py ......... [ 72%]\ntests/test_metrics/test_rolling_additional.py ............... [ 73%]\ntests/test_metrics/test_rolling_detailed.py ....... [ 73%]\ntests/test_metrics/test_round_trips_agg.py ..... [ 73%]\ntests/test_metrics/test_round_trips_extract.py ......... [ 74%]\ntests/test_metrics/test_round_trips_groupby.py .... [ 74%]\ntests/test_metrics/test_round_trips_stats.py ...... [ 74%]\ntests/test_metrics/test_stats_additional.py ................. [ 75%]\ntests/test_metrics/test_stats_hurst_coverage.py .... [ 75%]\ntests/test_metrics/test_stats_missing_lines.py ...... [ 76%]\ntests/test_metrics/test_stats_unreachable.py ... [ 76%]\ntests/test_metrics/test_timing_additional.py ....... [ 76%]\ntests/test_metrics/test_transactions_edge_cases.py ... [ 76%]\ntests/test_optimization/risk_parity_coverage/test_budget_validation.py . [ 77%]\n..... [ 77%]\ntests/test_optimization/risk_parity_coverage/test_custom_budget.py .. [ 77%]\ntests/test_optimization/risk_parity_coverage/test_edge_cases.py ....... [ 77%]\ntests/test_optimization/risk_parity_coverage/test_objective_function.py . [ 77%]\n... [ 77%]\ntests/test_optimization/risk_parity_coverage/test_output_structure.py .. [ 78%]\n... [ 78%]\ntests/test_optimization/test_edge_cases.py .......... [ 78%]\ntests/test_optimization/test_efficient_frontier.py ........ [ 79%]\ntests/test_optimization/test_frontier_full_coverage.py .............. [ 79%]\ntests/test_optimization/test_frontier_missing_coverage.py ... [ 80%]\ntests/test_optimization/test_objectives_full_coverage.py ............... [ 80%]\n..... [ 81%]\ntests/test_optimization/test_optimization.py ........................... [ 82%]\n............... [ 83%]\ntests/test_optimization/test_optimize.py ........... [ 84%]\ntests/test_optimization/test_risk_parity.py ............. [ 84%]\ntests/test_optimization/test_risk_parity_full_coverage.py .............. [ 85%]\n.......... [ 86%]\ntests/test_optimization/test_utils_full_coverage.py ............ [ 86%]\ntests/test_risk/evt/test_evt_cvar.py .............. [ 87%]\ntests/test_risk/evt/test_evt_nan.py ..... [ 87%]\ntests/test_risk/evt/test_evt_var.py ........... [ 88%]\ntests/test_risk/evt/test_extreme_risk.py .... [ 88%]\ntests/test_risk/evt/test_gev_fit.py .. [ 88%]\ntests/test_risk/evt/test_gpd_fit.py .......... [ 89%]\ntests/test_risk/evt/test_hill_estimator.py ......... [ 89%]\ntests/test_risk/risk_models/test_garch.py ............ [ 90%]\ntests/test_risk/test_backtesting.py .............. [ 91%]\ntests/test_risk/test_evt_remaining_coverage.py ...... [ 91%]\ntests/test_risk/test_garch_detailed.py ............................ [ 92%]\ntests/test_risk/test_models.py ........................ [ 94%]\ntests/test_simulation/test_base.py ..... [ 94%]\ntests/test_simulation/test_bootstrap.py ................ [ 95%]\ntests/test_simulation/test_monte_carlo.py ............. [ 96%]\ntests/test_simulation/test_paths.py ............... [ 96%]\ntests/test_simulation/test_scenarios.py ........... [ 97%]\ntests/test_viz/test_bokeh_coverage.py ......... [ 97%]\ntests/test_viz/test_html_backend.py ..... [ 98%]\ntests/test_viz/test_interactive/test_interactive.py .................... [ 99%]\n [ 99%]\ntests/test_viz/test_matplotlib_backend.py .. [ 99%]\ntests/test_viz/test_plotly_coverage.py ........... [100%]\n\n=============================== warnings summary ===============================\ntests/numerical/test_factor_multihorizon_preparation.py::test_prepares_each_horizon_without_discarding_short_horizon_rows\n /private/var/folders/7d/hnmknylj1w91h3cvq6mh3thm0000gn/T/fincore-quality-baseline-32293h70/run-03-non-serial-single/fincore/factor_analysis/portfolio.py:188: UserWarning: 'freq' not set, using business day calendar\n return positions(weights, period)\n\n-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html\n==== 1838 passed, 15 skipped, 4 deselected, 1 warning in 210.07s (0:03:30) =====\n", + "passed": 1838, "returncode": 0, - "selected": 1850, + "selected": 1853, "selector": "not serial and not slow and not integration", "skipped": 15, "warnings": 1, @@ -125,14 +125,14 @@ "auto", "--dist=loadscope" ], - "discovered": 1854, - "duration_seconds": 54.304, + "discovered": 1857, + "duration_seconds": 90.98, "integrity_ok": true, "label": "non-serial-xdist", - "output_tail": "============================= test session starts ==============================\nplatform darwin -- Python 3.11.8, pytest-8.4.2, pluggy-1.6.0\nbenchmark: 5.1.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)\nrootdir: /private/var/folders/7d/hnmknylj1w91h3cvq6mh3thm0000gn/T/fincore-quality-baseline-rujjt3zf/run-04-non-serial-xdist\nconfigfile: pyproject.toml\ntestpaths: tests\nplugins: asyncio-0.24.0, cov-6.0.0, Faker-37.5.3, anyio-4.11.0, flask-1.3.0, doctestplus-1.6.0, html-4.1.1, xdist-3.8.0, time-machine-2.16.0, timeout-2.4.0, metadata-3.1.1, rerunfailures-14.0, playwright-0.7.0, mock-3.14.1, ordering-0.6, sugar-1.1.1, benchmark-5.1.0, allure-pytest-2.15.2, langsmith-0.4.38, base-url-2.1.0, dash-2.18.2, picked-0.5.1, hypothesis-6.148.5, requests-mock-1.12.1\nasyncio: mode=Mode.STRICT, default_loop_scope=None\ncreated: 8/8 workers\n8 workers [1850 items]\n\n........................................................................ [ 3%]\n........................................................................ [ 7%]\n........................................................................ [ 11%]\n........................................................................ [ 15%]\n........................................................................ [ 19%]\n........................................................................ [ 23%]\n........................................................................ [ 27%]\n........................................................................ [ 31%]\n........................................................................ [ 35%]\n........................................................................ [ 38%]\n...............................................................s........ [ 42%]\n........................................................................ [ 46%]\n........................................................................ [ 50%]\n........................................................................ [ 54%]\n........................................................................ [ 58%]\n........................................................................ [ 62%]\n....ssssssss............................................................ [ 66%]\n........................................................................ [ 70%]\n........................................................................ [ 73%]\n........................................................................ [ 77%]\n........................................................................ [ 81%]\n........................................................................ [ 85%]\n........................................................................ [ 89%]\n...ssssss............................................................... [ 93%]\n........................................................................ [ 97%]\n.................................................. [100%]\n=============================== warnings summary ===============================\ntests/numerical/test_factor_multihorizon_preparation.py::test_prepares_each_horizon_without_discarding_short_horizon_rows\n /private/var/folders/7d/hnmknylj1w91h3cvq6mh3thm0000gn/T/fincore-quality-baseline-rujjt3zf/run-04-non-serial-xdist/fincore/factor_analysis/portfolio.py:188: UserWarning: 'freq' not set, using business day calendar\n return positions(weights, period)\n\n-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html\n================= 1835 passed, 15 skipped, 1 warning in 48.72s =================\n/Users/yunjinqi/opt/anaconda3/lib/python3.11/site-packages/pytest_benchmark/logger.py:39: PytestBenchmarkWarning: Benchmarks are automatically disabled because xdist plugin is active.Benchmarks cannot be performed reliably in a parallelized environment.\n warner(PytestBenchmarkWarning(text))\n", - "passed": 1835, + "output_tail": "============================= test session starts ==============================\nplatform darwin -- Python 3.11.8, pytest-8.4.2, pluggy-1.6.0\nbenchmark: 5.1.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)\nrootdir: /private/var/folders/7d/hnmknylj1w91h3cvq6mh3thm0000gn/T/fincore-quality-baseline-32293h70/run-04-non-serial-xdist\nconfigfile: pyproject.toml\ntestpaths: tests\nplugins: asyncio-0.24.0, cov-6.0.0, Faker-37.5.3, anyio-4.11.0, flask-1.3.0, doctestplus-1.6.0, html-4.1.1, xdist-3.8.0, time-machine-2.16.0, timeout-2.4.0, metadata-3.1.1, rerunfailures-14.0, playwright-0.7.0, mock-3.14.1, ordering-0.6, sugar-1.1.1, benchmark-5.1.0, allure-pytest-2.15.2, langsmith-0.4.38, base-url-2.1.0, dash-2.18.2, picked-0.5.1, hypothesis-6.148.5, requests-mock-1.12.1\nasyncio: mode=Mode.STRICT, default_loop_scope=None\ncreated: 8/8 workers\n8 workers [1853 items]\n\n........................................................................ [ 3%]\n........................................................................ [ 7%]\n........................................................................ [ 11%]\n........................................................................ [ 15%]\n........................................................................ [ 19%]\n........................................................................ [ 23%]\n........................................................................ [ 27%]\n........................................................................ [ 31%]\n........................................................................ [ 34%]\n........................................................................ [ 38%]\n........................................................................ [ 42%]\n............................ss.ssssss.s................................. [ 46%]\n........................................................................ [ 50%]\n........................................................................ [ 54%]\n........................................................................ [ 58%]\n........................................................................ [ 62%]\n........................................................................ [ 66%]\n........................................................................ [ 69%]\n........................................................................ [ 73%]\n........................................................................ [ 77%]\n........................................................................ [ 81%]\n........................................................................ [ 85%]\n........................................................................ [ 89%]\n.......................ssssss........................................... [ 93%]\n........................................................................ [ 97%]\n..................................................... [100%]\n=============================== warnings summary ===============================\ntests/numerical/test_factor_multihorizon_preparation.py::test_prepares_each_horizon_without_discarding_short_horizon_rows\n /private/var/folders/7d/hnmknylj1w91h3cvq6mh3thm0000gn/T/fincore-quality-baseline-32293h70/run-04-non-serial-xdist/fincore/factor_analysis/portfolio.py:188: UserWarning: 'freq' not set, using business day calendar\n return positions(weights, period)\n\n-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html\n============ 1838 passed, 15 skipped, 1 warning in 75.51s (0:01:15) ============\n/Users/yunjinqi/opt/anaconda3/lib/python3.11/site-packages/pytest_benchmark/logger.py:39: PytestBenchmarkWarning: Benchmarks are automatically disabled because xdist plugin is active.Benchmarks cannot be performed reliably in a parallelized environment.\n warner(PytestBenchmarkWarning(text))\n", + "passed": 1838, "returncode": 0, - "selected": 1850, + "selected": 1853, "selector": "not serial and not slow and not integration", "skipped": 15, "warnings": 1, @@ -156,18 +156,18 @@ "--ignore=tests/benchmarks", "-m", "not slow and not integration", - "--cov=/private/var/folders/7d/hnmknylj1w91h3cvq6mh3thm0000gn/T/fincore-quality-baseline-rujjt3zf/run-05-branch-coverage/fincore", + "--cov=/private/var/folders/7d/hnmknylj1w91h3cvq6mh3thm0000gn/T/fincore-quality-baseline-32293h70/run-05-branch-coverage/fincore", "--cov-branch", "--cov-report=term-missing" ], - "discovered": 1854, - "duration_seconds": 134.966, + "discovered": 1857, + "duration_seconds": 302.923, "integrity_ok": true, "label": "branch-coverage", - "output_tail": "ns.py 11 0 0 0 100%\nfincore/portfolio/positions.py 163 7 20 7 92% 194->200, 222->225, 269-270, 335, 463-467, 479, 529->532\nfincore/portfolio/round_trips.py 169 8 62 5 94% 96-99, 124-127, 260->262, 271->284, 303->310\nfincore/portfolio/transactions.py 149 44 40 11 66% 86-93, 128->131, 174->177, 178->181, 210-223, 253-271, 294, 301-308, 317, 354-355, 362, 373-383, 391->393, 496\nfincore/report/__init__.py 2 2 0 0 0% 8-10\nfincore/report/factor/__init__.py 2 2 0 0 0% 3-5\nfincore/report/factor/compute.py 21 5 6 2 67% 18-21, 28\nfincore/report/models.py 128 0 60 0 100%\nfincore/report/operations.py 10 0 0 0 100%\nfincore/report/portfolio/__init__.py 2 2 0 0 0% 3-5\nfincore/report/portfolio/compute.py 129 0 50 2 99% 74->76, 201->203\nfincore/report/renderers/__init__.py 2 2 0 0 0% 3-5\nfincore/report/renderers/html.py 66 3 20 3 93% 28, 30, 43\nfincore/report/renderers/interactive.py 24 0 8 0 100%\nfincore/report/renderers/matplotlib.py 37 1 10 2 94% 33, 58->60\nfincore/report/renderers/pdf.py 25 0 0 0 100%\nfincore/report/renderers/xlsx.py 27 0 6 0 100%\nfincore/report/risk.py 17 2 4 2 81% 23, 33\nfincore/report/styles.py 3 0 0 0 100%\nfincore/risk/__init__.py 2 2 0 0 0% 7-9\nfincore/risk/backtesting.py 111 1 30 1 99% 90\nfincore/risk/calibration.py 25 2 8 2 88% 35, 63\nfincore/risk/diagnostics.py 259 39 132 35 81% 70, 72, 74, 80, 82, 84, 88, 90, 92, 104-105, 111, 113, 121, 125, 129, 157, 163, 177, 179, 181, 183, 186, 197, 208, 213, 267, 339, 349, 354, 356, 358, 360, 363-364, 366, 374, 376, 378\nfincore/risk/evt.py 220 21 88 18 87% 37, 57, 61, 74, 213, 218-220, 228, 285, 290, 351-355, 430, 447, 460, 472, 537, 557, 572\nfincore/risk/garch.py 214 4 52 4 97% 157, 411, 427, 449\nfincore/risk/models.py 108 2 44 2 97% 189, 197\nfincore/risk/operations.py 14 0 0 0 100%\nfincore/risk/report.py 201 32 86 24 80% 73, 75, 82, 84, 86, 206, 210, 237-238, 240, 288, 290, 292, 294-296, 302, 325, 334, 337, 353-354, 372, 375, 382-383, 391, 400, 402, 408, 414, 418\nfincore/risk/specs.py 50 2 8 0 97% 97-98\nfincore/runtime/__init__.py 11 11 0 0 0% 8-20\nfincore/runtime/artifacts.py 76 0 32 2 98% 89->91, 113->103\nfincore/runtime/backends.py 16 0 2 0 100%\nfincore/runtime/builtins.py 22 0 8 0 100%\nfincore/runtime/catalog.py 68 1 22 1 98% 122\nfincore/runtime/data.py 70 0 32 0 100%\nfincore/runtime/engine.py 60 1 12 0 99% 61\nfincore/runtime/results.py 208 0 136 0 100%\nfincore/runtime/session.py 65 1 14 3 95% 73->79, 87->98, 97\nfincore/runtime/specs.py 59 0 22 0 100%\nfincore/runtime/time_series.py 85 22 40 12 68% 21-23, 34, 39, 51-53, 57, 63-64, 69, 70->exit, 84, 92, 102-105, 142, 145-148\nfincore/runtime/types.py 9 9 0 0 0% 3-14\nfincore/runtime/validation.py 36 0 16 0 100%\nfincore/simulation/__init__.py 2 2 0 0 0% 7-9\nfincore/simulation/base.py 53 0 10 0 100%\nfincore/simulation/bootstrap.py 57 0 20 0 100%\nfincore/simulation/monte_carlo.py 51 0 6 1 98% 197->205\nfincore/simulation/operations.py 12 0 0 0 100%\nfincore/simulation/paths.py 49 2 20 2 91% 135-136, 221->224\nfincore/simulation/scenarios.py 63 0 20 1 99% 71->70\nfincore/viz/__init__.py 2 2 0 0 0% 14-16\nfincore/viz/base.py 34 4 14 3 85% 74->78, 79-81, 84-86\nfincore/viz/contracts.py 8 0 0 0 100%\nfincore/viz/html_backend.py 89 6 18 2 93% 93->95, 124-126, 130-132, 144->147\nfincore/viz/interactive/__init__.py 9 9 2 0 0% 8-22\nfincore/viz/interactive/bokeh_backend.py 138 1 20 3 97% 358->361, 442, 492->503\nfincore/viz/interactive/plotly_backend.py 110 0 20 2 98% 450->466, 466->481\nfincore/viz/matplotlib_backend.py 76 0 20 6 94% 39->41, 58->60, 79->81, 82->92, 92->94, 110->112\n------------------------------------------------------------------------------------------\nTOTAL 11934 2468 4238 641 76%\n\n==== 1838 passed, 15 skipped, 1 deselected, 1 warning in 130.29s (0:02:10) =====\n", - "passed": 1838, + "output_tail": "ns.py 11 0 0 0 100%\nfincore/portfolio/positions.py 163 7 20 7 92% 194->200, 222->225, 269-270, 335, 463-467, 479, 529->532\nfincore/portfolio/round_trips.py 169 8 62 5 94% 96-99, 124-127, 260->262, 271->284, 303->310\nfincore/portfolio/transactions.py 149 44 40 11 66% 86-93, 128->131, 174->177, 178->181, 210-223, 253-271, 294, 301-308, 317, 354-355, 362, 373-383, 391->393, 496\nfincore/report/__init__.py 2 2 0 0 0% 8-10\nfincore/report/factor/__init__.py 2 2 0 0 0% 3-5\nfincore/report/factor/compute.py 21 5 6 2 67% 18-21, 28\nfincore/report/models.py 128 0 60 0 100%\nfincore/report/operations.py 10 0 0 0 100%\nfincore/report/portfolio/__init__.py 2 2 0 0 0% 3-5\nfincore/report/portfolio/compute.py 129 0 50 2 99% 74->76, 201->203\nfincore/report/renderers/__init__.py 2 2 0 0 0% 3-5\nfincore/report/renderers/html.py 66 3 20 3 93% 28, 30, 43\nfincore/report/renderers/interactive.py 24 0 8 0 100%\nfincore/report/renderers/matplotlib.py 37 1 10 2 94% 33, 58->60\nfincore/report/renderers/pdf.py 25 0 0 0 100%\nfincore/report/renderers/xlsx.py 27 0 6 0 100%\nfincore/report/risk.py 17 2 4 2 81% 23, 33\nfincore/report/styles.py 3 0 0 0 100%\nfincore/risk/__init__.py 2 2 0 0 0% 7-9\nfincore/risk/backtesting.py 111 1 30 1 99% 90\nfincore/risk/calibration.py 25 2 8 2 88% 35, 63\nfincore/risk/diagnostics.py 259 39 132 35 81% 70, 72, 74, 80, 82, 84, 88, 90, 92, 104-105, 111, 113, 121, 125, 129, 157, 163, 177, 179, 181, 183, 186, 197, 208, 213, 267, 339, 349, 354, 356, 358, 360, 363-364, 366, 374, 376, 378\nfincore/risk/evt.py 220 21 88 18 87% 37, 57, 61, 74, 213, 218-220, 228, 285, 290, 351-355, 430, 447, 460, 472, 537, 557, 572\nfincore/risk/garch.py 214 4 52 4 97% 157, 411, 427, 449\nfincore/risk/models.py 108 2 44 2 97% 189, 197\nfincore/risk/operations.py 14 0 0 0 100%\nfincore/risk/report.py 201 32 86 24 80% 73, 75, 82, 84, 86, 206, 210, 237-238, 240, 288, 290, 292, 294-296, 302, 325, 334, 337, 353-354, 372, 375, 382-383, 391, 400, 402, 408, 414, 418\nfincore/risk/specs.py 50 2 8 0 97% 97-98\nfincore/runtime/__init__.py 11 11 0 0 0% 8-20\nfincore/runtime/artifacts.py 76 0 32 2 98% 89->91, 113->103\nfincore/runtime/backends.py 16 0 2 0 100%\nfincore/runtime/builtins.py 22 0 8 0 100%\nfincore/runtime/catalog.py 68 1 22 1 98% 122\nfincore/runtime/data.py 70 0 32 0 100%\nfincore/runtime/engine.py 60 1 12 0 99% 61\nfincore/runtime/results.py 208 0 136 0 100%\nfincore/runtime/session.py 65 1 14 3 95% 73->79, 87->98, 97\nfincore/runtime/specs.py 59 0 22 0 100%\nfincore/runtime/time_series.py 85 22 40 12 68% 21-23, 34, 39, 51-53, 57, 63-64, 69, 70->exit, 84, 92, 102-105, 142, 145-148\nfincore/runtime/types.py 9 9 0 0 0% 3-14\nfincore/runtime/validation.py 36 0 16 0 100%\nfincore/simulation/__init__.py 2 2 0 0 0% 7-9\nfincore/simulation/base.py 53 0 10 0 100%\nfincore/simulation/bootstrap.py 57 0 20 0 100%\nfincore/simulation/monte_carlo.py 51 0 6 1 98% 197->205\nfincore/simulation/operations.py 12 0 0 0 100%\nfincore/simulation/paths.py 49 2 20 2 91% 135-136, 221->224\nfincore/simulation/scenarios.py 63 0 20 1 99% 71->70\nfincore/viz/__init__.py 2 2 0 0 0% 14-16\nfincore/viz/base.py 34 4 14 3 85% 74->78, 79-81, 84-86\nfincore/viz/contracts.py 8 0 0 0 100%\nfincore/viz/html_backend.py 89 6 18 2 93% 93->95, 124-126, 130-132, 144->147\nfincore/viz/interactive/__init__.py 9 9 2 0 0% 8-22\nfincore/viz/interactive/bokeh_backend.py 138 1 20 3 97% 358->361, 442, 492->503\nfincore/viz/interactive/plotly_backend.py 110 0 20 2 98% 450->466, 466->481\nfincore/viz/matplotlib_backend.py 76 0 20 6 94% 39->41, 58->60, 79->81, 82->92, 92->94, 110->112\n------------------------------------------------------------------------------------------\nTOTAL 11934 2468 4238 641 76%\n\n==== 1841 passed, 15 skipped, 1 deselected, 1 warning in 293.05s (0:04:53) =====\n", + "passed": 1841, "returncode": 0, - "selected": 1853, + "selected": 1856, "selector": "not slow and not integration", "skipped": 15, "warnings": 1, @@ -181,7 +181,7 @@ ], "schema_version": 1, "source": { - "commit": "fb3c9289409ac73e0fe89bdf2abff5db1cf6a4e0", + "commit": "75de146098de6a1fe81245f9c345ba8f9ba9f8a3", "dirty": false, "tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "untracked_inventory": {}, @@ -194,12 +194,12 @@ ".github/PAGES_SETUP.md": "6de153556154fbe6b2237ad68da2548d13f7d5fa020055231f09f68cb709c2e1", ".github/dependabot.yml": "e0dfdd6d9f46b5181a3f397c7c358a0bff8c6116b78795b1fe19f6f449dbf80d", ".github/pull_request_template.md": "e7f827e799592d4854090a769b43e089dd1d7c891aae7f8a32d5d229842c5c15", - ".github/workflows/ci.yml": "c4227efaa6aeaf9ff66352bafbf13f791b77bf5097a7f446c5e89f526965c68b", + ".github/workflows/ci.yml": "b8353254711238994b65228e2a69e3a402599680fa9aa3e1f6100fb8720e2b9e", ".github/workflows/docs.yml": "eef29779845306e16278dabd9221eb74ec4c0be9b4b4269f232d14a7e4059b58", - ".github/workflows/publish.yml": "e2bcc26d0a20515ad383b356d233ed42ba440a4b5f5fb489ed12115341e75ef0", + ".github/workflows/publish.yml": "e6a99313b970c22b36958d34ef4fbca644520107cff68dd246c681029e0c9713", ".github/workflows/test-priority.yml": "472d9eeba62f53ecbde24911f9f6159dbce622eafcd94b283619376e839e4e4a", ".gitignore": "84de05a29c235f5f66c11d26106478222aa95688f078b79cec063a1c207da63e", - ".pre-commit-config.yaml": "5e8d317b5defaed6677da0f9d60163c4b6092c39166a09fa3c195caea6e942a2", + ".pre-commit-config.yaml": "ced9c2806d7936ab1012f1ca8c3ab6b3d0183b7b4d95031c6f10e46a65e98b09", ".readthedocs.yaml": "e189d43e175719e522c8b9cd5460774616b0f357ef3ba2ed65376309de213f92", ".superpowers/sdd/2026-08-12-fincore-empyrical-pyfolio-convergence/progress.md": "029e68bf90a7e837b07326c2d8eef138ccb9ab6b71dca3b34b501b05656c8402", ".superpowers/sdd/2026-08-12-fincore-empyrical-pyfolio-convergence/review-eea7fb4..03d4e70.diff": "e93c2a07197c69d2da49cb816cd611d27971bf2986576afae4253718e87ea2a7", @@ -213,8 +213,8 @@ ".superpowers/sdd/2026-08-12-fincore-empyrical-pyfolio-convergence/task-7-report.md": "718325ad79b3451de1dae666c61b0b377d98bba335e30de7d2f28121f9376667", ".superpowers/sdd/2026-08-12-fincore-empyrical-pyfolio-convergence/task-8-report.md": "a636306ec2eea1ae9742ee8dde563da6390e935e35a24d61851a9a02ecc442ed", ".superpowers/sdd/2026-08-13-fincore-alphalens-integration/task-9-report.md": "2acae8452fe2d24420cd5d4e7a0554eafeab9590151559c5fe7f7013b2b971dc", - "CHANGELOG.md": "7557fef8a10943ff8836cd7598f7e4647bfa24eaf1b984bdf8fa564affec505d", - "CITATION.cff": "ededc736deb5157945c70782118948e59363dc186fd56c44bdf587dc050c3195", + "CHANGELOG.md": "4d7817bef3459ac0928f90bc7e885106f4b5aede386bb125b1eefe43a7315c1e", + "CITATION.cff": "31a7221c4ef7f48475983d8a194c296771bfd65dafaa84e26ac6dd18c4c4dc27", "CLAUDE.md": "1310585d68372a43292a003c22e5433b77cb8fe202a0a03990cc2a606e68c544", "CODE_OF_CONDUCT.md": "56a37169dc4da0de32e0d96fc15fe682d26679defdc8e96d5bad20f425421238", "CONTRIBUTING.md": "b3a5db0b2c6b9ac8ae152ccb07f861681da1bdacbe1b482643b769d040c5bd73", @@ -222,11 +222,11 @@ "LICENSE": "91678e4c2826977300350d3f428b962db60fb4b01772d28b94d7b5ae38dff4df", "MANIFEST.in": "91ed76ae35626981276ce9b11a8d228f87074866f5f969029196b60fa7a2560d", "NOTICE": "873c4b9adc3133648521bc8a0ed7768b0d6aa511040da3647ba2fcccbd25ae31", - "README.md": "724500458baac9f2e70ccf3ee74e2d3ac8f22b9ff80433d8fae26443bd95099c", + "README.md": "c8f6e1a375936e15c60a19d5dd8c8d2d82d4badb74f42030d466912d03a2b712", "SECURITY.md": "8ff10c2369e7b1736f183515ff71f759af8a0ab93fbb8c8a4679c74c59a03873", "SUPPORT.md": "50ce6554b5340e89c8490e7357e2009d75d181ac05cd30d742146b79232947d1", "THIRD_PARTY_LICENSES/Apache-2.0.txt": "cc370d11750096e1d59fb0e36e17b393150b3f1bf9b216e8482fdddb0d704698", - "THIRD_PARTY_NOTICES.md": "4dd799549e8a216ff5281888abd8354c308e43cbe4292b9635ee62774aa38a35", + "THIRD_PARTY_NOTICES.md": "92f534e9dd78669549a2a8a20409184348c3e5e70d6cb3da93844ddcfeec0882", "_bmad-output/COMPLETE-report.md": "c7cdc3ff3fb76f6087637d74d364994bff904d0404ba6226376ba759d629b0c7", "_bmad-output/FINAL-COMPLETION-REPORT.md": "45b7b2afe1cca78858e5d790dcb27a81aa43896c94ac017501485d5fad25dc52", "_bmad-output/FINAL-SUMMARY.md": "338bccdd814f6edec381219c7fbec145be30f7fcd01ab6d0b614bb04a1f9d519", @@ -293,6 +293,7 @@ "docs/plans/2026-08-17-fincore-platform-excellence.md": "4f7d6a8bbfce9dcc38f8d17c9da03d9c65f7ba62d1a262372c24d74ddf81d2f4", "docs/plans/2026-08-20-fincore-unified-analytics-platform.md": "c90f0ffe8896637061e593af1a717ed715baa6ed3cf94a37e22cc1c76868e2b2", "docs/plans/2026-08-30-fincore-0042-r2-breaking-unified-core.md": "6c30a22d14d8c2e6b22c8f986a519ed4e5f99df7544c21e8a74216d6d2daf8ae", + "docs/plans/2026-09-20-cq-2026-09-quality-stabilization.md": "3a5a5f8d6f610a8dec9c3837828bdbf9bb92e06d8bed4ec80bc81d03a72f4a91", "docs/quality/0042-r2-acceptance.md": "1202cdc12d72a7b1ca9b2db008590ccde1d29f1ee4df7ccceebce44f96abe73b", "docs/quality/0042-r2-architecture-baseline.json": "99f870c392a8bfec2af0ae76fdeb54920b7a4e67f3306ec92d0b0a78de74d746", "docs/quality/0042-r2-capability-baseline.json": "b6b7d6941d4a3e39ab3fa4e47d73026d97d1e9bdb985a6d015ea55b98084d0cb", @@ -314,7 +315,7 @@ "docs/quality/release-candidate-checklist.md": "4c3b5a7cc5cad2764d489e9316362ab2647fa27c584bcf1a94336cc74582ca3d", "docs/requirements-docs.txt": "b925c61fe99e15b5fd0118b9dd5ce23dd1730e021937477909fe1fd212344b6e", "docs/testing-guide.md": "ad7a7f47b74897d20fb3f467a27b62d7a368907d185fae2c78a319b04dadbd46", - "docs/upstream-provenance.md": "6fe8622a7687e6ffa4a4fbe8626e25966ab662e05c029da3957c371a1c644c2d", + "docs/upstream-provenance.md": "8f53327651c722e889634c65553d8f2f0d21ed1c1c38fccc379e63436197db71", "docs/user_guide.md": "29fa6e17ec38e3566a9ee183ecd151fc24e7025f902a7300a82814a0b8d9ffb7", "docs/\u5df2\u5b9e\u73b0\u51fd\u6570\u7d22\u5f15.md": "d49c4dc233bd5f0fe6a121a05636c62f030e9c34f0522f6e2e430367b7525ab8", "docs/\u6559\u7a0b/01_\u5165\u95e8_\u7b56\u7565\u7ee9\u6548\u5206\u6790.md": "4e07f4c14d9323a7285a2d95cee7ecdadc992601d8c18c9df381f8f1dd116bd2", @@ -540,7 +541,7 @@ "fincore/viz/interactive/bokeh_backend.py": "49e7cf6612f2fdae3206b91c1b6f205120e0326fe576cc64f2f64caac5f53ccd", "fincore/viz/interactive/plotly_backend.py": "b0a5540460be6d814d456a4994c95c613f212239142a69ccf019aa136368b2ed", "fincore/viz/matplotlib_backend.py": "b9a8194011fa133fde1a1b0382755b6310d3d690d4d4dad4ea07a01b16ff24ba", - "mkdocs.yml": "e199a7f7c869118b2954f55ca217778e7a86656973a6333703bf6daefdeb0a63", + "mkdocs.yml": "ecb97d3b20bbc7d5643b83ecf01b75142ce1fbf6e4a624a1b42d234e50ac3356", "mkdocs_docs/api/attribution.md": "511c5ec978d307776433ae82782f32c1d9b3485c4eb114e723e69ed47b7cf6d8", "mkdocs_docs/api/factor-analysis.md": "0039357450d4aa1c8a99f49f980b19127107eaf6e8fd8228847f0a82ebdfb732", "mkdocs_docs/api/fincore.md": "7c7a0e27e6de4489abdbfeda1bbe064fb9d5c4f131b70ddfe9d9db48a2d1a6c9", @@ -556,11 +557,12 @@ "mkdocs_docs/api/viz.md": "317691354039ed39f265bcc64715ed76b39bd46ce1480afdb2b49ffe7a871fa2", "mkdocs_docs/concepts/factor-research-protocol.md": "53ad7f99c2628ff7f18a5ff3b3c0ca5cffec31f71e1dfad8d34fb46ef736757d", "mkdocs_docs/development/api-stability.md": "767e4504ab9dbcf825d88a30384e84d53b1fe14bbb25b64ed62ffe9309261568", - "mkdocs_docs/development/changelog.md": "e29191b186a61872431974ad6bcb58362aff3915bcc7320f84bf5d8b8cd8e112", + "mkdocs_docs/development/changelog.md": "8dd053184616505a340053431b0cee334c722eecd331a7109d6376bb519e1da9", "mkdocs_docs/development/compatibility.md": "ec94d6338596f938acf76c531c61ade0e9cd802ba353ab43003dece8ca885d74", "mkdocs_docs/development/contributing.md": "90bb96664062803b0ce25a1e87101bbb6a5921297f84e40863ccc2a8ccd7cc6f", "mkdocs_docs/development/guide.md": "c6d969cddd8cd7a6b8a665c19246f335f054109cbda78b52ece4076456d474b0", "mkdocs_docs/development/releases/0.5.0.md": "8a1a3dd74961a1adfb1aa67187689a7cdc98aeb0f2c5105d845436072e35b191", + "mkdocs_docs/development/releases/0.5.1.md": "3038d199da463cc6dbd9528ca5e2d56662a3d049600eb1f148940d5a787fc960", "mkdocs_docs/ecosystem.md": "295a85cdd3d50ed6362b175394292763b9b9bc4032b7eedd0a0ab6897e76befb", "mkdocs_docs/getting-started/installation.md": "a1af545f4a557f65c67a8ff0095a17ca029a190042857922503e969aede0b804", "mkdocs_docs/getting-started/migration.md": "59993055c89d474b458b58bb316cdd0dfcc04bac90452095fd04b43e96a3556e", @@ -574,8 +576,8 @@ "mkdocs_docs/guide/reproducible-research.md": "09940692a3a76e5697c5c3bab97c6642f63fcff169c5bd10b2088e9548f69a67", "mkdocs_docs/guide/risk-validation.md": "ab1a61620028264c87356e8c9864a520645a8a3579bf49fe617798fbdf4aa22c", "mkdocs_docs/guide/visualization.md": "0a69c0d70a685c0442e5858185a6c35dd85ca29212b095292a384a4cabdb64db", - "mkdocs_docs/index.md": "96c0165d99f8ee014d5eaa30d7d879ccda915a7b5f7aa823797d0cc0d097b6fa", - "pyproject.toml": "7c7f46077fdf5837b7b8d856d60212de4f755daabe9e17074e37f0949c6ee691", + "mkdocs_docs/index.md": "37295c700440fba1fa690157a93b02f0dd0d6a3b2090f9d60f462af424baaf49", + "pyproject.toml": "13a20f630de55f1c891c848638fb1435ac6679349a107a2e622e46300da6247a", "requirements-0042-r2-acceptance.txt": "efc0b40798237b74abb390e7b50fec256379947e842c0f7408dd38270dbc2245", "requirements-test.txt": "e2b434696134b45e23851283f8b8c47d07a2f88b415b753855cde82bc684e90f", "requirements.txt": "1d9f31fe8c13c5095b4364d96888520e1b505cc638fbc3c663e267ae728a9b40", @@ -629,7 +631,7 @@ "scripts/run_round_trip_benchmarks.py": "c2fbe9c5d11f35555b8236b30094b243892398122860e31ac07e99e90cd451a9", "scripts/simple_import_test.py": "1ea674dce8ce839faf8751cd70ad9ce9a496a82f14dbaa187a5bffb476d92222", "scripts/simple_test.py": "3fe765fe1789455854293e9b5c724edf1b4e9d0e57dc78068ebf239e23c76823", - "scripts/snapshot_public_api.py": "7292af23c1ac2589d57577bc7d1f71f8e9434bb4a9b46928d6197531eff6e5cd", + "scripts/snapshot_public_api.py": "089e03fd56324e72571ca740e6ae2a07eba9fddda076b887a7e7b736447e1dbe", "scripts/test_installed_wheel.py": "19ea9e70fe50810021717d8af974d42c9332e66b135ce47dac531387c550c600", "scripts/test_python_versions_simple.bat": "efdc43ca139067b65e3a9cfd834b137a175027392fef59dd5dd8ece9269fd0db", "scripts/test_python_versions_simple.sh": "5da6f4d9cfdda166d8a7027f6574bc0e012a7514cdc2e9966bf5abe938fa1959", @@ -776,9 +778,9 @@ "tests/packaging/test_extras_union.py": "f55a88d944c246e86d2de17a51d70bc5f6b4b1579a7fa16df18be700e0740196", "tests/packaging/test_notices.py": "fafaebee4b8db54cb78cb0300ca1c8341bbf4fe6bdd623e7a816969ce8bf828c", "tests/packaging/test_optional_extras.py": "f181eeb77dedc2e9aff3441aac5e78b446a9dc76da9d936284a4eb2b6f8f3938", - "tests/packaging/test_release_candidate.py": "358e9e69c0d91d9d7023cd9e18a40f12f8ae950c350fa06a04c71915311e293d", - "tests/packaging/test_release_consistency.py": "fe9daac453f536aded9082624b4fa31ae3f8983cc677b4da6175893b21a5c01f", - "tests/packaging/test_wheel_contents.py": "ffb0860dde85a3ce9ca21db62da5df365ed3f8a372aa73072035c1293f270fd8", + "tests/packaging/test_release_candidate.py": "0247433d4a9526c776d934f432b6b5070d8c6fc3b20440e4b0240a1af5b71427", + "tests/packaging/test_release_consistency.py": "97e0e1c8edc2815117ea58ce4d2a433af50fd403d73965973e3960638aa9a74d", + "tests/packaging/test_wheel_contents.py": "88ad60ad81f95089bf02036f6ca7fc489574c4b6c67a4187c3a64f2fdecd216f", "tests/parity/fixtures/0042-r2-architecture-threshold-policy.json": "d216ff3a35026b9f9deea65a34d489fe4592cc8a5767beff6f4686b5b99e4c88", "tests/parity/fixtures/0042-r2-gate-manifest.json": "703ddefea944094ba0c4c06892bf06317e9b5c456b4e7e60fdb55bb979d03c02", "tests/parity/fixtures/0042-r2-matrix-evidence.schema.json": "61168cb4d0cb94193c1adb6091168a5cacf74390acd74159718083e5b891a44a", @@ -823,7 +825,7 @@ "tests/quality/test_0042_r2_matrix_evidence.py": "b6356cbb9280e0cdfd7c30976aec3b9029cdb951339f99379a6d87e607ea9ef6", "tests/quality/test_0042_r2_matrix_workflow.py": "1b2f4e4f535914e80f1b15817cdd470c7ead96ddc139b08a4b893c1d3ebdeffb", "tests/quality/test_0042_r2_module_disposition.py": "ef444dd73388475273232b1e1a26e432f8d75b2e4647b514a53dc8fdce8f44d7", - "tests/quality/test_0042_r2_planned_api.py": "43869d71e154fc350bfa6f49ec24e7dab0139a14cec330f1d55686abf7058cbb", + "tests/quality/test_0042_r2_planned_api.py": "fcabaccd7be79e290d561481f171231c98b76ed36d9b72ed6357a4f91ff5ff60", "tests/quality/test_0042_r2_profiling_contract.py": "df243e36e8a942e04292a52ea21fc60e019229756f8baeccb9019682458ccf09", "tests/quality/test_0042_r2_test_node_disposition.py": "cfc08bc16d6f3e664ac004ceeb61412a2b3fa801abe627c66ac371cfb3584dac", "tests/quality/test_0042_r2_tooling_source_root.py": "bbe59079b80665906ed4839dff69300e98b1d2a0c011685b309acd277f036cb0", @@ -842,7 +844,7 @@ "tests/quality/test_render_capability_inventory.py": "1ee92ec0324c49bbe3dc8809bb13e9ba3111132805b703c8b774409fbe014075", "tests/quality/test_repository_surface_disposition.py": "349343921ae332da7c3eb9bd621470c5b180c526738fcbc5849791a71c01d962", "tests/quality/test_run_0042_r2_acceptance.py": "986d0807954ac2649cc8e5bad10cc7b364c2cab52e5c1f58630db7874f551f29", - "tests/quality/test_snapshot_public_api_source.py": "7dc5b1ec890efcc22e2cba63c5d27c3c3edd451d88cee363a5b2d5b1be2e8f72", + "tests/quality/test_snapshot_public_api_source.py": "7bb64cc40ef9efad8b981b6d1b221274ad6085b7540b2a3c05bf3a7a99994a7f", "tests/quality/test_workflow_integrity.py": "843aafa24a773c3f135fdb35e07dc993fd1742898850c28183af66995162a3e3", "tests/risk/test_risk_canonical_domain.py": "e61b613dc6bde9ba40b6bd349bbe6b4f34c2da55233752eae887b293cc0a59ca", "tests/runtime/test_artifacts.py": "ebd4c9b462a3687df387b2d95d571741b2a0e34f41ae63a983fa2bb6e0f9a599", @@ -1009,6 +1011,6 @@ "tests/test_viz/test_matplotlib_backend.py": "65215188a84983aa74c900e72f70486b1b16a1830b7763f6f3579e5d6d047a38", "tests/test_viz/test_plotly_coverage.py": "6c46c55f5397073c7771d50e1f34f9f6dd86c9297e1ae0159fa37d0fd4a12aa6" }, - "included_file_manifest_sha256": "f44c243bb0503a3cfb68649037d5283e2582608ec1070a21ce5e611c24f18706" + "included_file_manifest_sha256": "aae6ff55dde15aa706dcb6f49ba30a15b0d5519f8f6c3ed2eecb15187c4316ff" } } diff --git a/docs/quality/current-baseline.md b/docs/quality/current-baseline.md index a5e10bc8..c3202bc7 100644 --- a/docs/quality/current-baseline.md +++ b/docs/quality/current-baseline.md @@ -1,14 +1,14 @@ # Current Quality Baseline -Generated: `2026-09-01T14:00:47.471138+00:00` +Generated: `2026-09-20T02:06:36.731364+00:00` ## Provenance -- Source commit: `fb3c9289409ac73e0fe89bdf2abff5db1cf6a4e0` +- Source commit: `75de146098de6a1fe81245f9c345ba8f9ba9f8a3` - Dirty state: `False` - Tracked diff SHA256: `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855` - Untracked manifest SHA256: `44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a` -- Disposable-copy manifest SHA256: `f44c243bb0503a3cfb68649037d5283e2582608ec1070a21ce5e611c24f18706` +- Disposable-copy manifest SHA256: `aae6ff55dde15aa706dcb6f49ba30a15b0d5519f8f6c3ed2eecb15187c4316ff` - Manifest exclusions: `docs/quality/current-baseline.json, docs/quality/current-baseline.md` ## Environment @@ -23,11 +23,11 @@ Generated: `2026-09-01T14:00:47.471138+00:00` | Run | Selector | Discovered | Selected | Passed | Skipped | Warnings | Duration | Exit | | --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | -| trusted-baseline | `not slow and not integration` | 1854 | 1853 | 1838 | 15 | 1 | 104.972s | 0 | -| serial | `serial` | 1854 | 3 | 3 | 0 | 0 | 6.476s | 0 | -| non-serial-single | `not serial and not slow and not integration` | 1854 | 1850 | 1835 | 15 | 1 | 103.155s | 0 | -| non-serial-xdist | `not serial and not slow and not integration` | 1854 | 1850 | 1835 | 15 | 1 | 54.304s | 0 | -| branch-coverage | `not slow and not integration` | 1854 | 1853 | 1838 | 15 | 1 | 134.966s | 0 | +| trusted-baseline | `not slow and not integration` | 1857 | 1856 | 1841 | 15 | 1 | 204.036s | 0 | +| serial | `serial` | 1857 | 3 | 3 | 0 | 0 | 9.555s | 0 | +| non-serial-single | `not serial and not slow and not integration` | 1857 | 1853 | 1838 | 15 | 1 | 215.449s | 0 | +| non-serial-xdist | `not serial and not slow and not integration` | 1857 | 1853 | 1838 | 15 | 1 | 90.980s | 0 | +| branch-coverage | `not slow and not integration` | 1857 | 1856 | 1841 | 15 | 1 | 302.923s | 0 | ## Branch Coverage