diff --git a/CLAUDE.md b/CLAUDE.md index e50b7a8e..b2d40e57 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -110,7 +110,7 @@ the project tree if desired. ## Capability map (what's built, by phase) -All 36 phases, P37a, P37b-i, P37b-ii, P37c and P37d are built and tested. One line of current fact per phase; the +All 36 phases, P37a, P37b-i, P37b-ii, P37c, P37d and P38 are built and tested. One line of current fact per phase; the authoritative rationale and full semantics live in the linked ADR, the design in `ARCHITECTURE.md`. The old per-phase narrative log this table replaced is archived verbatim at `docs/archive/claude-md-phase-log-2026-07.md` — do not @@ -159,6 +159,7 @@ the code, those win. | P37b-i | Presence-based partial clones: push, verify and gc walk what the store holds (`reachable_objects_partial`), not the fetch filter; push checks every gap id against the destination before sending; a view gap fails with `GapInView` before any write (preflight at the top of `materialize`, plus `undo` and `sparse set`); a partial clone fetches from its origin only. 37b-ii: on a lazy, online clone `ensure_view` fills the view closure by id before switch, fast-forward, undo and `sparse set`, `sparse set` may widen past the filter, a by-id reply is capped at `min(--max-pack-size, 2 GiB)` (a constant since #213, independent of the object cap) and a refused batch is split. | [0048](docs/adr/0048-presence-based-partial-clones.md) | | P37c | Merge, cherry-pick and rebase on a partial clone: a tree-recursive engine (`merge_trees`) carries a subtree by id when the sides agree and no protection rule applies, reads only where they differ or a rule intersects, and on a lazy, online clone fills what it asks for by id outside the store lock (a non-lazy clone gets the gap error with `sc backfill `); a carried protected subtree keeps the complete input wrap union; a conflict inside the view is marked and resolved like on a full clone (`sc conflicts`/`sc resolve`/`merge --abort`/`sc commit`; the out-of-view part is grafted from the decided root), while a conflict outside the view, or a result that must be sealed outside it, is refused before any ref, merge-state or working-tree change (fetched objects stay). A subtree identical on all three sides is carried even under a protection rule. Cherry-pick and rebase use the same engine (`replay_commit`): the fold's accumulator may hold absent subtrees, the view is filled before the final write, and a stopped pick or rebase keeps its carried subtrees in the decided root. Mode-only edits now merge and a file/directory collision fails before any write, on full clones too. | [0049](docs/adr/0049-merge-on-partial-clones.md) | | P37d | Agent sessions on a partial clone: `sc ws fork`/`run`/`harvest`/`abandon` and `sc work` work; a workspace or agent sees the host's sparse view only (`sc work` no longer gets a complete tree there), the view closure is filled (lazy, online) or refused with the gap error before anything is written, a workspace commit grafts the out-of-view subtrees from the base without reading them, and harvest lands through the ADR-0049 merge (any conflict falls back to a `work-` branch as on a full clone) | [0050](docs/adr/0050-sessions-on-partial-clones.md) | +| P38 | Gitea-compatible forge over bare Git and smart HTTP: recorded API subset, scoped auth, protected merges, maintenance and container operations; 24 recorded scenarios and six first-consumer acceptance scenarios pass. Hosted repos have none of the `.sc/` features; SSH and Actions remain outside v1. | [0058](docs/adr/0058-sc-forge-gitea-compatible-git-forge.md) | ## Standing boundaries & gotchas diff --git a/ROADMAP.md b/ROADMAP.md index f8491770..ad4a04bb 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -696,27 +696,13 @@ across every phase. ## Active -**P38 — sc-forge** (Proposed, [ADR-0058](docs/adr/0058-sc-forge-gitea-compatible-git-forge.md)): -a Gitea-compatible Git forge (bare repos over smart HTTP, a recorded subset of -`/api/v1`, SQLite metadata) so a platform can swap its project Git host by -config. Design: -`docs/superpowers/specs/2026-10-22-p38-forge-design.md`. Slices F0 (contract -capture) through F6 (acceptance on the first deployment); F0, F1 (server -skeleton, users, organizations, tokens, `admin` CLI), F2a (repositories API, lifecycle -and reconciler, collaborators, branches) and F2b (smart-HTTP git transport via `git http-backend`, -`pre-receive` ref policy, admission control, threat-model pass #1) and F3a (content reads: refs, tags, commits, -trees, contents, archives) and F3b (contents writes: create, update, delete as server-made commits) and F4a (branch protection -enforced on push, contents API and branch delete; commit statuses) and F4b (pull requests, reviews, comments, retention -refs) and F4c (merge with a crash-safe journal, required-check gating, kill -9 and protection-matrix tests) and F5a (two-stage gc, merge-commit retention, runtime cleanup of stale locks and quarantine directories) and F5b (structured logs, graceful SIGTERM drain, bind-gate tests, container image, operations guide) are built. Hosted repos are -bare Git and get none of the `.sc/` features. - -Other follow-up work is tracked as GitHub issues and listed under Deferred -below. +No phase is currently active. Follow-up work is tracked under Deferred below. ## Completed phases (usability-first ordering) | Phase | Goal | Demoable outcome | ADR | |-------|------|------------------|-----| +| **P38 — sc-forge** | Configurable project Git host | Bare Git over smart HTTP, recorded Gitea API subset, protected merges and operations tooling; all 24 recorded scenarios and all six first-consumer acceptance scenarios pass. Local acceptance only; production migration is separate. | [0058](docs/adr/0058-sc-forge-gitea-compatible-git-forge.md) | | **P4 — Merge & conflict resolution** | Combine work from two branches | `sc merge ` creates a merge snapshot; clean merges auto-resolve, conflicts are detected and reported | [0012](docs/adr/0012-three-way-merge.md) | | **P5 — Secret scanner (accidental-plaintext guard)** | Stop plaintext secrets being committed | pattern + entropy scan hard-rejects plaintext secrets, with `sc scan` and a hash-scoped allowlist | [0017](docs/adr/0017-secret-scanner.md) | | **P6 — Remotes: clone / push / fetch** | Sync a repo between locations | `sc clone `, `sc push`, `sc fetch` transfer objects + refs; `fetch` then `merge` integrates remote work | [0013](docs/adr/0013-remote-sync-model.md) | diff --git a/docs/adr/0058-sc-forge-gitea-compatible-git-forge.md b/docs/adr/0058-sc-forge-gitea-compatible-git-forge.md index 5f54655d..8c074467 100644 --- a/docs/adr/0058-sc-forge-gitea-compatible-git-forge.md +++ b/docs/adr/0058-sc-forge-gitea-compatible-git-forge.md @@ -1,6 +1,6 @@ # ADR-0058: sc-forge, a Gitea-compatible Git forge -- **Status:** Proposed +- **Status:** Accepted (2026-10-25) - **Date:** 2026-10-22 - **Phase:** 38 - **Builds on:** ADR-0028 (hosted Git through system `git`), ADR-0040 (bearer @@ -146,3 +146,25 @@ Whether `has_actions` PATCH is accepted or refused, the `/version` string, and an eventual TLS option are decided during F1 and F5. Foreign-token codes, merge message texts and the deliberate departures from Gitea are recorded in the spec ("Contract decisions from the recordings") and `crates/forge/conformance/`. + +## Acceptance outcome + +F0–F5 are implemented. F6 passed on 2026-10-25 against a disposable local +consumer deployment using forge source `dd563f231092b4c9832f56475a597c7dddd8e825` +(the runtime change merged in #319; its later commit changes only a maintenance +test). All six default consumer scenarios passed together: topology, delivery +including customer merge, request-to-agent-runtime, brownfield import, +brownfield one-shot and Claim recovery. Customer source imports remained on +Gitea. Recovery exercised an actual orchestrator with a controlled harness, +lost-acknowledgement replay, an explicit Worker budget reset and browser +readback without navigation. This is consumer integration evidence, not a +qualification of a real coding model. + +The recorded 24-scenario conformance gate remains the reproducible regression +suite in this repository. Consumer evidence is retained in the consumer's +private workspace; it is not available from this repository's CI. + +Acceptance does not approve a production migration. The local fixture used +the consumer's Redis-free middleware mode, so production rate limiting was +not qualified. SSH, Actions and the other v1 exclusions above remain excluded; +implementation follow-ons remain tracked in #316. diff --git a/docs/superpowers/specs/2026-10-22-p38-forge-design.md b/docs/superpowers/specs/2026-10-22-p38-forge-design.md index 27ed610e..14e11c9a 100644 --- a/docs/superpowers/specs/2026-10-22-p38-forge-design.md +++ b/docs/superpowers/specs/2026-10-22-p38-forge-design.md @@ -1,9 +1,8 @@ # Design: sc-forge, a Gitea-compatible Git forge (P38) - **Date:** 2026-10-22 (revision 2, after independent design review) -- **Status:** Draft, pre-implementation (ADR-0058 is Proposed) -- **ADR:** ADR-0058 is firmed from Proposed to Accepted when the phase is built - (ROADMAP "How a phase gets built") +- **Status:** Accepted (2026-10-25); implementation complete +- **ADR:** [ADR-0058](../../adr/0058-sc-forge-gitea-compatible-git-forge.md) is Accepted (2026-10-25). - **Contract source:** `crates/forge/conformance/` (recorded from real Gitea 1.22.6 and 1.26.2; see "Conformance") plus the client survey summarized below @@ -1071,7 +1070,28 @@ conflict checks. URLs already compare by value, including repository identity. T now requires wrong mergeability and wrong-repository URL mutations to fail the actual gate. Refusal texts were fixed in #315; combined-status decisions are recorded under "Statuses" above. Remaining lifecycle, resource and authentication limits from the implementation comments are tracked -in #316; F6 remains acceptance on the first consumer deployment. +in #316. F6 passed on the first consumer deployment; see below. + +## F6 acceptance outcome + +Completed on 2026-10-25 using a disposable local consumer deployment and forge +source `dd563f231092b4c9832f56475a597c7dddd8e825` (#319's runtime change). +One complete default sweep passed topology, delivery with customer merge, +request-to-agent-runtime, brownfield import, brownfield one-shot and Claim +recovery. Only the target Git host was selected as sc-forge; customer source +imports stayed on Gitea. The consumer's configuration and fixture repairs +were delivered through its own repositories. + +Claim recovery used the real orchestrator with a controlled harness. It +verified failure acknowledgement replay, persistence of the stopped Claim +across restart, explicit budget reset, a second Worker, unchanged Claim +ownership, unique failure/recovery comments and browser-visible recovery +without navigation. It does not qualify a real coding model. + +The consumer's private evidence is separate from this repository's reproducible +24-scenario conformance gate. The local run used Redis-free consumer middleware +and did not qualify production rate limiting or authorize QA/production +cutover. Existing v1 exclusions and #316 follow-ons remain in force. ## Open questions