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
1 change: 1 addition & 0 deletions 000-docs/000-INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ This directory is an Intent Solutions **addition** to the fork — upstream
| 004 | [DR-DECR — Fork-gate wiring](004-DR-DECR-fork-gate-wiring.md) | TEST_AUDIT G6 decision: tracked `lefthook-local.yml` + fork gates + hash pinning; F1 resolution; escape-scan baseline. |
| 005 | [DR-DECR — Dedicated production VPS topology](005-DR-DECR-dedicated-vps-topology.md) | Owner decision (2026-07-29): production on a dedicated VPS; the shared-host stack becomes permanent staging. Supersedes the one-server answer in `001`/`003`. |
| 006 | [DR-STND — Authoritative naming & boundaries](006-DR-STND-authoritative-naming-and-boundaries.md) | **CANONICAL** (owner amendment 2026-07-29, FINAL): the six Buzz assets, the host-vs-repo disambiguation rule, the four-plane flow, and the two gates (contribution vs deployment). Any doc naming a Buzz asset defers to this. |
| 007 | [AA-AUDR — Fork-contract breach audit 2026-08-03](007-AA-AUDR-fork-contract-breach-2026-08-03.md) | PR #16 merged 14 upstream-owned paths onto fork `main` (process breach only; prod untouched). Divergence inventory, causal chain (gates never in CI), remediation: revert → repair-branch sync → upstream via the contribution lane → gates as a required CI check. |
153 changes: 153 additions & 0 deletions 000-docs/007-AA-AUDR-fork-contract-breach-2026-08-03.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# 007-AA-AUDR — Fork-contract breach audit — 2026-08-03

**Status:** FINAL (audit record; append corrections, do not rewrite)
**Scope:** `intent-solutions-io/buzz` fork `main` vs `upstream/main` (`block/buzz`)
**Refs at audit time:** fork `main` = `71ad4571c` (2026-08-03 17:36 -0500);
`upstream/main` = `631b05c88` (2026-08-03 21:51 -0400)
**Verdict:** FORK.md contract breached — **process breach only**. No production,
data, or security impact. Nothing was pushed upstream.

---

## 1. What happened

PR **#16** (`fix(onboarding): auto-join invited members to General`,
merged 2026-08-03 22:36 UTC) was merged onto fork `main` modifying **14
upstream-owned paths** — relay crates, desktop code, all four upstream CI
workflows, and both lockfiles. FORK.md's contract is explicit: the fork is
**additive-only**; "a dressing commit that touches an upstream path is a
defect." The same working session also built fork relay images and chased a
GHCR credential wall — machinery the contract says we don't need, because
deploys use **upstream published images** and `CARRIED_PATCHES` is empty by
design.

The code itself is good — CI-proven, reviewer-hardened, reproduction-tested.
It is in the wrong lane: solved problems go **upstream** through the
contribution system, not onto fork `main`.

## 2. Divergence inventory (fork `main` `71ad4571c` vs `upstream/main`)

`git diff 631b05c88...71ad4571c --name-status` (pinned object IDs — the same
refs `upstream/main`/`origin/main` resolved to at audit time) shows 73
divergent paths.
Classification against the `scripts/fork-gates/check-additive-only.sh`
allowlist:
Comment thread
coderabbitai[bot] marked this conversation as resolved.

### 2.1 ALLOW — legitimate additive fork surface (57 paths)

All `A` (added) status, all under allowlisted prefixes:

| Prefix | Paths | Purpose |
|---|---|---|
| `.audit-harness/` | 33 | vendored IS audit harness |
| `.beads/` | 11 | task tracking (prefix `buzz`) |
| `000-docs/` | 7 | planning artifacts (001–006 + index) |
| `scripts/fork-gates/` | 2 | contract enforcement scripts |
| `FORK.md`, `TEST_AUDIT.md`, `lefthook-local.yml`, `scripts/audit-harness` | 4 | contract, test baseline, hook wiring, harness wrapper |

### 2.2 VIOLATIONS — upstream-owned paths modified by PR #16 (14 paths)

Confirmed as exactly the path set of the #16 squash
(`git diff 9b0ff3c92..71ad4571c --name-status`):

| Path | Status |
|---|---|
| `.github/workflows/ci.yml` | M |
| `.github/workflows/docker.yml` | M |
| `.github/workflows/release.yml` | M |
| `.github/workflows/signed-macos-canary.yml` | M |
| `Cargo.lock` | M |
| `crates/buzz-relay/src/api/invites.rs` | M |
| `crates/buzz-relay/src/handlers/side_effects.rs` | M |
| `desktop/src-tauri/Cargo.lock` | M |
| `desktop/src-tauri/src/commands/channels.rs` | M |
| `desktop/src-tauri/src/commands/channels_tests.rs` | M |
| `desktop/src/features/onboarding/welcome.test.mjs` | M |
| `desktop/src/features/onboarding/welcome.ts` | M |
| `desktop/src/features/settings/ui/SettingsPanels.tsx` | M |
| `desktop/tests/e2e/invites-settings-screenshots.spec.ts` | M |

### 2.3 PRE-EXISTING gate failures — not part of #16 (2 paths)

`.harness-hash` and `.harness-hash-extra-patterns` are **added** files
(hash-pin manifests, listed in FORK.md's must-survive table) that were never
added to the gate script's `ALLOW` array. A latent allowlist/contract
mismatch, present before #16. The repair branch fixes the allowlist to
legitimize them.

**Gate run on fork `main` at `71ad4571c`:** `check-additive-only.sh` **FAIL —
16 upstream-owned path(s)** (= 2.2 + 2.3); `check-must-survive.sh` PASS
(10/10 paths).

## 3. Causal chain

1. **The fork gates were never wired into CI.** They ran only via
`lefthook-local.yml` pre-push — a local hook an agent working through
tooling that pushes without lefthook (or from a fresh clone without
`lefthook install`) never executes. The fork's GitHub checks were
upstream's own CI, which knows nothing about the fork contract.
2. **PR #16 targeted fork `main` instead of the contribution lane.** The
working agent solved a real bug (invite claims don't join the canonical
General channel), then landed the fix where it was standing — the fork —
rather than routing it upstream per FORK.md ("upstream contributions ride
dedicated `contrib/*` branches").
3. **The merge went green** because the only required signals were upstream
CI compiles + reviewer comments. Nothing machine-checked the contract at
the merge boundary. An agent that hadn't read FORK.md had no forcing
function to encounter it.

Root cause in one line: **the contract lived in prose and a local hook, not
in a required check.**

## 4. What was NOT damaged

- **Production relay:** runs the **upstream published image**, digest-pinned
(`ghcr.io/block/buzz@sha256:a0f67…` — digest deliberately truncated here;
this fork is public, and full deployment evidence lives in the private ops
lane's deployment reference). The fork relay image built during the #16
session was **never deployed**.
- **Agent runtime:** `buzz-agent:fork-9b0ff3c92` is a **sanctioned** estate
artifact (private ops decision log entry 039), built from an allowlisted
fork state — unrelated to the breach.
- **Upstream:** nothing was pushed to `block/buzz`. No upstream PR, issue, or
branch was created from the breach content.
- **Data / members / keys:** untouched. The relay's Postgres, roster, and
membership were not part of this work.
- **Fork history:** clean of force-pushes. The breach is one revertable
squash commit.

## 5. Flagged follow-up (not part of this breach)

**Dormant updater tag suspect:** `buzz-updater.service` pins
`ghcr.io/block/buzz:relay`, but that tag does not currently resolve on GHCR.
The unit is dormant (timer not enabled). **Verify the tag resolves — or
re-pin to a digest — before the timer is ever enabled.** Tracked in the
adoption program's beads.

## 6. Remediation plan (filed with this audit; execution tracked in PRs)

This record is filed **before** remediation completes; each step's completion
evidence is its referenced PR, not this document.

1. **Revert** the #16 squash on fork `main` via PR — no force-push, no
history rewrite. → fork **PR #18**.
2. **Land the repair branch** `fix/fork-upstream-sync-20260803` (merge-based
upstream sync to `a5dbdf5e6`, 117 commits + gate-allowlist fix for §2.3)
via PR; upstream-path collisions resolve to **upstream's side**. → fork
**PR #19**.
3. **Route the solved problems upstream** through the contribution system
(dossier, issue-before-PR, upstream conventions) — the invite-claim fix,
the CI-brittleness findings, and the buildcache finding are candidates.
No direct upstream PRs outside that lane. Submission runs on the
contribution system's cadence, not this audit's.
4. **Never again** (planned; PR reference lands when opened): fork gates
become an **additive** CI workflow (`.github/workflows/fork-gates.yml`)
and a **required check** on `main`; the fork gains a declared-divergence
`CLAUDE.md` stating the contract for every future agent; both divergences
enter `ALLOW` + FORK.md's must-survive table in the same reviewed PR.

**Acceptance for "remediated"** (conditions to verify at completion, then
recorded in the closing PR): both fork-gate scripts PASS on restored `main`;
`git diff upstream/main...main` contains only allowlisted paths; a deliberate
canary PR touching `crates/…` goes red on the required check and is closed
unmerged.
Loading