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
76 changes: 73 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 <id> --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
Expand Down
20 changes: 19 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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) — **вещи, которые отчитывались об успехе, ничего не проверяя**.
Каждый дефект релиза вёл себя корректно — поиск возвращал правдоподобное, подсказки
были исполнимы, сборка была зелёной, — и именно это их скрывало.
Expand Down Expand Up @@ -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)

Expand Down
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)** ·
Expand Down Expand Up @@ -248,8 +248,8 @@ Three entry points — pick the one that matches what you need right now.

<table>
<tr>
<td align="center"><b>394</b><br>tracked artifacts</td>
<td align="center"><b>3290</b><br>tests passing</td>
<td align="center"><b>437</b><br>tracked artifacts</td>
<td align="center"><b>3331</b><br>tests passing</td>
<td align="center"><b>82</b><br>CLI commands</td>
<td align="center"><b>73</b><br>MCP tools</td>
</tr>
Expand Down
4 changes: 2 additions & 2 deletions crates/forgeplan-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions crates/forgeplan-mcp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
113 changes: 113 additions & 0 deletions docs/operations/dependabot-triage-2026-09-08.md
Original file line number Diff line number Diff line change
@@ -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
```
Loading