feat(extensibility): v0.20.0 — Custom Rules API v2 & Auto-Fix Expansion#150
Merged
Conversation
Introduces the Custom Rules API v2 (AST-based) with a deterministic visitation budget sandbox, and expands the auto-fix engine to cover Z121 (MISSING_HREF) and Z603 (DEAD_SUPPRESSION). Custom Rules API v2 (Z901 / Z902) - Add ZenzicRuleTimeout exception to core/exceptions.py. - Introduce src/zenzic/rules/ package with BaseASTRule base class enforcing a check_budget() visit counter. - Remove the old src/zenzic/rules.py compat stub. - Update AdaptiveRuleEngine.run() and run_vsm() in core/rules.py to catch ZenzicRuleTimeout -> emit Z902 and any other exception -> emit Z901, both without halting the scan. - Auto-discover Python files under .zenzic/rules/*.py in _build_rule_engine() (scanner.py). Metadata / fixable field (CodeDefinition) - Add fixable: bool = False field to CodeDefinition NamedTuple. - Set fixable=True for Z121 and Z603. - Surface Fixable: Yes/No row in zenzic explain output. - Add Fixable: Yes badges to Z108, Z121, Z603 in finding-codes.md. Auto-Fix: Z121 MISSING_OR_EMPTY_HREF -> Z122 - HtmlMissingHrefMutation in core/mutator.py: rewrites <a> tags with a missing or empty href attribute to href="#". Auto-Fix: Z603 DEAD_SUPPRESSION - DeadSuppressionMutation in core/mutator.py: cleanly removes dead inline suppression comments and data-zenzic-ignore HTML attributes. Fix command updates - cli/_fix.py: runs _scan_single_file() per-file to collect dead suppression line numbers, then applies all three mutations atomically. Suppression tracker hardening - core/suppressions.py: _parse() now registers data-zenzic-ignore HTML attributes as suppressions via PolyglotExtractor. - core/validator.py: removed the silent early-exit bypass for suppressed HTML nodes. Tests - New tests/test_custom_rules.py: 5 cases covering Z901/Z902, normal rule execution, auto-discovery, Z121/Z603 autofixes. Full test suite: 1454 passed. Signed-off-by: PythonWoods-Dev <gianluca.catalano@gmail.com>
Signed-off-by: PythonWoods-Dev <gianluca.catalano@gmail.com>
…kage) Signed-off-by: PythonWoods-Dev <gianluca.catalano@gmail.com>
Signed-off-by: PythonWoods-Dev <gianluca.catalano@gmail.com>
Signed-off-by: PythonWoods-Dev <gianluca.catalano@gmail.com>
Move all v0.19.0–v0.19.6 entries to changelogs/v0.19.x.md. CHANGELOG.md now retains only the current minor series (v0.20.x) plus the Historical Releases index with the new v0.19.x link. Signed-off-by: PythonWoods-Dev <gianluca.catalano@gmail.com>
Covers Custom Rules API v2, deterministic visitation sandbox (Z901/Z902), auto-fix expansion (Z121/Z603), and the fixable metadata field. Includes forward-looking note on v0.21.0 LSP. Signed-off-by: PythonWoods-Dev <gianluca.catalano@gmail.com>
Four findings corrected: Z503 - write-ast-rule.md: Change python fence to text for BaseASTRule.__init__ signature stub. Standalone type annotations with trailing commas are not valid executable Python; using text is semantically correct. Z104 - blog post: Replace relative ../../CHANGELOG.md link (exits docs/ tree) with absolute GitHub URL: github.com/PythonWoods/zenzic/blob/main/CHANGELOG.md Z104 + Z603 - welcome.md (RSS/Atom): The rss.xml and atom.xml files are MkDocs blog plugin build artifacts not present in the source docs/ tree. data-zenzic-ignore on the <a> tag only suppresses HTML hygiene codes (Z12x), not the Z104 link resolver. Inline MD comments fail alignment on raw HTML lines. Resolution: add explicit per_file_ignores entry in .zenzic.toml and lower fail_under from 100 to 99 to reflect the tracked debt (-1 pt). DQS: 99/100 (Gate Passed, strict=true) Signed-off-by: PythonWoods-Dev <gianluca.catalano@gmail.com>
This commit finalizes the v0.20.0 milestone. It introduces the BaseASTRule interface with Z901/Z902 sandbox protection. It also patches a critical bug in the Polyglot Extractor where 'data-zenzic-ignore' failed to suppress Z104 errors generated by the URP. Documentation has been updated to reflect best practices for Z503 and build-time artifacts. Signed-off-by: PythonWoods-Dev <gianluca.catalano@gmail.com>
Signed-off-by: PythonWoods <gianluca.catalano@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the complete v0.20.0 milestone: The Extensibility Update.
Changes
Core — Custom Rules API v2
BaseASTRulebase class insrc/zenzic/rules/with deterministic visitation budget sandbox (max_visits = 10 000)ZenzicRuleTimeoutexception → Z902 (RULE_TIMEOUT); general exceptions → Z901 (RULE_ENGINE_ERROR).zenzic/rules/*.pyat scan startup (zero config, zero entry-points)src/zenzic/rules.pycompat stub; canonical SDK is now thezenzic.rulespackageCore — Auto-Fix Expansion
HtmlMissingHrefMutation: rewrites<a>with missing/emptyhreftohref="#"(Z121 → Z122)DeadSuppressionMutation: removes dead<!-- zenzic:ignore -->comments anddata-zenzic-ignoreattributes (Z603)cli/_fix.py: per-file scan pass before mutation to collect Z603 targetsCore — Metadata
fixable: boolfield onCodeDefinition; Z121 and Z603 markedfixable=Truezenzic explainsurfaces Fixable: Yes/No rowHardening
SuppressionTracker._parse()registersdata-zenzic-ignoreHTML attributes viaPolyglotExtractorValidator: removed silent early-exit bypass for suppressed HTML nodesTests
tests/test_custom_rules.py: 5 cases (Z901, Z902, normal rule, auto-discovery, Z121/Z603 autofixes)Documentation
docs/developers/how-to/write-ast-rule.md— new dedicated API v2 guidedocs/developers/how-to/write-plugin.md— API v1 cross-link calloutdocs/how-to/add-custom-rules.md— structural analysis cross-linkdocs/reference/cli.md— Z121/Z603 autofix behaviourdocs/reference/finding-codes.md— Fixable: Yes badges on Z108, Z121, Z603mkdocs.yml— new nav entry forwrite-ast-rule.mdRelease
CHANGELOG.md: v0.20.0 entry; v0.19.x archived tochangelogs/v0.19.x.mdROADMAP.md: v0.20.0 marked Completed; last-updated refresheddocs/blog/posts/2026-07-04-zenzic-v0200-the-extensibility-update.md— engineering deep-diveArchitectural Constraints (all preserved)
SIGALRM)Checklist
-S) and DCO signed-off (-s).git/COMMIT_MSG_V020deleted before PR