frontface-proofit 1.2.0__tar.gz → 1.2.1__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 (25) hide show
  1. {frontface_proofit-1.2.0/src/frontface_proofit.egg-info → frontface_proofit-1.2.1}/PKG-INFO +28 -14
  2. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/README.md +27 -13
  3. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/pyproject.toml +4 -1
  4. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1/src/frontface_proofit.egg-info}/PKG-INFO +28 -14
  5. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/src/frontface_proofit.egg-info/SOURCES.txt +1 -0
  6. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/src/proofit/__main__.py +20 -6
  7. frontface_proofit-1.2.1/src/proofit/templates/runbook-template.md +103 -0
  8. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/tests/test_cli.py +29 -0
  9. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/LICENSE +0 -0
  10. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/setup.cfg +0 -0
  11. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/src/frontface_proofit.egg-info/dependency_links.txt +0 -0
  12. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/src/frontface_proofit.egg-info/entry_points.txt +0 -0
  13. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/src/frontface_proofit.egg-info/top_level.txt +0 -0
  14. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/src/proofit/__init__.py +0 -0
  15. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/src/proofit/checks.py +0 -0
  16. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/src/proofit/ledger.py +0 -0
  17. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/src/proofit/leet.py +0 -0
  18. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/src/proofit/linter.py +0 -0
  19. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/src/proofit/model.py +0 -0
  20. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/src/proofit/parser.py +0 -0
  21. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/tests/test_1337.py +0 -0
  22. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/tests/test_ledger.py +0 -0
  23. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/tests/test_linter.py +0 -0
  24. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/tests/test_parser.py +0 -0
  25. {frontface_proofit-1.2.0 → frontface_proofit-1.2.1}/tests/test_rules.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frontface-proofit
3
- Version: 1.2.0
3
+ Version: 1.2.1
4
4
  Summary: Fail-closed linter for locked-down runbooks: ten rules of workflow discipline as code
5
5
  Author: Ryan Wesley Hitchcock
6
6
  License: MIT
@@ -21,8 +21,10 @@ people following it do the same thing and get the same result. proofit checks
21
21
  a runbook draft against fourteen rules of workflow discipline — ten structural
22
22
  rules plus the 1337 module's four (cross-role duplication, header date,
23
23
  suspicious character count, missing-file verification) — and **rejects the
24
- draft if any rule is violated**. No warnings, no advisories. Fail-closed:
25
- exit 1 until it's fixed, exit 0 when it's locked down.
24
+ draft if any structural rule is violated**. Heuristic and convention rules
25
+ (R1, R5, R8, R13) come back as warnings — shown, but they don't fail the
26
+ draft unless `--strict` is passed. Fail-closed where it counts:
27
+ exit 1 until the structural rules pass, exit 0 when it's locked down.
26
28
 
27
29
  It checks the runbook's **shape, not its truth**: it can tell you a step is
28
30
  missing its verification block, not whether the verification would actually
@@ -74,10 +76,11 @@ mechanical: the rules that can be checked as structure *are* checked as
74
76
  structure, so compliance isn't a matter of discipline — it's a matter of
75
77
  passing the gate.
76
78
 
77
- Two rules (1 and 8) are phrase-list heuristics — tripwires, not proof. Under
78
- fail-closed they still block, so they are deliberately narrow: they fire only
79
- on clear hits. A foolproof gate that misfires on good drafts isn't foolproof,
80
- it's a tax. The narrowness is documented in the code and tested.
79
+ Two rules (1 and 8) are phrase-list heuristics — tripwires, not proof. They
80
+ report as warnings in default mode and block only under `--strict`, so they
81
+ are deliberately narrow: they fire only on clear hits. A foolproof gate that
82
+ misfires on good drafts isn't foolproof, it's a tax. The narrowness is
83
+ documented in the code and tested.
81
84
 
82
85
  ## Quickstart
83
86
 
@@ -85,14 +88,20 @@ Zero dependencies beyond Python 3.10+.
85
88
 
86
89
  ```bash
87
90
  cd proofit
88
- PYTHONPATH=src python3 -m unittest discover -s tests # 65 offline tests
91
+ PYTHONPATH=src python3 -m unittest discover -s tests # 90 offline tests
89
92
  ```
90
93
 
91
- Lint a draft:
94
+ Lint a known-good draft first (expect PASS: no violations):
95
+
96
+ ```bash
97
+ PYTHONPATH=src python3 -m proofit lint examples/fixed-runbook.md
98
+ ```
99
+
100
+ The blank template REJECTS until its placeholders are real observable checks. Then lint a draft:
92
101
 
93
102
  ```bash
94
103
  PYTHONPATH=src python3 -m proofit lint my-runbook.md
95
- # violations listed as RULE n [location] ERROR — message + fix
104
+ # violations listed as RULE n [location] ERROR|WARNING — message + fix
96
105
  # exit 1: REJECTED — fix and re-run
97
106
  # exit 0: PASS — the runbook is locked down
98
107
  ```
@@ -127,9 +136,10 @@ fixed draft passes).
127
136
  than producing meaningful per-rule violations. Write it in the template,
128
137
  get it checked — anything else isn't a bad runbook to proofit, it's not
129
138
  a runbook at all.
130
- - **Output:** a list of violations (`RULE n [location] ERROR — message`
131
- plus a `fix:` line), and an exit code: 1 if any violation exists, 0 if
132
- clean. Fail-closed — there is no warning level.
139
+ - **Output:** a list of findings (`RULE n [location] ERROR|WARNING — message`
140
+ plus a `fix:` line), and an exit code: 1 if any ERROR exists, 0 if
141
+ clean. Structural violations are fail-closed; heuristic and convention
142
+ hits are warnings unless `--strict`.
133
143
 
134
144
  ## Worked example
135
145
 
@@ -155,7 +165,11 @@ linter.
155
165
 
156
166
  **Why fail-closed instead of warnings?** Because the skill's promise is
157
167
  "unbreakable, zero-assumption directive." A warning you can ignore is the
158
- opposite of idiot-proof. The gate is the product.
168
+ opposite of idiot-proof — so structural violations are fail-closed, no
169
+ exceptions. The heuristic and convention rules (R1, R5, R8, R13) are the
170
+ narrow exception: they report as warnings because they're tripwires, not
171
+ proof, and tripwires can false-positive. Pass `--strict` to make them fail
172
+ the draft too. The gate is still the product.
159
173
 
160
174
  **Single-service workflow — do I need the routing section?** No. Rule 9 is
161
175
  vacuous when no services are named. Delete the Routing Architecture section
@@ -5,8 +5,10 @@ people following it do the same thing and get the same result. proofit checks
5
5
  a runbook draft against fourteen rules of workflow discipline — ten structural
6
6
  rules plus the 1337 module's four (cross-role duplication, header date,
7
7
  suspicious character count, missing-file verification) — and **rejects the
8
- draft if any rule is violated**. No warnings, no advisories. Fail-closed:
9
- exit 1 until it's fixed, exit 0 when it's locked down.
8
+ draft if any structural rule is violated**. Heuristic and convention rules
9
+ (R1, R5, R8, R13) come back as warnings — shown, but they don't fail the
10
+ draft unless `--strict` is passed. Fail-closed where it counts:
11
+ exit 1 until the structural rules pass, exit 0 when it's locked down.
10
12
 
11
13
  It checks the runbook's **shape, not its truth**: it can tell you a step is
12
14
  missing its verification block, not whether the verification would actually
@@ -58,10 +60,11 @@ mechanical: the rules that can be checked as structure *are* checked as
58
60
  structure, so compliance isn't a matter of discipline — it's a matter of
59
61
  passing the gate.
60
62
 
61
- Two rules (1 and 8) are phrase-list heuristics — tripwires, not proof. Under
62
- fail-closed they still block, so they are deliberately narrow: they fire only
63
- on clear hits. A foolproof gate that misfires on good drafts isn't foolproof,
64
- it's a tax. The narrowness is documented in the code and tested.
63
+ Two rules (1 and 8) are phrase-list heuristics — tripwires, not proof. They
64
+ report as warnings in default mode and block only under `--strict`, so they
65
+ are deliberately narrow: they fire only on clear hits. A foolproof gate that
66
+ misfires on good drafts isn't foolproof, it's a tax. The narrowness is
67
+ documented in the code and tested.
65
68
 
66
69
  ## Quickstart
67
70
 
@@ -69,14 +72,20 @@ Zero dependencies beyond Python 3.10+.
69
72
 
70
73
  ```bash
71
74
  cd proofit
72
- PYTHONPATH=src python3 -m unittest discover -s tests # 65 offline tests
75
+ PYTHONPATH=src python3 -m unittest discover -s tests # 90 offline tests
73
76
  ```
74
77
 
75
- Lint a draft:
78
+ Lint a known-good draft first (expect PASS: no violations):
79
+
80
+ ```bash
81
+ PYTHONPATH=src python3 -m proofit lint examples/fixed-runbook.md
82
+ ```
83
+
84
+ The blank template REJECTS until its placeholders are real observable checks. Then lint a draft:
76
85
 
77
86
  ```bash
78
87
  PYTHONPATH=src python3 -m proofit lint my-runbook.md
79
- # violations listed as RULE n [location] ERROR — message + fix
88
+ # violations listed as RULE n [location] ERROR|WARNING — message + fix
80
89
  # exit 1: REJECTED — fix and re-run
81
90
  # exit 0: PASS — the runbook is locked down
82
91
  ```
@@ -111,9 +120,10 @@ fixed draft passes).
111
120
  than producing meaningful per-rule violations. Write it in the template,
112
121
  get it checked — anything else isn't a bad runbook to proofit, it's not
113
122
  a runbook at all.
114
- - **Output:** a list of violations (`RULE n [location] ERROR — message`
115
- plus a `fix:` line), and an exit code: 1 if any violation exists, 0 if
116
- clean. Fail-closed — there is no warning level.
123
+ - **Output:** a list of findings (`RULE n [location] ERROR|WARNING — message`
124
+ plus a `fix:` line), and an exit code: 1 if any ERROR exists, 0 if
125
+ clean. Structural violations are fail-closed; heuristic and convention
126
+ hits are warnings unless `--strict`.
117
127
 
118
128
  ## Worked example
119
129
 
@@ -139,7 +149,11 @@ linter.
139
149
 
140
150
  **Why fail-closed instead of warnings?** Because the skill's promise is
141
151
  "unbreakable, zero-assumption directive." A warning you can ignore is the
142
- opposite of idiot-proof. The gate is the product.
152
+ opposite of idiot-proof — so structural violations are fail-closed, no
153
+ exceptions. The heuristic and convention rules (R1, R5, R8, R13) are the
154
+ narrow exception: they report as warnings because they're tripwires, not
155
+ proof, and tripwires can false-positive. Pass `--strict` to make them fail
156
+ the draft too. The gate is still the product.
143
157
 
144
158
  **Single-service workflow — do I need the routing section?** No. Rule 9 is
145
159
  vacuous when no services are named. Delete the Routing Architecture section
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "frontface-proofit"
7
- version = "1.2.0"
7
+ version = "1.2.1"
8
8
  description = "Fail-closed linter for locked-down runbooks: ten rules of workflow discipline as code"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -26,5 +26,8 @@ proofit = "proofit.__main__:main"
26
26
  [tool.setuptools.packages.find]
27
27
  where = ["src"]
28
28
 
29
+ [tool.setuptools.package-data]
30
+ proofit = ["templates/*.md"]
31
+
29
32
  [tool.pytest.ini_options]
30
33
  testpaths = ["tests"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frontface-proofit
3
- Version: 1.2.0
3
+ Version: 1.2.1
4
4
  Summary: Fail-closed linter for locked-down runbooks: ten rules of workflow discipline as code
5
5
  Author: Ryan Wesley Hitchcock
6
6
  License: MIT
@@ -21,8 +21,10 @@ people following it do the same thing and get the same result. proofit checks
21
21
  a runbook draft against fourteen rules of workflow discipline — ten structural
22
22
  rules plus the 1337 module's four (cross-role duplication, header date,
23
23
  suspicious character count, missing-file verification) — and **rejects the
24
- draft if any rule is violated**. No warnings, no advisories. Fail-closed:
25
- exit 1 until it's fixed, exit 0 when it's locked down.
24
+ draft if any structural rule is violated**. Heuristic and convention rules
25
+ (R1, R5, R8, R13) come back as warnings — shown, but they don't fail the
26
+ draft unless `--strict` is passed. Fail-closed where it counts:
27
+ exit 1 until the structural rules pass, exit 0 when it's locked down.
26
28
 
27
29
  It checks the runbook's **shape, not its truth**: it can tell you a step is
28
30
  missing its verification block, not whether the verification would actually
@@ -74,10 +76,11 @@ mechanical: the rules that can be checked as structure *are* checked as
74
76
  structure, so compliance isn't a matter of discipline — it's a matter of
75
77
  passing the gate.
76
78
 
77
- Two rules (1 and 8) are phrase-list heuristics — tripwires, not proof. Under
78
- fail-closed they still block, so they are deliberately narrow: they fire only
79
- on clear hits. A foolproof gate that misfires on good drafts isn't foolproof,
80
- it's a tax. The narrowness is documented in the code and tested.
79
+ Two rules (1 and 8) are phrase-list heuristics — tripwires, not proof. They
80
+ report as warnings in default mode and block only under `--strict`, so they
81
+ are deliberately narrow: they fire only on clear hits. A foolproof gate that
82
+ misfires on good drafts isn't foolproof, it's a tax. The narrowness is
83
+ documented in the code and tested.
81
84
 
82
85
  ## Quickstart
83
86
 
@@ -85,14 +88,20 @@ Zero dependencies beyond Python 3.10+.
85
88
 
86
89
  ```bash
87
90
  cd proofit
88
- PYTHONPATH=src python3 -m unittest discover -s tests # 65 offline tests
91
+ PYTHONPATH=src python3 -m unittest discover -s tests # 90 offline tests
89
92
  ```
90
93
 
91
- Lint a draft:
94
+ Lint a known-good draft first (expect PASS: no violations):
95
+
96
+ ```bash
97
+ PYTHONPATH=src python3 -m proofit lint examples/fixed-runbook.md
98
+ ```
99
+
100
+ The blank template REJECTS until its placeholders are real observable checks. Then lint a draft:
92
101
 
93
102
  ```bash
94
103
  PYTHONPATH=src python3 -m proofit lint my-runbook.md
95
- # violations listed as RULE n [location] ERROR — message + fix
104
+ # violations listed as RULE n [location] ERROR|WARNING — message + fix
96
105
  # exit 1: REJECTED — fix and re-run
97
106
  # exit 0: PASS — the runbook is locked down
98
107
  ```
@@ -127,9 +136,10 @@ fixed draft passes).
127
136
  than producing meaningful per-rule violations. Write it in the template,
128
137
  get it checked — anything else isn't a bad runbook to proofit, it's not
129
138
  a runbook at all.
130
- - **Output:** a list of violations (`RULE n [location] ERROR — message`
131
- plus a `fix:` line), and an exit code: 1 if any violation exists, 0 if
132
- clean. Fail-closed — there is no warning level.
139
+ - **Output:** a list of findings (`RULE n [location] ERROR|WARNING — message`
140
+ plus a `fix:` line), and an exit code: 1 if any ERROR exists, 0 if
141
+ clean. Structural violations are fail-closed; heuristic and convention
142
+ hits are warnings unless `--strict`.
133
143
 
134
144
  ## Worked example
135
145
 
@@ -155,7 +165,11 @@ linter.
155
165
 
156
166
  **Why fail-closed instead of warnings?** Because the skill's promise is
157
167
  "unbreakable, zero-assumption directive." A warning you can ignore is the
158
- opposite of idiot-proof. The gate is the product.
168
+ opposite of idiot-proof — so structural violations are fail-closed, no
169
+ exceptions. The heuristic and convention rules (R1, R5, R8, R13) are the
170
+ narrow exception: they report as warnings because they're tripwires, not
171
+ proof, and tripwires can false-positive. Pass `--strict` to make them fail
172
+ the draft too. The gate is still the product.
159
173
 
160
174
  **Single-service workflow — do I need the routing section?** No. Rule 9 is
161
175
  vacuous when no services are named. Delete the Routing Architecture section
@@ -14,6 +14,7 @@ src/proofit/leet.py
14
14
  src/proofit/linter.py
15
15
  src/proofit/model.py
16
16
  src/proofit/parser.py
17
+ src/proofit/templates/runbook-template.md
17
18
  tests/test_1337.py
18
19
  tests/test_cli.py
19
20
  tests/test_ledger.py
@@ -13,9 +13,25 @@ from . import __version__, lint_file
13
13
  from .ledger import Ledger
14
14
 
15
15
 
16
- def _template_path() -> str:
16
+ def _template_text() -> str:
17
+ """Blank runbook template text.
18
+
19
+ Packaged copy first (``src/proofit/templates/`` ships in the wheel
20
+ as package data, so this works from a pip install), repo-layout
21
+ copy as fallback (``proofit/templates/`` — the file the live demo
22
+ page fetches from the repo, which must stay at that path).
23
+ """
24
+ try:
25
+ from importlib import resources
26
+ return (resources.files("proofit") / "templates"
27
+ / "runbook-template.md").read_text(encoding="utf-8")
28
+ except (ImportError, OSError):
29
+ pass
17
30
  here = os.path.dirname(os.path.abspath(__file__))
18
- return os.path.normpath(os.path.join(here, "..", "..", "templates", "runbook-template.md"))
31
+ repo_path = os.path.normpath(os.path.join(
32
+ here, "..", "..", "templates", "runbook-template.md"))
33
+ with open(repo_path, encoding="utf-8") as f:
34
+ return f.read()
19
35
 
20
36
 
21
37
  def cmd_lint(path: str, *, strict: bool = False) -> int:
@@ -103,12 +119,10 @@ def cmd_ledger(argv: list[str]) -> int:
103
119
 
104
120
 
105
121
  def cmd_template() -> int:
106
- path = _template_path()
107
122
  try:
108
- with open(path, encoding="utf-8") as f:
109
- sys.stdout.write(f.read())
123
+ sys.stdout.write(_template_text())
110
124
  except OSError as e:
111
- print(f"error: template not found at {path}: {e}", file=sys.stderr)
125
+ print(f"error: template not found: {e}", file=sys.stderr)
112
126
  return 2
113
127
  return 0
114
128
 
@@ -0,0 +1,103 @@
1
+ # Runbook: [workflow name]
2
+
3
+ <!--
4
+ Write the draft in this shape, then run: python -m proofit lint this-file.md
5
+ Fail-closed: ANY violation rejects the draft until fixed.
6
+ One action per Do:. Name exact visible labels in **bold**. No new
7
+ prerequisites after step 1. End with Validation & Closure, never a step.
8
+ -->
9
+
10
+ ## Ground Rules & Prerequisites
11
+
12
+ ### Required Baseline
13
+
14
+ [Exact starting condition: state, setup, preconditions.]
15
+
16
+ ### Routing Architecture
17
+
18
+ [Delete this whole section if the workflow uses a single service.]
19
+
20
+ #### Input spec
21
+
22
+ [Exact format, structure, and constraints of the input.]
23
+
24
+ #### Service 1: [name]
25
+
26
+ - **When to use:** [exact condition or trigger]
27
+ - **Free-tier limits:** [rate limits, context window, monthly quota]
28
+ - **Prompt (verbatim):**
29
+ ```
30
+ [paste the exact prompt — no improvisation at runtime]
31
+ ```
32
+ - **Expected output format:** [schema, field names, data types]
33
+
34
+ #### Service 2: [name]
35
+
36
+ - **When to use:** [exact condition or trigger]
37
+ - **Free-tier limits:** [rate limits, context window, monthly quota]
38
+ - **Prompt (verbatim):**
39
+ ```
40
+ [paste the exact prompt]
41
+ ```
42
+ - **Expected output format:** [schema, field names, data types]
43
+
44
+ #### Rate limit handling
45
+
46
+ [What to do when a free-tier limit is hit: wait time, fallback service, graceful degradation.]
47
+
48
+ #### Error paths
49
+
50
+ [What to do if any service fails or returns unexpected data.]
51
+
52
+ ### Needed Tools/Items
53
+
54
+ - Hardware: [e.g. a laptop with 8 GB RAM]
55
+ - Software: [e.g. Chrome, Python 3.12]
56
+ - Accounts: [e.g. a free-tier account on each service above — no API keys]
57
+ - Permissions: [e.g. admin on the target machine]
58
+ - Files: [e.g. ~/data/input.csv]
59
+ - Internet access: [e.g. required throughout]
60
+
61
+ ### Expected Outcome
62
+
63
+ [What will exist after completion, and what it should contain.]
64
+
65
+ ## Step-by-Step Directives
66
+
67
+ ### Step 1: [action name]
68
+
69
+ **Do:** [exactly ONE action — "Open **Settings**.", never "Open Settings and click Display."]
70
+
71
+ **Look for:** [exact visual anchor or expected output, including what visibly changes]
72
+
73
+ **Verify:** [observable success condition — what the screen displays, what exists, what the output contains]
74
+
75
+ **If wrong:** [the most likely mistake for this step]
76
+
77
+ **Fix:** [the shortest recovery path — resume the guide instead of restarting when possible]
78
+
79
+ ### Step 2: [action name]
80
+
81
+ **Do:** [one action]
82
+
83
+ **Look for:** [visual anchor]
84
+
85
+ **Verify:** [observable success condition]
86
+
87
+ **If wrong:** [most likely mistake]
88
+
89
+ **Fix:** [shortest recovery path]
90
+
91
+ ## Validation & Closure
92
+
93
+ ### Success Condition
94
+
95
+ [The exact final state. The reader should know with certainty the task succeeded.]
96
+
97
+ ### Consistency Checkpoints
98
+
99
+ - [ ] All inputs met spec requirements (format, structure, constraints).
100
+ - [ ] Each service received the correct prompt and context.
101
+ - [ ] Each service's output matched the expected format.
102
+ - [ ] Error recovery was never triggered, OR was triggered and resolved correctly.
103
+ - [ ] The complete workflow produces the intended result.
@@ -49,6 +49,35 @@ class TestCLI(unittest.TestCase):
49
49
  self.assertIn("lint", r.stdout)
50
50
 
51
51
 
52
+ class TestTemplatePackaging(unittest.TestCase):
53
+ """The template ships in the wheel (1.2.0 bug: it did not).
54
+
55
+ `proofit/templates/runbook-template.md` is the canonical file —
56
+ the live demo page fetches it from the repo — and
57
+ `src/proofit/templates/runbook-template.md` is the packaged copy.
58
+ The two must stay byte-identical, and `proofit template` must
59
+ print exactly that file, from a pip install as well as from source.
60
+ """
61
+
62
+ def test_packaged_template_matches_repo_template(self):
63
+ sys.path.insert(0, os.path.join(PKG, "src"))
64
+ from importlib import resources
65
+ packaged = (resources.files("proofit") / "templates"
66
+ / "runbook-template.md").read_bytes()
67
+ with open(os.path.join(PKG, "templates",
68
+ "runbook-template.md"), "rb") as f:
69
+ repo = f.read()
70
+ self.assertEqual(packaged, repo)
71
+
72
+ def test_template_command_prints_repo_template(self):
73
+ r = run_cli("template")
74
+ self.assertEqual(r.returncode, 0)
75
+ with open(os.path.join(PKG, "templates",
76
+ "runbook-template.md"),
77
+ encoding="utf-8") as f:
78
+ self.assertEqual(r.stdout, f.read())
79
+
80
+
52
81
  # PARAM-PROOFIT-001: WARNINGs pass by default, fail under --strict;
53
82
  # ERRORs fail in both modes.
54
83
  R1_ONLY = """# Runbook: test