tmaudit 0.5.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.
Files changed (43) hide show
  1. tmaudit-0.5.0/LICENSE +24 -0
  2. tmaudit-0.5.0/PKG-INFO +386 -0
  3. tmaudit-0.5.0/README.md +350 -0
  4. tmaudit-0.5.0/pyproject.toml +99 -0
  5. tmaudit-0.5.0/setup.cfg +4 -0
  6. tmaudit-0.5.0/src/tmaudit/__init__.py +68 -0
  7. tmaudit-0.5.0/src/tmaudit/__main__.py +5 -0
  8. tmaudit-0.5.0/src/tmaudit/cache.py +259 -0
  9. tmaudit-0.5.0/src/tmaudit/cli.py +479 -0
  10. tmaudit-0.5.0/src/tmaudit/configs/__init__.py +18 -0
  11. tmaudit-0.5.0/src/tmaudit/configs/compile_configs.py +296 -0
  12. tmaudit-0.5.0/src/tmaudit/configs/paper_configs.py +686 -0
  13. tmaudit-0.5.0/src/tmaudit/detector_config/__init__.py +21 -0
  14. tmaudit-0.5.0/src/tmaudit/detector_config/detector_min.py +113 -0
  15. tmaudit-0.5.0/src/tmaudit/forge.py +320 -0
  16. tmaudit-0.5.0/src/tmaudit/llm_fallback.py +328 -0
  17. tmaudit-0.5.0/src/tmaudit/plugins.py +464 -0
  18. tmaudit-0.5.0/src/tmaudit/report.py +353 -0
  19. tmaudit-0.5.0/src/tmaudit/templates/__init__.py +1 -0
  20. tmaudit-0.5.0/src/tmaudit/templates/compile_check_TEMPLATE.py +131 -0
  21. tmaudit-0.5.0/src/tmaudit/templates/fix_abstract_unicode_TEMPLATE.py +136 -0
  22. tmaudit-0.5.0/src/tmaudit/templates/verify_TEMPLATE.py +1719 -0
  23. tmaudit-0.5.0/src/tmaudit.egg-info/PKG-INFO +386 -0
  24. tmaudit-0.5.0/src/tmaudit.egg-info/SOURCES.txt +41 -0
  25. tmaudit-0.5.0/src/tmaudit.egg-info/dependency_links.txt +1 -0
  26. tmaudit-0.5.0/src/tmaudit.egg-info/entry_points.txt +2 -0
  27. tmaudit-0.5.0/src/tmaudit.egg-info/requires.txt +9 -0
  28. tmaudit-0.5.0/src/tmaudit.egg-info/top_level.txt +1 -0
  29. tmaudit-0.5.0/tests/test_bug5_unit.py +100 -0
  30. tmaudit-0.5.0/tests/test_c10_reproducibility.py +478 -0
  31. tmaudit-0.5.0/tests/test_c6_threshold.py +113 -0
  32. tmaudit-0.5.0/tests/test_c7_citation_context.py +447 -0
  33. tmaudit-0.5.0/tests/test_c8_statistical_power.py +511 -0
  34. tmaudit-0.5.0/tests/test_c9_figure_caption.py +495 -0
  35. tmaudit-0.5.0/tests/test_cache.py +371 -0
  36. tmaudit-0.5.0/tests/test_detector_config.py +169 -0
  37. tmaudit-0.5.0/tests/test_example_plugin.py +163 -0
  38. tmaudit-0.5.0/tests/test_forge.py +468 -0
  39. tmaudit-0.5.0/tests/test_forge_happy.py +217 -0
  40. tmaudit-0.5.0/tests/test_llm_fallback.py +408 -0
  41. tmaudit-0.5.0/tests/test_paper_configs.py +252 -0
  42. tmaudit-0.5.0/tests/test_plugin_api.py +682 -0
  43. tmaudit-0.5.0/tests/test_report.py +342 -0
tmaudit-0.5.0/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Liu Zewen
4
+
5
+ Permission is hereby granted, free of charge, to any person
6
+ obtaining a copy of this software and associated documentation
7
+ files (the "Software"), to deal in the Software without
8
+ restriction, including without limitation the rights to use,
9
+ copy, modify, merge, publish, distribute, sublicense, and/or
10
+ sell copies of the Software, and to permit persons to whom the
11
+ Software is furnished to do so, subject to the following
12
+ conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
+ OTHER DEALINGS IN THE SOFTWARE.
tmaudit-0.5.0/PKG-INFO ADDED
@@ -0,0 +1,386 @@
1
+ Metadata-Version: 2.4
2
+ Name: tmaudit
3
+ Version: 0.5.0
4
+ Summary: Config-driven TMLR paper audit + LaTeX compile pipeline
5
+ Author-email: Liu Zewen <aidless@example.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/aidless/tmaudit
8
+ Project-URL: Issues, https://github.com/aidless/tmaudit/issues
9
+ Project-URL: Source, https://github.com/aidless/tmaudit
10
+ Project-URL: Changelog, https://github.com/aidless/tmaudit/blob/main/CHANGELOG.md
11
+ Project-URL: v0.4.0 release, https://github.com/aidless/tmaudit/releases/tag/v0.4.0
12
+ Keywords: tmaudit,tmlr,paper-audit,latex,compile,plugins,neurips,iclr,reviewer,audit
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Scientific/Engineering
22
+ Classifier: Topic :: Software Development :: Quality Assurance
23
+ Classifier: Topic :: Text Processing :: Markup :: LaTeX
24
+ Requires-Python: >=3.9
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Provides-Extra: dev
28
+ Requires-Dist: pyflakes>=3.0; extra == "dev"
29
+ Requires-Dist: pytest>=7; extra == "dev"
30
+ Requires-Dist: mypy>=1.0; extra == "dev"
31
+ Requires-Dist: build>=0.10; extra == "dev"
32
+ Requires-Dist: twine>=4; extra == "dev"
33
+ Requires-Dist: scipy>=1.10; extra == "dev"
34
+ Requires-Dist: PyYAML>=6.0; extra == "dev"
35
+ Dynamic: license-file
36
+
37
+ # tmaudit — Deploy & Quick Start
38
+
39
+ [![CI](https://github.com/aidless/tmaudit/actions/workflows/ci.yml/badge.svg)](https://github.com/aidless/tmaudit/actions/workflows/ci.yml)
40
+ ![Python](https://img.shields.io/badge/python-3.9%20%7C%203.10%20%7C%203.11%20%7C%203.12-blue)
41
+ ![Tests](https://img.shields.io/badge/tests-176%20passing-brightgreen)
42
+ ![Meta--tests](https://img.shields.io/badge/meta--tests-12%2F12%20caught-success)
43
+ ![Categories](https://img.shields.io/badge/audit%20categories-C1..C10-blue)
44
+ ![PR%20Checks](https://img.shields.io/badge/PR%20checks-40%20checkboxes-blueviolet)
45
+ ![Issues](https://img.shields.io/badge/issues-4%20templates-blueviolet)
46
+ ![Security](https://img.shields.io/badge/security-policy%20in%20place-green)
47
+ ![Version](https://img.shields.io/badge/version-0.5.0-blue)
48
+ ![Roadmap](https://img.shields.io/badge/roadmap-through%20v0.5.0-green)
49
+ ![License](https://img.shields.io/badge/license-MIT-lightgrey)
50
+
51
+ This directory is a **deployable Python package** named `tmaudit`. It
52
+ ships three things in one place:
53
+
54
+ 1. The **templates** for the three operational scripts that every
55
+ `PAPER<N>_CONSOLIDATED/` directory needs
56
+ (`verify_p<N>.py`, `_compile_check.py`,
57
+ `_fix_abstract_unicode.py`).
58
+ 2. The **per-paper configurations** (C1..C10 audit rules: C1–C7
59
+ in v0.1.0–v0.2.0, plus C8 statistical power, C9 figure-caption,
60
+ and C10 reproducibility in v0.3.0; abstract Unicode
61
+ replacements) for Paper 1, 2, 3, 4, 5.
62
+ 3. A **CLI** (`tmaudit`) that forks the templates into any paper
63
+ directory and (optionally) runs them.
64
+
65
+ ## Three ways to use it
66
+
67
+ ### (A) Run the single-file `tmaudit.pyz` (zero install)
68
+
69
+ ```bash
70
+ # on any machine with Python 3.9+
71
+ python tmaudit.pyz list
72
+ python tmaudit.pyz verify --paper 1
73
+ python tmaudit.pyz compile --paper 5
74
+ python tmaudit.pyz fix-unicode --paper 1
75
+ python tmaudit.pyz audit-all
76
+ ```
77
+
78
+ The `.pyz` is a self-extracting Python zip archive; the user does not
79
+ need to `pip install` anything. The file is `~46 KB` and contains all
80
+ five `PAPER_CONFIGS` and all three templates.
81
+
82
+ This is the **recommended distribution form** for handing the tool
83
+ to a co-author or to the TMLR reviewers.
84
+
85
+ ### (B) `pip install --editable .` (development)
86
+
87
+ ```powershell
88
+ cd <your tmaudit checkout>
89
+ python -m pip install --editable .
90
+ tmaudit list
91
+ tmaudit verify --paper 1
92
+ ```
93
+
94
+ Edits to `src/tmaudit/templates/*.py` or
95
+ `src/tmaudit/configs/*.py` are picked up immediately on the next
96
+ `tmaudit` invocation. This is the **recommended form for ongoing
97
+ development** of the templates themselves.
98
+
99
+ ### (C) `pip install .` (deployment to a venv)
100
+
101
+ ```bash
102
+ python -m venv .venv
103
+ source .venv/bin/activate # or .venv\Scripts\activate on Windows
104
+ pip install .
105
+ tmaudit list
106
+ ```
107
+
108
+ This produces a `tmaudit` console-script entry in the venv. The
109
+ template and config files are inside the wheel.
110
+
111
+ ## v0.3.0 highlights
112
+
113
+ **Released: 2026-07-10.** This release adds 3 new audit categories
114
+ (C8, C9, C10) and brings the project to **10 categories, 176 unit
115
+ tests, 12/12 meta-test bugs caught, 5/5 papers auditable**.
116
+
117
+ | Category | What it checks | Severity | Always runs? |
118
+ |---|---|---|---|
119
+ | **C1** (v0.1.0) | Symbol inline definition | HIGH | Yes |
120
+ | **C2** (v0.1.0) | Bonferroni consistency | HIGH | Yes |
121
+ | **C3** (v0.1.0) | Formalization of key concept | MEDIUM | Yes |
122
+ | **C4** (v0.1.0) | Self-citation threshold | MEDIUM | Yes |
123
+ | **C5** (v0.1.0) | Test-name d | MEDIUM | Yes |
124
+ | **C6** (v0.1.1) | Blacklist word frequency | LOW | Yes |
125
+ | **C7** (v0.1.2) | Ceremonial citation detection | MEDIUM | Yes |
126
+ | **C8** (v0.3.0) | **Statistical power** (d-mismatch, post-hoc power) | HIGH/MED | No (opt-in) |
127
+ | **C9** (v0.3.0) | **Figure-caption consistency** (4 sub-checks) | HIGH/MED | Yes (sub-check 3 opt-in) |
128
+ | **C10** (v0.3.0) | **Reproducibility** (availability, metadata, consistency) | HIGH/MED/LOW | Yes (sub-check 2 opt-in) |
129
+ | **C7-LLM** (v0.2.0) | LLM fallback for C7 borderline cases (opt-in via `TMAUDIT_LLM_*` env) | MEDIUM | No |
130
+
131
+ **v0.2.0 added** (still shipping): `audit-all --output report.md`
132
+ generates a single Markdown report covering all papers; the report
133
+ is uploaded as a CI artefact.
134
+
135
+ **v0.2.0 added** (still shipping): per-paper config for Paper 2,
136
+ Paper 3, Paper 4 (was placeholder in v0.1.1). All 5 papers
137
+ (P1..P5) are now auditable.
138
+
139
+ **Per-paper config** for v0.3.0: `c8_claimed_effects` (statistical),
140
+ `c9_figure_keywords` (figure-caption), `c10_reproducibility_claims`
141
+ (reproducibility). Empty list = opt-out (with graceful degradation
142
+ in C9 and C10).
143
+
144
+ See [`RELEASE_NOTES_v0.3.0.md`](./RELEASE_NOTES_v0.3.0.md) for the
145
+ full release notes and [`engineering_notes_verify_template.md`](./engineering_notes_verify_template.md)
146
+ §12 (C8+C10) and §13 (C9) for the design rationale.
147
+
148
+ ## CLI reference
149
+
150
+ ```text
151
+ tmaudit list # show all known paper configs
152
+ tmaudit verify --paper N [--dry-run] # fork verify_pN.py + run audit
153
+ tmaudit compile --paper N [--dry-run] # fork _compile_check.py + 4-pass build
154
+ tmaudit fix-unicode --paper N [--dry-run] # fork _fix_abstract_unicode.py
155
+ tmaudit audit-all [--start 1] [--end 5] # verify all papers in a range
156
+ ```
157
+
158
+ Every subcommand also accepts `--paper-dir PATH` to override the
159
+ default paper directory.
160
+
161
+ ## The standard 3-step protocol for any new paper
162
+
163
+ ```powershell
164
+ cd F:\Research\PAPER<N>_CONSOLIDATED
165
+
166
+ # 1. audit
167
+ tmaudit verify --paper N
168
+
169
+ # 2. fix abstract Unicode (if any finding)
170
+ tmaudit fix-unicode --paper N
171
+ tmaudit verify --paper N
172
+
173
+ # 3. compile
174
+ tmaudit compile --paper N
175
+ ```
176
+
177
+ ## Package layout
178
+
179
+ ```
180
+ TEMPLATE/
181
+ ├── pyproject.toml # build config
182
+ ├── tmaudit.pyz # single-file distribution (46 KB)
183
+ ├── README.md # this file
184
+ ├── engineering_notes_verify_template.md # 6-bug engineering diary
185
+ ├── _setup_pkg.py # one-time: copy templates into src/
186
+ ├── _build_pyz.py # one-time: build tmaudit.pyz
187
+ ├── _compile_appendix.py # LaTeX compile for the appendix
188
+ ├── _regen_appendix.py # regenerate appendix_engineering.tex
189
+ ├── _status.py # TEMPLATE/ state summary
190
+ └── src/
191
+ └── tmaudit/ # the actual package
192
+ ├── __init__.py
193
+ ├── __main__.py # `python -m tmaudit`
194
+ ├── cli.py # argparse CLI
195
+ ├── forge.py # template-substitution engine
196
+ ├── templates/
197
+ │ ├── __init__.py
198
+ │ ├── verify_TEMPLATE.py # ≈ 22 KB, ~400 lines
199
+ │ ├── compile_check_TEMPLATE.py # ≈ 4.5 KB
200
+ │ └── fix_abstract_unicode_TEMPLATE.py # ≈ 5 KB
201
+ └── configs/
202
+ ├── __init__.py # re-exports
203
+ ├── paper_configs.py # VERIFY_CONFIGS for paper 1..5
204
+ └── compile_configs.py # COMPILE_CONFIGS for paper 1..5
205
+ ```
206
+
207
+ ## Adding a new paper (e.g., Paper 6)
208
+
209
+ Edit **two** files:
210
+
211
+ 1. `src/tmaudit/configs/paper_configs.py` — add a new entry to
212
+ `PAPER_CONFIGS` (or `VERIFY_CONFIGS` after re-export). The fields
213
+ are documented in the docstring at the top of that file.
214
+ 2. `src/tmaudit/configs/compile_configs.py` — add a matching entry
215
+ to `COMPILE_CONFIGS`. The fields are documented in the docstring
216
+ there.
217
+
218
+ Then:
219
+
220
+ ```powershell
221
+ python -m pip install --editable . --break-system-packages
222
+ python _build_pyz.py
223
+ tmaudit list # confirm Paper 6 shows up
224
+ tmaudit verify --paper 6 # fork + run; will report any HIGH-severity
225
+ # issues caused by your config choices
226
+ ```
227
+
228
+ ## Verifying the .pyz is portable
229
+
230
+ ```bash
231
+ # On the source machine:
232
+ python _build_pyz.py
233
+ # -> tmaudit.pyz (46 KB)
234
+
235
+ # Copy tmaudit.pyz to a fresh machine with no Python packages installed
236
+ # (only a base Python 3.9+ interpreter):
237
+ scp tmaudit.pyz other-host:/tmp/
238
+ ssh other-host 'python /tmp/tmaudit.pyz list'
239
+ # -> should print the same 5-paper table
240
+ ```
241
+
242
+ The `.pyz` has **no external dependencies** (only the Python standard
243
+ library). It works on Linux, macOS, and Windows alike.
244
+
245
+ ## Bug history
246
+
247
+ The **twelve historical bugs** encountered while building this
248
+ package are documented in
249
+ [`engineering_notes_verify_template.md`](./engineering_notes_verify_template.md).
250
+ Each bug has a dedicated regression test in
251
+ `tests/test_forge_happy.py`, `tests/test_bug5_unit.py`,
252
+ `tests/test_c6_threshold.py`, `tests/test_c7_citation_context.py`,
253
+ `tests/test_cache.py`, `tests/test_c10_reproducibility.py`,
254
+ `tests/test_c8_statistical_power.py`, and
255
+ `tests/test_c9_figure_caption.py`. The meta-test
256
+ (`_check_all_regressions.py`) injects each bug in turn, asserts the
257
+ regression test catches it, and restores the source. **12/12 bugs
258
+ are caught.**
259
+
260
+ The fix patterns (raw-string regex literals, brace-counting state
261
+ machines, non-letter-class regex, second/third-pass audit logic,
262
+ sentinel-character sub-string extraction, etc.) are all implemented
263
+ in `src/tmaudit/forge.py` and
264
+ `src/tmaudit/templates/verify_TEMPLATE.py`.
265
+
266
+ ## Continuous integration
267
+
268
+ ### Workflow
269
+
270
+ `.github/workflows/ci.yml` runs on every push and pull request.
271
+ It consists of **five** jobs:
272
+
273
+ 1. **pytest** (matrix: Python 3.9, 3.10, 3.11, 3.12 on `ubuntu-latest`)
274
+ — runs the **176-test** suite and uploads JUnit XML artifacts.
275
+ 2. **meta-test** (Python 3.11) — runs `_check_all_regressions.py`
276
+ to verify that each of the **12 regression tests** actually catches
277
+ its target bug. Builds `tmaudit.pyz` and runs it as a smoke
278
+ test.
279
+ 3. **validate-community-files** (Python 3.11) — runs
280
+ `_check_github_templates.py` to verify the `.github/`
281
+ directory structure (4 issue templates, PR template, CODEOWNERS,
282
+ dependabot.yml, CODE_OF_CONDUCT, SUPPORT, workflows).
283
+ 4. **audit-all** (Python 3.11) — runs
284
+ `tmaudit audit-all --start 1 --end 5 --output audit-report.md
285
+ --no-cache` and uploads the Markdown report as a CI artefact.
286
+ 5. **lint** (Python 3.11) — runs `pyflakes` on `src/tmaudit/`
287
+ and `tests/`.
288
+
289
+ ### Local validation (before pushing)
290
+
291
+ To run the same checks locally before pushing:
292
+
293
+ ```bash
294
+ pip install -e . pytest pyflakes
295
+ pytest
296
+ python _check_all_regressions.py
297
+ python _build_pyz.py
298
+ python tmaudit.pyz list
299
+ python -m pyflakes src/tmaudit/ tests/
300
+ ```
301
+
302
+ ### Local CI simulation (`act` / `_act_*`)
303
+
304
+ The preferred tool for local CI simulation is
305
+ [nektos/act](https://github.com/nektos/act):
306
+
307
+ ```bash
308
+ act -l # list jobs
309
+ act -j pytest # run the pytest job
310
+ act -j meta-test # run the meta-test job (after pytest)
311
+ act -j lint # run the lint job
312
+ ```
313
+
314
+ `act` requires `act` installed **and** a working Docker daemon.
315
+ If either is unavailable (e.g., on a restricted sandbox machine),
316
+ this repo ships two **fallback** simulators:
317
+
318
+ | Script | `act` equivalent | What it does |
319
+ |---|---|---|
320
+ | `_act_dryrun.py` | `act -n` (dry-run) | Parses `ci.yml`, expands the matrix, prints what each step would do. **No commands are executed.** |
321
+ | `_act_simulate.py` | `act` (real run) | Same as dryrun, but actually runs the `run:` steps via `subprocess`. Implements stubs for `actions/checkout@v4`, `actions/setup-python@v5`, `actions/upload-artifact@v4`. |
322
+
323
+ ```bash
324
+ python _act_dryrun.py # show what would be executed
325
+ python _act_dryrun.py --list # show jobs only
326
+ python _act_simulate.py --list # list jobs (act -l equivalent)
327
+ python _act_simulate.py --job pytest # run pytest job
328
+ ```
329
+
330
+ ### CI simulation results
331
+
332
+ `_act_dryrun.py` was used to validate the workflow before
333
+ pushing. Results:
334
+
335
+ - ✅ `ci.yml` is valid YAML (parsed by PyYAML)
336
+ - ✅ **5 jobs**, 4 + 1 + 1 + 1 + 1 matrix rows, ~25 steps
337
+ - ✅ `meta-test` correctly depends on `pytest` (Kahn's algorithm topo sort)
338
+ - ✅ `matrix.python-version` substituted correctly into `${{ ... }}` expressions
339
+ - ✅ `if: always()` preserved on the upload-artifact step
340
+ - ✅ `with:` arguments (e.g., `cache: pip`, `cache-dependency-path: pyproject.toml`) preserved
341
+
342
+ The CI workflow's `run:` blocks are identical to commands
343
+ we have already executed successfully on the host:
344
+
345
+ | CI step | Local result |
346
+ |---|---|
347
+ | `python -m pip install -e .` | tmaudit installed ✅ |
348
+ | `python -m pip install pytest scipy` | deps installed ✅ |
349
+ | `python -m pytest -m "not slow"` | **223 passed, 1 skipped in ~4s** ✅ |
350
+ | `python _check_all_regressions.py` | **14/14 bugs caught** ✅ |
351
+ | `python _check_github_templates.py` | **44/44 OK** ✅ |
352
+ | `python -m src.tmaudit audit-all ...` | audit-report.md generated ✅ |
353
+ | `python -m src.tmaudit audit-all ...` | report uploaded as artefact ✅ |
354
+ | `python _build_pyz.py` | tmaudit.pyz built ✅ |
355
+ | `python tmaudit.pyz list` | 5 papers listed ✅ |
356
+ | `python -m pyflakes src/tmaudit/ tests/` | 0 errors ✅ |
357
+
358
+ ### What `_act_*` cannot simulate
359
+
360
+ - `actions/setup-python@v5` cannot actually install a different
361
+ Python version (the host has only one Python; the matrix
362
+ includes 3.9/3.10/3.11/3.12). The simulator prints a
363
+ warning but does not fail.
364
+ - `actions/upload-artifact@v4` is simulated by copying files
365
+ to `_act_run/artifacts/<name>/`.
366
+ - The Docker isolation that real `act` provides is not present;
367
+ steps run on the host shell.
368
+
369
+ ### Pre-push hook recommendation
370
+
371
+ To enforce CI validation before every push:
372
+
373
+ ```bash
374
+ # .git/hooks/pre-push
375
+ python _check_yaml.py && python _act_dryrun.py
376
+ ```
377
+
378
+ The `_check_yaml.py` script validates `ci.yml` is parseable
379
+ and has the expected structure (catches YAML syntax errors
380
+ before pushing).
381
+
382
+ ### Full evidence
383
+
384
+ For the full simulation transcript (including the 5 sandbox
385
+ issues encountered and how they were worked around), see
386
+ [`act_summary.md`](./act_summary.md).