# v5.46.x Plans Audit — 2026-06-04

**Scope:** `PLAN_V5_46_0_DISTRIBUTION.md` + `PLAN_V5_46_1_CROSS_REPO_PR_AUTO_OPEN.md`.
**Audited against:** v5.45.0 + v5.45.1 shipped state, user directives (2026-06-04), P1-P11 invariants, `docs/DECISIONS.md` PD-37+PD-38.
**Auditor:** Claude Sonnet 4.6 on branch `docs/v5.46-audit`.
**v5.46.0 plan revision date:** 2026-06-02.
**v5.45.0 DP3 OVERRIDE date:** 2026-06-04.
**Gap:** plan revised BEFORE make-canonical shipped. All `yadgar install` references are pre-override drift.

---

## Summary table

| Plan | P1 | P2 | P3 | P4 | P5 | P6 | P7 | P8 | P9 | P10 | P11 | v5.45.x consistency | Ship-readiness |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| v5.46.0 | Missing | Missing | N/A | N/A | N/A | Partial | Missing | Partial | Partial | Missing | N/A | FAIL (4+ stale refs) | 2/5 |
| v5.46.1 | Present | Present | N/A | N/A | Present | Present | Present | Missing | Present | Present | N/A | Present | 3/5 |

---

## v5.46.0 findings

### P1 — Architecture conformance

**Status: Missing.**

The plan has no `## Architecture Conformance` section and cites no `docs/architecture.md` sections. v5.46.0 adds `flake.nix` (new package output), a Homebrew formula, and Forgejo Actions workflows — all new distribution artifacts that affect how yadgar is deployed. None are cross-referenced to architecture sections (Docker Deployment, Transport Modes, Module Responsibilities).

The plan DOES confirm container source-of-truth stays at `docker.io/openfantasy/yadgar` — this is correct and architecturally aligned — but it is not framed as an architectural conformance statement.

Required per P1 invariant (codified 2026-06-04): `## Architecture Conformance` section citing `docs/architecture.md` sections for each touched deployment path.

### P2 — Touched invariants register

**Status: Missing.**

No `## Touched Invariants` section. The plan touches or preserves:
- I25 (three-way-sync registry): `scripts/bump_version.py` adds a fourth sync target (`flake.nix`). This is an I25 CHANGE — the invariant previously covered `pyproject.toml + server.json + nix module`. A fourth target needs explicit registration.
- I27 (plan-first): preserved (this plan is the plan-first doc).
- I9 (hot path latency): N/A — distribution-only, no daemon hot path.

### P3 — Config knob lifecycle

**Status: N/A.**

No new config knobs. `cyclonedx-py` is an optional dev/sbom dep, not a runtime knob. N/A.

### P4 — Schema constraint lifecycle

**Status: N/A.**

No schema changes. N/A.

### P5 — MCP contract changes

**Status: N/A.**

No MCP changes. N/A.

### P6 — Cross-plan coordination

**Status: Partial — missing stub coordination with v5.46.1.**

What is present:
- Cites parent: v5.45.0 (foundation).
- Cites downstream: v5.47.0 (update mechanism).
- Documents `BREW_BUMP_TOKEN` + `NIX_BUMP_TOKEN` secrets.

**Critical gap:** v5.46.1 (the child plan, split from v5.46.0) says:

> "v5.46.0 ships `.forgejo/workflows/release.yaml` with `open-brew-pr` + `open-nix-pr` jobs as stubs (commented out or `if: false` gated). v5.46.1 fills in those jobs."

But v5.46.0 describes those jobs as **full implementations** (Step 7, lines 300-303), not stubs. There is a direct conflict: v5.46.1 expects stubs; v5.46.0 says to implement them. This ambiguity means the implementer will do double-work or leave v5.46.1 with nothing to do.

**Other cross-plan items:**
- v5.46.0 ↔ v5.48.0: daemon graceful-restart not referenced. v5.46.0 `pull-images` re-pull semantics are relevant to v5.48 graceful-restart on `action=install`. No coordination documented.
- v5.46.0 ↔ v5.62.0 (Typer CLI): plan proposes `yadgar install` in Homebrew formula `post_install`. v5.62.0 plans `yg` as the short alias for the full Typer CLI. No `yadgar install` subcommand in v5.62 scope was found. Not coordinated.

### P7 — Bug class precedent + production write-path test

**Status: Missing.**

No `## Bug Class Precedent` section. Distribution changes that warrant production-path tests:
1. `scripts/bump_version.py` — must not silently produce a version mismatch. Precedent: v5.42.6 X5 yaml stale (knob-invisibility bug class). The version-sync vector is directly analogous. Tests listed in Step 1 TDD are mostly present (tests 1-3, 5-6), but:
   - No test simulates the exact release workflow path (Forgejo Action trigger → `build-sdist` → `gen-sbom` → `gen-checksums` → `attach-to-release`) as a production-path end-to-end test. CI path is not exercised via the listed tests.
2. No post-ship verification probes documented (required per P7).

### P8 — Implementer-ready detail

**Status: Partial.**

Strong areas:
- Homebrew formula skeleton is concrete (lines 114-142).
- Nix flake skeleton is concrete (lines 150-176).
- Step-by-step plan with day estimates is provided.
- TDD test list is detailed.
- Release workflow jobs listed with named steps.

Gaps:
- `scripts/bump_version.py` — no function signature specified. Implementer must decide CLI interface (positional args? `--from`/`--to`?). Plan says "Args: `<old> <new>`" but this is not enough to write the argparse definition.
- `scripts/gen_sbom.sh` — no error path specified: what happens when `cyclonedx-py environment` fails (no venv, no pyproject, missing dep)?
- Forgejo release-create API endpoint not specified. Plan says "use `curl` + Forgejo REST API" but does not give the endpoint. Pre-flight confirms it, but the plan body doesn't capture the confirmed endpoint for the implementer.
- `nix/modules/home-manager.nix` move — plan says "Adjust for flake-input paths (replace `homeDir` references, etc)". The 1300-line file is in the nix repo. Implementer needs to know: how many `homeDir` references are there, what are they replaced with, and does the resulting file import correctly in a fresh `nix flake check`? "Etc" is not implementer-ready.

### P9 — Rollback path

**Status: Partial.**

Present for:
- Cross-repo PR auto-open failures: "release still ships (assets uploaded); user manually bumps brew/nix formulas." Correct.
- NixOS backward-compat shim: opt-in migration documented.

Missing:
- If `nix flake check` fails post-`flake.lock` generation, rollback path (delete `flake.nix` + `flake.lock`) not documented.
- If brew formula fails `brew audit --strict` after tap repo creation, rollback is `brew untap` — not documented.
- If the `homebrew-yadgar` Codeberg repo is created but the formula is broken, it's a public repo. Rollback procedure (delete repo? make private? push a fix?) not documented.

### P10 — External dependency pinning

**Status: Missing.**

New external dependencies introduced by v5.46.0:
- `cyclonedx-py>=4.0` — minimum bound only, no upper bound, no lockfile reference.
- `nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"` in `flake.nix` — this is a floating channel, not pinned. Will be pinned via `flake.lock` at lock time, but the plan does not specify:
  - Which nixpkgs commit to use as baseline.
  - Whether `nixos-unstable` is the right channel (it is, for a flake that ships `python314Packages`).
  - `flake-utils` source: `github:numtide/flake-utils` — no SHA pin documented.
- Python 3.14 Homebrew fallback: if `python@3.13` is used instead, no upper bound on Python version is specified (what happens when `python@3.15` ships?).

Supply-chain risk: `cyclonedx-py` — OWASP-maintained, no CVE monitoring path documented.

### P11 — Agent dispatch budget

**Status: N/A.**

No benchmark agent dispatch in this plan. Estimated effort 3-4 calendar days. N/A.

---

### v5.45.x consistency findings

#### CRITICAL — `yadgar install` CLI does not exist

The plan references `yadgar install` in 5 places:

| Location | Text | Problem |
|---|---|---|
| Line 86 (`docs/INSTALL.md` purpose) | "Cross-references…for the post-install `yadgar install` step." | `yadgar install` does not exist. No such CLI subcommand was shipped. |
| Line 134 (Homebrew formula `post_install`) | `ohai "Run \`yadgar install\` to complete setup (interactive)."` | Brew formula will print a broken instruction. |
| Line 135 (Homebrew formula `post_install`) | `ohai "Or \`yadgar install --non-interactive\` for CI environments."` | Same — broken. |
| Line 308 (Step 8 `docs/INSTALL.md` content) | "For each: install command + post-install `yadgar install` reference." | INSTALL.md will reference non-existent CLI. |
| Line 382 (Dependencies) | "…must exist for Homebrew formula's `post_install` to suggest `yadgar install`." | Confirms the Homebrew formula breaks on the `yadgar install` call. |

**Root cause:** v5.46.0 plan was last revised 2026-06-02. DP3 OVERRIDE (make-canonical, no `yadgar install` CLI) was issued 2026-06-04 as part of `V5_45_0_DP_OVERRIDES.md`. The plan predates the shipped reality.

**Severity: BLOCKING dispatch.** The Homebrew formula would ship broken instructions to all macOS users installing via `brew install`.

**The deeper problem — NEW DP not in the plan:** The make-canonical decision (v5.45.0) means `make setup` requires a repo checkout. The entire point of the distribution plan is to support users who do NOT have a repo checkout (pipx / Homebrew / Nix flake users). These users have no Makefile available. The plan has no answer to: "What do Homebrew/pipx users run after `brew install yadgar` to complete setup?"

Options (not evaluated in plan):
1. `brew install yadgar` installs the Python package only (no daemon setup). User must separately clone the repo + run `make setup`. Bad UX.
2. The Homebrew formula bundles a setup script that ships inside the Python wheel (already done: `install_assets/` is wheel-packaged per `pyproject.toml:82-84`). Formula `post_install` runs that script directly via `python -c "from yadgar.install_assets import ..."`or exposes a `yadgar setup` CLI subcommand backed by the bundled scripts.
3. v5.46.0 ships a thin `yadgar setup` CLI (keep the existing `yadgar/cli/setup.py`, expand it to orchestrate the bundled shell scripts via subprocess). Not `yadgar install` — just `yadgar setup` with the existing name.

This is the central new DP that emerged from v5.45.x reality. It must be resolved before implementing the Homebrew formula.

#### `scripts/setup.sh` reference audit

Not found in either v5.46.x plan. v5.45.0 CHANGELOG confirms `setup.sh` was deleted. This is consistent — no cleanup needed here.

#### `check_docker()` reference audit

Not referenced in either v5.46.x plan. v5.45.0 shipped `check_docker()` as a backward-compat alias. v5.46.0 plan step 3 comments mention TODO propagation of runtime var — consistent with shipped state. No action needed.

#### v5.45.1 numbering consistency

v5.45.0 DP_RESOLUTIONS.md (2026-06-04) names macOS launchd as v5.45.2. v5.45.0 DP_OVERRIDES.md says "v5.45.2 (macOS) becomes v5.45.1 (next split-out)". The shipped PLAN document is `PLAN_V5_45_1_MACOS_LAUNCHD.md` and CHANGELOG entry is `[5.45.1]`. So the shipped number is **v5.45.1** (macOS launchd).

v5.46.1 plan P6 references `docs/PLAN_V5_46_0_DISTRIBUTION.md` only — no v5.45.1 reference. This is fine.

v5.46.0 plan references v5.45.0 only as the prerequisite. No reference to v5.45.1 (macOS launchd). This is a gap: v5.46.0 ships a Homebrew formula with `post_install` that ostensibly triggers daemon setup. On macOS, that setup requires the launchd path from v5.45.1. The plan does not cross-reference v5.45.1 as a prerequisite for the macOS path to work. This is a missing cross-plan dependency.

#### `install_assets/` wheel packaging

v5.45.0 shipped `pyproject.toml:82-84` with `[tool.hatch.build.targets.wheel.shared-data]` shipping `install_assets/` at `share/yadgar/install_assets`. The v5.46.0 plan Step 6 (wheel asset packaging) says "Add `[tool.hatch.build.targets.wheel.include]`… so `install_assets/` ships in the wheel." This is ALREADY DONE. Step 6 as written will be a no-op or a conflict. The plan must update Step 6 to: "Verify existing wheel asset packaging from v5.45.0 covers the new `systemd/` templates needed for the Homebrew formula `post_install`; no new packaging step needed."

#### Nix flake NixOS detection alignment

v5.45.0 ships NixOS detection via `detect_os.sh` returning `linux-nixos` → Makefile refuses with "use nix flake" message. The v5.46.0 nix flake is the solution promised to NixOS users. However:
- The plan says `nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"` which is a rolling channel. NixOS LTS users (using a stable channel like `nixos-25.05`) will need a channel-compatible derivation. Not addressed.
- `python314Packages.buildPythonPackage` — Python 3.14 was not in stable nixpkgs as of the plan date. The flake's reliance on `nixos-unstable` is necessary but not documented as such.

#### `pipx install yadgar` (line 31)

This is a legitimate use case for distributing the Python package itself. `pipx install yadgar` installs the CLI + Python package — this is correct and not broken. The issue is only the `yadgar install` post-install step, not pipx itself. This reference is **not** a stale ref — `pipx install yadgar` is valid.

---

### Open DPs — status

#### Moot DPs (resolved by v5.45.0/1 ship)

None of the v5.46.0 open questions were directly resolved by v5.45.x. However:
- Open question 3 (bump script scope): the plan leans toward "generate only + let release workflow PR" — this is still a valid lean.
- Open question 4 (NixOS module path): the plan leans toward "move into yadgar repo at `nix/modules/home-manager.nix`" — not resolved by v5.45.x. v5.45.1 shipped launchd, not nix modules.

#### Still blocking

| DP | Status | Reason |
|---|---|---|
| OQ1 (Python 3.14 on Homebrew) | Blocking | Must check `brew info python@3.14` before formula. No resolve yet. |
| OQ2 (License classifier mismatch) | Blocking | `pyproject.toml:28` confirms `MIT License` classifier vs `license = "Apache-2.0"`. Fix required in Step 0. |
| OQ3 (bump script scope) | Non-blocking | Lean documented. Confirm at dispatch. |
| OQ4 (NixOS module path) | Blocking | 1300-line file move scope not implementer-ready. |
| OQ5 (tag pattern for pre-release) | Non-blocking | Lean documented with conditional syntax. |
| OQ6 (signed artifacts) | Non-blocking | Explicitly deferred. |

#### NEW DP (post-v5.45.x reality)

**NEW DP-A — `make setup` vs non-repo install post-install UX.**

`make setup` is make-canonical. Brew/pipx/nix users have no Makefile. After `brew install yadgar`:
- They cannot run `make setup`.
- `yadgar install` does not exist.
- The bundled `install_assets/` are available via `importlib.resources` inside the wheel, but no CLI orchestrates them.

Options:
1. Keep `yadgar setup` (existing `cli/setup.py`) and expand it to orchestrate bundled scripts via subprocess.
2. Ship a new thin subcommand (e.g., `yadgar bootstrap`) that runs setup from wheel-bundled assets.
3. Homebrew formula `post_install` directly executes bundled scripts via `python -c "..."`.

This DP MUST be resolved before implementing the Homebrew formula or `docs/INSTALL.md`. It is the single most important gap in the plan.

---

### Stale references found in v5.46.0

| Pattern | Line(s) | Verdict |
|---|---|---|
| `yadgar install` | 86, 134, 135, 308, 382 | STALE — CLI does not exist |
| `scripts/setup.sh` | (not found) | Clean |
| `check_docker` | (not found) | Clean |
| `v5.45.1` | (not referenced) | Fine — no stale numbering |
| `v5.45.2` | (not referenced) | Fine |
| `pipx install yadgar` | 31 | VALID — not stale (CLI exists for install; only post-install step is broken) |
| Stale plan-branch SHAs | None listed in plan body | N/A — plan doesn't cite SHAs |
| `flake.nix` | Multiple | Not stale — flake.nix does not yet exist, plan correctly notes this |
| `scripts/bump_version.py` | Multiple | Not stale — file does not yet exist, plan correctly notes this |

---

### Cross-plan coordination

| Pair | Status | Notes |
|---|---|---|
| v5.46.0 ↔ v5.46.1 | GAP | v5.46.1 expects stubs in `release.yaml`; v5.46.0 describes full jobs. Conflict. |
| v5.46.0 ↔ v5.47.0 | OK | v5.47.0 update mechanism needs install-method detection (pipx/brew/nix-flake/container); v5.46.0 makes those paths real. No explicit coordination text but no conflict. |
| v5.46.0 ↔ v5.48.0 | Missing | `action=install` in v5.48 does a daemon restart. v5.46.0 `pull-images` semantics (what happens to a running daemon during `make pull-images`?) not addressed. |
| v5.46.0 ↔ v5.45.0 | Partial | v5.45.0 dependency noted. But Step 6 (wheel packaging) is already done — plan does not acknowledge this. |
| v5.46.0 ↔ v5.45.1 | Missing | macOS launchd (v5.45.1) is a prerequisite for brew formula `post_install` to work on macOS. Not cross-referenced. |
| v5.46.0 ↔ v5.62.0 | Missing | v5.62.0 ships `yg` alias + full Typer CLI. If `yadgar install` or `yadgar setup` is expanded in v5.46.0 to handle non-repo installs, that expansion must align with v5.62.0's subcommand structure. No coordination documented. |

---

### Brutal honesty critique — v5.46.0

The v5.46.0 plan has a solid conceptual scope: PyPI polish + Homebrew + Nix flake + release automation + SBOM. The file table is concrete, the TDD list is real, and the effort estimates are credible. The Homebrew formula skeleton and Nix flake snippet are specific enough to be useful.

However, the plan was last revised 2026-06-02 and v5.45.0 shipped with a make-canonical decision on 2026-06-04 that invalidates the plan's core assumption: that `yadgar install` exists as a post-install step. The Homebrew formula `post_install` block on lines 133-136 will print broken instructions to every macOS user who installs via Homebrew. This is not a minor cleanup — it requires a design decision about how non-repo-checkout users run setup, which the plan never resolves.

The P1-P11 gap is significant: the plan has zero planning-invariant sections. For a plan that adds new repos, new packaging formats, and cross-repo automation, P2 (I25 is changed), P6 (v5.46.0/v5.46.1 stub coordination conflict), P7 (no production-path test for release workflow), and P10 (unpinned `cyclonedx-py` and floating nixpkgs) are all material gaps that create implementation risk.

The license classifier mismatch (Open Question 2) is confirmed present in the current `pyproject.toml:28`. It's listed as a pre-flight check, which is correct, but Step 2 should explicitly say "fix this before anything else."

**Ship-readiness: 2/5.** The plan is a solid draft that predates a fundamental direction change. It needs: (1) the `yadgar install` → `yadgar setup`/`make setup` remediation, (2) P1/P2/P6/P7/P10 sections, (3) stub coordination clarification with v5.46.1, (4) v5.45.1 cross-reference for macOS path.

---

### Recommended next steps before dispatching v5.46.0 implementation

1. **Resolve NEW DP-A first.** Decide the non-repo install post-setup UX. Options: (a) expand `yadgar setup` (existing CLI) to orchestrate bundled scripts via `importlib.resources`; (b) new `yadgar bootstrap` subcommand; (c) Homebrew formula runs scripts directly via embedded Python. Record decision in `docs/DECISIONS.md`. This determines the formula's `post_install` block and `docs/INSTALL.md` content.

2. **Fix all `yadgar install` references** once DP-A resolved. Lines 86, 134, 135, 308, 382. The formula `post_install` block in particular must be rewritten.

3. **Add P1-P11 sections** to the plan. Minimum required: P2 (I25 change for bump_version.py), P6 (stub coordination with v5.46.1), P7 (post-ship probes for release workflow), P10 (pin `cyclonedx-py`, document nixpkgs channel choice).

4. **Clarify stub coordination with v5.46.1.** Either: (a) v5.46.0 ships `open-brew-pr`/`open-nix-pr` as full jobs → v5.46.1 is redundant and should be folded in; or (b) v5.46.0 ships them as `if: false` stubs → update the v5.46.0 plan's Step 7 text to reflect this.

5. **Update Step 6 (wheel packaging).** `install_assets/` is already wheel-packaged via v5.45.0 (`pyproject.toml:82-84`). Step 6 should verify this coverage, not re-add it. Update step scope.

6. **Add v5.45.1 cross-reference.** macOS launchd (v5.45.1) must be verified working before the Homebrew formula `post_install` triggers daemon setup on macOS. Add as a soft dependency / prerequisite note.

---

## v5.46.1 findings

### P1 — Architecture conformance

**Status: Present.**

The plan has an `## Architecture Conformance` section that explicitly cites:
- Observability § (no new Prometheus metrics — CI only).
- Security § (`auth_middleware.py`) — cross-repo PATs in Forgejo repo secrets, not in `~/.yadgar/` or config.yaml.
- Module Responsibilities § — all new code in `.forgejo/workflows/`, not Python source.

Minimal but sufficient for the scope. No architecture changes proposed. Conformance is correct.

### P2 — Touched invariants register

**Status: Present.**

`## Touched Invariants` section present. Lists:
- I9 (hot path latency): preserves — CI only. Correct.
- I25 (three-way-sync registry): preserves — no new config knobs. Correct.
- I27 (plan-first): preserves.

Complete for the plan's scope.

### P3 — Config knob lifecycle

**Status: N/A.**

Handled: the plan explicitly discusses secret rotation policy for `BREW_BUMP_TOKEN` / `NIX_BUMP_TOKEN` — these are Forgejo repo secrets, not yadgar config knobs. Correct classification. N/A.

### P4 — Schema constraint lifecycle

**Status: N/A.** No schema changes. Correct.

### P5 — MCP contract changes

**Status: Present.** "No MCP changes. CI workflow only." Explicitly confirmed. N/A status correctly stated.

### P6 — Cross-plan coordination

**Status: Present.**

`## Cross-Plan Coordination` section present. Cross-references:
- v5.46.0 (parent) — with the critical coordination requirement: v5.46.0 must ship stubs for the jobs v5.46.1 fills in. This is stated in v5.46.1 but NOT reflected in v5.46.0 (see v5.46.0 P6 gap above).
- v5.47.0 (downstream) — format alignment confirmed, no conflict.

No migration number conflicts — correct (CI workflow only, no migrations).

### P7 — Bug class precedent + production write-path test

**Status: Present.**

`## Bug Class Precedent` section present. Two precedents:
- Idempotency (Precedent 1): Forgejo `GET /pulls` check before opening. Prevents duplicate PRs. Correct.
- Token scope leak (Precedent 2): `BREW_BUMP_TOKEN` must be scoped to PR-create only. Correct.

Verification probes listed (4 items). These are post-ship probes, not pre-dispatch unit tests — but they are present. The Step 1 TDD scaffolding covers idempotency via mock Forgejo API — adequate.

### P8 — Implementer-ready detail

**Status: Missing.**

Gaps:
- `scripts/open_brew_pr.sh` + `scripts/open_nix_pr.sh` — plan says "shell scripts called by CI workflow" but gives no implementation skeleton. Unlike v5.46.0's Homebrew formula skeleton and Nix flake snippet, v5.46.1 provides no equivalent script skeleton.
- Forgejo API request body for PR creation: plan says Step 0 "Verify Forgejo API endpoint for PR create: `POST /api/v1/repos/{owner}/{repo}/pulls`" but does not pre-document the required JSON body fields (`title`, `body`, `head`, `base`). Implementer must discover these at dispatch time.
- Idempotency check: plan says "call `GET /repos/{owner}/{repo}/pulls?state=open&head={branch}`" but does not specify how to handle the case where the branch exists but no PR is open (branch was pushed but PR-open failed on a prior retry). Does the script re-open the PR or fail silently?
- `yadgar/tests/test_cross_repo_pr.py` test structure: plan gives 3 test cases but no fixture setup (what does the mock Forgejo API look like? `pytest-httpx`? `responses` lib? `unittest.mock`?).

### P9 — Rollback path

**Status: Present.**

No rollback needed — correct rationale. Manual fallback command documented. Adequate for the scope.

### P10 — Dependency pinning

**Status: Present.**

"CI workflow uses `curl` (system-provided) + Forgejo REST API — no new PyPI/npm deps." Correct. If a Forgejo Actions action is used, pin to SHA (noted as requirement for Step 0). The plan correctly defers the pin until Step 0 confirms whether an action is needed. Adequate.

### P11 — Agent dispatch budget

**Status: N/A.** Correctly noted as N/A.

---

### v5.45.x consistency findings — v5.46.1

- No `yadgar install` references. Clean.
- No `scripts/setup.sh` references. Clean.
- No `check_docker` references. Clean.
- Non-goal line 31: "No GitHub/other-host support — Forgejo API only (Codeberg)." Explicit and correct. The caller's question ("codeberg-only or include GitHub?") is answered: Codeberg/Forgejo only.
- The plan notes it depends on v5.46.0's `homebrew-yadgar` tap repo being created + formula template being ready. This is correct sequencing.
- v5.45.1 macOS launchd: not referenced in v5.46.1, which is appropriate — v5.46.1 is CI workflow only.

---

### Open DPs — v5.46.1

| DP | Status |
|---|---|
| DP-A verifying host (was v5.45.1) | N/A — v5.46.1 is CI-only |
| Token-scope confirmation (Precedent 2) | Blocking (per Step 0) — must verify token cannot push to `main` of tap repo |
| Forgejo Actions action SHA pin | Blocking (per Step 0) — resolve before dispatch |
| Idempotency retry case (branch pushed, no PR) | Should clarify but not critical |

#### Moot DPs

None. Plan was drafted 2026-06-04, consistent with shipped state.

---

### Stale references found in v5.46.1

None. The plan is clean.

---

### Cross-plan coordination — v5.46.1

| Pair | Status | Notes |
|---|---|---|
| v5.46.1 ↔ v5.46.0 | Partial gap | v5.46.1 correctly says v5.46.0 must ship stubs. v5.46.0 plan does not agree. Needs reconciliation on the v5.46.0 side. |
| v5.46.1 ↔ v5.47.0 | OK | v5.47.0 releases API format is downstream of v5.46.0 not v5.46.1. No conflict. |

---

### Brutal honesty critique — v5.46.1

The v5.46.1 plan is structurally sound. It has all P1-P11 sections (except the non-applicable ones), a clear idempotency design, good security precedents, and a realistic effort estimate. The split rationale from v5.46.0 is documented and correct: cross-repo PATs have a different security surface that deserves its own dispatch.

The main weakness is P8: the plan tells the implementer WHAT to build but not HOW to build the shell scripts. No skeleton for `open_brew_pr.sh` is provided, and the Forgejo API body fields are not pre-documented. This is remediable with one day of pre-dispatch research (Step 0 covers most of it) but leaves implementer discovery work that could have been eliminated.

The second weakness is the dependency on v5.46.0's stub coordination — a dependency the plan correctly documents but cannot fix unilaterally. If v5.46.0 ships the jobs as full implementations (as its plan currently describes), v5.46.1 has nothing to do. This must be reconciled at the v5.46.0 level before v5.46.1 dispatch.

**Ship-readiness: 3/5.** Clean, honest, narrow scope. Blocked only by v5.46.0 stub coordination + P8 script skeleton gap.

---

## Cross-cutting recommendations

1. **Coordination meeting between v5.46.0 and v5.46.1 plans.** The stub-vs-full-implementation conflict on `open-brew-pr` + `open-nix-pr` must be resolved before either plan is dispatched. Options: (a) fold v5.46.1 into v5.46.0 (single dispatch); (b) v5.46.0 explicitly stubs the jobs and v5.46.1 fills them — update v5.46.0 Step 7 to say "stub only."

2. **P1-P11 template adoption.** v5.46.0 predates the planning invariants codification (which happened 2026-06-04, same day as the macOS launchd ship). Before dispatch, v5.46.0 needs retrospective P1-P11 sections added. v5.46.1 is already compliant.

3. **NEW DP-A must be documented in `docs/DECISIONS.md`.** The non-repo-install post-setup UX gap is a real architectural decision that affects v5.46.0, v5.62.0 (Typer CLI), and the `yadgar setup` CLI building block. It should not be left in a plan-file comment — it belongs in DECISIONS.md as an OPEN-QUESTION with resolution path.

4. **License classifier mismatch** (pyproject.toml line 28: `MIT License` vs `license = "Apache-2.0"`): this is confirmed present in the repo right now and is a PyPI correctness issue independent of v5.46.0 dispatch. It can be fixed as a standalone commit before or with v5.46.0 Step 2.

5. **`install_assets/` wheel packaging status.** Both plans should document that `pyproject.toml:82-84` already ships `install_assets/` in the wheel. The v5.46.0 Step 6 should be revised to "verify coverage" rather than "add packaging."

---

## Required pre-dispatch remediation list

1. **[CRITICAL, v5.46.0] Resolve NEW DP-A — non-repo install post-setup UX.** Decide what `brew install yadgar` users run after install. Record decision in `docs/DECISIONS.md`. Rewrite Homebrew formula `post_install` block (lines 133-136) and `docs/INSTALL.md` plan (lines 86, 308) to match.

2. **[CRITICAL, v5.46.0 + v5.46.1] Reconcile stub coordination.** v5.46.0 Step 7 must be updated: `open-brew-pr` + `open-nix-pr` are either (a) stubs with `if: false` gate in v5.46.0, filled by v5.46.1; or (b) full jobs in v5.46.0, making v5.46.1 a no-op. Pick one, update both plan docs.

3. **[BLOCKING, v5.46.0] Add P1-P11 sections.** Minimum: P2 (I25 change for `bump_version.py` adding a 4th sync target), P6 (stub coordination), P7 (post-ship verification probes), P10 (pin `cyclonedx-py`, document nixpkgs channel rationale).

4. **[BLOCKING, v5.46.0] Add v5.45.1 cross-reference.** Document that macOS launchd (v5.45.1, paper-only) must be runtime-verified before the Homebrew formula `post_install` can trigger daemon setup on macOS. Add as a prerequisite condition in the Dependencies section.

5. **[BLOCKING, v5.46.0] Update Step 6 (wheel packaging).** `install_assets/` is already wheel-packaged (v5.45.0, `pyproject.toml:82-84`). Step 6 should be "verify existing packaging covers new systemd/launchd template additions" not "add packaging."

6. **[P8, v5.46.1] Add script skeleton for `open_brew_pr.sh`.** Document the Forgejo API body fields for PR creation. Document the idempotency check implementation (exact `GET` query + response parsing). This resolves the primary P8 gap in v5.46.1.

7. **[INFORMATIONAL, v5.46.0] License classifier fix.** `pyproject.toml:28` has `"License :: OSI Approved :: MIT License"` but `license = "Apache-2.0"`. Fix in standalone commit or v5.46.0 Step 2. Does not block dispatch but is a PyPI correctness issue.

8. **[INFORMATIONAL, v5.46.0] v5.62.0 coordination.** If DP-A is resolved by expanding `yadgar setup` CLI, verify that the resulting subcommand design is compatible with v5.62.0's Typer wrapper scope (63 subcommands 1:1 with MCP tools). The `yadgar setup` orchestration CLI is not a 1:1 MCP tool mirror — its placement in the v5.62.0 command tree needs explicit decision.
