spotregen 0.1.0__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.
@@ -0,0 +1,77 @@
1
+ Metadata-Version: 2.3
2
+ Name: spotregen
3
+ Version: 0.1.0
4
+ Summary: Regenerative Software tooling: check intent, evaluations and provenance of regenerable units, and drive blind regeneration
5
+ Author: bartzbeielstein
6
+ Author-email: bartzbeielstein <32470350+bartzbeielstein@users.noreply.github.com>
7
+ License: AGPL-3.0-or-later
8
+ Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.13
11
+ Classifier: Topic :: Software Development :: Quality Assurance
12
+ Requires-Python: >=3.13
13
+ Project-URL: Documentation, https://advm1.gm.fh-koeln.de/~bartz/spotregen/
14
+ Project-URL: Repository, https://git-ce.rwth-aachen.de/thomas.bartz-beielstein/spotregen
15
+ Project-URL: Issues, https://git-ce.rwth-aachen.de/thomas.bartz-beielstein/spotregen/-/issues
16
+ Description-Content-Type: text/markdown
17
+
18
+ # spotregen
19
+
20
+ Tooling for **Regenerative Software** in the sense of Chad Fowler: code is
21
+ disposable, the knowledge around it is the asset. A module is safely replaceable
22
+ when it can be deleted and rebuilt from knowledge that lives outside its
23
+ implementation. `spotregen` reads that knowledge from a tracked `regen/` tree and
24
+ checks it against the source tree.
25
+
26
+ * Standard library only: zero runtime dependencies, Python 3.13 or later.
27
+ * It never imports the modules it describes; it reads the source with `ast`.
28
+ * A deterministic gate (`spotregen check`) for `make guard`, plus reports
29
+ (`status`, `deletion-test`, `context`, `compact`, `new-unit`) and two
30
+ non-deterministic drivers (`blind`, `local`) that regenerate a unit with an LLM.
31
+
32
+ ## Install
33
+
34
+ ```bash
35
+ uv add --dev spotregen
36
+ ```
37
+
38
+ ## Use
39
+
40
+ ```bash
41
+ spotregen check [--strict] # the gate: exit 1 on errors
42
+ spotregen status # units by pace and coverage
43
+ spotregen deletion-test UNIT # blast radius and knowledge gaps
44
+ spotregen context UNIT [-o FILE] # regeneration bundle, no bodies
45
+ spotregen compact # compaction candidates
46
+ spotregen new-unit MODULE --pace P --risk R [--dry-run]
47
+ spotregen blind UNIT [...] # regenerate with `claude -p` (needs claude)
48
+ spotregen local UNIT --model M [...] # regenerate with a local LM Studio model
49
+ ```
50
+
51
+ `--root DIR` selects the repository (default: search upwards for
52
+ `regen/architecture.toml`); `python -m spotregen` works as well. A repository
53
+ carries:
54
+
55
+ * `regen/architecture.toml`: the compilation target (allowed imports, accepted
56
+ cycles, pace policy, conventions, scan directories).
57
+ * `regen/units/<unit>.toml`: one regenerable unit with intent, evaluations and
58
+ consumers.
59
+ * `regen/decisions/<id>.toml`: provenance records.
60
+
61
+ The schema, the finding codes and the tutorials are in the documentation,
62
+ <https://advm1.gm.fh-koeln.de/~bartz/spotregen/>. A minimal repository for trying
63
+ it out is built by `spotregen.make_sample_repo`.
64
+
65
+ ## Develop
66
+
67
+ ```bash
68
+ make sync && make test-fast # environment and fast tests
69
+ make verify # guard + lint + test + doc, the gate before a push
70
+ ```
71
+
72
+ See [CONTRIBUTING.md](CONTRIBUTING.md) and [RELEASING.md](RELEASING.md). The design
73
+ is recorded in [ADR 0001](docs/adr/0001-spotregen-package.md).
74
+
75
+ ## License
76
+
77
+ AGPL-3.0-or-later.
@@ -0,0 +1,60 @@
1
+ # spotregen
2
+
3
+ Tooling for **Regenerative Software** in the sense of Chad Fowler: code is
4
+ disposable, the knowledge around it is the asset. A module is safely replaceable
5
+ when it can be deleted and rebuilt from knowledge that lives outside its
6
+ implementation. `spotregen` reads that knowledge from a tracked `regen/` tree and
7
+ checks it against the source tree.
8
+
9
+ * Standard library only: zero runtime dependencies, Python 3.13 or later.
10
+ * It never imports the modules it describes; it reads the source with `ast`.
11
+ * A deterministic gate (`spotregen check`) for `make guard`, plus reports
12
+ (`status`, `deletion-test`, `context`, `compact`, `new-unit`) and two
13
+ non-deterministic drivers (`blind`, `local`) that regenerate a unit with an LLM.
14
+
15
+ ## Install
16
+
17
+ ```bash
18
+ uv add --dev spotregen
19
+ ```
20
+
21
+ ## Use
22
+
23
+ ```bash
24
+ spotregen check [--strict] # the gate: exit 1 on errors
25
+ spotregen status # units by pace and coverage
26
+ spotregen deletion-test UNIT # blast radius and knowledge gaps
27
+ spotregen context UNIT [-o FILE] # regeneration bundle, no bodies
28
+ spotregen compact # compaction candidates
29
+ spotregen new-unit MODULE --pace P --risk R [--dry-run]
30
+ spotregen blind UNIT [...] # regenerate with `claude -p` (needs claude)
31
+ spotregen local UNIT --model M [...] # regenerate with a local LM Studio model
32
+ ```
33
+
34
+ `--root DIR` selects the repository (default: search upwards for
35
+ `regen/architecture.toml`); `python -m spotregen` works as well. A repository
36
+ carries:
37
+
38
+ * `regen/architecture.toml`: the compilation target (allowed imports, accepted
39
+ cycles, pace policy, conventions, scan directories).
40
+ * `regen/units/<unit>.toml`: one regenerable unit with intent, evaluations and
41
+ consumers.
42
+ * `regen/decisions/<id>.toml`: provenance records.
43
+
44
+ The schema, the finding codes and the tutorials are in the documentation,
45
+ <https://advm1.gm.fh-koeln.de/~bartz/spotregen/>. A minimal repository for trying
46
+ it out is built by `spotregen.make_sample_repo`.
47
+
48
+ ## Develop
49
+
50
+ ```bash
51
+ make sync && make test-fast # environment and fast tests
52
+ make verify # guard + lint + test + doc, the gate before a push
53
+ ```
54
+
55
+ See [CONTRIBUTING.md](CONTRIBUTING.md) and [RELEASING.md](RELEASING.md). The design
56
+ is recorded in [ADR 0001](docs/adr/0001-spotregen-package.md).
57
+
58
+ ## License
59
+
60
+ AGPL-3.0-or-later.
@@ -0,0 +1,79 @@
1
+ [project]
2
+ name = "spotregen"
3
+ version = "0.1.0"
4
+ description = "Regenerative Software tooling: check intent, evaluations and provenance of regenerable units, and drive blind regeneration"
5
+ readme = "README.md"
6
+ classifiers = [
7
+ "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)",
8
+ "Programming Language :: Python :: 3",
9
+ "Programming Language :: Python :: 3.13",
10
+ "Topic :: Software Development :: Quality Assurance",
11
+ ]
12
+ requires-python = ">=3.13"
13
+ dependencies = []
14
+
15
+ [project.license]
16
+ text = "AGPL-3.0-or-later"
17
+
18
+ [[project.authors]]
19
+ name = "bartzbeielstein"
20
+ email = "32470350+bartzbeielstein@users.noreply.github.com"
21
+
22
+ [project.urls]
23
+ Documentation = "https://advm1.gm.fh-koeln.de/~bartz/spotregen/"
24
+ Repository = "https://git-ce.rwth-aachen.de/thomas.bartz-beielstein/spotregen"
25
+ Issues = "https://git-ce.rwth-aachen.de/thomas.bartz-beielstein/spotregen/-/issues"
26
+
27
+ [project.scripts]
28
+ spotregen = "spotregen.cli:main"
29
+
30
+ [build-system]
31
+ requires = ["uv_build>=0.9.18"]
32
+ build-backend = "uv_build"
33
+
34
+ [dependency-groups]
35
+ dev = [
36
+ "pytest>=9.0.2",
37
+ "pytest-cov>=6.0.0",
38
+ "black>=24.1.0",
39
+ "isort>=5.13.0",
40
+ "ruff>=0.3.0",
41
+ "ty>=0.0.29",
42
+ "reuse>=5.0.0",
43
+ "pre-commit>=4.0.0",
44
+ "quartodoc>=0.9.1",
45
+ "ipykernel>=7.1.0",
46
+ "jupyter>=1.1.1",
47
+ "nbformat>=5.10.4",
48
+ "pyyaml>=6.0",
49
+ ]
50
+
51
+ [tool.pytest.ini_options]
52
+ testpaths = ["tests"]
53
+ python_files = ["test_*.py"]
54
+ python_classes = ["Test*"]
55
+ python_functions = ["test_*"]
56
+ markers = [
57
+ "slow: end-to-end tests with fake claude / fake endpoint, and the parity test (deselect with -m 'not slow')",
58
+ "regen: durable evaluations of a regenerable unit (regen/units/*.toml); they must survive a rewrite of the implementation",
59
+ ]
60
+
61
+ [tool.black]
62
+ target-version = ["py313"]
63
+
64
+ [tool.isort]
65
+ profile = "black"
66
+
67
+ [tool.ruff]
68
+ line-length = 88
69
+ target-version = "py313"
70
+
71
+ [tool.coverage.run]
72
+ branch = true
73
+ source = ["src/spotregen"]
74
+
75
+ [tool.coverage.report]
76
+ fail_under = 85
77
+
78
+ [tool.ty.environment]
79
+ python-version = "3.13"
@@ -0,0 +1,81 @@
1
+ [project]
2
+ name = "spotregen"
3
+ version = "0.1.0"
4
+ description = "Regenerative Software tooling: check intent, evaluations and provenance of regenerable units, and drive blind regeneration"
5
+ readme = "README.md"
6
+ license = { text = "AGPL-3.0-or-later" }
7
+ classifiers = [
8
+ "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)",
9
+ "Programming Language :: Python :: 3",
10
+ "Programming Language :: Python :: 3.13",
11
+ "Topic :: Software Development :: Quality Assurance",
12
+ ]
13
+ authors = [
14
+ { name = "bartzbeielstein", email = "32470350+bartzbeielstein@users.noreply.github.com" }
15
+ ]
16
+ requires-python = ">=3.13"
17
+ # Zero runtime dependencies is a contract (ADR 0001): `make guard` fails if this
18
+ # list is ever non-empty. The tool uses the standard library only.
19
+ dependencies = []
20
+
21
+ [project.urls]
22
+ Documentation = "https://advm1.gm.fh-koeln.de/~bartz/spotregen/"
23
+ Repository = "https://git-ce.rwth-aachen.de/thomas.bartz-beielstein/spotregen"
24
+ Issues = "https://git-ce.rwth-aachen.de/thomas.bartz-beielstein/spotregen/-/issues"
25
+
26
+ [project.scripts]
27
+ spotregen = "spotregen.cli:main"
28
+
29
+ [build-system]
30
+ requires = ["uv_build>=0.9.18"]
31
+ build-backend = "uv_build"
32
+
33
+ [dependency-groups]
34
+ dev = [
35
+ # Testing
36
+ "pytest>=9.0.2",
37
+ "pytest-cov>=6.0.0",
38
+ # Linting / formatting / types / licences
39
+ "black>=24.1.0",
40
+ "isort>=5.13.0",
41
+ "ruff>=0.3.0",
42
+ "ty>=0.0.29",
43
+ "reuse>=5.0.0",
44
+ "pre-commit>=4.0.0",
45
+ # Documentation (Quarto + quartodoc)
46
+ "quartodoc>=0.9.1",
47
+ "ipykernel>=7.1.0",
48
+ "jupyter>=1.1.1",
49
+ "nbformat>=5.10.4",
50
+ "pyyaml>=6.0",
51
+ ]
52
+
53
+ [tool.pytest.ini_options]
54
+ testpaths = ["tests"]
55
+ python_files = ["test_*.py"]
56
+ python_classes = ["Test*"]
57
+ python_functions = ["test_*"]
58
+ markers = [
59
+ "slow: end-to-end tests with fake claude / fake endpoint, and the parity test (deselect with -m 'not slow')",
60
+ "regen: durable evaluations of a regenerable unit (regen/units/*.toml); they must survive a rewrite of the implementation",
61
+ ]
62
+
63
+ [tool.black]
64
+ target-version = ["py313"]
65
+
66
+ [tool.isort]
67
+ profile = "black"
68
+
69
+ [tool.ruff]
70
+ line-length = 88
71
+ target-version = "py313"
72
+
73
+ [tool.coverage.run]
74
+ branch = true
75
+ source = ["src/spotregen"]
76
+
77
+ [tool.coverage.report]
78
+ fail_under = 85
79
+
80
+ [tool.ty.environment]
81
+ python-version = "3.13"
@@ -0,0 +1,82 @@
1
+ # SPDX-FileCopyrightText: 2026 bartzbeielstein
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ """spotregen: Regenerative Software tooling (stdlib only).
5
+
6
+ Chad Fowler's *Regenerative Software* treats code as disposable and the system's
7
+ knowledge as the asset. This package reads that knowledge from the tracked
8
+ ``regen/`` tree of a repository and checks it against the source tree. It uses the
9
+ standard library only and never imports the modules it describes.
10
+
11
+ The command line is ``spotregen [--root DIR] <command>`` (see `spotregen.cli.main`);
12
+ the functions below are the programmatic interface. The drivers that regenerate a
13
+ unit with an LLM live in `spotregen.drivers` and are not imported here.
14
+ """
15
+
16
+ from importlib.metadata import PackageNotFoundError, version
17
+
18
+ from spotregen.checks import (
19
+ Finding,
20
+ check_architecture,
21
+ check_decisions,
22
+ check_unit,
23
+ run_checks,
24
+ )
25
+ from spotregen.compact import compaction_report
26
+ from spotregen.context import build_context, public_contract
27
+ from spotregen.reports import deletion_report, status_table
28
+ from spotregen.sample import make_sample_repo
29
+ from spotregen.scaffold import scaffold_unit
30
+ from spotregen.scan import find_importers
31
+ from spotregen.spec import (
32
+ Alternative,
33
+ Architecture,
34
+ Consumer,
35
+ Decision,
36
+ IntentItem,
37
+ RegenSpec,
38
+ SpecError,
39
+ Unit,
40
+ find_repo_root,
41
+ load_architecture,
42
+ load_decision,
43
+ load_spec,
44
+ load_unit,
45
+ resolve_unit,
46
+ )
47
+
48
+ try:
49
+ __version__ = version("spotregen")
50
+ except PackageNotFoundError: # pragma: no cover - running from an unbuilt tree
51
+ __version__ = "0+unknown"
52
+
53
+ __all__ = [
54
+ "Alternative",
55
+ "Architecture",
56
+ "Consumer",
57
+ "Decision",
58
+ "Finding",
59
+ "IntentItem",
60
+ "RegenSpec",
61
+ "SpecError",
62
+ "Unit",
63
+ "__version__",
64
+ "build_context",
65
+ "check_architecture",
66
+ "check_decisions",
67
+ "check_unit",
68
+ "compaction_report",
69
+ "deletion_report",
70
+ "find_importers",
71
+ "find_repo_root",
72
+ "load_architecture",
73
+ "load_decision",
74
+ "load_spec",
75
+ "load_unit",
76
+ "make_sample_repo",
77
+ "public_contract",
78
+ "resolve_unit",
79
+ "run_checks",
80
+ "scaffold_unit",
81
+ "status_table",
82
+ ]
@@ -0,0 +1,9 @@
1
+ # SPDX-FileCopyrightText: 2026 bartzbeielstein
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ """Entry point of ``python -m spotregen``."""
5
+
6
+ from spotregen.cli import main
7
+
8
+ if __name__ == "__main__":
9
+ raise SystemExit(main())
@@ -0,0 +1,115 @@
1
+ # SPDX-FileCopyrightText: 2026 bartzbeielstein
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ """Checks for the external tools the drivers depend on (standard library only).
5
+
6
+ The drivers call ``claude``, ``git`` and ``lsof``, or talk to a local model server.
7
+ They fail early and clearly when one of these is missing: `ExternalToolError` for a
8
+ missing executable or an unreachable endpoint, `ConfigurationError` for an option the
9
+ drivers refuse. The command line maps both to exit code 2.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import json
15
+ import shutil
16
+
17
+ __all__ = [
18
+ "ConfigurationError",
19
+ "ExternalToolError",
20
+ "probe_endpoint",
21
+ "require_executable",
22
+ ]
23
+
24
+
25
+ class ExternalToolError(RuntimeError):
26
+ """A required executable is not installed or an endpoint is not reachable.
27
+
28
+ Examples:
29
+ ```{python}
30
+ from spotregen._tools import ExternalToolError, require_executable
31
+
32
+ try:
33
+ require_executable("no-such-tool-xyz", "install it first")
34
+ except ExternalToolError as exc:
35
+ print(exc)
36
+ ```
37
+ """
38
+
39
+
40
+ class ConfigurationError(ValueError):
41
+ """A driver option is refused, for example a file outside the repository.
42
+
43
+ Examples:
44
+ ```{python}
45
+ from spotregen._tools import ConfigurationError
46
+
47
+ print(issubclass(ConfigurationError, ValueError))
48
+ ```
49
+ """
50
+
51
+
52
+ def require_executable(name: str, hint: str = "") -> str:
53
+ """Find an executable on ``PATH`` or fail with a clear message.
54
+
55
+ Args:
56
+ name: Executable name, for example ``"claude"``.
57
+ hint: How to get it, appended to the error message. Defaults to ``""``.
58
+
59
+ Returns:
60
+ str: The absolute path of the executable.
61
+
62
+ Raises:
63
+ ExternalToolError: If the executable is not on ``PATH``.
64
+
65
+ Examples:
66
+ ```{python}
67
+ from spotregen._tools import require_executable
68
+
69
+ print(require_executable("sh").endswith("sh"))
70
+ ```
71
+ """
72
+ found = shutil.which(name)
73
+ if found is None:
74
+ suffix = f" ({hint})" if hint else ""
75
+ raise ExternalToolError(f"'{name}' was not found on PATH{suffix}")
76
+ return found
77
+
78
+
79
+ def probe_endpoint(url: str, timeout: float = 5.0) -> list[str]:
80
+ """Ask an OpenAI-compatible server which models it serves (``GET /v1/models``).
81
+
82
+ Args:
83
+ url: Base URL of the server, for example ``"http://127.0.0.1:1234"``.
84
+ timeout: Seconds to wait. Defaults to 5.0.
85
+
86
+ Returns:
87
+ list[str]: The model identifiers the server lists.
88
+
89
+ Raises:
90
+ ExternalToolError: If the server cannot be reached or does not answer with the
91
+ expected JSON.
92
+
93
+ Examples:
94
+ ```{python}
95
+ from spotregen._tools import ExternalToolError, probe_endpoint
96
+
97
+ try:
98
+ probe_endpoint("http://127.0.0.1:9", timeout=1.0)
99
+ except ExternalToolError as exc:
100
+ print("unreachable:", "127.0.0.1:9" in str(exc))
101
+ ```
102
+ """
103
+ import urllib.error # imported here: the command line imports this module
104
+ import urllib.request # for its exceptions and must not pay for urllib
105
+
106
+ target = url.rstrip("/") + "/v1/models"
107
+ try:
108
+ with urllib.request.urlopen(target, timeout=timeout) as response:
109
+ payload = json.load(response)
110
+ return [str(item["id"]) for item in payload["data"]]
111
+ except (OSError, urllib.error.URLError, ValueError, KeyError, TypeError) as exc:
112
+ raise ExternalToolError(
113
+ f"cannot reach a model server at {target}: {exc}. "
114
+ "Start LM Studio's local server (or pass --endpoint)."
115
+ ) from exc