Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 152 additions & 55 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -1,76 +1,173 @@
# Zenzic Agent Guidelines
# Zenzic Agent Guidelines — v0.6.1 "Obsidian Glass" Stable

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.
Zenzic is the high-performance, engine-agnostic Safe Harbor for Markdown documentation.
It is a STABLE product. Agents must prioritize precision, security, and "Value-First" communication.

## Build & Test
---

```bash
uv sync --all-groups # install all dependency groups (once after clone)
just test # run tests — Hypothesis dev profile (50 examples)
just test-full # CI-grade run (500 examples)
just preflight # full local CI: lint + format + typecheck + pytest + reuse
just verify # preflight + self-lint (zenzic check all --strict)
```
## 🎯 Mission: The Safe Harbor

Common individual sessions:
- **Target:** Engineers, Technical Writers, and curious users.
- **Philosophy:** "If the engine builds the site, Zenzic guarantees the source."
- **Communication:** README is a Landing Page, not a manual. Move technical deep-dives to the documentation portal (zenzic.dev).

```bash
nox -s lint -- --fix # ruff autofix
nox -s fmt # ruff format in-place
nox -s typecheck # mypy --strict on src/
nox -s reuse # SPDX/REUSE compliance check
```
---

## 🚀 Key Features (v0.6.1 — Obsidian Glass Stable)

- **Instant Entry:** `uvx zenzic check all ./path` is the primary curiosity path.
- **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.
- **Standalone Mode:** Default engine for pure Markdown projects with no recognised build system. Replaces the old "Vanilla" identity entirely.
- **Zensical Bridge:** Transparent Proxy for `mkdocs.yml` compatibility under `engine = "zensical"`.
- **Enterprise Docusaurus:** Full versioning, `@site/` alias, and slug logic alignment.
- **Offline Mode:** `--offline` flag for flat `.html` URL structure.
- **SEO Guardrail:** `Z401 MISSING_DIRECTORY_INDEX` detection for directories without a landing page.
- **Finding Codes (Zxxx):** Every diagnostic carries a unique `Zxxx` identifier for enterprise-grade auditing and future filtering.

---

## 🧱 The 3 Pillars (Non-Negotiable)

1. **Lint the Source:** Never depend on HTML output. Analyze raw Markdown and configs.
2. **No Subprocesses:** 100% pure Python. No `subprocess.run`, no Node.js execution.
3. **Pure Functions First:** Deterministic logic. No I/O in hot-path loops.

---

## 🛡️ Core Laws for Code

See [justfile](../justfile) for the full recipe list and [noxfile.py](../noxfile.py) for session definitions.
- **Zero I/O in hot paths:** No `Path.exists()` or `open()` inside link/file loops.
- **Mandatory ExclusionManager:** No discovery without an explicit exclusion manager.
- **Exit Codes:** 0 (Success), 1 (Quality), 2 (Shield/Secrets), 3 (Blood Sentinel/Fatal).
- **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()`.

## Architecture
---

## 📐 Architecture Map

```text
src/zenzic/
├── main.py / cli.py # Typer CLI (commands: check, score, diff)
├── core/ # Hot-path analysis engine (zero I/O — see Core Laws)
│ ├── adapter.py # BaseAdapter Protocol + RouteMetadata
│ ├── adapters/ # docusaurus_v3, mkdocs, zensical, vanilla
│ ├── discovery.py # Universal file discovery (os.walk + LayeredExclusionManager)
│ ├── exclusion.py # LayeredExclusionManager (4-level: System → VCS → Config → CLI)
│ ├── rules.py # AdaptiveRuleEngine + O(V+E) circular detection
│ ├── shield.py # Credential scanner (9 families, 8-step normalization, lookback buffer)
│ ├── resolver.py # InMemoryPathResolver (link resolution)
│ ├── scanner.py # Two-Pass Reference Pipeline (Harvest → Cross-Check → Report)
│ └── validator.py # validate_links_async orchestrator
├── models/ # Pydantic models (config, references, vsm)
└── integrations/mkdocs.py # Native MkDocs plugin
cli.py — Typer CLI entry-points; builds Finding objects via _to_findings()
lab.py — Interactive showcase (9 Acts); menu-driven with positional arg
core/
adapter.py — Public re-exports (StandaloneAdapter, MkDocsAdapter, …)
adapters/
_standalone.py — StandaloneAdapter: no-op engine for pure Markdown projects
_mkdocs.py — MkDocs engine adapter
_docusaurus.py — Docusaurus v3 engine adapter
_zensical.py — Zensical engine adapter (+ Transparent Proxy)
_factory.py — get_adapter() factory; contains vanilla→standalone migration guard
__init__.py — Public adapter registry
codes.py — Zxxx finding code registry (SINGLE SOURCE OF TRUTH)
reporter.py — SentinelReporter; renders Finding objects to Rich output
scanner.py — File discovery, orphan detection, shield bridge
validator.py — Link / anchor / path-traversal validation
rules.py — VSM-based rule engine (Z001, Z002)
shield.py — Credential scanner (exits 2/3)
scorer.py — Quality score engine
models/
config.py — ZenzicConfig / BuildContext (Pydantic)
vsm.py — Virtual Site Map (Route, build_vsm, detect_collisions)
references.py — Reference integrity (IntegrityReport, ReferenceFinding)
ui.py — Shared Rich colour constants and emoji helpers
tests/
test_standalone_mode.py — StandaloneAdapter unit tests + factory routing
test_vsm.py — Virtual Site Map tests
test_blue_vsm_edge.py — VSM edge-case stress tests
test_protocol_evolution.py — Adapter protocol compliance + Hypothesis stress tests
test_cli.py — CLI integration tests (Typer runner)
test_scanner.py — Scanner / orphan / i18n tests
test_rules.py — Rule engine tests
test_shield.py — Shield / credential detection tests
```

Third-party adapters and rules are discoverable via `zenzic.adapters` / `zenzic.rules` entry-point groups.
---

## 🔎 Finding Code Standard (Zxxx)

All diagnostics emitted by Zenzic carry a `Zxxx` code. The registry is in
`src/zenzic/core/codes.py`. **Never add a new finding without registering its code there first.**

| Range | Category | Examples |
|-------|----------|---------|
| Z1xx | Link Integrity | Z101 LINK_BROKEN, Z102 ANCHOR_MISSING, Z104 FILE_NOT_FOUND |
| Z2xx | Security | Z201 SHIELD_SECRET, Z202 PATH_TRAVERSAL |
| Z3xx | Reference Integrity | Z301 DANGLING_REF, Z302 DEAD_DEF |
| Z4xx | Structure | Z401 MISSING_DIRECTORY_INDEX, Z402 ORPHAN_PAGE |
| Z5xx | Content Quality | Z501 PLACEHOLDER, Z503 SNIPPET_ERROR |
| Z9xx | Engine / System | Z902 RULE_TIMEOUT |

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.

---

## 🏭 Adapter Identity Rules

- **"standalone"** is the canonical engine name for projects with no build config. Use `StandaloneAdapter`.
- **"vanilla"** is a removed legacy name. Any usage raises `ConfigurationError` with code `Z000`.
- `pyproject.toml` entry-point: `standalone = "zenzic.core.adapters:StandaloneAdapter"`.
- In Standalone Mode, navigation-based checks (orphan detection) are disabled because there is no declared nav.
- When `zenzic init` finds no engine config, it writes `engine = "standalone"` in the `[build_context]` block.

---

## 🧪 Quality Gate

- **Coverage:** ≥ 80% mandatory.
- **Mutation:** Mutmut audit on `rules.py` and `shield.py`.
- **Property Testing:** Hypothesis for `resolver.py` and adapter stress-testing.
- **Test naming:** All test functions relating to the Standalone adapter use the prefix `test_standalone_*`.

---

## 📝 README Restyling Rules

When editing `README.md` or `README.it.md`:

1. **Above the Fold:** Hook + uvx command + Quick Start + Sentinel Report must be visible within 2 scrolls.
2. **Problem/Solution:** Use tables to contrast "Without Zenzic" vs "With Zenzic".
3. **Deduplicate:** Technical implementation details belong in `/docs/internals` on zenzic.dev.
4. **Bilingual Parity:** EN and IT must be perfectly mirrored in structure and quality.
5. **Branding:** Keep "Shield", "Blood Sentinel", "VSM", "Ghost Routes" as-is (Proper Nouns).
6. **Standalone, not Vanilla:** Never write "Vanilla Mode" in user-facing copy. Use "Standalone Mode".

---

## 🧹 Maintenance & Sunset Clauses (Technical Debt Tracking)

### 1. Vanilla-to-Standalone Migration Guard

- **Status:** Deprecated.
- **Location:** `src/zenzic/core/adapters/_factory.py` (check for `engine == "vanilla"`).
- **Behavior:** Raises a `ConfigurationError` with code `Z000` to guide users to `engine = "standalone"`.
- **Sunset Target:** **v0.7.0**.
- **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.

### 2. Finding Codes (Zxxx)

- **Standard:** All diagnostics must use the `Zxxx` format.
- **Rule:** Never introduce a new finding string without a corresponding code in `src/zenzic/core/codes.py`.

---

## 🗺️ Sprint History (for institutional memory)

### Direttiva 036 — Finding Code Mapping

## Core Laws
Codified all diagnostic outputs into the `Zxxx` scheme. `codes.py` created as single source of truth.

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__`.
2. **Subprocess-free linting**: `zenzic check` never calls `mkdocs build` or any external process.
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.
### Direttiva 037 — Standalone Renaissance

Violating any of these laws is a blocking defect — do not introduce exceptions.
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`.

## Code Conventions
### Direttiva 038 — Final Audit Record

- **Type checking**: `mypy --strict` must pass on all of `src/`. Never suppress with `# type: ignore` without a comment explaining why.
- **Linting**: ruff rules `E, F, W, I, B, C4, UP, A`; line length 100; isort `known-first-party = ["zenzic"]`.
- **SPDX headers**: every source file must start with `# SPDX-FileCopyrightText: ...` and `# SPDX-License-Identifier: Apache-2.0`. Run `nox -s reuse` to verify.
- **No stubs**: no `TODO`, placeholder text, or stub implementations in committed code.
- **Coverage**: ≥ 80% branch coverage enforced by pytest. Mutation goal ≥ 90% on `rules.py`, `shield.py`, `reporter.py`.
- **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`.
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.

## Tests
### Direttiva 039 — The Guardrail Lifecycle

- Tests live in `tests/`; helpers in `tests/_helpers.py`; fixtures in `tests/conftest.py`.
- Hypothesis profiles: `dev` (50), `ci` (500), `purity` (1000) — set via `HYPOTHESIS_PROFILE`.
- Markers: `slow`, `integration` — run with `-m "not slow"` to skip heavy tests locally.
- The `_reset_zenzic_logger` autouse fixture resets the `RichHandler` after each test; do not remove it.
Migration guard in `_factory.py` annotated with `# TODO: Remove this migration guard in v0.7.0.` and error message prefixed with `[Z000]`. Docstring clarified.

## Key Docs
### Direttiva 040 — Institutional Memory

- [CONTRIBUTING.md](../CONTRIBUTING.md) — dev workflow, PR conventions, Core Laws reference
- [SECURITY.md](../SECURITY.md) — vulnerability reporting and scope
- [CHANGELOG.md](../CHANGELOG.md) — version history
- [RELEASE.md](../RELEASE.md) — release checklist
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.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ dist/

# Zenzic: Drafts
drafts/
Draft/
*.egg
MANIFEST
.installed.cfg
Expand Down
72 changes: 71 additions & 1 deletion CHANGELOG.it.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,76 @@ Le versioni seguono il [Semantic Versioning](https://semver.org/).

## [Non rilasciato]

## [0.6.1] — 2026-04-19 — Obsidian Glass (Stable)

### Modifiche che rompono la compatibilità

- **Standalone Engine sostituisce Vanilla (Direttiva 037).** `VanillaAdapter` e la
keyword `engine = "vanilla"` sono stati rimossi. Tutti i progetti devono migrare a
`engine = "standalone"`. Qualsiasi `zenzic.toml` che usa ancora `engine = "vanilla"`
genera una `ConfigurationError [Z000]` all'avvio con un messaggio di migrazione chiaro.
*Migrazione:* sostituire `engine = "vanilla"` con `engine = "standalone"` nel proprio
`zenzic.toml` o nel blocco `[tool.zenzic]`.

### Aggiunto

- **Codici Finding (Zxxx) (Direttiva 036).** Ogni diagnostica emessa da Zenzic ora
porta un identificatore univoco leggibile dalla macchina (es. `Z101 LINK_BROKEN`,
`Z201 SHIELD_SECRET`, `Z401 MISSING_DIRECTORY_INDEX`). Il registro completo si trova
in `src/zenzic/core/codes.py` — unica fonte di verità per tutti i codici.
- **Menu interattivo del Lab.** `zenzic lab` senza argomenti mostra ora l'indice degli
atti per scegliere quale scenario esplorare. Eseguire `zenzic lab <N>` per avviare
un atto specifico (0–8). L'opzione `--act` è stata sostituita da un argomento
posizionale.
- **Identità Standalone Mode.** `StandaloneAdapter` è il motore no-op canonico per
progetti Markdown puri. `zenzic init` ora scrive `engine = "standalone"` quando non
viene rilevata nessuna configurazione di framework.

- **Flag `--offline` per la risoluzione URL Flat.** Disponibile su `check all`,
`check links` e `check orphans`. Forza tutti gli adapter a produrre URL `.html`
(es. `guida/install.md` → `/guida/install.html`) invece di slug in stile directory.
- **Supporto multi-versione Docusaurus v3.** `DocusaurusAdapter` ora identifica
`versions.json`, `versioned_docs/` e le traduzioni versionate.
- **Proxy Trasparente Zensical.** Se viene dichiarato `engine = "zensical"` ma
`zensical.toml` è assente, l'adapter crea automaticamente un ponte con il tuo
`mkdocs.yml` esistente.
- **Ghost Routing consapevole delle versioni.** I percorsi della documentazione
versionata sono automaticamente classificati come `REACHABLE`.
- **Risoluzione Alias @site/.** Aggiunto il supporto per l'alias di percorso `@site/`
in `DocusaurusAdapter`, permettendo la corretta risoluzione dei link relativi al progetto.
- **Integrità dell'Indice di Directory.** Nuovo metodo `provides_index(path)` nel protocollo
`BaseAdapter` per il rilevamento engine-aware delle directory prive di landing page.
Il finding `MISSING_DIRECTORY_INDEX` (severità: `info`), emesso da `zenzic check all`,
avvisa di ogni sottodirectory che contiene sorgenti Markdown ma nessun indice fornito
dall'engine — prevenendo i 404 gerarchici prima del deploy.
- **Notifiche nel Banner Sentinel.** Nuovi messaggi di stato per l'attivazione della
**Modalità Offline** e della **Modalità Proxy**.

### Corretto

- **Audit dei Guardiani: Allineamento Specifiche Ufficiali.**
- **Versioning Docusaurus:** Corretta la mappatura URL della versione "latest" (prima voce
in `versions.json`) per escludere il prefisso dell'etichetta di versione, allineandosi
al comportamento ufficiale di Docusaurus. In precedenza ogni file versionato riceveva
un prefisso `/versione/`, generando falsi positivi per tutte le pagine della versione latest.
- **Slug Docusaurus:** Gli slug frontmatter assoluti (es. `slug: /mio-percorso`) sono
ora correttamente preceduti dalla `routeBasePath` (es. `/docs/mio-percorso/`),
allineandosi alla specifica Docusaurus `normalizeUrl([versionMetadata.path, docSlug])`.
- **Collasso Intelligente dei File:** La logica `isCategoryIndex` ora rispecchia
esattamente Docusaurus: `README.md`, `INDEX.md` (case-insensitive) e
`{NomeCartella}/{NomeCartella}.md` collassano nell'URL della directory genitore,
prevenendo falsi positivi per le convenzioni valide di landing page di categoria.
- **Risoluzione Alias `@site/`:** `InMemoryPathResolver` ora risolve i link `@site/`
rispetto al corretto confine `repo_root` invece di sfuggire tramite `../`,
eliminando errori `PathTraversal` spuri per tutti i link relativi al progetto Docusaurus.
- **Integrità dei Metadati.** Corretto l'allineamento delle stringhe di versione in
`CITATION.cff` e `pyproject.toml`.
- **Default routeBasePath Docusaurus.** Ripristinato `docs` come prefisso URL predefinito
per i progetti Docusaurus per corrispondere al comportamento ufficiale dell'engine.

- **Parità Documentale Bilingue.** Copertura completa della documentazione EN/IT per
tutte le feature della v0.6.1 nelle guide Architettura, Motori e Comandi.

## [0.6.1rc2] — 2026-04-16 — Obsidian Bastion (Hardened)

### SICUREZZA: Risultati Operation Obsidian Stress
Expand Down Expand Up @@ -97,7 +167,7 @@ Le versioni seguono il [Semantic Versioning](https://semver.org/).
`check_nav_contract`, e tutte le funzioni dello scanner. Nessun default
`None` retrocompatibile.

## [0.6.0a2] — 2026-04-13 — Obsidian Glass
## [0.6.0a2] — 2026-04-13 — Obsidian Glass (Alpha 2)

### Aggiunto

Expand Down
Loading
Loading