From b25594acb162cf5cfce35683785f6bd567ff5c8d Mon Sep 17 00:00:00 2001 From: Alessandro Cecchini Date: Tue, 8 Sep 2026 13:35:51 +0200 Subject: [PATCH 1/3] Plan feature, performance and ownership handoff evidence --- plans/2026-09-08-handoff-evidence.md | 81 ++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 plans/2026-09-08-handoff-evidence.md diff --git a/plans/2026-09-08-handoff-evidence.md b/plans/2026-09-08-handoff-evidence.md new file mode 100644 index 0000000..4fb6403 --- /dev/null +++ b/plans/2026-09-08-handoff-evidence.md @@ -0,0 +1,81 @@ +# Prepare the production review and ownership handoff evidence + + +Maintain this ExecPlan according to PLANS.md. This focused evidence PR follows publication gate #28 and closes independent M6/M9 documentation and measurement work. It does not authorize merge, publication, settings changes or transfer. + +## Purpose / Big Picture + + +Receiving maintainers need a concise, accurate map of what bearshape does, which behavior is tested, where the implementation lives, and which release decisions remain. Provide reproducible performance observations and a review packet tied to fixing PRs and artifact evidence, without claiming unresolved compatibility is complete. + +## Progress + + +- [x] (2026-09-08) Created codex/handoff-evidence and matching worktree from 3ee4c1d. +- [ ] Open focused draft PR and map public features to existing positive/negative tests. +- [ ] Add a small repeatable benchmark and compare exact-rc0 baseline/candidate on matched Python and hardware. +- [ ] Write support/module/audit-finding and administrative handoff evidence. +- [ ] Validate docs, hooks and current combined artifacts/hosted checks. +- [ ] Present remaining contract decisions and obtain user validation before merge. + +## Surprises & Discoveries + + +Most features already have focused positive/negative tests; wholesale test reorganization would add churn. The fixes needed new actual caller, lifecycle, converter and checker proofs. Real CuPy 14.2.0 accepts structured arrays through its converter, contradicting an old comment; 95 GPU tests now pass at both Python endpoints. Native CuPy typing and native union-alternative rollback remain separate unresolved release decisions. + +## Decision Log + + +Decision: Keep a concise feature-to-test map and link existing tests instead of duplicating them for coverage counts. Rationale: maintainers should see the contract and closing evidence directly. Date: 2026-09-08. + +Decision: Record medians and min/max for ordinary successful checks, Like conversion, Value, trees, nesting and diagnostic failures. Rationale: metadata checks, conversion and leaf traversal have different scaling. Use no noisy timing threshold in CI and make no universal speed claim. Benchmark ordinary already-correct cases while explicitly retaining the unresolved union blocker. + +Decision: Keep ownership URLs pointed at the real current repository and document exact proposed settings without changing them. Rationale: transfer and access controls require explicit owner authorization. Record PyPI publisher configuration as unverified until an authorized administrator checks it. + +## Outcomes & Retrospective + + +Evidence work pending. Production readiness remains withheld for A04 and the CuPy static support decision. The final review must distinguish implemented/validated source changes from administrative release readiness and merge approval. + +## Context and Orientation + + +Worktree /Users/ale/Code/bearshape-worktrees/handoff-evidence, branch codex/handoff-evidence. Runtime code is under src/bearshape; tests are organized by shape/dimensions/dtypes/memo/decorator/backend/tree/checker contracts. The shared workflow proves the CPU platform matrix and normally installed artifacts. GPU logs under /Users/ale/Code/bearshape-implementation-2026-09-08/evidence prove real CuPy behavior separately. + +The audit benchmark used Python 3.10.20, NumPy and exact beartype 0.23.0rc0. The rc0-compat worktree retains the old runtime with the rc0 floor; its .tox/py310-bt023rc0-cpu interpreter is suitable for a matched baseline. The current candidate uses the same interpreter generation and hardware. Verify dependency versions and source origins before comparing. + +## Plan of Work + + +Add tools/benchmark_runtime.py using timeit, statistics and existing NumPy/optree dependencies. Report interpreter/platform, package versions/origin, call counts, repeat count and medians/min/max. Use tiny and million-element native arrays, cap conversion/failure repetitions appropriately, and vary tree leaf count. Do not mutate runtime behavior or add optimization caches. + +Inspect the public-feature tests and record representative positive/negative classes in docs/maintainers/production-readiness.md. Include intended users and deployment boundaries, module map, backend/checker/platform support evidence, private beartype integration assumptions, A01–A10 closing PRs, migrations, known blockers and artifact/CI links. Add the page to documentation navigation and keep the README short. + +Record the inspected main/ruleset/environment state and exact proposed controls: reviewed required validation status, protected release tags, pypi reviewers and tag-only policy, OIDC publisher identity, docs hosting and package owners. No administrative mutation occurs. Complete the release validation-only run and preserve its artifact identity in the report when available. + +## Concrete Steps + + +Run the benchmark script with the rc0-compat Python 3.10 interpreter and the current candidate's Python 3.10 environment, using the same script and machine. Save JSON outputs under evidence/performance-*. Compare only matched workloads and versions. + +Run uv run --locked prek run -a, the manual actionlint hook, the clean docs build and tools/check_docs.py. Inspect the feature map's referenced test classes and final hosted jobs. Update this plan and the roadmap with verified counts and open decisions. + +## Validation and Acceptance + + +Every maintained feature family has identifiable positive/negative evidence, with runtime-only syntax and upstream static limitations explicit. The benchmark is reproducible and reports spread; no speed claim depends on mismatched environments. The handoff report maps all audit findings to fixes or explicit blockers, includes source/artifact identity and observed CI/GPU results, and states administrative controls accurately. User validation and unresolved contract decisions remain visible. + +## Idempotence and Recovery + + +Measurements and documentation can be repeated without changing runtime or external ownership. Use task-local files and environments; do not overwrite audit evidence. Do not merge any actual PR base, publish packages, change protections or contact maintainers. Preserve the original checkout and all focused PR review boundaries. + +## Artifacts and Notes + + +Store measurement and handoff evidence under /Users/ale/Code/bearshape-implementation-2026-09-08/evidence. The report should link public PRs and Actions runs; local logs supply detailed supporting evidence. Keep actual final candidate hashes distinct from earlier validation artifacts. + +## Interfaces and Dependencies + + +No runtime dependency or public API changes. The benchmark uses standard timing tools plus the existing optional CPU backends. The report and navigation use the existing Zensical site and corrected Markdown formatter configuration. From 6845638bfbc55095ffd9000943a3bc50756aa966 Mon Sep 17 00:00:00 2001 From: Alessandro Cecchini Date: Tue, 8 Sep 2026 13:54:46 +0200 Subject: [PATCH 2/3] Document production contract, measured costs and handoff evidence --- CHANGELOG.md | 4 + docs/maintainers/production-readiness.md | 307 +++++++++++++++++++++++ plans/2026-09-08-handoff-evidence.md | 10 +- tests/test_decorator.py | 44 +++- tools/benchmark_runtime.py | 163 ++++++++++++ tools/check_docs.py | 1 + zensical.toml | 3 + 7 files changed, 527 insertions(+), 5 deletions(-) create mode 100644 docs/maintainers/production-readiness.md create mode 100644 tools/benchmark_runtime.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 3987146..c0a1bf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,10 @@ and this project follows ### Added +- Add the production contract/test map, reproducible runtime measurements and + ownership handoff evidence with unresolved release decisions stated + explicitly. + - Add CUDA runtime evidence for CuPy conversion, native device/stream preservation and optree containers on the corrected candidate. diff --git a/docs/maintainers/production-readiness.md b/docs/maintainers/production-readiness.md new file mode 100644 index 0000000..24997fc --- /dev/null +++ b/docs/maintainers/production-readiness.md @@ -0,0 +1,307 @@ +# Production review and ownership handoff + +This is the 8 September 2026 review record for **bearshape 0.1.0rc0**. The +candidate is independently versioned from beartype and requires +`beartype>=0.23.0rc0,<0.24`. Exact `0.23.0rc0` is the required integration +target. + +**Release readiness is withheld.** Native composite-union rollback remains +incorrect in one important composition case, and the release policy for CuPy's +limited upstream static typing awaits an explicit decision. Repository and +publication protections also require configuration. The implementation PRs are +unmerged; successful validation does not authorize publication or ownership +transfer. + +## Purpose and intended users + +bearshape checks array shape, dtype and related tree constraints at Python API +boundaries using beartype. Its main users are scientific Python developers, +model and numerical-library authors, and application teams that want useful +runtime failures alongside editor/type-checker support. It complements native +NumPy, JAX, Torch and CuPy types while retaining backend operations. + +Use it around meaningful function and module boundaries. Strict checks inspect +metadata; tree checks visit leaves; Like checks may convert data and allocate or +transfer memory. It is not a static shape prover, a replacement array backend, +or an untrusted-expression sandbox. `Value` expressions are developer-authored +contracts; permitted attribute access can invoke ordinary Python behavior. + +The next evolution should close the integration boundary with beartype and +maintain the tested annotation contract. New syntax, additional checker engines +and speculative caching are not needed for this release. Zuban is outside the +selected support contract. A future addition needs an explicit plan and real +positive, negative and inference fixtures. + +## Observed support + + + +| Surface | Evidence | Boundary | +| --------------- | ----------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| CPython | Linux 3.10–3.14; macOS/Windows 3.10 and 3.14 CPU jobs | Other interpreter implementations are unverified | +| beartype | Exact 0.23.0rc0 in required lanes and normal installs | Native composite-union rollback blocks full compatibility; the metadata range is not proof for future releases | +| NumPy | Locked current and 2.2 floor; strict/Like/scalar/structured/endian/temporal tests | Extended precision depends on platform | +| JAX | Locked current and 0.5 floor; jit/vmap/grad numerical and violation cases | Checks inside JIT run while tracing; see [frameworks](../features/frameworks.md) | +| Torch | Locked current and 2.6 floor; autograd and compile cases | Compile evidence uses `backend="eager"` with outer Python validation | +| optree | Locked current and 0.14 floor; containers and structure binding | Default registry only; no custom namespace API | +| CuPy | 95 tests on H200, CUDA 12.9, CuPy 14.2.0, Python 3.10.20/3.14.3 | Other GPU/driver combinations and multiple-device behavior are unverified; native static typing is limited | +| Static checkers | pyright, mypy, ty and pyrefly positive/negative/inference batches on Python 3.10–3.14 and configured floors | Dimensions are runtime constraints; advanced syntax and native CuPy limitations are explicit | +| Minimal install | Normally installed wheel with only declared dependencies at Python endpoints | Root import loads none of NumPy/JAX/Torch/CuPy/optree; custom strict arrays work without NumPy | + + + +The locked checker versions are pyright 1.1.411, mypy 2.3.1, ty 0.0.79 and +pyrefly 1.2.0. Separate floors exercise pyright 1.1.408 and mypy 1.19, plus the +selected ty/pyrefly versions. The harness checks exact diagnostic locations and +categories, including deliberate invalid calls; a checker crash or missing tool +fails the run. See [static typing](../features/static-typing.md) for accepted +annotation forms. + +## Implementation map + + + +| Module | Responsibility and maintenance boundary | +| ------------------------------------------- | --------------------------------------------------------------------------------------- | +| `__init__.py`, `_imports.py` | Lightweight public identity, factories/symbols and explicit optional-dependency loading | +| `_dimensions.py`, `_shape.py` | Shape tokens, arithmetic and bounded parsing of permitted expressions | +| `_dtypes.py` | Dtype families, structured equality, byte order and normalization | +| `_runtime_hints.py` | Runtime hint classes and useful instance-check failure reporting | +| `_array_types.py` | Strict and Like validation, selected converters and failed-leaf rollback | +| `_memo.py` | Invocation-owned automatic state, explicit ContextVars and scope lookup | +| `_decorator.py` | Memo-only/combined decorator modes, metadata, async cleanup and explicit contexts | +| `_tree.py`, `optree.py` | Tree leaves and structures with explicit traversal backend | +| `numpy.py`, `jax.py`, `torch.py`, `cupy.py` | Backend aliases, conversion boundaries and static declarations | +| `_typing.py` | Shared static input families; no runtime backend imports | +| `claw.py` | Direct re-export of the caller-sensitive upstream import hook | + + + +Automatic memo discovery recognizes generated beartype frames and stores state +in the live frame's locals. This is an integration assumption on upstream code +generation, covered at exact rc0 across the declared CPython matrix. Explicit +contexts use ContextVars; child tasks inherit live memo references unless they +create their own context. Failed leaf checks restore their own mutations, and +diagnostic formatting restores state without retaining failed user objects. + +A leaf callback cannot observe rejection of an entire surrounding native union +alternative after a later ordinary type check fails. Neither global replay +caches nor bytecode guesses provide that missing boundary. No upstream +monkeypatch or replacement type-checker implementation was introduced. + +## Feature-to-test map + +Paths below are relative to the repository root. Each row identifies existing +positive and negative evidence, not merely annotation declarations. + + + +| Contract | Representative tests | +| ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Named/fixed/anonymous dimensions and rank | `tests/test_shape.py`: `TestNamedDim`, `TestFixedDim`, `TestAnonymous`; `tests/test_numpy.py`: `TestCrossArgConsistency` | +| Arithmetic, variadics and broadcasting | `tests/test_shape.py`: `TestSymbolicDim`, `TestVariadicDim`, `TestNamedDimEdgeCases`; `tests/test_numpy.py`: `TestBroadcastableDims`, `TestMultipleVariadicRejected` | +| Scalar and invalid token combinations | `tests/test_dimensions.py`: `TestMixedScalarRejection`, `TestScalarArithmeticRejection`, `TestBooleanDimRejection` | +| Value lookup, arithmetic and rejected expressions | `tests/test_shape.py`: `TestValueDim`, `TestSymbolicEdgeCases`; `tests/test_numpy.py`: `TestValueExpressions`; `tests/test_decorator.py`: `TestValueWithCheckDecorator` | +| Dtype families, byte order, structured fields and temporal units | `tests/test_dtypes.py`: `TestDtypeSpecMatches`, `TestByteorderMatching`, `TestShapedVoidAndStructured`, `TestDatetimeTimedelta`; `tests/test_numpy.py`: `TestStructuredDtypeIntegration`, `TestStructuredLikeDtypeEnforcement` | +| Scalar-like range/casting and boolean rejection | `tests/test_numpy.py`: `TestScalarLikeBoundariesExtended`, `TestScalarLikeCastingVariants`, `TestNumericScalarBooleanRejection` | +| Strict versus Like backend conversion | Backend `Test*ConversionContract` classes; NumPy `TestCustomConversionContract`; CuPy `TestCuPyConverterContract` | +| Return checks, nested calls and readable diagnostics | `tests/test_numpy.py`: `TestReturnViolations`, `TestNestedCalls`, `TestDiagnosticMessages`; corresponding backend tests | +| Invocation lifetime, independent checks, memory release and threads | `tests/test_memo.py`: `TestIndependentCheckLifetime`, `TestThreadSafety`, `TestFrameBasedMemo` | +| Decorator metadata, modes, async cancellation and task contexts | `tests/test_decorator.py`: `TestDecoratorEdgeCases`, `TestAsyncCheckDecorator`, `TestMemoIsolation`, `TestCheckRejectsGenerators`, `TestCallBoundaryContracts` | +| Tree leaf dtype/shape, structures and return constraints | `tests/test_tree.py`: `TestBasicTree`, `TestCrossLeafConsistency`, `TestStructureBindingFailures`, `TestMultiLevelFailures`, `TestReturnTypeFailures` | +| Real import-hook caller discovery | `tests/test_claw.py`: `test_instruments_caller_package` imports actual temporary packages/submodules with default/custom configuration | +| Framework transformations and device behavior | `tests/test_jax.py`: `TestJaxTransformations`; `tests/test_torch.py`: `TestTorchTransformations`; `tests/test_cupy.py`: `TestCuPyDeviceBehavior`, `TestCuPyTrees` | +| Optional imports and custom backend operation | `tests/test_coverage_edges.py`: `TestOptionalBackendImports`, `TestVersionExport`; `tools/smoke_minimal.py` from a minimal installed wheel | +| Static consumers and expected failures | `tests/test_typecheck.py`, `tests/typing/check_*consumers.py`, `tests/typing_negative/invalid_*calls.py` | +| Documentation and distributions | `tests/test_examples.py`, `tools/check_docs.py`, `tools/check_notebook.py`, `tools/check_distribution.py`, `tools/check_installed.py` | +| Publication identity and bypass rejection | `tests/test_release.py`: 19 cases using disposable real Git histories and event files | + + + +The endpoint and platform jobs exercise these files with the actual interpreter +and dependencies. Expected missing-CuPy and platform-precision skips are +visible; preflight checks fail if an expected CPU backend is absent. The +native-union case below remains outside the passing contract and blocks release +rather than being hidden behind an expected-failure marker. + +## Audit findings and independent review units + + + +| Finding | Change and closing evidence | Status | +| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | +| A01: exact rc0 installation | [#13](https://github.com/acecchini/bearshape/pull/13), [#25](https://github.com/acecchini/bearshape/pull/25): normal resolver installs and endpoint artifact consumers | Implemented and validated | +| A02: caller-package import hook | [#14](https://github.com/acecchini/bearshape/pull/14): direct alias and real package import violations | Implemented and validated | +| A03: stale state and retained failures | [#15](https://github.com/acecchini/bearshape/pull/15): live-frame ownership, independent failures, mutation, weak references and threads | Implemented and validated | +| A04: composite alternative rollback | Exact hosted wheel still rejects the valid example below | **Release blocker; decision pending** | +| A05: converter fallback and trust | [#16](https://github.com/acecchini/bearshape/pull/16), [#26](https://github.com/acecchini/bearshape/pull/26): actual backend converter oracles and GPU cases | Implemented and validated | +| A06: consumer typing | [#17](https://github.com/acecchini/bearshape/pull/17), [#19](https://github.com/acecchini/bearshape/pull/19), [#20](https://github.com/acecchini/bearshape/pull/20): four engines, Like inputs and structural Tree callers | CPU surfaces validated; CuPy policy pending | +| A07: incomplete distributions | [#18](https://github.com/acecchini/bearshape/pull/18), [#25](https://github.com/acecchini/bearshape/pull/25): license, typing marker, source inputs and installed consumers | Implemented and validated | +| A08: publication without validation | [#28](https://github.com/acecchini/bearshape/pull/28): immutable workflow/package identity, full gate and same artifacts | Code validated; administrative controls pending | +| A09: documentation drift | [#24](https://github.com/acecchini/bearshape/pull/24): formatter round trip, rendered structures, executed snippets/notebook | Implemented and validated | +| A10: hooks/CI/dependency drift | [#23](https://github.com/acecchini/bearshape/pull/23): locked reusable matrix, CPU resolution, four-checker pre-push and strict aggregate gate | Implemented and validated | + + + +[#21](https://github.com/acecchini/bearshape/pull/21) supplies framework/minimal +proofs. [#22](https://github.com/acecchini/bearshape/pull/22) and +[#27](https://github.com/acecchini/bearshape/pull/27) are validation aggregates +that preserve focused PR branches. Merge prerequisites and living decisions are +recorded in each PR's ExecPlan and the roadmap in +[#12](https://github.com/acecchini/bearshape/pull/12). + +### Remaining native-union decision + +This valid call is still rejected by the tested wheel with exact rc0: + +```python +import numpy as np +from beartype import beartype +from bearshape import C, N +from bearshape.numpy import F32 + + +@beartype +def choose(pair: tuple[F32[N], str] | tuple[F32[C], int], y: F32[N]) -> None: + pass + + +choose((np.ones(2, dtype=np.float32), 1), np.ones(3, dtype=np.float32)) +``` + +The first alternative binds `N=2`, then fails its `str` check. The second +alternative succeeds and should bind only `C=2`. `y` should then establish +`N=3`, but the failed alternative's binding survives and rejects it. + +The pending choice is an upstream-supported whole-alternative integration +boundary, potentially requiring a later beartype candidate, or an explicitly +accepted and enforced restriction on composition while retaining exact rc0. A +warning alone would leave silent incorrect behavior. No restriction or upstream +modification has been adopted without that decision. + +### CuPy static boundary + +CuPy 14.2.0 supplies neither `py.typed` nor usable native ndarray stubs. A real +installed-CuPy consumer reveals Unknown/Any for ordinary native operations: +strict pyright/mypy report missing typing information, while ty/pyrefly can +accept the code with Unknown. The protocol fallback proves only its small +structural surface; it does not establish native method inference. + +The pending release decision is to accept an explicit limited static CuPy +support statement alongside verified GPU runtime behavior, or require complete +upstream native typing before release. The evidence does not establish parity +with NumPy/JAX/Torch. + +## Validated artifact identity + +The actual +[validation-only release run](https://github.com/acecchini/bearshape/actions/runs/34221337124) +completed with 38 successful jobs and its sole publishing job intentionally +skipped. It ran all +runtime/checker/floor/docs/notebook/archive/minimal/installed checks against +source commit `3ee4c1d8a0c3d22f537a24b447a9d75e025a5b2d`. The `release-evidence` +artifact records: + +```text +version: 0.1.0rc0 +wheel SHA256: +c1806203da013c9eaf2482a309c686a984c0a7031a495efbd100a824536b57d2 +sdist SHA256: +e2454095144fb4bb5a08d3bd998d0f6a8bee4bc5ad81dfab763c339ca91666df +``` + +The wheel was built from the source archive and installed normally outside the +checkout at both Python endpoints. The exact same wheel also passed all 95 CuPy +GPU cases on both endpoints without skips. The consumer driver copies the +archive's own lockfile, tests and tooling, leaves package source absent, and +verifies site-packages origins and exact beartype rc0. The same artifact pair is +what the publisher would download; it does not rebuild distributions. Later +source changes produce their own source-archive hashes and require their +applicable validation before publication. + +## Performance observations + +A matched comparison uses normally installed baseline/candidate wheels on the +same macOS arm64 host, CPython 3.10.20, beartype 0.23.0rc0, NumPy 2.2.6, optree +0.19.1 and typing_extensions 4.16.0. The baseline is the rc0-floor artifact +before runtime corrections; the candidate is the hosted artifact identified +above. Five repetitions report medians and min/max, without a CI timing gate. + + + +| Workload | Baseline median (µs) | Candidate median (µs) | Candidate min–max (µs) | +| ----------------------- | -------------------- | --------------------- | ---------------------- | +| `native/3` | 0.120 | 0.120 | 0.119–0.124 | +| `strict/3` | 21.827 | 19.818 | 19.702–20.084 | +| `strict/1000000` | 21.732 | 19.730 | 19.668–19.761 | +| `explicit/3` | 14.554 | 14.042 | 13.979–14.076 | +| `like/3` | 11.356 | 10.208 | 10.177–10.223 | +| `value/3` | 16.295 | 15.770 | 15.730–15.795 | +| `nested/3` | 44.192 | 40.943 | 40.873–41.015 | +| `like-sequence/1000000` | 13950.325 | 13596.900 | 13385.142–13735.867 | +| `tree/1` | 34.232 | 32.245 | 32.095–34.930 | +| `tree/100` | 517.754 | 487.143 | 485.315–488.897 | +| `diagnostic/3` | 124.950 | 120.643 | 119.869–122.627 | + + + +Run `uv run --locked python tools/benchmark_runtime.py` to reproduce the +workloads. The script records versions, origins and per-case call counts. +Ordinary cases use 10,000 calls per repetition; expensive sequence conversions, +100-leaf trees and diagnostics use explicit smaller counts recorded in JSON. The +results are local observations, not cross-platform guarantees or a comparison +with another shape library. + +Strict native checks show little dependence on element count. Sequence +conversion scales with data size; tree validation scales with leaf count. +Profiling the strict path identifies scope/frame discovery and repeated +signature inspection as remaining costs. No new cache or optimization was +introduced while the composition boundary is unresolved. Prefer checks at +meaningful API boundaries and revisit scope work after the integration contract +is settled. + +## Migration and administrative handoff + +Users move from the prior beartype generation to the rc0 floor. Backend Like +validation now obeys the selected converter and retains the original argument; +values accepted only through a NumPy fallback may be rejected. Like/Tree static +annotations accept the tested ordinary callers while preserving useful native +types. Bare `@check` remains memo-only; combine it with `@beartype` or use +`@check(conf=...)` for checking. Public identity remains lowercase `bearshape`. + +Read-only GitHub inspection on 2026-09-08 found no protection on `main`, no +repository rulesets, and no required approval reviewers on `pypi`. That +environment currently permits `main` branches and `v*` tags, with administrator +bypass enabled. `github-pages` permits `docs`/`main` branches. These controls +were not changed. PyPI publisher configuration and package ownership have not +been verified through an authenticated package-owner interface. + +Before publication, the owner and receiving organization should approve and +apply the following concrete settings: + +1. Protect `main` with reviewed pull requests, stale-approval dismissal, blocked + force-push/deletion, and the observed `validate / Required validation` + check from the final CI workflow. Verify the exact check identity after the + PR set is merged; do not require a stale job name. +1. Protect release tags against unreviewed creation, replacement and deletion. + Add named receiving maintainers or a designated release team as the + authorized release actors. +1. Require release-review approval on `pypi`, prevent self-review, disallow + administrator bypass, and restrict deployments to approved version tags. + The publish workflow must itself run from the matching tag and commit. +1. Verify the PyPI trusted publisher's repository owner/name, workflow + `pypi.yml` and environment `pypi`. Reconfigure the identity for the + receiving organization during an explicitly authorized transfer; retain + OIDC rather than adding an upload token. +1. Confirm GitHub/PyPI ownership and recovery access with the actual receiving + maintainers. Coordinate GitHub Pages hosting, its deployment environment, + redirects and repository/package metadata. Update public URLs only after + the transfer is real, then verify them. +1. Resolve the two contract decisions above, review the focused PRs and complete + their approved merge order. Run the final immutable candidate validation, + inspect hashes and GPU evidence, then separately authorize the prerelease + publication and ownership operations. + +The repository changes make these steps reviewable; they do not perform them. +See the repository's `CONTRIBUTING.md` for the validation-only and tag-based +release procedure. diff --git a/plans/2026-09-08-handoff-evidence.md b/plans/2026-09-08-handoff-evidence.md index 4fb6403..212489f 100644 --- a/plans/2026-09-08-handoff-evidence.md +++ b/plans/2026-09-08-handoff-evidence.md @@ -12,9 +12,9 @@ Receiving maintainers need a concise, accurate map of what bearshape does, which - [x] (2026-09-08) Created codex/handoff-evidence and matching worktree from 3ee4c1d. -- [ ] Open focused draft PR and map public features to existing positive/negative tests. -- [ ] Add a small repeatable benchmark and compare exact-rc0 baseline/candidate on matched Python and hardware. -- [ ] Write support/module/audit-finding and administrative handoff evidence. +- [x] (2026-09-08) Opened #29 and mapped 17 feature families to positive/negative tests; added four default-argument/wrapped-signature cases passing at both endpoints. +- [x] (2026-09-08) Added a bounded benchmark and compared normally installed wheels with identical Python/backend versions; recorded medians/spread and profiled scope cost. +- [x] (2026-09-08) Wrote the support/module map, A01–A10 closure table, exact artifact/run evidence and concrete administrative proposal. - [ ] Validate docs, hooks and current combined artifacts/hosted checks. - [ ] Present remaining contract decisions and obtain user validation before merge. @@ -35,7 +35,7 @@ Decision: Keep ownership URLs pointed at the real current repository and documen ## Outcomes & Retrospective -Evidence work pending. Production readiness remains withheld for A04 and the CuPy static support decision. The final review must distinguish implemented/validated source changes from administrative release readiness and merge approval. +The feature map, matched measurement and handoff report are implemented. Strict native checks measured 19.8 microseconds versus 21.8 in the baseline; no material regression was observed. Scope/signature lookup remains a significant cost, with optimization deferred until the composition boundary is settled. Both exact hosted artifact GPU runs passed 95 tests; the release dry run completed 38 successful jobs and skipped publication. Documentation/hosted checks for this evidence PR remain. Production readiness remains withheld for A04 and the CuPy static support decision. The final review must distinguish implemented/validated source changes from administrative release readiness and merge approval. ## Context and Orientation @@ -79,3 +79,5 @@ Store measurement and handoff evidence under /Users/ale/Code/bearshape-implement No runtime dependency or public API changes. The benchmark uses standard timing tools plus the existing optional CPU backends. The report and navigation use the existing Zensical site and corrected Markdown formatter configuration. + +Revision note — 2026-09-08: Corrected an initial optree version mismatch by comparing two normal wheel environments with identical dependencies. Added focused boundary tests where the feature map found no direct proof; both Python endpoints pass. diff --git a/tests/test_decorator.py b/tests/test_decorator.py index acbf44b..56531c4 100644 --- a/tests/test_decorator.py +++ b/tests/test_decorator.py @@ -5,7 +5,7 @@ import numpy as np import pytest -from beartype import beartype +from beartype import BeartypeConf, beartype from beartype.roar import BeartypeCallHintParamViolation import bearshape @@ -853,3 +853,45 @@ def test_rejects_async_generator_with_conf(self) -> None: @bearshape.check(conf=BeartypeConf()) async def f(x: F32[N]) -> F32[N]: # type: ignore[misc] yield x + + +class TestCallBoundaryContracts: + @pytest.mark.parametrize("combined", [False, True]) + def test_value_uses_default_and_keyword_arguments(self, combined: bool) -> None: + from beartype.roar import BeartypeCallHintReturnViolation + + decorate = bearshape.check(conf=BeartypeConf()) if combined else beartype + + @decorate + def make(output_size: int, *, size: int = 3) -> F32[Value("size")]: # type: ignore[valid-type] + return np.ones(output_size, dtype=np.float32) + + assert make(3).shape == (3,) + assert make(5, size=5).shape == (5,) + with pytest.raises(BeartypeCallHintReturnViolation): + make(4) + with pytest.raises(BeartypeCallHintReturnViolation): + make(3, size=5) + + @pytest.mark.parametrize("combined", [False, True]) + def test_wrapped_signature_remains_checked(self, combined: bool) -> None: + import inspect + from functools import wraps + + decorate = bearshape.check(conf=BeartypeConf()) if combined else beartype + + def original(value: F32[N]) -> F32[N]: + """Identity contract preserved through a wrapper.""" + return value + + @wraps(original) + def wrapped(*args: object, **kwargs: object) -> object: + return original(*args, **kwargs) # type: ignore[arg-type] + + checked = decorate(wrapped) + value = np.ones(3, dtype=np.float32) + assert checked(value) is value + assert inspect.signature(checked) == inspect.signature(original) + assert checked.__doc__ == original.__doc__ + with pytest.raises(BeartypeCallHintParamViolation): + checked(np.ones(3, dtype=np.int32)) diff --git a/tools/benchmark_runtime.py b/tools/benchmark_runtime.py new file mode 100644 index 0000000..c6cabaa --- /dev/null +++ b/tools/benchmark_runtime.py @@ -0,0 +1,163 @@ +"""Measure representative runtime costs without imposing a timing gate.""" + +from __future__ import annotations + +import argparse +import json +import platform +import statistics +import sys +import timeit +from collections.abc import Callable +from functools import partial +from importlib.metadata import version + +import numpy as np +from beartype import BeartypeConf, beartype +from beartype.roar import BeartypeCallHintParamViolation + +import bearshape +from bearshape import N, Value, check +from bearshape.numpy import F32, F32Like +from bearshape.optree import Tree + + +def bare(value: np.ndarray) -> np.ndarray: + return value + + +@beartype +def native(value: np.ndarray) -> np.ndarray: + return value + + +@beartype +def strict(value: F32[N]) -> F32[N]: + return value + + +@check(conf=BeartypeConf()) +def explicit(value: F32[N]) -> F32[N]: + return value + + +@beartype +def like(value: F32Like[N]) -> object: + return value + + +@check(conf=BeartypeConf()) +def value_dimension(size: int, value: F32[Value("size")]) -> F32[Value("size")]: # noqa: ARG001 + """The size argument is consumed by the Value annotations.""" + return value + + +@check(conf=BeartypeConf()) +def nested(value: F32[N]) -> F32[N]: + return strict(value) + + +@beartype +def tree(value: Tree[F32[N]]) -> Tree[F32[N]]: + return value + + +def diagnostic(value: np.ndarray) -> None: + try: + strict(value) + except BeartypeCallHintParamViolation: + return + message = "Benchmark's invalid input unexpectedly passed" + raise AssertionError(message) + + +def measure( + label: str, call: Callable[[], object], *, calls: int, repeats: int +) -> dict[str, str | int | float]: + call() + samples = [ + seconds * 1_000_000 / calls + for seconds in timeit.repeat(call, number=calls, repeat=repeats) + ] + return { + "case": label, + "calls_per_repeat": calls, + "repeats": repeats, + "median_us": statistics.median(samples), + "min_us": min(samples), + "max_us": max(samples), + } + + +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--calls", type=int, default=10_000) + parser.add_argument("--repeats", type=int, default=5) + args = parser.parse_args() + if args.calls < 1 or args.repeats < 1: + parser.error("calls and repeats must be positive") + results = [] + for size in (3, 1_000_000): + array = np.ones(size, dtype=np.float32) + results.extend( + measure( + f"{function.__name__}/{size}", + partial(function, array), + calls=args.calls, + repeats=args.repeats, + ) + for function in (bare, native, strict, explicit, like, nested) + ) + results.append( + measure( + f"value/{size}", + partial(value_dimension, size, array), + calls=args.calls, + repeats=args.repeats, + ) + ) + sequence = array.tolist() + results.append( + measure( + f"like-sequence/{size}", + partial(like, sequence), + calls=min(args.calls, max(5, 5_000_000 // size)), + repeats=args.repeats, + ) + ) + invalid = np.ones(size, dtype=np.int32) + results.append( + measure( + f"diagnostic/{size}", + partial(diagnostic, invalid), + calls=min(args.calls, 1_000), + repeats=args.repeats, + ) + ) + for leaves in (1, 100): + arrays = [np.ones(3, dtype=np.float32) for _ in range(leaves)] + results.append( + measure( + f"tree/{leaves}", + partial(tree, arrays), + calls=max(1, args.calls // leaves), + repeats=args.repeats, + ) + ) + evidence = { + "python": sys.version, + "platform": platform.platform(), + "machine": platform.machine(), + "bearshape_origin": bearshape.__file__, + "versions": { + package: version(package) + for package in ("bearshape", "beartype", "numpy", "optree") + }, + "results": results, + } + json.dump(evidence, sys.stdout, indent=2) + sys.stdout.write("\n") + + +if __name__ == "__main__": + main() diff --git a/tools/check_docs.py b/tools/check_docs.py index 07db5e2..066d038 100644 --- a/tools/check_docs.py +++ b/tools/check_docs.py @@ -11,6 +11,7 @@ ROOT = Path(__file__).resolve().parents[1] TABLE_ROWS = { + "maintainers/production-readiness": [10, 12, 18, 11, 12], "api/index": [8], "api/bearshape": [5, 3], "features/claw": [3], diff --git a/zensical.toml b/zensical.toml index c3832c4..c6819f1 100644 --- a/zensical.toml +++ b/zensical.toml @@ -43,6 +43,9 @@ nav = [ { "Examples" = [ "examples/index.md", ]}, + { "Maintainers" = [ + "maintainers/production-readiness.md", + ]}, ] [project.theme] From 2cf9a477f256d064594410cdba0f1d0fa5523cbc Mon Sep 17 00:00:00 2001 From: Alessandro Cecchini Date: Tue, 8 Sep 2026 14:03:15 +0200 Subject: [PATCH 3/3] Record completed hosted validation and pending user review --- plans/2026-09-08-handoff-evidence.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plans/2026-09-08-handoff-evidence.md b/plans/2026-09-08-handoff-evidence.md index 212489f..ca353ea 100644 --- a/plans/2026-09-08-handoff-evidence.md +++ b/plans/2026-09-08-handoff-evidence.md @@ -15,7 +15,7 @@ Receiving maintainers need a concise, accurate map of what bearshape does, which - [x] (2026-09-08) Opened #29 and mapped 17 feature families to positive/negative tests; added four default-argument/wrapped-signature cases passing at both endpoints. - [x] (2026-09-08) Added a bounded benchmark and compared normally installed wheels with identical Python/backend versions; recorded medians/spread and profiled scope cost. - [x] (2026-09-08) Wrote the support/module map, A01–A10 closure table, exact artifact/run evidence and concrete administrative proposal. -- [ ] Validate docs, hooks and current combined artifacts/hosted checks. +- [x] (2026-09-08) Full hooks, rendered tables, 93 Python snippets, browser inspection and every hosted check passed at 6845638. - [ ] Present remaining contract decisions and obtain user validation before merge. ## Surprises & Discoveries @@ -35,7 +35,7 @@ Decision: Keep ownership URLs pointed at the real current repository and documen ## Outcomes & Retrospective -The feature map, matched measurement and handoff report are implemented. Strict native checks measured 19.8 microseconds versus 21.8 in the baseline; no material regression was observed. Scope/signature lookup remains a significant cost, with optimization deferred until the composition boundary is settled. Both exact hosted artifact GPU runs passed 95 tests; the release dry run completed 38 successful jobs and skipped publication. Documentation/hosted checks for this evidence PR remain. Production readiness remains withheld for A04 and the CuPy static support decision. The final review must distinguish implemented/validated source changes from administrative release readiness and merge approval. +The feature map, matched measurement and handoff report are implemented. Strict native checks measured 19.8 microseconds versus 21.8 in the baseline; no material regression was observed. Scope/signature lookup remains a significant cost, with optimization deferred until the composition boundary is settled. Both exact hosted artifact GPU runs passed 95 tests; the release dry run completed 38 successful jobs and skipped publication. Documentation, browser inspection and all hosted checks for this evidence PR pass. Production readiness remains withheld for A04 and the CuPy static support decision. The final review must distinguish implemented/validated source changes from administrative release readiness and merge approval. ## Context and Orientation @@ -81,3 +81,5 @@ Store measurement and handoff evidence under /Users/ale/Code/bearshape-implement No runtime dependency or public API changes. The benchmark uses standard timing tools plus the existing optional CPU backends. The report and navigation use the existing Zensical site and corrected Markdown formatter configuration. Revision note — 2026-09-08: Corrected an initial optree version mismatch by comparing two normal wheel environments with identical dependencies. Added focused boundary tests where the feature map found no direct proof; both Python endpoints pass. + +Revision note — 2026-09-08: Recorded the completed hosted validation and retained user merge approval as the only remaining review action for this focused scope. Program-level release decisions remain in the roadmap and handoff report.