patchcraft 0.5.1__tar.gz → 0.5.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- patchcraft-0.5.3/.pre-commit-config.yaml +45 -0
- patchcraft-0.5.3/AGENTS.md +137 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/CHANGELOG.md +187 -1
- patchcraft-0.5.3/CITATION.cff +51 -0
- patchcraft-0.5.3/CODE_OF_CONDUCT.md +83 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/CONTRIBUTING.md +97 -6
- {patchcraft-0.5.1 → patchcraft-0.5.3}/MANIFEST.in +10 -3
- patchcraft-0.5.3/MAP.md +107 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/PKG-INFO +3 -3
- {patchcraft-0.5.1 → patchcraft-0.5.3}/README.md +3 -2
- {patchcraft-0.5.1 → patchcraft-0.5.3}/README.pt-BR.md +3 -2
- {patchcraft-0.5.1 → patchcraft-0.5.3}/README.pypi.md +2 -2
- patchcraft-0.5.3/SECURITY.md +66 -0
- patchcraft-0.5.3/STATUS.md +85 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/docs/ADR/0003-reversibility-classes.md +1 -0
- patchcraft-0.5.3/docs/ADR/0004-precision-and-effort-parameters.md +227 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/docs/AUXILIARY.md +4 -2
- {patchcraft-0.5.1 → patchcraft-0.5.3}/docs/FOCO-1.0.md +14 -2
- {patchcraft-0.5.1 → patchcraft-0.5.3}/docs/GUIDE.md +5 -5
- {patchcraft-0.5.1 → patchcraft-0.5.3}/docs/SCOPE.md +1 -1
- patchcraft-0.5.3/docs/STUDIES/2026-09-03-strata-conformity.md +110 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/docs/THEORY.md +7 -5
- {patchcraft-0.5.1 → patchcraft-0.5.3}/docs/USAGE.md +37 -26
- {patchcraft-0.5.1 → patchcraft-0.5.3}/pyproject.toml +4 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/src/patchcraft/_version.py +3 -3
- {patchcraft-0.5.1 → patchcraft-0.5.3}/src/patchcraft/reconstruct.py +18 -5
- {patchcraft-0.5.1 → patchcraft-0.5.3}/src/patchcraft/resize.py +12 -3
- {patchcraft-0.5.1 → patchcraft-0.5.3}/src/patchcraft/stitch.py +14 -7
- {patchcraft-0.5.1 → patchcraft-0.5.3}/src/patchcraft.egg-info/PKG-INFO +3 -3
- {patchcraft-0.5.1 → patchcraft-0.5.3}/src/patchcraft.egg-info/SOURCES.txt +14 -6
- {patchcraft-0.5.1 → patchcraft-0.5.3}/src/patchcraft.egg-info/scm_file_list.json +29 -6
- {patchcraft-0.5.1 → patchcraft-0.5.3}/src/patchcraft.egg-info/scm_version.json +2 -2
- patchcraft-0.5.3/tests/test_citation.py +51 -0
- patchcraft-0.5.3/tests/test_docs_usage.py +34 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tests/test_exactness.py +1 -1
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tests/test_reconstruct.py +57 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tests/test_resize.py +35 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tests/test_stitch.py +35 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tools/check_dist.py +4 -2
- patchcraft-0.5.1/docs/superpowers/plans/2026-09-01-fase1-bugs-performance.md +0 -1179
- patchcraft-0.5.1/docs/superpowers/plans/2026-09-01-fase2-acel.md +0 -1643
- patchcraft-0.5.1/docs/superpowers/plans/2026-09-01-fase3-g1-predicado.md +0 -1705
- {patchcraft-0.5.1 → patchcraft-0.5.3}/.gitignore +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/.python-version +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/LICENSE +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/accel/Cargo.lock +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/accel/Cargo.toml +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/accel/README.md +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/accel/src/kernel.rs +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/accel/src/lib.rs +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/docs/ADR/0001-patch-extraction-api.md +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/docs/ADR/0002-patchify-transform.md +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/docs/PERFORMANCE.md +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/docs/ROADMAP.md +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/docs/STUDIES/2026-08-04-patch-techniques.md +0 -0
- /patchcraft-0.5.1/docs/superpowers/specs/2026-09-01-fase1-bugs-performance-design.md → /patchcraft-0.5.3/docs/design/2026-09-01-fase1-bugs-performance.md +0 -0
- /patchcraft-0.5.1/docs/superpowers/specs/2026-09-01-fase2-acel-design.md → /patchcraft-0.5.3/docs/design/2026-09-01-fase2-acelerador.md +0 -0
- /patchcraft-0.5.1/docs/superpowers/specs/2026-09-01-fase3-g1-predicado-design.md → /patchcraft-0.5.3/docs/design/2026-09-01-fase3-predicado.md +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/setup.cfg +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/setup.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/src/patchcraft/__init__.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/src/patchcraft/_accel.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/src/patchcraft/_foldgeom.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/src/patchcraft/cache.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/src/patchcraft/extract.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/src/patchcraft/geometry.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/src/patchcraft/metrics.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/src/patchcraft/pair.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/src/patchcraft/py.typed +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/src/patchcraft.egg-info/dependency_links.txt +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/src/patchcraft.egg-info/requires.txt +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/src/patchcraft.egg-info/top_level.txt +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tests/__init__.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tests/_datasets.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tests/_rng.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tests/conftest.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tests/test_accel.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tests/test_cache.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tests/test_datasets_helper.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tests/test_extract.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tests/test_geometry.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tests/test_import.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tests/test_metrics.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tests/test_pair.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tests/test_public_api.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tests/test_reference.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tests/test_rng.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/tools/benchmark.py +0 -0
- {patchcraft-0.5.1 → patchcraft-0.5.3}/uv.lock +0 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Runs the gates CI runs, before the commit rather than after it.
|
|
2
|
+
#
|
|
3
|
+
# Deliberately absent: `ruff-format`. This project has never used it and
|
|
4
|
+
# adopting it here would reformat 36 of 65 files in a commit that changed no
|
|
5
|
+
# behaviour. `ruff check` is the gate; formatting is not.
|
|
6
|
+
#
|
|
7
|
+
# `mypy` runs through the project environment rather than through a pre-commit
|
|
8
|
+
# virtualenv, because it needs torch to resolve any annotation in `src/` and
|
|
9
|
+
# installing torch into an isolated hook environment would cost hundreds of
|
|
10
|
+
# megabytes per hook update.
|
|
11
|
+
#
|
|
12
|
+
# Install: see the "Run tests" section of CONTRIBUTING.md. On a machine with a
|
|
13
|
+
# global `core.hooksPath`, `pre-commit install` writes to `.git/hooks/`, which
|
|
14
|
+
# git then ignores, and the hook is silently inert. CONTRIBUTING says how to
|
|
15
|
+
# check.
|
|
16
|
+
|
|
17
|
+
repos:
|
|
18
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
19
|
+
rev: v6.0.0
|
|
20
|
+
hooks:
|
|
21
|
+
- id: check-added-large-files
|
|
22
|
+
args: ["--maxkb=512"]
|
|
23
|
+
- id: check-merge-conflict
|
|
24
|
+
- id: check-toml
|
|
25
|
+
- id: check-yaml
|
|
26
|
+
- id: end-of-file-fixer
|
|
27
|
+
- id: trailing-whitespace
|
|
28
|
+
- id: mixed-line-ending
|
|
29
|
+
args: ["--fix=no"]
|
|
30
|
+
|
|
31
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
32
|
+
rev: v0.16.5
|
|
33
|
+
hooks:
|
|
34
|
+
- id: ruff-check
|
|
35
|
+
args: ["src", "tests", "tools"]
|
|
36
|
+
pass_filenames: false
|
|
37
|
+
|
|
38
|
+
- repo: local
|
|
39
|
+
hooks:
|
|
40
|
+
- id: mypy-strict
|
|
41
|
+
name: mypy --strict src
|
|
42
|
+
entry: mypy --strict src
|
|
43
|
+
language: system
|
|
44
|
+
types: [python]
|
|
45
|
+
pass_filenames: false
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# PatchCraft: the canonical guide
|
|
2
|
+
|
|
3
|
+
> **Single source, agent-agnostic.** The branded files ([`CLAUDE.md`](CLAUDE.md))
|
|
4
|
+
> point here and do not duplicate content. On any disagreement, this file wins.
|
|
5
|
+
>
|
|
6
|
+
> **Route**: this guide = *the rules* · [`MAP.md`](MAP.md) = *where things are* ·
|
|
7
|
+
> [`CONTRIBUTING.md`](CONTRIBUTING.md) = *how to run the gates and release* ·
|
|
8
|
+
> [`STATUS.md`](STATUS.md) = *where things stand now* ·
|
|
9
|
+
> [`docs/FOCO-1.0.md`](docs/FOCO-1.0.md) = *what is left before 1.0*.
|
|
10
|
+
> Do not repeat between them. Link.
|
|
11
|
+
|
|
12
|
+
## 0. The invariants
|
|
13
|
+
|
|
14
|
+
Each of these was earned. Where one names an incident, the incident is real and
|
|
15
|
+
is in the changelog.
|
|
16
|
+
|
|
17
|
+
### I1. Measure before you write it down
|
|
18
|
+
|
|
19
|
+
Every number in this repository has a command that reproduces it. A sentence
|
|
20
|
+
that says "faster", "exact" or "negligible" without one is a defect waiting to
|
|
21
|
+
be found, and several have been.
|
|
22
|
+
|
|
23
|
+
The failures this rule comes from: a predicate published as `k_max <= 4`,
|
|
24
|
+
measured false and retracted in public; a benchmark that reported the
|
|
25
|
+
byte-native path as nine times slower because `torch`'s `uint8.sum()` silently
|
|
26
|
+
promotes to `int64`, so it measured the opposite of what it claimed; a security
|
|
27
|
+
note asserting `Cache` runs `torch.load`, which it does not.
|
|
28
|
+
|
|
29
|
+
Recalling is not measuring. Reading the code is not measuring either, when the
|
|
30
|
+
question is numeric.
|
|
31
|
+
|
|
32
|
+
### I2. `docs/THEORY.md` §9 is the arbiter
|
|
33
|
+
|
|
34
|
+
It says so itself. When two documents disagree about what a function accepts,
|
|
35
|
+
rejects or returns, §9 is the truth and the other document is the bug. When §9
|
|
36
|
+
and the code disagree, decide which is wrong before changing either, and say
|
|
37
|
+
which in the commit.
|
|
38
|
+
|
|
39
|
+
§9 has been wrong twice. That is not a reason to trust it less; it is why the
|
|
40
|
+
rule exists.
|
|
41
|
+
|
|
42
|
+
### I3. A fix ships with a test that fails on the old code
|
|
43
|
+
|
|
44
|
+
Without one it is not a fix, it is a coincidence. The suite already contains
|
|
45
|
+
several tests whose only job is to prevent a specific defect from returning,
|
|
46
|
+
and each names the measurement in its docstring.
|
|
47
|
+
|
|
48
|
+
### I4. The exactness suite exists to falsify, not to confirm
|
|
49
|
+
|
|
50
|
+
`tests/test_exactness.py` enumerates the legal geometry space independently of
|
|
51
|
+
the predicate and hunts for both counterexamples: a case inside the rule that
|
|
52
|
+
is not exact, and a case outside it that is exact by luck. If you change the
|
|
53
|
+
predicate, the enumerator must not learn about the change.
|
|
54
|
+
|
|
55
|
+
### I5. The public surface is 20 names, frozen by test
|
|
56
|
+
|
|
57
|
+
`tests/test_public_api.py` pins the names, their signatures and the fields of
|
|
58
|
+
the four data carriers. Adding a name is a decision recorded in an ADR, never a
|
|
59
|
+
convenience taken mid-task. [`docs/FOCO-1.0.md`](docs/FOCO-1.0.md) says what
|
|
60
|
+
1.0 freezes.
|
|
61
|
+
|
|
62
|
+
### I6. Both code paths stay green
|
|
63
|
+
|
|
64
|
+
The library has a pure-torch path and, on five of six wheels, a Rust one. They
|
|
65
|
+
are bit-identical by test. Any change to the fold, the count map or the
|
|
66
|
+
accelerator must run both: `pytest -m "not gpu"` with the extension built, and
|
|
67
|
+
again with `PATCHCRAFT_ACCEL=0`.
|
|
68
|
+
|
|
69
|
+
### I7. The version answers one question
|
|
70
|
+
|
|
71
|
+
Not "did a returned value change", because a fix changes values by definition.
|
|
72
|
+
The question is whether the **contract moved** (`0.Y.0`) or the
|
|
73
|
+
**implementation stopped violating it** (`0.y.Z`). The rule and its four worked
|
|
74
|
+
examples are in [`CONTRIBUTING.md`](CONTRIBUTING.md), and getting it wrong is
|
|
75
|
+
what nearly shipped 0.5.2 as 0.6.0.
|
|
76
|
+
|
|
77
|
+
### I8. Nothing ephemeral lives in the project folder
|
|
78
|
+
|
|
79
|
+
Caches, build output and virtual environments are redirected by user-level
|
|
80
|
+
environment variables. `accel/target` reached 269 MiB inside the tree before
|
|
81
|
+
this was enforced. Never commit a machine path to fix it: that mistake is
|
|
82
|
+
already in the history, as a `cache_dir = "Z:\caches\pytest"` that created a
|
|
83
|
+
literal directory of that name on Linux.
|
|
84
|
+
|
|
85
|
+
### I9. A tracked file ships to PyPI unless two files say otherwise
|
|
86
|
+
|
|
87
|
+
`setuptools-scm`'s file finder offers every git-tracked file to the sdist, so
|
|
88
|
+
`MANIFEST.in` is a blocklist over everything git knows about, and
|
|
89
|
+
`tools/check_dist.py` holds the matching allowlist. Adding a top-level
|
|
90
|
+
directory means updating both. The gate will tell you; do not silence it.
|
|
91
|
+
|
|
92
|
+
### I10. Do not invent what already exists
|
|
93
|
+
|
|
94
|
+
Check for an official or established solution before writing one. The
|
|
95
|
+
accelerator's packaging, the versioning rule, the citation format and the
|
|
96
|
+
outreach layout were all taken from prior art rather than designed here, and
|
|
97
|
+
each is better for it. Writing something new is fine when nothing fits; writing
|
|
98
|
+
it without looking is not.
|
|
99
|
+
|
|
100
|
+
## 1. Writing
|
|
101
|
+
|
|
102
|
+
Prose in this repository has no em-dashes. Replace the semantic role with a
|
|
103
|
+
sentence that carries it, never with another symbol. Keep articles and
|
|
104
|
+
connectives; one idea per paragraph. `README.md` is a call page, not a manual:
|
|
105
|
+
the manual is [`docs/GUIDE.md`](docs/GUIDE.md), and complex examples belong
|
|
106
|
+
there.
|
|
107
|
+
|
|
108
|
+
Documents that state a version go stale. There is exactly one version string
|
|
109
|
+
left in the documentation, the BibTeX entry in GUIDE section 9, plus
|
|
110
|
+
[`CITATION.cff`](CITATION.cff). Do not add a third.
|
|
111
|
+
|
|
112
|
+
## 2. Before you touch anything
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
uv sync --locked --extra cache --extra dev
|
|
116
|
+
ruff check src tests tools
|
|
117
|
+
mypy --strict src
|
|
118
|
+
pytest -m "not gpu"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
For a change to the fold, the predicate or the accelerator, add:
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
PATCHCRAFT_SWEEP_FULL=1 pytest tests/test_exactness.py
|
|
125
|
+
cargo test --manifest-path accel/Cargo.toml
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The same gates run as a pre-commit hook. On a machine with a global
|
|
129
|
+
`core.hooksPath`, that hook is installed but inert;
|
|
130
|
+
[`CONTRIBUTING.md`](CONTRIBUTING.md) says how to tell.
|
|
131
|
+
|
|
132
|
+
## 3. What this project is not
|
|
133
|
+
|
|
134
|
+
No batch axis, no dataset, no dataloader, no model, no padding to make an
|
|
135
|
+
awkward geometry fit. Those are out by decision and the line is drawn in
|
|
136
|
+
[`docs/SCOPE.md`](docs/SCOPE.md) and [`docs/THEORY.md`](docs/THEORY.md) §0.
|
|
137
|
+
A request to add one of them is a scope conversation, not a feature.
|
|
@@ -6,6 +6,190 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.5.3] - 2026-09-03
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- `docs/STUDIES/2026-09-03-strata-conformity.md`, a review of this repository
|
|
13
|
+
against Strata v1.2.2. Its §9 bounded the review before it bounded the
|
|
14
|
+
project: name the genre and apply its standard, and take no change as the
|
|
15
|
+
default verdict unless a defect pays for the fix. The genre is a library, so
|
|
16
|
+
the standard is tests, packaging and CI. The finding is conformance, one gap
|
|
17
|
+
and one piece of debris. The gap is the absence of a DOI, which is the only
|
|
18
|
+
item missing from the publishing pattern and cannot be applied to releases
|
|
19
|
+
already out. The debris was a stale `.pytest_cache`, removed, with the
|
|
20
|
+
redirect verified to hold.
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
- `STATUS.md`, the snapshot: what is released, what is unreleased, and who each
|
|
25
|
+
open item waits on. Writing it surfaced that `docs/FOCO-1.0.md` still listed
|
|
26
|
+
B1, B2, B3 and B6 as open although all four were closed in 0.5.0, the same
|
|
27
|
+
bookkeeping gap B5 had. Each is now recorded with what closed it, verified
|
|
28
|
+
rather than assumed: the retracted predicate survives only in the phase spec
|
|
29
|
+
and in the blocker's own text, the falsification suite enumerates 126,736
|
|
30
|
+
geometries, the surface is pinned with `inspect.signature`, and `tilings`
|
|
31
|
+
returns 73 specs with one whole-image entry and none labelled `overlap`.
|
|
32
|
+
B4 is the only blocker still open.
|
|
33
|
+
- `AGENTS.md`, the canonical agent-facing guide, and a thin `CLAUDE.md` that
|
|
34
|
+
points at it rather than duplicating it. Its ten invariants are the ones this
|
|
35
|
+
repository actually enforces, and each names the incident it came from: the
|
|
36
|
+
predicate published and retracted, the benchmark that measured the opposite
|
|
37
|
+
of what it claimed because `uint8.sum()` promotes silently, the 269 MiB of
|
|
38
|
+
Rust build output that lived in the tree, and the machine path once committed
|
|
39
|
+
to `pyproject.toml` that created a literal `Z:\caches\pytest` directory on
|
|
40
|
+
Linux. `AGENTS.md` ships in the sdist; `CLAUDE.md` does not, having no reader
|
|
41
|
+
there.
|
|
42
|
+
- Issue forms and a pull-request template. A report about this library is
|
|
43
|
+
irreproducible without the geometry, the dtype, the torch version and
|
|
44
|
+
`accel_available()`, so the forms make those required rather than suggested,
|
|
45
|
+
and every bug form asks whether the behaviour survives `PATCHCRAFT_ACCEL=0`,
|
|
46
|
+
which is the one answer that separates the native kernel from the library.
|
|
47
|
+
"Wrong numeric result" is a form of its own, because a wrong number is a
|
|
48
|
+
first-class defect here. The PR template asks whether a returned value moved
|
|
49
|
+
and offers the four answers the versioning rule distinguishes.
|
|
50
|
+
- `SECURITY.md`. It names the real edges instead of being boilerplate: the
|
|
51
|
+
native kernel writes through raw pointers and trusts the geometry the Python
|
|
52
|
+
side validated, which is the sharpest thing in the library; `Cache` joins its
|
|
53
|
+
`namespace` straight into a path, so a namespace derived from untrusted input
|
|
54
|
+
escapes the root; nothing in the shipped package opens a network connection;
|
|
55
|
+
and image decoding happens in Pillow before this library sees anything. It
|
|
56
|
+
also says what is not a security issue here, because a wrong numeric result
|
|
57
|
+
belongs in a public issue with its measurement.
|
|
58
|
+
- `CODE_OF_CONDUCT.md`, Contributor Covenant 2.1, taken verbatim from the
|
|
59
|
+
source repository rather than retyped.
|
|
60
|
+
- `MAP.md`, one page of wayfinding: an annotated tree of the repository and a
|
|
61
|
+
want-to/go-to table. It follows the shape the sibling projects use, and it
|
|
62
|
+
opens by saying what the repository actually is, which is 20 public names
|
|
63
|
+
over eight modules plus the evidence that they behave as documented. Every
|
|
64
|
+
link and anchor in it is checked, and every path it names exists.
|
|
65
|
+
- `.pre-commit-config.yaml`, running the gates CI runs. `ruff-format` is
|
|
66
|
+
deliberately absent: the project has never used it and adopting it would
|
|
67
|
+
reformat 36 of 65 files in a commit that changed no behaviour. Two things
|
|
68
|
+
surfaced while wiring it up. `docs/FOCO-1.0.md` had no trailing newline, now
|
|
69
|
+
fixed with the file's own CRLF rather than a bare LF, which is a mistake the
|
|
70
|
+
`mixed-line-ending` hook caught on the first attempt. And on a machine with a
|
|
71
|
+
global `core.hooksPath`, `pre-commit install` writes a hook git then ignores,
|
|
72
|
+
so it is inert without saying so; `CONTRIBUTING.md` gives the one command
|
|
73
|
+
that tells you which case you are in.
|
|
74
|
+
- `CITATION.cff`, validated against Citation File Format 1.2.0, so GitHub shows
|
|
75
|
+
the "Cite this repository" button and the metadata has one authoritative
|
|
76
|
+
home. It ships in the sdist. The BibTeX entry in GUIDE section 9 stays,
|
|
77
|
+
because `cffconvert`'s generated form drops the version and emits a
|
|
78
|
+
placeholder key, but the `.cff` is now the source and the release checklist
|
|
79
|
+
moves both. A test pins its version against the newest released section of
|
|
80
|
+
this file, since comparing it to `patchcraft.__version__` cannot work in a
|
|
81
|
+
checkout, where setuptools-scm resolves a development version.
|
|
82
|
+
|
|
83
|
+
### Changed
|
|
84
|
+
- **`docs/USAGE.md` is executed instead of transcribed, which closes the last
|
|
85
|
+
1.0 blocker.** The page claimed eighteen public names when there were twenty
|
|
86
|
+
and had spent three releases describing an API that had moved, and the script
|
|
87
|
+
that once generated it was never tracked, so it could not be regenerated.
|
|
88
|
+
Making the page run in place is the durable fix: `tests/test_docs_usage.py`
|
|
89
|
+
collects it as a doctest, so a stale line fails CI rather than misleading a
|
|
90
|
+
reader. Only five outputs were genuinely wrong; the other eight failures were
|
|
91
|
+
formatting, where the output touched the closing fence and doctest read the
|
|
92
|
+
fence as expected text. `ELLIPSIS` and `NORMALIZE_WHITESPACE` are enabled in
|
|
93
|
+
`pyproject.toml` so the page may still elide a temp path or wrap a long repr
|
|
94
|
+
for the reader. The version literal is gone from it: the version comes from
|
|
95
|
+
the git tag, so any literal is wrong the moment it is written.
|
|
96
|
+
|
|
97
|
+
### Fixed
|
|
98
|
+
- **THEORY §9 justified promoting `bfloat16` with a fact that is false of it,
|
|
99
|
+
and §9 is the arbiter of the contract.** Both half formats were promoted to
|
|
100
|
+
a `float32` accumulator citing `float16`'s finite maximum of 65504. Only
|
|
101
|
+
`float16` overflows there: on the documented case its numerator reaches
|
|
102
|
+
`inf` in 144 of 256 pixels, while `bfloat16` carries `float32`'s exponent
|
|
103
|
+
and peaked at `9.0112e+04` against a finite maximum of `3.390e+38`. What the
|
|
104
|
+
promotion buys `bfloat16` is precision, since it has 8 mantissa bits to
|
|
105
|
+
`float16`'s 11, and on ordinary [0, 1] data it cut the maximum error from
|
|
106
|
+
`9.262e-03` to `1.935e-03`. §9.2 now carries one entry per format with the
|
|
107
|
+
measurement behind each, and the two docstrings and GUIDE section 4 say the
|
|
108
|
+
same. Two tests pin it.
|
|
109
|
+
- Closed blocker B5 in `docs/FOCO-1.0.md`. The contradiction it named, §9.2
|
|
110
|
+
accepting the half-precision promotion in one list and excluding it as out
|
|
111
|
+
of scope eight lines below, had already been removed in 0.3.0 and never
|
|
112
|
+
recorded. Checking that is what surfaced the `bfloat16` error above.
|
|
113
|
+
|
|
114
|
+
## [0.5.2] - 2026-09-03
|
|
115
|
+
|
|
116
|
+
### Fixed
|
|
117
|
+
|
|
118
|
+
- **`stitch(weight="hann")` corrupted the corner band of every patch of 99 or
|
|
119
|
+
more.** The denominator was floored by an absolute `clamp(min=1e-6)` whose
|
|
120
|
+
comment called it a defensive no-op. It was not: the 2-D hann corner weight
|
|
121
|
+
is `(pi/(n+1))**4`, which crosses below `1e-6` at patch 99, so the corner
|
|
122
|
+
band was divided by the floor rather than by the real weight. Measured at
|
|
123
|
+
640x640, patch 256, stride 128: maximum error 0.94 on data in [0, 1] and 960
|
|
124
|
+
wrong pixels, identical in float64 because the constant and not the precision
|
|
125
|
+
was the cause. The floor is now `finfo(dtype).tiny`, the model already used
|
|
126
|
+
in `metrics.py`, which never reaches a legitimate weight: the smallest 2-D
|
|
127
|
+
hann corner even at patch 1024 is 8.8e-11. THEORY 9.9 claimed no covered
|
|
128
|
+
pixel is zeroed by the window, which was true of the window and false of the
|
|
129
|
+
result.
|
|
130
|
+
- **`reconstruct` returned a view aliasing the caller's patches on a
|
|
131
|
+
single-patch grid.** Writing to the patches afterwards changed an image the
|
|
132
|
+
function had already returned, measured as 0.744 becoming 99.0. `extract`
|
|
133
|
+
guards the mirror image of this case and `reconstruct` did not.
|
|
134
|
+
- **`resize(..., backend="pil")` raised a raw `RuntimeError` on `int8`.** The
|
|
135
|
+
inbound `clamp(0, 255)` was applied in the input dtype, where the bound 255
|
|
136
|
+
is unrepresentable, so torch raised `value cannot be converted to type
|
|
137
|
+
int8_t without overflow` before clamping anything. Every integer dtype now
|
|
138
|
+
works on both backends, and THEORY 9.4 gained the row for integer tensors on
|
|
139
|
+
the PIL backend, which it had never specified.
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
### Removed
|
|
143
|
+
|
|
144
|
+
- The agentic workflow's leftovers. `.superpowers/` at the repository root
|
|
145
|
+
held 62 files of review diffs and task-progress notes, hidden from
|
|
146
|
+
`git status` by a nested `.gitignore` containing `*`, so it sat in the tree
|
|
147
|
+
unseen and reached the 0.5.0 sdist. The three implementation plans under
|
|
148
|
+
`docs/superpowers/plans/` were 4527 lines of checkbox task lists addressed
|
|
149
|
+
"For agentic workers", and they shipped to PyPI inside every sdist.
|
|
150
|
+
|
|
151
|
+
### Added
|
|
152
|
+
|
|
153
|
+
- `docs/ADR/0004-precision-and-effort-parameters.md`, in `Proposed` status: names the
|
|
154
|
+
precision policy the library already applies in five places, and designs an `effort=`
|
|
155
|
+
preset under the constraint that it may change speed and memory but never a returned
|
|
156
|
+
value. Nothing is implemented; the ADR records the design, the effort per step and the
|
|
157
|
+
order. It amends ADR 0003 on one measured point, that the exactness predicate is a
|
|
158
|
+
property of the geometry and the accumulator rather than of the geometry alone.
|
|
159
|
+
- `outreach/`, material for presenting the project publicly, in the shape the
|
|
160
|
+
sibling projects use: a dated news source at the root and one subfolder per
|
|
161
|
+
channel, with the rule that no channel text changes before the source does.
|
|
162
|
+
It publishes no new measurement, and it is pruned from the sdist.
|
|
163
|
+
|
|
164
|
+
### Changed
|
|
165
|
+
|
|
166
|
+
- The three design specs that were under `docs/superpowers/specs/` moved to
|
|
167
|
+
`docs/design/`. They are the record of what was measured before each phase
|
|
168
|
+
was built, including the spike table that rejected `conv_transpose2d` and
|
|
169
|
+
`index_add_` before the Rust kernel was written, and Amendment A, which
|
|
170
|
+
`tests/test_exactness.py` cites for the per-pixel error bound.
|
|
171
|
+
- The sdist is 264 KiB where it was 316 KiB.
|
|
172
|
+
- Nothing ephemeral is kept in the project folder any more. `accel/target`
|
|
173
|
+
had reached 269 MiB of Rust build output, and `dist/`, `.pytest_cache` and
|
|
174
|
+
`src/patchcraft.egg-info` were accumulating alongside it. The caches are
|
|
175
|
+
now redirected by user-level environment variables, joining the ones this
|
|
176
|
+
machine already had for uv, ruff, mypy, pip and `__pycache__`, and
|
|
177
|
+
`CONTRIBUTING.md` records the convention and why it is not committed here.
|
|
178
|
+
- `.vscode/settings.json` stays tracked and is pruned from the sdist instead.
|
|
179
|
+
- **The versioning rule was self-contradictory and is corrected.** One row said
|
|
180
|
+
an output value change is a `0.Y.0`, the next said a fix is a `0.y.Z`, and a
|
|
181
|
+
bug fix satisfies both, so the table made every fix a minor and left patch
|
|
182
|
+
releases unable to fix anything. It also contradicted the project's own
|
|
183
|
+
history: `0.2.1` changed `stitch(weight="hann")` output for every geometry
|
|
184
|
+
and shipped as a patch. The rule now turns on whether the contract moved or
|
|
185
|
+
the implementation stopped violating it, which sorts `0.2.1`, `0.3.0`,
|
|
186
|
+
`0.5.0` and `0.5.2` correctly. `CONTRIBUTING.md` carries the rule with those
|
|
187
|
+
four worked, and GUIDE section 8 item 6 no longer cites a patch release as
|
|
188
|
+
an example of what only a minor may do.
|
|
189
|
+
Its `${workspaceFolder}/.venv` path is not broken: `.venv` is a directory
|
|
190
|
+
junction to the real environment outside the tree, so the setting resolves
|
|
191
|
+
and is portable to any checkout following the same convention.
|
|
192
|
+
|
|
9
193
|
## [0.5.1] - 2026-09-02
|
|
10
194
|
|
|
11
195
|
> Numbered `0.6.0` while it was being built. Corrected before release: the
|
|
@@ -587,7 +771,9 @@ First public release. Public API stable; signatures will only change in 1.x.
|
|
|
587
771
|
- [`README.md`](README.md) covers installation, the car-vs-track metaphor,
|
|
588
772
|
validation lab.
|
|
589
773
|
|
|
590
|
-
[Unreleased]: https://github.com/LeoPR/PatchCraft/compare/v0.5.
|
|
774
|
+
[Unreleased]: https://github.com/LeoPR/PatchCraft/compare/v0.5.3...HEAD
|
|
775
|
+
[0.5.3]: https://github.com/LeoPR/PatchCraft/releases/tag/v0.5.3
|
|
776
|
+
[0.5.2]: https://github.com/LeoPR/PatchCraft/releases/tag/v0.5.2
|
|
591
777
|
[0.5.1]: https://github.com/LeoPR/PatchCraft/releases/tag/v0.5.1
|
|
592
778
|
[0.5.0]: https://github.com/LeoPR/PatchCraft/releases/tag/v0.5.0
|
|
593
779
|
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
title: "PatchCraft: image patch extraction, reconstruction, pairing and seam-aware stitching"
|
|
3
|
+
message: "If you use this software, please cite it using these metadata."
|
|
4
|
+
type: software
|
|
5
|
+
authors:
|
|
6
|
+
- given-names: Leonardo
|
|
7
|
+
family-names: Marques de Souza
|
|
8
|
+
email: leonardo.marques.souza@gmail.com
|
|
9
|
+
version: "0.5.3"
|
|
10
|
+
date-released: "2026-09-03"
|
|
11
|
+
repository-code: "https://github.com/LeoPR/PatchCraft"
|
|
12
|
+
license: MIT
|
|
13
|
+
abstract: >
|
|
14
|
+
PatchCraft cuts one image into patches and puts it back. One call takes one
|
|
15
|
+
(C, H, W) float tensor and returns one tensor: there is no batch axis, no
|
|
16
|
+
dataset, no dataloader and no model, and that boundary is documented as
|
|
17
|
+
binding rather than provisional. It owns the unfold and fold arithmetic, the
|
|
18
|
+
geometry validation and the seam blending, so a pipeline can own the rest.
|
|
19
|
+
|
|
20
|
+
Two silent defects motivate it. The intuitive reshape of F.unfold's output
|
|
21
|
+
gives the right shape with the wrong pixels, and a stride that does not cover
|
|
22
|
+
the image leaves pixels at zero without any error: on a 128 by 128 image with
|
|
23
|
+
patch 32 and stride 20, 3840 of 16384 pixels. Both are checked once here,
|
|
24
|
+
with tests around them.
|
|
25
|
+
|
|
26
|
+
The numeric contract is stated as a caller-evaluable predicate rather than a
|
|
27
|
+
promise. The extract and reconstruct round trip is bit-exact if and only if
|
|
28
|
+
every value of the overlap coverage map is a power of two, always true at
|
|
29
|
+
stride equal to patch size, and outside that rule the per-pixel error is
|
|
30
|
+
bounded by (k+1) times eps times the absolute value, with k the pixel's
|
|
31
|
+
coverage count. An earlier and weaker form of that claim was published, then
|
|
32
|
+
measured false and publicly retracted; a falsification suite now enumerates
|
|
33
|
+
the 126,736 legal geometries of the space independently of the predicate and
|
|
34
|
+
tries to break both halves of it.
|
|
35
|
+
|
|
36
|
+
Five of the six published wheels carry a Rust kernel for the overlapping
|
|
37
|
+
fold, compiled into the wheel itself rather than into a separate package, and
|
|
38
|
+
bit-identical to the pure-torch path by test. Every other platform installs a
|
|
39
|
+
universal wheel and runs the same operation in torch.
|
|
40
|
+
|
|
41
|
+
Pre-1.0: output values may change when the middle digit moves, and the
|
|
42
|
+
changelog records each change with the measurement behind it.
|
|
43
|
+
keywords:
|
|
44
|
+
- image-processing
|
|
45
|
+
- patches
|
|
46
|
+
- super-resolution
|
|
47
|
+
- pytorch
|
|
48
|
+
- tiling
|
|
49
|
+
- reconstruction
|
|
50
|
+
- seam-blending
|
|
51
|
+
- numerical-reproducibility
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
|
|
6
|
+
|
|
7
|
+
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
|
|
8
|
+
|
|
9
|
+
## Our Standards
|
|
10
|
+
|
|
11
|
+
Examples of behavior that contributes to a positive environment for our community include:
|
|
12
|
+
|
|
13
|
+
* Demonstrating empathy and kindness toward other people
|
|
14
|
+
* Being respectful of differing opinions, viewpoints, and experiences
|
|
15
|
+
* Giving and gracefully accepting constructive feedback
|
|
16
|
+
* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
|
|
17
|
+
* Focusing on what is best not just for us as individuals, but for the overall community
|
|
18
|
+
|
|
19
|
+
Examples of unacceptable behavior include:
|
|
20
|
+
|
|
21
|
+
* The use of sexualized language or imagery, and sexual attention or advances of any kind
|
|
22
|
+
* Trolling, insulting or derogatory comments, and personal or political attacks
|
|
23
|
+
* Public or private harassment
|
|
24
|
+
* Publishing others' private information, such as a physical or email address, without their explicit permission
|
|
25
|
+
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
|
26
|
+
|
|
27
|
+
## Enforcement Responsibilities
|
|
28
|
+
|
|
29
|
+
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
|
|
30
|
+
|
|
31
|
+
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
|
|
32
|
+
|
|
33
|
+
## Scope
|
|
34
|
+
|
|
35
|
+
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
|
|
36
|
+
|
|
37
|
+
## Enforcement
|
|
38
|
+
|
|
39
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at leonardo.marques.souza@gmail.com. All complaints will be reviewed and investigated promptly and fairly.
|
|
40
|
+
|
|
41
|
+
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
|
|
42
|
+
|
|
43
|
+
## Enforcement Guidelines
|
|
44
|
+
|
|
45
|
+
Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
|
|
46
|
+
|
|
47
|
+
### 1. Correction
|
|
48
|
+
|
|
49
|
+
**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
|
|
50
|
+
|
|
51
|
+
**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
|
|
52
|
+
|
|
53
|
+
### 2. Warning
|
|
54
|
+
|
|
55
|
+
**Community Impact**: A violation through a single incident or series of actions.
|
|
56
|
+
|
|
57
|
+
**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
|
|
58
|
+
|
|
59
|
+
### 3. Temporary Ban
|
|
60
|
+
|
|
61
|
+
**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
|
|
62
|
+
|
|
63
|
+
**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
|
|
64
|
+
|
|
65
|
+
### 4. Permanent Ban
|
|
66
|
+
|
|
67
|
+
**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
|
|
68
|
+
|
|
69
|
+
**Consequence**: A permanent ban from any sort of public interaction within the community.
|
|
70
|
+
|
|
71
|
+
## Attribution
|
|
72
|
+
|
|
73
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
|
74
|
+
|
|
75
|
+
Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
|
76
|
+
|
|
77
|
+
For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at [https://www.contributor-covenant.org/translations][translations].
|
|
78
|
+
|
|
79
|
+
[homepage]: https://www.contributor-covenant.org
|
|
80
|
+
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
|
81
|
+
[Mozilla CoC]: https://github.com/mozilla/diversity
|
|
82
|
+
[FAQ]: https://www.contributor-covenant.org/faq
|
|
83
|
+
[translations]: https://www.contributor-covenant.org/translations
|