From e6436922f9f2f45c2e69e7fbf53ba53f528699c9 Mon Sep 17 00:00:00 2001 From: gogocat Date: Tue, 8 Sep 2026 21:24:45 +0300 Subject: [PATCH] release: v0.37.0 Trust the number, the write, and the gate that checks it. Three defects that all reported success while doing nothing: an EvidencePack with no verdict/congruence_level scoring 1.00, forgeplan deprecate/renew/reopen writing their reason nowhere the file could keep it, and the embedding correctness oracle never once running in CI since it was written. - CHANGELOG: renamed Unreleased -> 0.37.0, added the sprint headline, a scope note, the #478 and PROB-102 Fixed entries, and a Security section pointing at today's dependabot triage. - Version bumped to 0.37.0 in all 5 pin locations (workspace.package + 4 path-dependency pins across forgeplan-cli/forgeplan-mcp). - CLAUDE.md Current status entry (English per author request) and the test-count line (3290 -> 3331, measured fresh on this branch). - README badges and dogfood table refreshed: 394 -> 437 artifacts, 3290 -> 3331 tests. - docs/operations/dependabot-triage-2026-09-08.md: 33 open (1 rust LOW lru, accepted-with-justification, carried since v0.33.0; 32 npm website, scheduled), cargo-deny confirmed green on dev directly rather than inferred from Dependabot's silence (RustSec isn't mirrored there and that gap cost two prior releases a red gate). Verified fresh on this branch: cargo fmt clean, MCP tool count 73 no drift, smoke-test.sh green, 3331 tests passed across all three crates (one known #454 git-flake and one resource-contention timeout, both confirmed non-regressions by isolated rerun). Refs: PRD-086, PROB-102, PROB-105, #478, #472, #481 Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 76 +++++++++++- CLAUDE.md | 20 +++- Cargo.lock | 6 +- Cargo.toml | 2 +- README.md | 6 +- crates/forgeplan-cli/Cargo.toml | 4 +- crates/forgeplan-mcp/Cargo.toml | 4 +- .../dependabot-triage-2026-09-08.md | 113 ++++++++++++++++++ 8 files changed, 216 insertions(+), 15 deletions(-) create mode 100644 docs/operations/dependabot-triage-2026-09-08.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 7145c44d..189e5744 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,22 @@ corresponding sprint evidence under `.forgeplan/evidence/`. ## [Unreleased] +## [0.37.0] - 2026-09-08 + +Sprint headline: **Trust the number, and the write, and the gate that proves it.** +An EvidencePack with no `verdict` and no `congruence_level` has been scoring a +perfect **1.00** — the opposite of every document describing this system. A +`forgeplan deprecate` was printing a reason and putting it nowhere a fresh clone +could ever see it. A test file written to catch a live engine swap has run zero +times in CI since the swap it exists for. None of the three looked broken — +each reported success, correctly formatted, right up until someone read the +file it was supposed to have written to. + +Scope note for scripted consumers: no new CLI flag, no new config key, MCP tool +count unchanged (73). One breaking behaviour change: R_eff for any artifact +whose weakest evidence pack lacks `verdict`/`congruence_level` drops from 1.0 to +0.1 — **run `forgeplan score --all` after upgrading** (see below). + ### Changed — BREAKING, re-score required - **Evidence that declares nothing no longer scores full marks** (PROB-101, @@ -138,14 +154,68 @@ corresponding sprint evidence under `.forgeplan/evidence/`. instructions. Verified: **0 findings across all 69 PRDs**, while hand-written vague prose still produces findings with line numbers. +### Fixed + +- **`forgeplan deprecate` / `renew` / `reopen` printed a reason and stored it + nowhere durable.** The command echoed the reason back and `forgeplan get` + showed it, but the markdown file never received the `## Deprecation` / + `## Renewal` / `## Reopened` section — only the status did, because status + lives in frontmatter and the section does not. `.forgeplan/lance/` is + gitignored, so the reason did not exist on a fresh clone. Worse than a + missing write: the next lifecycle command on that artifact synced the + section-less file body back over the index, erasing the reason there too — + the disagreement between file and index was temporary, the loss was not. + Root cause was a collision between two individually-correct behaviours: + `render_projection` is files-first by design (a user's on-disk edits must + survive `link`/`tag`/`activate`), and it discarded whatever body these + three commands handed it. The three CLI call sites and the MCP `deprecate` + handler now use the forcing variant, safe only there because a + file→store sync always runs immediately before. Recovery for anyone + already hit by this: `forgeplan update --body @path` projects + correctly and restores the section by hand. + +- **The embedding correctness oracle ran in CI exactly zero times since it + was written** (PROB-102). `tests/embedding_reference.rs` pins the engine's + output against pre-tract values from the v0.35.0 ONNX → tract swap it + exists to catch; the file is entirely behind `semantic-search`, so + `check`/`clippy` compiled it and `cargo nextest run --workspace` — invoked + without the feature — never even built it into that run. A new CI job + runs it in isolation with the model cached across runs, and converts the + oracle's normal quiet local-dev skip (a missing model reads as PASS, not + skipped) into a loud failure for this job specifically — a cold cache + proving nothing would otherwise reproduce the exact defect being closed, + one layer down. + ### Internal - ADR-025 (orchestration sits above ForgePlan; per-surface dispositions) and ADR-026 (storage classes for machine-written records) resolve two vNext audit blockers that required a human decision. EVID-169 records the basis. -- PROB-102: `embedding_reference.rs` — the correctness oracle for the - embedding engine — runs zero tests in CI, because `cargo nextest run` passes - no features while `check` and `clippy` do. Recorded, not yet fixed. +- PROB-104: a leaf pack with an evidence neighbour reports the neighbour's + score. Recorded, not yet fixed — found while scoping this release, not + introduced by it. + +### Security + +33 open Dependabot alerts at release time (8 high / 15 medium / 10 low), one +Rust, 32 npm — full triage in +[`docs/operations/dependabot-triage-2026-09-08.md`](docs/operations/dependabot-triage-2026-09-08.md). + +- **`lru` LOW (GHSA-rhfx-m35p-ff5j) — accepted-with-justification, carried + forward.** The only consumer is `tantivy 0.24.2`, which pins `lru 0.12.x`; + the fix landed in `0.16.3`, a major bump only `tantivy` can take. Forgeplan + never constructs an `lru` cache or calls the affected method. Same verdict + as v0.33.0 through v0.36.0. +- **All 32 npm alerts — scheduled.** Confined to `website/`, a statically + generated docs site shipping no server and no part of any released + artifact. One of them (#442) carries an `astro` 6→7 major inside a + Dependabot group PR opened before the `Website build` CI gate existed — its + green checkmarks don't include the one check that would exercise a + two-major jump. Filed as #485 rather than merged on stale-green. +- `cargo-deny` (`security` workflow) is **green on `dev`** — checked directly + rather than inferred from an empty Dependabot list, because RustSec is not + mirrored into Dependabot and that gap has cost this project a red `dev` gate + twice before (v0.34.0, v0.35.0) without Dependabot ever showing a symptom. ## [0.36.0] - 2026-09-04 diff --git a/CLAUDE.md b/CLAUDE.md index cff6cb88..88e98463 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -88,6 +88,24 @@ semantic search via BGE-M3, typed links, lifecycle with validation gates. ## Current status +- **v0.37.0** (2026-09-08) — **trust the number, the write, and the gate that checks it**. + An EvidencePack with no `verdict` and no `congruence_level` scored a flat **1.00** — + the opposite of what every document describing this system says. `forgeplan deprecate` + printed a reason and put it nowhere a fresh clone could ever see: the `## Deprecation` + section only reached LanceDB (`.forgeplan/lance/` is gitignored), and the next lifecycle + command synced the section-less file back over the index — the file/index disagreement + was temporary, the data loss was not. The embedding correctness oracle + (`embedding_reference.rs`) had never run in CI since it was written: the file is + entirely behind `semantic-search`, `check`/`clippy` compile it, `cargo nextest run + --workspace` does not, so its three assertions against the live engine never even + entered that build. **None of this looked broken** — each one reported success in the + right format, right up until someone read the file it claimed to have written to. + **Breaking**: R_eff for any artifact whose weakest evidence pack lacks `verdict`/ + `congruence_level` drops from 1.0 to 0.1 — **run `forgeplan score --all` after + upgrading**. Also: a new CI job runs the embedding oracle with a cached model, plus + `--test-threads=1` for it — on the first cold run, two tests that both need the model + ran concurrently and raced for the same download. Open: PROB-104 (a leaf pack with an + evidence neighbour reports the neighbour's score). - **v0.36.0** (2026-09-04) — **вещи, которые отчитывались об успехе, ничего не проверяя**. Каждый дефект релиза вёл себя корректно — поиск возвращал правдоподобное, подсказки были исполнимы, сборка была зелёной, — и именно это их скрывало. @@ -148,7 +166,7 @@ semantic search via BGE-M3, typed links, lifecycle with validation gates. Migration: run `forgeplan score --all`; expect a small number of artifacts whose only evidence was retired to drop to 0 (1 of 89 here) — that is real debt the old formula masked. -- **82 CLI commands** (+`setup`; прежние «82» считали авто-`help` от clap), **73 MCP tools**, **3290 tests + 9 doc-tests** (CI `nextest`), **0 warnings** on both feature configs +- **82 CLI commands** (+`setup`; прежние «82» считали авто-`help` от clap), **73 MCP tools**, **3331 tests + 9 doc-tests** (CI `nextest`), **0 warnings** on both feature configs - **EPIC-001/002/003 ✅**, **Epic #287 ✅** (brownfield). Phase 5 (Desktop Tauri) — backlog - FPF KB semantic search via BGE-M3 on `tract` (pure-Rust inference — RFC-013; feature-gated, graceful fallback) diff --git a/Cargo.lock b/Cargo.lock index e80be5c1..982b62bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2253,7 +2253,7 @@ checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "forgeplan" -version = "0.36.0" +version = "0.37.0" dependencies = [ "anyhow", "assert_cmd", @@ -2279,7 +2279,7 @@ dependencies = [ [[package]] name = "forgeplan-core" -version = "0.36.0" +version = "0.37.0" dependencies = [ "anyhow", "arrow-array", @@ -2320,7 +2320,7 @@ dependencies = [ [[package]] name = "forgeplan-mcp" -version = "0.36.0" +version = "0.37.0" dependencies = [ "anyhow", "chrono", diff --git a/Cargo.toml b/Cargo.toml index cd3467d9..103da272 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ members = [ ] [workspace.package] -version = "0.36.0" +version = "0.37.0" edition = "2024" license = "MIT" repository = "https://github.com/ForgePlan/forgeplan" diff --git a/README.md b/README.md index 4b8a1ca6..5ef0d0e3 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Structured artifacts (PRD, RFC, ADR, Epic, Spec), quality scoring, evidence, and [![License: MIT](https://img.shields.io/badge/license-MIT-000.svg?style=flat-square)](LICENSE) [![Release](https://img.shields.io/github/v/release/ForgePlan/forgeplan?include_prereleases&style=flat-square&color=orange)](https://github.com/ForgePlan/forgeplan/releases) [![CI](https://img.shields.io/github/actions/workflow/status/ForgePlan/forgeplan/ci.yml?branch=main&style=flat-square)](https://github.com/ForgePlan/forgeplan/actions) -[![Artifacts](https://img.shields.io/badge/artifacts-394-blue?style=flat-square)](.forgeplan/) +[![Artifacts](https://img.shields.io/badge/artifacts-437-blue?style=flat-square)](.forgeplan/) **[Website](https://forgeplan.dev)** · **[Documentation](docs/README.md)** · @@ -248,8 +248,8 @@ Three entry points — pick the one that matches what you need right now. - - + + diff --git a/crates/forgeplan-cli/Cargo.toml b/crates/forgeplan-cli/Cargo.toml index 67e007ee..79aee510 100644 --- a/crates/forgeplan-cli/Cargo.toml +++ b/crates/forgeplan-cli/Cargo.toml @@ -18,8 +18,8 @@ name = "forgeplan" path = "src/main.rs" [dependencies] -forgeplan-core = { path = "../forgeplan-core", version = "0.36.0" } -forgeplan-mcp = { path = "../forgeplan-mcp", version = "0.36.0" } +forgeplan-core = { path = "../forgeplan-core", version = "0.37.0" } +forgeplan-mcp = { path = "../forgeplan-mcp", version = "0.37.0" } clap = { version = "4", features = ["derive"] } anyhow.workspace = true chrono.workspace = true diff --git a/crates/forgeplan-mcp/Cargo.toml b/crates/forgeplan-mcp/Cargo.toml index bb6786a7..0d14b22e 100644 --- a/crates/forgeplan-mcp/Cargo.toml +++ b/crates/forgeplan-mcp/Cargo.toml @@ -18,7 +18,7 @@ name = "forgeplan_mcp" path = "src/lib.rs" [dependencies] -forgeplan-core = { path = "../forgeplan-core", version = "0.36.0" } +forgeplan-core = { path = "../forgeplan-core", version = "0.37.0" } rmcp = { version = "1.7", features = ["server", "transport-io"] } schemars = "0.8" serde.workspace = true @@ -33,7 +33,7 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] } semantic-search = ["forgeplan-core/semantic-search"] [dev-dependencies] -forgeplan-core = { path = "../forgeplan-core", version = "0.36.0", features = ["test-helpers"] } +forgeplan-core = { path = "../forgeplan-core", version = "0.37.0", features = ["test-helpers"] } tempfile = "3" serde_yaml.workspace = true # Phase 2.4: enable the rmcp `client` role for E2E integration tests so we diff --git a/docs/operations/dependabot-triage-2026-09-08.md b/docs/operations/dependabot-triage-2026-09-08.md new file mode 100644 index 00000000..7d0fcf15 --- /dev/null +++ b/docs/operations/dependabot-triage-2026-09-08.md @@ -0,0 +1,113 @@ +# Dependabot triage — 2026-09-08 (v0.37.0 release window) + +Per RED-LINE #10 (CLAUDE.md): each release tags every open Dependabot alert as +**addressed** / **scheduled** / **accepted-with-justification**. Follows the +`docs/operations/RELEASE-PROTOCOL.md` step-4 contract. + +## Snapshot at release time + +```bash +gh api repos/ForgePlan/forgeplan/dependabot/alerts --paginate \ + -q '[.[] | select(.state=="open")] | length' +``` + +**33 open: 8 HIGH / 15 MEDIUM / 10 LOW — 1 Rust, 32 npm.** + +The split is the same shape as every prior release triage: the one Rust alert sits +in the dependency tree of the shipped `forgeplan` binary; all 32 npm alerts are +confined to `website/` — a static Astro documentation site that ships no server and +is not part of any released artifact. + +## Rust — the shipped binary + +| Package | Sev | GHSA | Fix in | Verdict | +|---|---|---|---|---| +| `lru` | LOW | GHSA-rhfx-m35p-ff5j | 0.16.3 | **accepted-with-justification** | + +### `lru` LOW — accepted-with-justification + +`IterMut` violates Stacked Borrows by invalidating an internal pointer. **Cannot be +updated without an upstream change**: the only consumer is `tantivy 0.24.2` (confirmed +again in `Cargo.lock` — `lru 0.12.5`, no direct `forgeplan-core`/`forgeplan-cli`/ +`forgeplan-mcp` dependency on the crate), which pins `lru 0.12.x`, while the fix +landed in `0.16.3` — a major bump only `tantivy` can take. Forgeplan never +constructs an `lru` cache itself and never calls `IterMut`; the advisory describes +undefined behaviour observable under Miri, not a reachable exploit in this +dependency path. **Carried forward** — same verdict as v0.33.0, v0.34.0, v0.35.0. +Re-evaluate when `tantivy` bumps its `lru` bound. + +## RustSec — not a Dependabot alert, checked separately + +GitHub's Dependabot feed does not mirror RustSec, and this gap has bitten this +project twice before this window (v0.34.0: crossbeam-epoch red on `dev` for 11 +days; v0.35.0: h2 red for three consecutive merges). Both times the miss was +"Dependabot showed nothing, so nobody looked at `cargo-deny` directly." + +Checked directly, not inferred from Dependabot's silence: + +```bash +gh run list --branch dev --limit 5 --json name,conclusion,createdAt \ + -q '.[] | select(.name == "security")' +``` + +`security` (the `cargo-deny` workflow) is **green on `dev`** — last run +2026-09-08T17:18:26Z, immediately after the rust-deps (#473) and github-actions +(#459) Dependabot PRs merged, `success`. Stated explicitly here rather than left +to be assumed from an empty Dependabot list, per the lesson the two prior misses +left behind. + +## npm — `website/` only + +| Package | Sev | Count | +|---|---|---| +| `browserslist` | HIGH | 2 | +| `astro` | HIGH | 2 | +| `vite` | HIGH | 1 | +| `sharp` | HIGH | 1 | +| `nanoid` | HIGH | 1 | +| `js-yaml` | HIGH | 1 | +| `dompurify` | MEDIUM | 6 | +| `mermaid` | MEDIUM | 4 | +| `astro` | MEDIUM | 3 | +| `vite` | MEDIUM | 1 | +| `@astrojs/rss` | MEDIUM | 1 | +| `dompurify` | LOW | 4 | +| `postcss-selector-parser` | LOW | 1 | +| `mermaid` | LOW | 1 | +| `esbuild` | LOW | 1 | +| `astro` | LOW | 1 | +| `@babel/core` | LOW | 1 | + +**Verdict: scheduled** — same reasoning as every prior triage, restated because it +still holds and because one open item makes it concrete this time: + +1. **Zero exposure through the released product.** Build-time and render-time + dependencies of a statically generated documentation site; the `forgeplan` + binary, MCP server, and marketplace plugins carry none of them. +2. **A blanket update is a known-bad move here** — established by PR #401 (a + sweeping `npm update` broke the build on a peer-major conflict). This + release's own scoping work found the concrete case: **#442** (`npm-website` + Dependabot group, opened 2026-08-17) carries `astro` 6→7 and `@astrojs/mdx` + 5→7 inside it, and predates the `Website build` CI gate — its green + checkmarks don't include the one check that would actually exercise a + two-major-version jump. Filed as its own issue (#485) with the concrete + next step (rebase so the gate runs, verify with a real `npm run build`) + rather than merged on old green. +3. **Bundling it here would make the release un-reviewable.** v0.37.0 already + carries a breaking scoring-semantics change (PRD-086) plus a lifecycle + data-loss fix (#478) plus a CI-coverage fix (PROB-102). A front-end + dependency sweep on top of that would make bisecting any regression + materially harder. + +**Trigger for the scheduled work:** #485 (already filed) — rebase #442 so the +`Website build` gate actually runs against it, then apply by hand with a +verified `npm run build`, not as a merged auto-group. + +## Verification + +```bash +cargo deny check advisories # → advisories ok +grep -A1 'name = "lru"' Cargo.lock # → 0.12.5 (tantivy-pinned) +gh api repos/ForgePlan/forgeplan/dependabot/alerts --paginate \ + -q '[.[] | select(.state=="open")] | length' # → 33 +```
394
tracked artifacts
3290
tests passing
437
tracked artifacts
3331
tests passing
82
CLI commands
73
MCP tools