# v0.71.0 — CI Truthfulness, Test Harness & Documentation Cleanup

> **Full details:** [v0.71.0.md-full.md](v0.71.0.md-full.md)

## What's New

v0.71.0 is the final release of the Assessment-13-Driven Hardening Arc. It
resolves the remaining MEDIUM- and LOW-severity findings that span CI gate
accuracy, test harness schema drift, the SQL API catalog generator, Rust code
quality, and stale planning documents. After this release, every finding in
Assessment 13 is resolved and the project is ready for the v1.0 stable release
gate.

### CI-001: Fuzz Smoke Covers All Nine Targets (CI-001)

The `fuzz-smoke.yml` workflow previously ran only six of the nine committed fuzz
targets, leaving `sql_builder_fuzz`, `merge_sql_fuzz`, and `row_id_fuzz` —
all high-value string-generation surfaces — without CI coverage.

Fix: the workflow target list is generated dynamically from
`fuzz/fuzz_targets/*.rs`. A new CI step runs before the fuzz jobs:
`scripts/check_fuzz_targets.py` fails if any `fuzz/fuzz_targets/*.rs` file is
not represented in the matrix, preventing future drift.

### CI-002: `just fuzz-all` Exits Non-Zero on Failure (CI-002)

The `fuzz-all` justfile recipe used `|| true` after each target, masking
crashes and making the command unsuitable as a release gate.

Fix: the `|| true` suffix is removed. Target failures are accumulated and
reported at the end. A new `fuzz-all-best-effort` recipe preserves the old
behaviour for exploratory local runs.

### CI-003: E2E Coverage Workflow Schedule Aligned (CI-003)

The coverage workflow claimed E2E coverage ran weekly in comments but the job
was gated to `workflow_dispatch` only — so scheduled runs always skipped it.

Fix: the E2E coverage job is moved to a `schedule: cron: '0 2 * * 0'` trigger
(weekly Sunday 02:00 UTC) in addition to `workflow_dispatch`. The timeout is
increased to 90 minutes. The misleading comments are updated.

### CI-004: `docs-lint` Added to `just lint` (CI-004)

Contributors running the local `just lint` gate required by AGENTS.md could
miss documentation drift because `docs-lint` was a separate recipe not called
by `lint`. This allowed breaking doc changes to pass local checks and fail only
in CI.

Fix: `just lint` now calls `docs-lint` as a final step. The AGENTS.md
contributor workflow is updated to reflect this. An alias `just lint-all = lint`
is added for consistency with prior documentation.

### DEP-001: Advisory Ignore Expiry/Review Metadata (DEP-001)

All five RUSTSEC advisory ignores in `deny.toml` gain structured metadata:
`# Owner:`, `# Added:`, `# Review-By:`, `# Upstream:`, and `# Remove-When:`
comment fields. A new script `scripts/check_deny_expiry.py` fails if any
advisory ignore has a `Review-By` date in the past, providing a lightweight
human-review cadence enforced by CI.

### DOC-001 / CODE-001: SQL API Catalog Generator Rewritten (DOC-001, CODE-001)

The `scripts/gen_catalogs.py` generator used regexes over Rust source to infer
function signatures. Nested generics and multiline `TableIterator` return types
were routinely truncated, producing entries like `TableIterator<` in
`docs/SQL_API_CATALOG.md`. CI guaranteed the broken output was reproducible, not
correct.

Fix: the generator is rewritten to consume pgrx's generated SQL output
(`target/release/pg_trickle.sql` produced by `cargo pgrx schema`) as its source
of truth. SQL `CREATE FUNCTION` statements are parsed with a simple
context-free parser to extract name, arguments, and return type. A quality gate
is added: `gen_catalogs.py` fails if any extracted return type ends with `<`,
contains unbalanced generics, or is empty for a non-void function.

### CODE-002: Tarjan SCC Unwraps Converted to Errors (CODE-002)

`tarjan_strongconnect()` contained `unwrap()` calls with `// nosemgrep:
rust.panic-in-sql-path` suppression comments. The invariants are valid but
panics in SQL-reachable code violate the repo coding convention.

Fix: `lowlinks.get_mut(&v).unwrap()` and `stack.pop().unwrap()` are converted
to `ok_or(PgTrickleError::InternalError("SCC invariant violated: ..."))`.
`debug_assert!` guards keep the invariant visible in debug builds without
affecting release code paths.

### TEST-005: Test Harness Catalog Schema Generated from Archive (TEST-005)

`tests/common/mod.rs` maintained a hand-written subset of the catalog schema
that had drifted from the extension SQL: `initiated_by` was missing
`SELF_MONITOR`, and `unit_kind` was missing `cyclic_scc`,
`repeatable_read_group`, and `fused_chain`.

Fix: a new `scripts/gen_test_schema.py` script extracts the relevant
`CREATE TABLE` DDL blocks from `sql/archive/pg_trickle--<latest>.sql` and
emits a Rust string constant used by `tests/common/mod.rs`. A CI step runs
`scripts/gen_test_schema.py --check` which fails when the generated output
differs from the committed constant, preventing future drift.

### ARCH-003 / DOC-002: `plans/PLAN.md` Archived (ARCH-003, DOC-002)

`plans/PLAN.md` opened with two duplicated "Implementation Status (v0.9.0 Cycle)"
blocks, conflicting with the current v0.67+ roadmap. Contributors could not
determine which planning document was authoritative.

Fix: the historical content is moved to `plans/archive/PLAN_HISTORICAL.md`
with a header noting it reflects the v0.9 era. `plans/PLAN.md` is rewritten
as a short Architecture & Roadmap Index that links to `ROADMAP.md`,
`docs/ARCHITECTURE.md`, the current assessment series, and the ADR catalogue.

### DOC-003: `plans/INDEX.md` Regenerated (DOC-003)

`plans/INDEX.md` was maintained by hand and had not been updated since the
v0.52 assessment series. It was missing all Overall Assessment files from 9
through 13 and all roadmap-arc planning files added during v0.62–v0.67.

Fix: `scripts/gen_plans_index.py` regenerates `plans/INDEX.md` from the actual
files under `plans/`. A CI step runs the script in `--check` mode to prevent
future drift. The index is sorted by file date and categorised by prefix
(`PLAN_OVERALL_ASSESSMENT_*`, `PLAN_DOCUMENTATION_*`, `PLAN_ADR_*`, etc.).

## Breaking Changes

None. All changes are internal tooling, documentation, and code quality.
