|
1 | | -# Zenzic — Agent Guidelines |
| 1 | +# Zenzic Agent Guidelines — v0.6.1 "Obsidian Glass" Stable |
2 | 2 |
|
3 | | -Zenzic is an engine-agnostic linter and security shield for Markdown documentation (Docusaurus v3, MkDocs, Zensical, bare Markdown). It ships as a CLI (`zenzic`), a Python library, and a native MkDocs plugin. Python ≥ 3.11 required. |
| 3 | +Zenzic is the high-performance, engine-agnostic Safe Harbor for Markdown documentation. |
| 4 | +It is a STABLE product. Agents must prioritize precision, security, and "Value-First" communication. |
4 | 5 |
|
5 | | -## Build & Test |
| 6 | +--- |
6 | 7 |
|
7 | | -```bash |
8 | | -uv sync --all-groups # install all dependency groups (once after clone) |
9 | | -just test # run tests — Hypothesis dev profile (50 examples) |
10 | | -just test-full # CI-grade run (500 examples) |
11 | | -just preflight # full local CI: lint + format + typecheck + pytest + reuse |
12 | | -just verify # preflight + self-lint (zenzic check all --strict) |
13 | | -``` |
| 8 | +## 🎯 Mission: The Safe Harbor |
14 | 9 |
|
15 | | -Common individual sessions: |
| 10 | +- **Target:** Engineers, Technical Writers, and curious users. |
| 11 | +- **Philosophy:** "If the engine builds the site, Zenzic guarantees the source." |
| 12 | +- **Communication:** README is a Landing Page, not a manual. Move technical deep-dives to the documentation portal (zenzic.dev). |
16 | 13 |
|
17 | | -```bash |
18 | | -nox -s lint -- --fix # ruff autofix |
19 | | -nox -s fmt # ruff format in-place |
20 | | -nox -s typecheck # mypy --strict on src/ |
21 | | -nox -s reuse # SPDX/REUSE compliance check |
22 | | -``` |
| 14 | +--- |
| 15 | + |
| 16 | +## 🚀 Key Features (v0.6.1 — Obsidian Glass Stable) |
| 17 | + |
| 18 | +- **Instant Entry:** `uvx zenzic check all ./path` is the primary curiosity path. |
| 19 | +- **Zenzic Lab:** 9 interactive Acts for onboarding (zero-config showroom). Run `zenzic lab` to see the menu; `zenzic lab <N>` to run a specific act. |
| 20 | +- **Standalone Mode:** Default engine for pure Markdown projects with no recognised build system. Replaces the old "Vanilla" identity entirely. |
| 21 | +- **Zensical Bridge:** Transparent Proxy for `mkdocs.yml` compatibility under `engine = "zensical"`. |
| 22 | +- **Enterprise Docusaurus:** Full versioning, `@site/` alias, and slug logic alignment. |
| 23 | +- **Offline Mode:** `--offline` flag for flat `.html` URL structure. |
| 24 | +- **SEO Guardrail:** `Z401 MISSING_DIRECTORY_INDEX` detection for directories without a landing page. |
| 25 | +- **Finding Codes (Zxxx):** Every diagnostic carries a unique `Zxxx` identifier for enterprise-grade auditing and future filtering. |
| 26 | + |
| 27 | +--- |
| 28 | + |
| 29 | +## 🧱 The 3 Pillars (Non-Negotiable) |
| 30 | + |
| 31 | +1. **Lint the Source:** Never depend on HTML output. Analyze raw Markdown and configs. |
| 32 | +2. **No Subprocesses:** 100% pure Python. No `subprocess.run`, no Node.js execution. |
| 33 | +3. **Pure Functions First:** Deterministic logic. No I/O in hot-path loops. |
| 34 | + |
| 35 | +--- |
| 36 | + |
| 37 | +## 🛡️ Core Laws for Code |
23 | 38 |
|
24 | | -See [justfile](../justfile) for the full recipe list and [noxfile.py](../noxfile.py) for session definitions. |
| 39 | +- **Zero I/O in hot paths:** No `Path.exists()` or `open()` inside link/file loops. |
| 40 | +- **Mandatory ExclusionManager:** No discovery without an explicit exclusion manager. |
| 41 | +- **Exit Codes:** 0 (Success), 1 (Quality), 2 (Shield/Secrets), 3 (Blood Sentinel/Fatal). |
| 42 | +- **Finding Codes:** Every `Finding` object must carry a `Zxxx` code from `src/zenzic/core/codes.py`. Never hardcode a raw string code; always use `codes.normalize()`. |
25 | 43 |
|
26 | | -## Architecture |
| 44 | +--- |
| 45 | + |
| 46 | +## 📐 Architecture Map |
27 | 47 |
|
28 | 48 | ```text |
29 | 49 | src/zenzic/ |
30 | | -├── main.py / cli.py # Typer CLI (commands: check, score, diff) |
31 | | -├── core/ # Hot-path analysis engine (zero I/O — see Core Laws) |
32 | | -│ ├── adapter.py # BaseAdapter Protocol + RouteMetadata |
33 | | -│ ├── adapters/ # docusaurus_v3, mkdocs, zensical, vanilla |
34 | | -│ ├── discovery.py # Universal file discovery (os.walk + LayeredExclusionManager) |
35 | | -│ ├── exclusion.py # LayeredExclusionManager (4-level: System → VCS → Config → CLI) |
36 | | -│ ├── rules.py # AdaptiveRuleEngine + O(V+E) circular detection |
37 | | -│ ├── shield.py # Credential scanner (9 families, 8-step normalization, lookback buffer) |
38 | | -│ ├── resolver.py # InMemoryPathResolver (link resolution) |
39 | | -│ ├── scanner.py # Two-Pass Reference Pipeline (Harvest → Cross-Check → Report) |
40 | | -│ └── validator.py # validate_links_async orchestrator |
41 | | -├── models/ # Pydantic models (config, references, vsm) |
42 | | -└── integrations/mkdocs.py # Native MkDocs plugin |
| 50 | + cli.py — Typer CLI entry-points; builds Finding objects via _to_findings() |
| 51 | + lab.py — Interactive showcase (9 Acts); menu-driven with positional arg |
| 52 | + core/ |
| 53 | + adapter.py — Public re-exports (StandaloneAdapter, MkDocsAdapter, …) |
| 54 | + adapters/ |
| 55 | + _standalone.py — StandaloneAdapter: no-op engine for pure Markdown projects |
| 56 | + _mkdocs.py — MkDocs engine adapter |
| 57 | + _docusaurus.py — Docusaurus v3 engine adapter |
| 58 | + _zensical.py — Zensical engine adapter (+ Transparent Proxy) |
| 59 | + _factory.py — get_adapter() factory; contains vanilla→standalone migration guard |
| 60 | + __init__.py — Public adapter registry |
| 61 | + codes.py — Zxxx finding code registry (SINGLE SOURCE OF TRUTH) |
| 62 | + reporter.py — SentinelReporter; renders Finding objects to Rich output |
| 63 | + scanner.py — File discovery, orphan detection, shield bridge |
| 64 | + validator.py — Link / anchor / path-traversal validation |
| 65 | + rules.py — VSM-based rule engine (Z001, Z002) |
| 66 | + shield.py — Credential scanner (exits 2/3) |
| 67 | + scorer.py — Quality score engine |
| 68 | + models/ |
| 69 | + config.py — ZenzicConfig / BuildContext (Pydantic) |
| 70 | + vsm.py — Virtual Site Map (Route, build_vsm, detect_collisions) |
| 71 | + references.py — Reference integrity (IntegrityReport, ReferenceFinding) |
| 72 | + ui.py — Shared Rich colour constants and emoji helpers |
| 73 | +tests/ |
| 74 | + test_standalone_mode.py — StandaloneAdapter unit tests + factory routing |
| 75 | + test_vsm.py — Virtual Site Map tests |
| 76 | + test_blue_vsm_edge.py — VSM edge-case stress tests |
| 77 | + test_protocol_evolution.py — Adapter protocol compliance + Hypothesis stress tests |
| 78 | + test_cli.py — CLI integration tests (Typer runner) |
| 79 | + test_scanner.py — Scanner / orphan / i18n tests |
| 80 | + test_rules.py — Rule engine tests |
| 81 | + test_shield.py — Shield / credential detection tests |
43 | 82 | ``` |
44 | 83 |
|
45 | | -Third-party adapters and rules are discoverable via `zenzic.adapters` / `zenzic.rules` entry-point groups. |
| 84 | +--- |
| 85 | + |
| 86 | +## 🔎 Finding Code Standard (Zxxx) |
| 87 | + |
| 88 | +All diagnostics emitted by Zenzic carry a `Zxxx` code. The registry is in |
| 89 | +`src/zenzic/core/codes.py`. **Never add a new finding without registering its code there first.** |
| 90 | + |
| 91 | +| Range | Category | Examples | |
| 92 | +|-------|----------|---------| |
| 93 | +| Z1xx | Link Integrity | Z101 LINK_BROKEN, Z102 ANCHOR_MISSING, Z104 FILE_NOT_FOUND | |
| 94 | +| Z2xx | Security | Z201 SHIELD_SECRET, Z202 PATH_TRAVERSAL | |
| 95 | +| Z3xx | Reference Integrity | Z301 DANGLING_REF, Z302 DEAD_DEF | |
| 96 | +| Z4xx | Structure | Z401 MISSING_DIRECTORY_INDEX, Z402 ORPHAN_PAGE | |
| 97 | +| Z5xx | Content Quality | Z501 PLACEHOLDER, Z503 SNIPPET_ERROR | |
| 98 | +| Z9xx | Engine / System | Z902 RULE_TIMEOUT | |
| 99 | + |
| 100 | +When creating a `Finding`, always call `codes.normalize(raw_code)` to map legacy strings to canonical `Zxxx` codes. The `_to_findings()` function in `cli.py` is the authorised conversion point. |
| 101 | + |
| 102 | +--- |
| 103 | + |
| 104 | +## 🏭 Adapter Identity Rules |
| 105 | + |
| 106 | +- **"standalone"** is the canonical engine name for projects with no build config. Use `StandaloneAdapter`. |
| 107 | +- **"vanilla"** is a removed legacy name. Any usage raises `ConfigurationError` with code `Z000`. |
| 108 | +- `pyproject.toml` entry-point: `standalone = "zenzic.core.adapters:StandaloneAdapter"`. |
| 109 | +- In Standalone Mode, navigation-based checks (orphan detection) are disabled because there is no declared nav. |
| 110 | +- When `zenzic init` finds no engine config, it writes `engine = "standalone"` in the `[build_context]` block. |
| 111 | + |
| 112 | +--- |
| 113 | + |
| 114 | +## 🧪 Quality Gate |
| 115 | + |
| 116 | +- **Coverage:** ≥ 80% mandatory. |
| 117 | +- **Mutation:** Mutmut audit on `rules.py` and `shield.py`. |
| 118 | +- **Property Testing:** Hypothesis for `resolver.py` and adapter stress-testing. |
| 119 | +- **Test naming:** All test functions relating to the Standalone adapter use the prefix `test_standalone_*`. |
| 120 | + |
| 121 | +--- |
| 122 | + |
| 123 | +## 📝 README Restyling Rules |
| 124 | + |
| 125 | +When editing `README.md` or `README.it.md`: |
| 126 | + |
| 127 | +1. **Above the Fold:** Hook + uvx command + Quick Start + Sentinel Report must be visible within 2 scrolls. |
| 128 | +2. **Problem/Solution:** Use tables to contrast "Without Zenzic" vs "With Zenzic". |
| 129 | +3. **Deduplicate:** Technical implementation details belong in `/docs/internals` on zenzic.dev. |
| 130 | +4. **Bilingual Parity:** EN and IT must be perfectly mirrored in structure and quality. |
| 131 | +5. **Branding:** Keep "Shield", "Blood Sentinel", "VSM", "Ghost Routes" as-is (Proper Nouns). |
| 132 | +6. **Standalone, not Vanilla:** Never write "Vanilla Mode" in user-facing copy. Use "Standalone Mode". |
| 133 | + |
| 134 | +--- |
| 135 | + |
| 136 | +## 🧹 Maintenance & Sunset Clauses (Technical Debt Tracking) |
| 137 | + |
| 138 | +### 1. Vanilla-to-Standalone Migration Guard |
| 139 | + |
| 140 | +- **Status:** Deprecated. |
| 141 | +- **Location:** `src/zenzic/core/adapters/_factory.py` (check for `engine == "vanilla"`). |
| 142 | +- **Behavior:** Raises a `ConfigurationError` with code `Z000` to guide users to `engine = "standalone"`. |
| 143 | +- **Sunset Target:** **v0.7.0**. |
| 144 | +- **Instruction:** Do NOT remove this guard in 0.6.x patches. MUST be deleted entirely in the 0.7.0 release to achieve zero-legacy codebase. |
| 145 | + |
| 146 | +### 2. Finding Codes (Zxxx) |
| 147 | + |
| 148 | +- **Standard:** All diagnostics must use the `Zxxx` format. |
| 149 | +- **Rule:** Never introduce a new finding string without a corresponding code in `src/zenzic/core/codes.py`. |
| 150 | + |
| 151 | +--- |
| 152 | + |
| 153 | +## 🗺️ Sprint History (for institutional memory) |
| 154 | + |
| 155 | +### Direttiva 036 — Finding Code Mapping |
46 | 156 |
|
47 | | -## Core Laws |
| 157 | +Codified all diagnostic outputs into the `Zxxx` scheme. `codes.py` created as single source of truth. |
48 | 158 |
|
49 | | -1. **Zero I/O in the hot path**: nothing inside `src/zenzic/core/` may call `Path.exists()`, `open()`, or subprocesses inside per-link or per-file loops. Only two I/O phases are permitted: `discovery.py` file enumeration (via `os.walk` + `LayeredExclusionManager`) and `InMemoryPathResolver.__init__`. |
50 | | -2. **Subprocess-free linting**: `zenzic check` never calls `mkdocs build` or any external process. |
51 | | -3. **Mandatory ExclusionManager**: every file-discovery entry point requires a `LayeredExclusionManager` argument — no `Optional`, no `None` default. Omitting it is a `TypeError` at call time, not a silent full-tree scan at runtime. |
| 159 | +### Direttiva 037 — Standalone Renaissance |
52 | 160 |
|
53 | | -Violating any of these laws is a blocking defect — do not introduce exceptions. |
| 161 | +Full rename: `VanillaAdapter` → `StandaloneAdapter`, `_vanilla.py` → `_standalone.py`, entry-point `vanilla` → `standalone`. Breaking change: `engine = "vanilla"` raises `ConfigurationError [Z000]`. Test suite fully migrated to `test_standalone_mode.py`. |
54 | 162 |
|
55 | | -## Code Conventions |
| 163 | +### Direttiva 038 — Final Audit Record |
56 | 164 |
|
57 | | -- **Type checking**: `mypy --strict` must pass on all of `src/`. Never suppress with `# type: ignore` without a comment explaining why. |
58 | | -- **Linting**: ruff rules `E, F, W, I, B, C4, UP, A`; line length 100; isort `known-first-party = ["zenzic"]`. |
59 | | -- **SPDX headers**: every source file must start with `# SPDX-FileCopyrightText: ...` and `# SPDX-License-Identifier: Apache-2.0`. Run `nox -s reuse` to verify. |
60 | | -- **No stubs**: no `TODO`, placeholder text, or stub implementations in committed code. |
61 | | -- **Coverage**: ≥ 80% branch coverage enforced by pytest. Mutation goal ≥ 90% on `rules.py`, `shield.py`, `reporter.py`. |
62 | | -- **Discovery**: never use `Path.rglob()` or `glob.glob()` directly. All file enumeration goes through `discovery.iter_markdown_sources()` or `discovery.walk_files()` with a `LayeredExclusionManager`. |
| 165 | +CHANGELOG.md, CHANGELOG.it.md, and RELEASE.md updated to reflect the Breaking Change (Vanilla → Standalone), the Zxxx code introduction, and the interactive Lab menu. |
63 | 166 |
|
64 | | -## Tests |
| 167 | +### Direttiva 039 — The Guardrail Lifecycle |
65 | 168 |
|
66 | | -- Tests live in `tests/`; helpers in `tests/_helpers.py`; fixtures in `tests/conftest.py`. |
67 | | -- Hypothesis profiles: `dev` (50), `ci` (500), `purity` (1000) — set via `HYPOTHESIS_PROFILE`. |
68 | | -- Markers: `slow`, `integration` — run with `-m "not slow"` to skip heavy tests locally. |
69 | | -- The `_reset_zenzic_logger` autouse fixture resets the `RichHandler` after each test; do not remove it. |
| 169 | +Migration guard in `_factory.py` annotated with `# TODO: Remove this migration guard in v0.7.0.` and error message prefixed with `[Z000]`. Docstring clarified. |
70 | 170 |
|
71 | | -## Key Docs |
| 171 | +### Direttiva 040 — Institutional Memory |
72 | 172 |
|
73 | | -- [CONTRIBUTING.md](../CONTRIBUTING.md) — dev workflow, PR conventions, Core Laws reference |
74 | | -- [SECURITY.md](../SECURITY.md) — vulnerability reporting and scope |
75 | | -- [CHANGELOG.md](../CHANGELOG.md) — version history |
76 | | -- [RELEASE.md](../RELEASE.md) — release checklist |
| 173 | +This file (`.github/copilot-instructions.md`) created / restored as the canonical agent briefing document, embedding all sprint directives and sunset clauses for permanent institutional memory. |
0 commit comments