Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
8b9e503
fix(get): report the artifact's edges instead of collapsing them to a…
explosivebit Sep 4, 2026
d9d0b7e
fix(validate): body-links-drift was comparing against a set that is a…
explosivebit Sep 4, 2026
fefaabb
chore(gitignore): stop asserting a rotation that was never confirmed
explosivebit Sep 4, 2026
3c4681b
docs(forgeplan): record PROB-100 and its evidence
explosivebit Sep 4, 2026
44feca0
Merge pull request #467 from ForgePlan/chore/sync-main-to-dev-after-v…
explosivebit Sep 4, 2026
51e4236
Merge pull request #468 from ForgePlan/fix/links-invisible-to-record
explosivebit Sep 4, 2026
3081723
fix(embed): decide there is no work before paying for the model
explosivebit Sep 4, 2026
a285ce6
docs(forgeplan): shape the trust-layer work and record three findings
explosivebit Sep 4, 2026
8c51d94
fix(core): `update --body` kept three frontmatter fields and deleted …
explosivebit Sep 4, 2026
f37f80b
docs(adr): resolve the two vNext blockers that were waiting on a human
explosivebit Sep 5, 2026
88f2b56
docs: activate ADR-025/ADR-026 on owner approval; codify the explanat…
explosivebit Sep 5, 2026
cc898b1
style(core): cargo fmt on the assertion 8c51d94 added
explosivebit Sep 5, 2026
8c20fe2
fix(scoring): the trust layer stops reporting values it never computed
explosivebit Sep 5, 2026
9cd69a3
fix(scoring): close what an adversarial review found in the PRD-086 f…
explosivebit Sep 6, 2026
8dbbd5f
docs(forgeplan): file PROB-104 — the review finding deferred out of P…
explosivebit Sep 6, 2026
3768c68
fix(phase): the monotonicity guard turned a write-safety test into an…
explosivebit Sep 6, 2026
5e9b9a9
Merge pull request #470 from ForgePlan/fix/trust-layer-and-update-bod…
explosivebit Sep 6, 2026
daa103b
fix(validate): the SPEC validator passed empty templates and blocked …
explosivebit Sep 7, 2026
3e16e48
docs(handoff): record the SPEC-validator work so it survives the session
explosivebit Sep 7, 2026
c8e7bd3
docs(spec): say both contract shapes are legitimate, and test the rea…
explosivebit Sep 7, 2026
ebb1d37
evidence(prob-105): EVID-171 — before/after measurements, 3320 tests,…
explosivebit Sep 7, 2026
551ddb9
Merge pull request #472 from ForgePlan/fix/spec-validator-inverted
explosivebit Sep 8, 2026
10bfd50
docs(agents): give findings a home, and say which one
explosivebit Sep 8, 2026
5aee2b4
Merge pull request #477 from ForgePlan/docs/findings-have-a-home
explosivebit Sep 8, 2026
009de50
chore(prob-105): deprecate as resolved, with the reason actually in t…
explosivebit Sep 8, 2026
31db352
Merge pull request #480 from ForgePlan/chore/deprecate-prob-105
explosivebit Sep 8, 2026
738ec04
fix(lifecycle): deprecate/renew/reopen wrote their reason nowhere dur…
explosivebit Sep 8, 2026
eed9353
fix(ci): run the embedding correctness oracle instead of only compili…
explosivebit Sep 8, 2026
e2554c7
chore(deps): bump the rust-deps group across 1 directory with 9 updat…
dependabot[bot] Sep 8, 2026
37972fa
chore(deps): bump the github-actions group across 1 directory with 5 …
dependabot[bot] Sep 8, 2026
424d3c4
fix(ci): serialize the embedding oracle to remove a cold-cache downlo…
explosivebit Sep 8, 2026
1af60e5
Merge pull request #481 from ForgePlan/fix/lifecycle-reason-never-rea…
explosivebit Sep 8, 2026
e643692
release: v0.37.0
explosivebit Sep 8, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,4 @@ Accepted
- crates/forgeplan-core/src/artifact/**



Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ R_eff recursive вычисляет weakest link по всему дереву з
- crates/forgeplan-core/src/scoring/reff.rs



Original file line number Diff line number Diff line change
Expand Up @@ -320,3 +320,4 @@ stays scoped to the typed-error migration:




Original file line number Diff line number Diff line change
Expand Up @@ -270,3 +270,4 @@ Forgeplan-core получает **3 новые core capabilities**:




Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,4 @@ title: R_eff excludes terminal-status evidence from the weakest-link min
- **Фильтровать и draft (буквальный acceptance #436)** — отвергнуто: ломает score-гейт Standard-flow (см. Decision §2).



Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
depth: standard
id: ADR-025
kind: adr
links:
- target: ADR-001
relation: based_on
- target: ADR-009
relation: refines
status: active
title: Orchestration sits above ForgePlan; the core is the contract layer
---

---
assigned_number: 25
predicted_number: 25
slug: adr-orchestration-sits-above-forgeplan-the-core-is-the-contract-layer
---

# ADR-025: Orchestration sits above ForgePlan; the core is the contract layer

## Context

Two active ADRs contradict each other, and the contradiction predates vNext:

- **ADR-001**: "AI agent is the orchestrator, not Forgeplan." Rejects adapter
traits; ForgePlan does not integrate into external systems, they read it.
- **ADR-009 §Decision**: "Forgeplan-core становится оркестратором — знает когда
какой playbook запускать, кому делегировать каждый шаг."

The vNext audit flagged this as the blocker no document can resolve (B2:
"недостижим, пока человек не выберет сторону"). The owner has chosen:
**orchestration of agents lives above ForgePlan**. Orchestrators (Claude Code,
Kandev, Conductor, human operators) decide who runs and when. ForgePlan is the
system of record they run against: artifacts, contracts, evidence, verdicts,
lifecycle.

The audit also found sixteen shipped CLI/MCP surfaces that sit on or across
this boundary (PB-01/B4) and demanded a per-surface disposition instead of a
blanket claim. This ADR is that disposition.

## Decision

ADR-001 is **reaffirmed**. ADR-009's orchestrator clause (§Decision, first
sentence) is **superseded by this ADR**; the rest of ADR-009 — the 4-primitive
+ Pack marketplace model — stands unchanged.

The boundary test for any surface: **does it manage the artifact graph, or
does it manage a process?** Graph management stays in core. Process management
belongs to the orchestrator above.

### Disposition of the sixteen surfaces

| Surface | Verdict | Reasoning |
|---|---|---|
| `dispatch` | **KEEP** | Read-only planner: computes conflict-free buckets from the graph. Spawning was already documented as the orchestrator's job. A projection, not a process. |
| `order`, `blocked` | **KEEP** | Pure graph projections over dependency edges. |
| `progress` | **KEEP** | Reads FR checkboxes out of artifact bodies. A projection. |
| `graph`, `tree`, `stale`, `blindspots` | **KEEP** | Same class, never contested. |
| `claim` / `release` / `claims` | **KEEP, reframed as locks** | These are write-mutexes on artifacts — integrity infrastructure for one workspace, not work assignment. "Who is assigned" belongs to trackers; "who may write this artifact right now without collision" is the graph's own safety and stays. Docs and hints must stop using assignment language. |
| `session` | **KEEP, explicitly non-canonical** | Per-machine plumbing, already gitignored. |
| `phase` / `phase-advance` | **ABSORB, no new investment** | Three parallel state ladders exist today: lifecycle status, DerivedStatus, phase. Phase state is already per-machine (`.forgeplan/state/` is gitignored — it does not even travel with the repo). Keep advisory as shipped, fix the #330 regression because shipped code must not lie, and fold phase into the lifecycle model in vNext (FPV-03) rather than growing it. |
| `estimate` / `calibrate` | **MOVE TO EXTENSION** | Effort estimation is planning-tool territory. It reads the graph but does not manage it. Marketplace extension; deprecation window in core. |
| `remember` / `recall` (memory kind) | **DEPRECATE** | The boundary doc says "not a general-purpose memory platform" and the shipped reality agrees: 2 memory artifacts exist, `new memory` fails with "No template found", and #411 shows they cannot join the graph. NOTE covers durable engineering micro-facts as first-class artifacts; conversational memory is Hindsight's job. Closing #411 by removal, not repair. |
| playbook runtime (5 dispatchers, `playbook run`/`ingest`, ADR-011's `claude --print`) | **MOVE TO EXTENSION, supersede ADR-011** | Spawning agent processes is the definition of the orchestration this ADR places above the core. The playbook *format* (methodology → steps mapping) remains marketplace data; the *runtime* leaves the core binary. This is the largest consequence and gets its own migration RFC before any code moves. |

## Consequences

- The FPV-01 blocker (two active ADRs claiming opposite things) is resolved;
the vNext boundary doc's ownership table now matches an actual decision.
- ADR-009 needs an amendment note pointing here; ADR-011 needs supersession
when the playbook-runtime RFC lands. Neither is edited retroactively —
supersede, do not delete.
- #411 closes as deprecation. The two existing memory artifacts get migrated
to NOTE or exported before removal.
- No code changes in this ADR. Each MOVE/DEPRECATE row requires its own RFC
with a deprecation window; KEEP rows require only documentation alignment
(assignment language out of claim/release hints).

## Related Artifacts

| Artifact | Relation |
|---|---|
| ADR-001 | based_on |
| ADR-009 | refines |






122 changes: 122 additions & 0 deletions .forgeplan/adrs/ADR-026-storage-classes-for-machine-written-records.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
---
depth: standard
id: ADR-026
kind: adr
links:
- target: ADR-003
relation: refines
- target: ADR-025
relation: based_on
status: active
title: Storage classes for machine-written records
---

---
assigned_number: 26
predicted_number: 26
slug: adr-storage-classes-for-machine-written-records
---

# ADR-026: Storage classes for machine-written records

## Context

vNext introduces four object classes that no shipped decision houses:
WorkContract, ExecutionReceipt, EvidenceBundle, VerificationVerdict, plus an
authority/audit trail. The audit blocked FPV-03/04/05 on this (B3): ADR-003
declares markdown files the single source of truth and RED LINE #11 forbids
direct edits — but receipts and verdicts are written by machines, at volume,
and a git-tracked tree of machine-written files makes both rules unenforceable
as stated. ADR-018 already rejected a second authoritative non-markdown store.

Two constraints frame every option:

- **Local-first, git for sync** (Non-Goals). Anything that must survive a
clone or be trusted by another machine has to ride git.
- **One owner per state** (FORGE-O). ForgePlan should not become the canonical
store for facts another system already owns — CI results are the CI
provider's; ForgePlan references them.

## Decision

One rule, three storage classes. The rule:

> **Git-tracked if a human must review it or another machine must trust it.
> Local if it is raw per-machine material. Referenced if another system owns
> it. Machine-written tracked files are append-only, schema-validated,
> digest-linked, and mutated only through CLI/MCP — RED LINE #11 extends to
> them verbatim.**

### Class A — canonical, git-tracked, append-only

| Object | Home | Form |
|---|---|---|
| WorkContract | `.forgeplan/contracts/` | JSON, one file per contract version, digest in the record |
| EvidenceBundle | `.forgeplan/evidence/` | the EVID artifact evolved: structured machine section + human prose, same id space |
| VerificationVerdict | `.forgeplan/verdicts/` | JSON, digest-links to bundle and contract |

Reviewable in the PR that carries them, survive cloning, referenced by digest
so retargeting is detectable. Append-only means a new version is a new file
and supersession is a link — no merge conflicts by construction, and "edit"
is not an operation that exists.

This amends ADR-003 rather than violating it: *versioned files under
`.forgeplan/` are the source of truth; markdown for human-authored artifacts,
schema-validated JSON for machine-issued records; LanceDB stays derived.*
ADR-003's actual load-bearing idea was never "markdown" — it was "canonical
truth is versioned plain files, indexes are disposable."

### Class B — local raw material, gitignored

| Object | Home |
|---|---|
| ExecutionReceipt | `.forgeplan/receipts/` |
| audit/authority event stream | the existing journal (`forgeplan-core::journal`) |

Receipts are what a host reports about a run: commands, exit codes, streams.
High-volume, per-machine, valuable for minutes-to-days. They are the raw
material verification consumes on the machine where the run happened. What
deserves to outlive the machine gets promoted: the EvidenceBundle embeds the
receipt extract it relies on plus the receipt digest, and the bundle is
Class A. This mirrors the CI precedent — the CI provider owns the run, the
graph keeps the reference and the extract.

The same promotion rule covers audit: routine events stay in the local
journal; trust-relevant transitions (activation, dismissal, force, gate
override) are recorded in the artifact's own tracked state history, which is
per-artifact and append-capped, so the durable trail rides git without a
global conflict-prone log file.

### Class C — referenced, never stored

CI results, deployment state, tracker assignments. A digest or URL plus the
observation timestamp, inside a Class A record. Copying another system's
state into the graph creates a second owner and guarantees drift.

## Consequences

- FPV-03/04/05 unblock: every object in the protocol has a declared home
before a schema is written.
- `.gitignore` gains `receipts/`; `contracts/` and `verdicts/` are tracked
from birth. `.forgeplan/state/` is already gitignored today, consistent
with phase state being advisory and per-machine (ADR-025).
- RED LINE #11 needs one sentence added: machine-issued records under
`contracts/`, `evidence/`, `verdicts/` are written only by the binary;
hand-editing them is the same violation as hand-editing an artifact.
- The pre-existing `journal` module becomes the audit stream's home instead
of a new subsystem.
- Verification MUST re-derive git facts (delta, SHAs) from the repository at
verdict time rather than trusting receipt contents — the receipt says what
the host claims happened; the repo says what happened.

## Related Artifacts

| Artifact | Relation |
|---|---|
| ADR-003 | refines |
| ADR-025 | based_on |





Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
---
depth: tactical
id: EVID-168
kind: evidence
links:
- target: PROB-100
relation: informs
status: draft
title: 'PROB-100: 7 of 8 drift findings were false; get now reports edges'
---

---
assigned_number: 168
predicted_number: 168
slug: evid-prob-100-7-of-8-drift-findings-were-false-get-now-reports-edges
---

# EVID-168: measured before and after, on real artifacts

Both defects in PROB-100 were reproduced on this workspace's own artifacts, not
on fixtures, and re-measured after the fix. Fixtures would not have caught either
one: every layer worked in isolation.

## body-links-drift (#446)

`forgeplan validate SPEC-003`

| | ids named | false | true |
|---|---|---|---|
| before | 8 | 7 | 1 |
| after | 1 | 0 | 1 |

The seven false ones: `ADR-009`, `PRD-065`, `SPEC-004` are real edges —
`forgeplan graph` prints all three for `SPEC-003` — and `FR-1`, `FR-2`, `FR-3`,
`FR-5` are requirement numbers that can never be link targets.

The one true finding, `EPIC-007`, survives the fix. Checked directly: the graph
has no `SPEC-003 → EPIC-007` edge, so the body table names something the artifact
is not linked to. That is what the rule is for.

`forgeplan validate ADR-009`: 10 ids named before, 8 after. The two that dropped
(`ADR-008`, `PROB-042`) are real edges.

## forgeplan get (#447)

`forgeplan get SPEC-003 --json`

- before: 14 keys, none about links
- after: `links.outbound` = `PRD-065 (refines)`, `ADR-009 (based_on)`,
`SPEC-004 (informs)` — identical to `forgeplan graph`
- after: `links.inbound` = `EVID-089 (informs)`, which
`graph | grep "SPEC-003 -->"` cannot show at all

Empty case, fresh workspace: `{"outbound": [], "inbound": []}` and `Links: none`.
The field is present either way, so "no links" is distinguishable from "not
reported" — the ambiguity the issue was filed about.

## Tests

8 new. 2 on the prefix filter, 3 on the store merge, 3 end-to-end on the real
binary against a real workspace.

The prefix-filter test was mutation-checked: with the filter removed it fails.
It detects the defect rather than confirming current behaviour — the distinction
that let #348 survive for months behind a test asserting the broken string.

## Gate results

| Gate | Result |
|---|---|
| `cargo fmt --all -- --check` | exit 0, 0 diffs |
| `cargo clippy --workspace --all-targets -- -D warnings` | exit 0, 0 warnings |
| `cargo test --workspace --no-fail-fast` | 3295 passed, 3 failed, 92 binaries |

The 3 failures are #454 / PROB-090, not this change. Each passes in isolation and
fails only under parallel load; none touches the modified code. Two are in
`git/`, untouched here. The third, `c33_forgeplan_decompose_no_llm_smoke`,
asserts that **no** LLM provider is configured — it breaks when a sibling test
sets the variable. That widens #454, whose title says "flaky git tests": the
class is any test asserting on process-global state. CI does not see it because
it runs `cargo nextest`, one process per test; local `cargo test` shares one.

Disk was at 100% with 6.2 GiB free before this run. That state previously
produced `passed=0 failed=0` at exit 0 — a gate reporting a value that is not a
result. 37 GiB was freed before measuring, so these numbers are from a run that
actually happened.

## Structured Fields

verdict: supports
congruence_level: 3
evidence_type: measurement

base_sha: ca5a7c2c
result_sha: 9dd7242
changed_paths: crates/forgeplan-cli/src/commands/get.rs, crates/forgeplan-cli/src/commands/validate.rs, crates/forgeplan-cli/tests/cli_get_links.rs, crates/forgeplan-core/src/db/store.rs, crates/forgeplan-core/src/lifecycle/mod.rs, crates/forgeplan-core/src/validation/checks.rs, crates/forgeplan-core/src/validation/rules.rs, crates/forgeplan-mcp/src/convert.rs, crates/forgeplan-mcp/src/server.rs, crates/forgeplan-mcp/src/types.rs, .gitignore


Loading
Loading