Implements ADR-012 decision 7. Placed in state-hub because central must do its own reading: the pod can clone Forgejo anonymously, and driving this from Repo Manager would push a workstation-computed projection into central, which ADR-010 decision 5 forbids. Also the only sanctioned removal path — the hub has no hard-delete for work records by design. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 2583210@bnt-lap001 Assistant-Session: f2bff2d5-e9b2-4338-92ca-10282a927006
146 lines
5.1 KiB
Markdown
146 lines
5.1 KiB
Markdown
---
|
|
id: STATE-WP-0083
|
|
type: workplan
|
|
title: "Forge-derived projection reset, per repository"
|
|
domain: infotech
|
|
repo: state-hub
|
|
status: active
|
|
owner: codex
|
|
topic_slug: infotech
|
|
created: "2026-08-25"
|
|
updated: "2026-08-25"
|
|
related:
|
|
- CUST-ADR-012
|
|
- CUST-WP-0068
|
|
---
|
|
|
|
# Forge-derived projection reset, per repository
|
|
|
|
## Goal
|
|
|
|
Implement `ADR-012` decision 7: discard a repository's projection and rebuild it
|
|
from what Forgejo holds. Per repository, routine, idempotent, and verifiable.
|
|
|
|
This is the only sanctioned way to remove a hub record. The hub has no
|
|
hard-delete for work records — `DELETE /tasks/{id}` is `cancel_task`,
|
|
`DELETE /workstreams/{id}` is `410 Gone`, and no `session.delete` exists for
|
|
either. Re-derivation is not one option among several; it is the mechanism.
|
|
|
|
## Why here and not in Repo Manager
|
|
|
|
`ADR-012` decision 1 says central derives from the forge, and the pod can reach
|
|
it: `git ls-remote https://forgejo.coulomb.social/...` succeeds anonymously from
|
|
inside the cluster, and `git` is already in the image.
|
|
|
|
Driving the reset from Repo Manager would mean computing a projection on a
|
|
workstation and pushing it into central — precisely the injection of derived
|
|
state `ADR-010` decision 5 forbids. Central must do its own reading. The cost is
|
|
that workplan parsing exists in two places; `scripts/consistency_check.py`
|
|
already parses frontmatter and task blocks here, so the capability is present
|
|
and should be extracted rather than rewritten.
|
|
|
|
## What it must not do
|
|
|
|
- **Not restore preliminary overlay records.** They exist because the forge does
|
|
not hold them; a rebuild from the forge cannot reproduce them and must not
|
|
pretend to.
|
|
- **Not destroy hub-native records.** Progress events, decisions and inbox
|
|
messages originate in the hub (`ADR-010` decision 4). They are not
|
|
forge-derived and must survive a rebuild of forge-derived state.
|
|
- **Not proceed silently when records would be lost.** Stop, name them, and
|
|
require an explicit acknowledgement.
|
|
|
|
## Derive a repository's projection from the forge
|
|
|
|
```task
|
|
id: STATE-WP-0083-T01
|
|
status: todo
|
|
priority: high
|
|
```
|
|
|
|
Given a repository slug, clone or fetch its default branch from Forgejo into a
|
|
temporary location, parse the workplan files, and compute the projection that
|
|
state would produce: workplans, tasks, their identifiers, statuses and backing
|
|
paths.
|
|
|
|
Read-only and side-effect free. Record the commit the derivation came from —
|
|
`ADR-012` decision 2 requires provenance, and the existing `git_fingerprint` is
|
|
worthless precisely because nothing ever wrote it correctly.
|
|
|
|
Acceptance: deriving `the-custodian` twice from the same commit yields identical
|
|
output, and the commit is reported.
|
|
|
|
## Report the difference before changing anything
|
|
|
|
```task
|
|
id: STATE-WP-0083-T02
|
|
status: todo
|
|
priority: high
|
|
```
|
|
|
|
Compare the derived projection against what the hub currently holds for that
|
|
repository, and report: records the forge has that the hub lacks, records the
|
|
hub has that the forge does not, and records whose fields differ.
|
|
|
|
This is the half that is immediately useful without any destructive capability,
|
|
and it is what makes decision 7's "verifiable" real. It also answers the
|
|
question `CUST-WP-0068-T09` is waiting on — which stale rows would actually
|
|
clear — before anyone commits to clearing them.
|
|
|
|
Acceptance: a dry-run diff for a repository with known drift matches what
|
|
manual inspection shows.
|
|
|
|
## Apply the reset transactionally
|
|
|
|
```task
|
|
id: STATE-WP-0083-T03
|
|
status: todo
|
|
priority: high
|
|
```
|
|
|
|
Replace the repository's forge-derived records with the derived projection in
|
|
one transaction: create what is missing, update what differs, remove what no
|
|
longer derives. Hub-native records are untouched.
|
|
|
|
Refuse by default when removal would destroy a record with no counterpart in the
|
|
forge; report what would be lost and require an explicit acknowledgement to
|
|
proceed. That refusal is evaluated per repository, so one unresolved repository
|
|
never blocks the rest.
|
|
|
|
Acceptance: reset twice produces the same projection; a repository holding
|
|
records the forge lacks is refused with those records named; hub-native record
|
|
counts are unchanged across a reset.
|
|
|
|
## Fleet form as a loop over the repository form
|
|
|
|
```task
|
|
id: STATE-WP-0083-T04
|
|
status: todo
|
|
priority: medium
|
|
```
|
|
|
|
The fleet-wide reset iterates the per-repository reset and shares its
|
|
implementation, so the rarely-used dangerous path is exercised by the frequently
|
|
used safe one. Repositories that refuse are skipped and reported, never aborting
|
|
the pass.
|
|
|
|
Acceptance: a fleet dry-run reports per-repository outcomes including refusals,
|
|
and completes despite them.
|
|
|
|
## Retire what the reset replaces
|
|
|
|
```task
|
|
id: STATE-WP-0083-T05
|
|
status: wait
|
|
priority: medium
|
|
```
|
|
|
|
Once reset is trusted, `CUST-WP-0068-T09` can clear its stale rows — 4 workplan
|
|
rows from the prefix migration and 305 task rows across 44 workplans.
|
|
|
|
`ADR-003` decision 2's `mtime`-based fingerprints should also be replaced by the
|
|
source commit at this point; `ADR-012` invalidated that composition and the
|
|
replacement belongs with the provenance work in `T01`.
|
|
|
|
Acceptance: `CUST-WP-0068-T09` closes; no fingerprint input depends on a local
|
|
filesystem.
|