Receive source-owned depends_on edges through Forge projection (STATE-WP-0094-T05)
Derive frontmatter and task-block depends_on edges from the pinned commit and reconcile workplan_dependencies under an explicit ownership contract: only forge:<repo> rows are created or removed, external relations are preserved, missing/ambiguous/self targets are recorded and hold owned edges, failures roll back, and repeat receipts are noop. Additive migration b3c4d5e6f7a8. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 671493@bnt-lap001 Assistant-Session: 60d7b11f-78f9-4731-9367-918511b2762d
This commit is contained in:
parent
b2af3c1c1d
commit
fceb5f27f0
6 changed files with 637 additions and 0 deletions
84
docs/forge-dependency-edge-receiving.md
Normal file
84
docs/forge-dependency-edge-receiving.md
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# Forge dependency-edge receiving (STATE-WP-0094-T05)
|
||||
|
||||
Status: source implementation landed 2026-10-04; not deployed. Deployment and
|
||||
any receiving schedule need separate founder authorization.
|
||||
|
||||
## Problem
|
||||
|
||||
`docs/owner-return-handoff.md` ("T05 graph freshness assessment") records that
|
||||
normal Forge receiving (`api/services/forge_projection.py`) did not derive
|
||||
`depends_on` edges or reconcile `workplan_dependencies`. Only C-20 created
|
||||
edges, from a workstation checkout, and nothing ever removed an edge whose
|
||||
declaration disappeared. Adding a projection that "replaces every dependency
|
||||
row" would delete externally authored relations, so receiving needs an explicit
|
||||
ownership contract first.
|
||||
|
||||
## Contract
|
||||
|
||||
1. **Source.** Edges are derived only from the immutable commit that receiving
|
||||
already pins (`expected_commit` = derived commit), from the same files as the
|
||||
rest of the projection:
|
||||
- workplan frontmatter `depends_on`, `depends_on_workplans`,
|
||||
`depends_on_tasks` - split like C-20: ids ending `-T\d{2,3}` are task
|
||||
targets (`starts_after`), all others workplan targets (`blocks`);
|
||||
- task-block `depends_on` - the waiting task is the from side
|
||||
(`from_task_id`). As in C-20, task-block edges of closed workplans
|
||||
(`finished`/`archived`) and closed tasks (`done`/`cancel`) are history and
|
||||
not desired.
|
||||
- A bare `T##` target is qualified with the declaring workplan id.
|
||||
- Bound historical workplans (`historical_preservation`) declare no edges.
|
||||
- A declaration that is a mapping or nested list refuses the whole derive
|
||||
(`ForgeDeriveError`); it is never dropped.
|
||||
2. **Ownership.** A row is source-owned iff
|
||||
`workplan_dependencies.source_owner = 'forge:<repo-slug>'` (additive,
|
||||
nullable column, migration `b3c4d5e6f7a8`) and its from-workplan belongs to
|
||||
that repository. `source_commit` records the commit that introduced it.
|
||||
Receiving creates rows only with that owner and removes only rows with that
|
||||
owner. Rows with NULL or any other owner (API, MCP, C-20 fix path, other
|
||||
tools) are externally authored and are never modified or removed.
|
||||
3. **Already present externally.** When a declared edge already exists as an
|
||||
external row (same from workplan, from task, target and relationship), it is
|
||||
preserved, not adopted, and reported in `external_edges`. Adoption is a
|
||||
deliberate future decision (see risks).
|
||||
4. **Target resolution (cross-repository).** Fleet-wide, excluding
|
||||
projection-retired workplans and their tasks: workplans by ADR-007 derived
|
||||
UUID or record-id slug; tasks by derived UUID or `record_id`. Exactly one
|
||||
candidate resolves. Targets created in the same receipt resolve, because
|
||||
resolution runs after the workplan/task writes are flushed.
|
||||
5. **Missing / ambiguous / invalid targets.** Zero candidates = `missing`, more
|
||||
than one = `ambiguous` (candidates listed; no winner chosen), a self edge =
|
||||
`self`, a waiting task the hub lacks = `from-task-missing`. Each is recorded
|
||||
in `unresolved_edges`; nothing is silently dropped. The receipt itself still
|
||||
applies (a target in a not-yet-received repository must not block the
|
||||
source repository's workplan projection).
|
||||
6. **Removal.** Only source-owned rows whose key is no longer declared are
|
||||
removed - including rows of workplans retired in the same acknowledged
|
||||
receipt. If the from side (workplan or waiting task) has any unresolved
|
||||
declaration, its owned rows are retained and a note is emitted, because the
|
||||
unresolved target may be one of them.
|
||||
7. **Transactional failure.** Edge reconciliation runs inside the same session
|
||||
as the workplan/task projection and flushes at the end. Any error propagates
|
||||
and the endpoint commits nothing; a refused receipt returns before edges are
|
||||
touched.
|
||||
8. **Repeat noop.** Owned rows are not rewritten when unchanged, so the same
|
||||
commit received twice reports `status: noop` with zero created/removed edges.
|
||||
(`unresolved_edges` is still reported every time.)
|
||||
|
||||
Outcome schema additions (`state-hub.projection-reset.v1`): `created_edges`,
|
||||
`removed_edges`, `unresolved_edges`, `external_edges` lists and their counts.
|
||||
|
||||
## Coexistence with C-20
|
||||
|
||||
C-20 keys existence on (from task, target, relationship) regardless of owner,
|
||||
so it does not duplicate a source-owned edge; edges its fix path creates are
|
||||
external to receiving. Existing hub edges therefore stay external until an
|
||||
explicit adoption decision.
|
||||
|
||||
## Open risks
|
||||
|
||||
- Pre-existing C-20/API edges are never adopted, so a removed declaration does
|
||||
not remove an edge C-20 created earlier; adoption needs its own decision.
|
||||
- `diff_against_hub` (dry run) does not yet preview edge changes.
|
||||
- Ambiguity by slug for workplans is mostly prevented by the global slug index;
|
||||
task `record_id` ambiguity across workplans is the realistic case.
|
||||
- Not deployed; no evidence of scheduled freshness. T05 stays in progress.
|
||||
Loading…
Add table
Add a link
Reference in a new issue