scribpy 0.0.1b2__tar.gz → 0.0.2b0__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.
Files changed (87) hide show
  1. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/Makefile +5 -2
  2. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/PKG-INFO +1 -1
  3. scribpy-0.0.2b0/demo/doc/guide/setup.md +5 -0
  4. scribpy-0.0.2b0/demo/doc/index.md +6 -0
  5. scribpy-0.0.2b0/demo/scribpy.toml +12 -0
  6. scribpy-0.0.2b0/demo1.py +84 -0
  7. scribpy-0.0.2b0/doc/DEVELOPMENT_CHECKS.md +374 -0
  8. scribpy-0.0.2b0/doc/FUNCTIONAL_CHAINS.md +840 -0
  9. scribpy-0.0.2b0/doc/RELEASE_AND_PIPELINES.md +405 -0
  10. scribpy-0.0.2b0/doc/adr/ADR-0001-phase-2-project-context-chain.md +346 -0
  11. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/pyproject.toml +10 -1
  12. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/src/scribpy/__main__.py +3 -4
  13. scribpy-0.0.2b0/src/scribpy/cli/__init__.py +5 -0
  14. scribpy-0.0.2b0/src/scribpy/cli/main.py +118 -0
  15. scribpy-0.0.2b0/src/scribpy/config/__init__.py +26 -0
  16. scribpy-0.0.2b0/src/scribpy/config/loader.py +237 -0
  17. scribpy-0.0.2b0/src/scribpy/config/types.py +67 -0
  18. scribpy-0.0.2b0/src/scribpy/core/__init__.py +8 -0
  19. scribpy-0.0.2b0/src/scribpy/core/demo.py +125 -0
  20. scribpy-0.0.2b0/src/scribpy/core/index_check.py +62 -0
  21. scribpy-0.0.2b0/src/scribpy/model/__init__.py +59 -0
  22. scribpy-0.0.2b0/src/scribpy/model/diagnostic.py +42 -0
  23. scribpy-0.0.2b0/src/scribpy/model/document.py +42 -0
  24. scribpy-0.0.2b0/src/scribpy/model/index.py +26 -0
  25. scribpy-0.0.2b0/src/scribpy/model/markdown.py +91 -0
  26. scribpy-0.0.2b0/src/scribpy/model/project.py +32 -0
  27. scribpy-0.0.2b0/src/scribpy/model/protocols.py +67 -0
  28. scribpy-0.0.2b0/src/scribpy/model/results.py +62 -0
  29. scribpy-0.0.2b0/src/scribpy/model/source.py +23 -0
  30. scribpy-0.0.2b0/src/scribpy/project/__init__.py +11 -0
  31. scribpy-0.0.2b0/src/scribpy/project/indexer.py +159 -0
  32. scribpy-0.0.2b0/src/scribpy/project/scanner.py +94 -0
  33. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/src/scribpy/utils/__init__.py +20 -2
  34. scribpy-0.0.2b0/src/scribpy/utils/diagnostics.py +106 -0
  35. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/src/scribpy/utils/markdown_generator.py +38 -23
  36. scribpy-0.0.2b0/src/scribpy/utils/toml.py +27 -0
  37. scribpy-0.0.2b0/tests/config/test_config.py +220 -0
  38. scribpy-0.0.2b0/tests/core/test_demo.py +88 -0
  39. scribpy-0.0.2b0/tests/core/test_index_check.py +124 -0
  40. scribpy-0.0.2b0/tests/model/test_core_models.py +130 -0
  41. scribpy-0.0.2b0/tests/model/test_diagnostic.py +50 -0
  42. scribpy-0.0.2b0/tests/model/test_protocols.py +109 -0
  43. scribpy-0.0.2b0/tests/model/test_results.py +88 -0
  44. scribpy-0.0.2b0/tests/project/test_indexer.py +136 -0
  45. scribpy-0.0.2b0/tests/project/test_scanner.py +103 -0
  46. scribpy-0.0.2b0/tests/test_cli.py +132 -0
  47. scribpy-0.0.2b0/tests/utils/test_diagnostics.py +171 -0
  48. scribpy-0.0.1b2/src/scribpy/cli/__init__.py +0 -15
  49. scribpy-0.0.1b2/src/scribpy/config/__init__.py +0 -14
  50. scribpy-0.0.1b2/src/scribpy/core/__init__.py +0 -20
  51. scribpy-0.0.1b2/src/scribpy/model/__init__.py +0 -13
  52. scribpy-0.0.1b2/src/scribpy/project/__init__.py +0 -19
  53. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/.claude/settings.json +0 -0
  54. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/.claude/settings.local.json +0 -0
  55. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/.github/workflows/ci.yml +0 -0
  56. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/.github/workflows/publish.yml +0 -0
  57. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/.gitignore +0 -0
  58. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/.gitlab-ci.yml +0 -0
  59. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/.python-version +0 -0
  60. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/.vscode/settings.json +0 -0
  61. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/CLAUDE.md +0 -0
  62. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/LICENSE +0 -0
  63. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/README.md +0 -0
  64. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/doc/SDD.md +0 -0
  65. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/main.py +0 -0
  66. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/scripts/ci.sh +0 -0
  67. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/src/scribpy/__init__.py +0 -0
  68. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/src/scribpy/assets/__init__.py +0 -0
  69. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/src/scribpy/builders/__init__.py +0 -0
  70. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/src/scribpy/editors/__init__.py +0 -0
  71. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/src/scribpy/exporters/__init__.py +0 -0
  72. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/src/scribpy/extensions/__init__.py +0 -0
  73. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/src/scribpy/lint/__init__.py +0 -0
  74. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/src/scribpy/parser/__init__.py +0 -0
  75. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/src/scribpy/parsers/__init__.py +0 -0
  76. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/src/scribpy/plugins/__init__.py +0 -0
  77. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/src/scribpy/py.typed +0 -0
  78. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/src/scribpy/themes/__init__.py +0 -0
  79. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/src/scribpy/transforms/__init__.py +0 -0
  80. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/src/scribpy/utils/file_utils.py +0 -0
  81. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/tests/__init__.py +0 -0
  82. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/tests/conftest.py +0 -0
  83. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/tests/utils/__init__.py +0 -0
  84. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/tests/utils/test_file_utils.py +0 -0
  85. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/tests/utils/test_markdown_generator.py +0 -0
  86. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/uv.lock +0 -0
  87. {scribpy-0.0.1b2 → scribpy-0.0.2b0}/work/.gitignore +0 -0
@@ -1,4 +1,4 @@
1
- .PHONY: format lint format-check typecheck test check ci clean-dist build check-dist publish-test publish
1
+ .PHONY: format lint docstrings format-check typecheck test check ci clean-dist build check-dist publish-test publish
2
2
 
3
3
  format:
4
4
  uv run ruff format src/ tests/
@@ -9,6 +9,9 @@ format-check:
9
9
  lint:
10
10
  uv run ruff check src/ tests/
11
11
 
12
+ docstrings:
13
+ uv run ruff check src/ --select D --ignore D100,D104
14
+
12
15
  typecheck:
13
16
  uv run mypy src/
14
17
 
@@ -18,7 +21,7 @@ test:
18
21
  code=$$?; [ $$code -eq 5 ] && exit 0 || exit $$code
19
22
 
20
23
  # Local dev: format (mutating) + all checks
21
- check: format lint typecheck test
24
+ check: format lint docstrings typecheck test
22
25
 
23
26
  # CI: all checks via the consolidated script (no early exit, full summary)
24
27
  ci:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scribpy
3
- Version: 0.0.1b2
3
+ Version: 0.0.2b0
4
4
  Summary: Manipulate, edit, and generate documents from Markdown files.
5
5
  Project-URL: Homepage, https://github.com/antoinebarre/scribpy
6
6
  Project-URL: Repository, https://github.com/antoinebarre/scribpy
@@ -0,0 +1,5 @@
1
+ # Setup
2
+
3
+ This file is the second document in the explicit index.
4
+
5
+ The configured order is controlled by `demo/scribpy.toml`.
@@ -0,0 +1,6 @@
1
+ # Scribpy Phase 2 Demo
2
+
3
+ This file is the first document in the explicit index.
4
+
5
+ It demonstrates that Scribpy can load a project, discover Markdown files, and
6
+ validate the document index before parsing or building documentation.
@@ -0,0 +1,12 @@
1
+ [project]
2
+ name = "scribpy-phase-2-demo"
3
+
4
+ [paths]
5
+ source = "doc"
6
+
7
+ [index]
8
+ mode = "explicit"
9
+ files = [
10
+ "index.md",
11
+ "guide/setup.md",
12
+ ]
@@ -0,0 +1,84 @@
1
+ """Run a small phase 2 Scribpy project-context demo."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ ROOT = Path(__file__).resolve().parent
9
+ SRC = ROOT / "src"
10
+ DEMO_ROOT = ROOT / "demo"
11
+
12
+ if str(SRC) not in sys.path:
13
+ sys.path.insert(0, str(SRC))
14
+
15
+ from scribpy.cli.main import main as cli_main # noqa: E402
16
+ from scribpy.config import load_config # noqa: E402
17
+ from scribpy.core import run_index_check # noqa: E402
18
+ from scribpy.model import Diagnostic # noqa: E402
19
+ from scribpy.project import ( # noqa: E402
20
+ build_document_index,
21
+ resolve_project_root,
22
+ scan_project,
23
+ )
24
+ from scribpy.utils import format_diagnostics # noqa: E402
25
+
26
+
27
+ def main() -> int:
28
+ """Run the project context and document index demo.
29
+
30
+ Returns:
31
+ Process exit code from the CLI check.
32
+ """
33
+ config_path = DEMO_ROOT / "scribpy.toml"
34
+ print(f"Demo project: {DEMO_ROOT.relative_to(ROOT)}")
35
+ print(f"Configuration: {config_path.relative_to(ROOT)}")
36
+ print()
37
+
38
+ config, config_diagnostics = load_config(config_path)
39
+ _print_diagnostics("Configuration diagnostics", config_diagnostics)
40
+ if config is None:
41
+ return 1
42
+
43
+ project_root = resolve_project_root(config_path)
44
+ source_files, scan_diagnostics = scan_project(project_root, config)
45
+ _print_diagnostics("Scan diagnostics", scan_diagnostics)
46
+
47
+ print("Discovered Markdown files:")
48
+ for source_file in source_files:
49
+ print(f" - {source_file.relative_path.as_posix()}")
50
+ print()
51
+
52
+ index, index_diagnostics = build_document_index(config, source_files)
53
+ _print_diagnostics("Index diagnostics", index_diagnostics)
54
+
55
+ if index is not None:
56
+ print(f"Document index mode: {index.mode}")
57
+ print("Document index order:")
58
+ for path in index.paths:
59
+ print(f" - {path.as_posix()}")
60
+ print()
61
+
62
+ api_result = run_index_check(DEMO_ROOT)
63
+ print(f"API run_index_check failed: {api_result.failed}")
64
+ _print_diagnostics("API diagnostics", api_result.diagnostics)
65
+
66
+ print("CLI command: scribpy index check --root demo")
67
+ cli_exit_code = cli_main(["index", "check", "--root", str(DEMO_ROOT)])
68
+ print(f"CLI exit code: {cli_exit_code}")
69
+ return cli_exit_code
70
+
71
+
72
+ def _print_diagnostics(title: str, diagnostics: tuple[Diagnostic, ...]) -> None:
73
+ print(f"{title}:")
74
+ if not diagnostics:
75
+ print(" none")
76
+ print()
77
+ return
78
+
79
+ print(format_diagnostics(diagnostics))
80
+ print()
81
+
82
+
83
+ if __name__ == "__main__":
84
+ raise SystemExit(main())
@@ -0,0 +1,374 @@
1
+ # Development Checks — Scribpy
2
+
3
+ **Version:** 0.1.0-draft
4
+ **Date:** 2026-05-06
5
+ **Scope:** local and CI quality controls
6
+
7
+ ---
8
+
9
+ ## 1. Purpose
10
+
11
+ This document explains the quality checks used during Scribpy development:
12
+ formatting, linting, docstring validation, typing, tests, coverage, and
13
+ distribution checks.
14
+
15
+ The goal is to make `make check` understandable and reproducible. Each check
16
+ must have a clear purpose, a stable command, and an explicit configuration
17
+ source.
18
+
19
+ ---
20
+
21
+ ## 2. Command Overview
22
+
23
+ Main local command:
24
+
25
+ ```text
26
+ make check
27
+ ```
28
+
29
+ Execution order:
30
+
31
+ ```text
32
+ format -> lint -> docstrings -> typecheck -> test
33
+ ```
34
+
35
+ Defined in `Makefile`:
36
+
37
+ | Target | Command | Purpose |
38
+ |--------|---------|---------|
39
+ | `format` | `uv run ruff format src/ tests/` | Apply automatic formatting |
40
+ | `lint` | `uv run ruff check src/ tests/` | Run static lint rules |
41
+ | `docstrings` | `uv run ruff check src/ --select D --ignore D100,D104` | Check Google-style source docstrings |
42
+ | `typecheck` | `uv run mypy src/` | Run strict static typing |
43
+ | `test` | `uv run pytest` | Run tests and coverage |
44
+ | `check` | `format lint docstrings typecheck test` | Run the full local quality gate |
45
+
46
+ `make check` is intentionally mutating because `format` rewrites files. For a
47
+ non-mutating formatting check, use:
48
+
49
+ ```text
50
+ make format-check
51
+ ```
52
+
53
+ ---
54
+
55
+ ## 3. Formatting
56
+
57
+ Command:
58
+
59
+ ```text
60
+ uv run ruff format src/ tests/
61
+ ```
62
+
63
+ Configuration:
64
+
65
+ ```toml
66
+ [tool.ruff]
67
+ cache-dir = "work/.ruff_cache"
68
+ ```
69
+
70
+ Controlled points:
71
+
72
+ - Python source formatting under `src/`;
73
+ - test formatting under `tests/`;
74
+ - deterministic formatting through Ruff's formatter.
75
+
76
+ Rationale:
77
+
78
+ - formatting is automated instead of debated in review;
79
+ - generated cache stays under `work/`, not in the user home or repository root.
80
+
81
+ ---
82
+
83
+ ## 4. Static Lint
84
+
85
+ Command:
86
+
87
+ ```text
88
+ uv run ruff check src/ tests/
89
+ ```
90
+
91
+ Configuration:
92
+
93
+ ```toml
94
+ [tool.ruff.lint]
95
+ select = ["E", "F", "I", "UP"]
96
+ ```
97
+
98
+ Controlled rule families:
99
+
100
+ | Code family | Meaning |
101
+ |-------------|---------|
102
+ | `E` | pycodestyle errors |
103
+ | `F` | Pyflakes correctness checks |
104
+ | `I` | import sorting |
105
+ | `UP` | pyupgrade modernization |
106
+
107
+ Controlled points:
108
+
109
+ - syntax-level and import correctness;
110
+ - unused imports and undefined names;
111
+ - import ordering;
112
+ - modern Python syntax for the supported Python version.
113
+
114
+ Rationale:
115
+
116
+ - this is a compact baseline with low noise;
117
+ - it catches common correctness issues without forcing broad style rules too
118
+ early.
119
+
120
+ ---
121
+
122
+ ## 5. Docstring Rules
123
+
124
+ Command:
125
+
126
+ ```text
127
+ uv run ruff check src/ --select D --ignore D100,D104
128
+ ```
129
+
130
+ Configuration:
131
+
132
+ ```toml
133
+ [tool.ruff.lint.pydocstyle]
134
+ convention = "google"
135
+ ```
136
+
137
+ Controlled points:
138
+
139
+ - public functions and classes in `src/` have docstrings where required;
140
+ - docstrings follow the Google convention recognized by Ruff/pydocstyle;
141
+ - sections such as `Args`, `Returns`, `Raises`, and `Attributes` follow the
142
+ expected structure;
143
+ - docstring formatting issues such as missing summary separation or invalid
144
+ escape sequences are reported.
145
+
146
+ Ignored rules:
147
+
148
+ | Rule | Reason |
149
+ |------|--------|
150
+ | `D100` | Module docstrings are useful but not mandatory for every source module yet |
151
+ | `D104` | Package `__init__.py` files are export façades and are not forced to carry package-level documentation |
152
+
153
+ Scope:
154
+
155
+ - `src/` only.
156
+ - `tests/` are excluded from docstring checks to avoid requiring docstrings on
157
+ every test function and test class.
158
+
159
+ Rationale:
160
+
161
+ - source APIs must be documented consistently;
162
+ - tests should stay readable without boilerplate;
163
+ - `__init__.py` files are excluded from coverage and should remain lightweight
164
+ export façades, not containers for business logic.
165
+
166
+ ---
167
+
168
+ ## 6. Type Checking
169
+
170
+ Command:
171
+
172
+ ```text
173
+ uv run mypy src/
174
+ ```
175
+
176
+ Configuration:
177
+
178
+ ```toml
179
+ [tool.mypy]
180
+ strict = true
181
+ packages = ["scribpy"]
182
+ cache_dir = "work/.mypy_cache"
183
+ ```
184
+
185
+ Controlled points:
186
+
187
+ - strict typing for source code;
188
+ - typed package importability;
189
+ - no implicit optional misuse;
190
+ - no untyped definitions where mypy strict requires annotations;
191
+ - mypy cache stored under `work/`.
192
+
193
+ Rationale:
194
+
195
+ - Scribpy's architecture relies on typed contracts and immutable data objects;
196
+ - type errors should be caught before functional chains are built on top of
197
+ unstable interfaces.
198
+
199
+ ---
200
+
201
+ ## 7. Tests and Coverage
202
+
203
+ Command:
204
+
205
+ ```text
206
+ uv run pytest
207
+ ```
208
+
209
+ Configuration:
210
+
211
+ ```toml
212
+ [tool.pytest.ini_options]
213
+ testpaths = ["tests"]
214
+ addopts = "--tb=short --cov=src/scribpy --cov-report=term-missing --cov-report=xml:work/coverage.xml --cov-report=html:work/htmlcov --junitxml=work/junit.xml"
215
+ pythonpath = ["src"]
216
+ cache_dir = "work/.pytest_cache"
217
+ ```
218
+
219
+ Coverage configuration:
220
+
221
+ ```toml
222
+ [tool.coverage.run]
223
+ data_file = "work/.coverage"
224
+ source = ["src/scribpy"]
225
+ omit = [
226
+ "src/scribpy/__init__.py",
227
+ "src/scribpy/__main__.py",
228
+ "src/scribpy/**/__init__.py",
229
+ ]
230
+
231
+ [tool.coverage.report]
232
+ fail_under = 80
233
+ show_missing = true
234
+ ```
235
+
236
+ Controlled points:
237
+
238
+ - all tests under `tests/`;
239
+ - source coverage under `src/scribpy`;
240
+ - short tracebacks for readable failure output;
241
+ - terminal missing-line coverage report;
242
+ - XML report for CI tooling;
243
+ - HTML report for local inspection;
244
+ - JUnit report for CI test result ingestion.
245
+
246
+ Generated files:
247
+
248
+ | Path | Purpose |
249
+ |------|---------|
250
+ | `work/.coverage` | Coverage data file |
251
+ | `work/coverage.xml` | Coverage XML report |
252
+ | `work/htmlcov/` | HTML coverage report |
253
+ | `work/junit.xml` | JUnit test report |
254
+ | `work/.pytest_cache` | Pytest cache |
255
+
256
+ Coverage omissions:
257
+
258
+ - `src/scribpy/__init__.py`;
259
+ - `src/scribpy/__main__.py`;
260
+ - all package `__init__.py` files.
261
+
262
+ Rationale:
263
+
264
+ - `__init__.py` files should stay as import/export façades;
265
+ - business logic must live in regular modules so it is covered;
266
+ - excluding `__init__.py` avoids false pressure to test import plumbing while
267
+ preserving coverage pressure on real logic.
268
+
269
+ Important rule:
270
+
271
+ ```text
272
+ Do not put business logic in __init__.py.
273
+ ```
274
+
275
+ If logic appears in `__init__.py`, it may be excluded from coverage and create a
276
+ false sense of test safety.
277
+
278
+ ---
279
+
280
+ ## 8. CI Command
281
+
282
+ Command:
283
+
284
+ ```text
285
+ make ci
286
+ ```
287
+
288
+ Implementation:
289
+
290
+ ```text
291
+ bash scripts/ci.sh
292
+ ```
293
+
294
+ Purpose:
295
+
296
+ - run the consolidated CI workflow;
297
+ - allow CI to report a full summary instead of stopping at the first local
298
+ `make check` failure.
299
+
300
+ `make check` remains the local fast feedback command.
301
+
302
+ ---
303
+
304
+ ## 9. Distribution Checks
305
+
306
+ Commands:
307
+
308
+ ```text
309
+ make build
310
+ make check-dist
311
+ ```
312
+
313
+ Defined behavior:
314
+
315
+ | Target | Command | Purpose |
316
+ |--------|---------|---------|
317
+ | `clean-dist` | `rm -rf dist` | Remove previous distribution artifacts |
318
+ | `build` | `uv build` | Build package distributions |
319
+ | `check-dist` | `uv run --with twine twine check dist/*` | Validate built distributions |
320
+
321
+ Rationale:
322
+
323
+ - distribution validation is separate from `make check`;
324
+ - local development checks stay fast;
325
+ - packaging checks are available before publishing.
326
+
327
+ ---
328
+
329
+ ## 10. Current Quality Gate
330
+
331
+ The current local gate is:
332
+
333
+ ```text
334
+ make check
335
+ ```
336
+
337
+ It controls:
338
+
339
+ 1. formatting;
340
+ 2. static lint;
341
+ 3. Google-style source docstrings;
342
+ 4. strict typing;
343
+ 5. tests;
344
+ 6. coverage threshold and reports.
345
+
346
+ Expected successful output includes:
347
+
348
+ ```text
349
+ ruff format: unchanged or reformatted
350
+ ruff check: All checks passed
351
+ docstrings: All checks passed
352
+ mypy: Success
353
+ pytest: all tests passed
354
+ coverage: fail_under reached
355
+ ```
356
+
357
+ ---
358
+
359
+ ## 11. Documentation Layout
360
+
361
+ Development decision records live under:
362
+
363
+ ```text
364
+ doc/adr/
365
+ ```
366
+
367
+ This separates ADRs from package-level design documentation such as:
368
+
369
+ - `doc/SDD.md`;
370
+ - `doc/FUNCTIONAL_CHAINS.md`;
371
+ - this check policy document.
372
+
373
+ ADRs are development governance documents. They describe decisions, rationale,
374
+ and trade-offs; they are not user-facing package documentation.