From 44b495dfed0d1b4c02fc9c84e25d8532caaf9449 Mon Sep 17 00:00:00 2001 From: "claude@clouddev1" Date: Thu, 25 Jun 2026 14:38:58 +0000 Subject: [PATCH] docs: handoff-80 + docs direct-push carve-out (ADR-0059 Amendment 1) Session handoff covering the clause-concept-hints feature (ADR-0058, #42) and the working-method establishment (ADR-0059, #41; fixes #43/#44). Records the docs direct-push carve-out: handoff/session docs and small docs amendments are owner-direct-pushed to main, because a docs-only PR posts no ci/gate run (paths-ignored) and stalls on the required check. Amends CLAUDE.md, ADR-0059 (Amendment 1), and its README index row. --- CLAUDE.md | 8 ++ docs/adr/0059-dev-workflow.md | 23 +++++ docs/adr/README.md | 2 +- docs/handoff/20260625-handoff-80.md | 144 ++++++++++++++++++++++++++++ 4 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 docs/handoff/20260625-handoff-80.md diff --git a/CLAUDE.md b/CLAUDE.md index de9c4c0..ac33d71 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -303,6 +303,14 @@ operational rules an agent must follow: or merge. - **Paste the `/runda` / DA review into the PR** so the public repo carries the audit trail. +- **Handoff / session docs are owner-direct-pushed to `main`, not PR'd** (a + deliberate extension of the reservation-ledger carve-out). Reason: a + docs-only change is `paths-ignore`d by `ci.yaml`, so it posts no `ci / gate` + run — and branch protection *requires* `ci / gate*`, so a docs-only PR + stalls forever on a required check that never arrives. Direct-push (owner + is whitelisted, docs paths burn no CI) sidesteps that. The same applies to + small docs amendments like this one. If docs-via-PR is ever wanted, first + add a "skipped → success" gate shim (or drop the docs paths-ignore). ## Issue tracking — Gitea via `tea` diff --git a/docs/adr/0059-dev-workflow.md b/docs/adr/0059-dev-workflow.md index de02db7..20507ee 100644 --- a/docs/adr/0059-dev-workflow.md +++ b/docs/adr/0059-dev-workflow.md @@ -190,3 +190,26 @@ test the script but not run its pushing path. - **Automating PR creation/merge** — humans push and merge (D6). - **A CONTRIBUTING-side description of the reserve lock** — it's maintainer infrastructure, not contributor guidance (kept here instead). + +## Amendment 1 (2026-06-25): docs direct-push carve-out + +Extends the D5 owner-whitelist: **handoff / session docs (and small docs +amendments like this one) are owner-direct-pushed to `main`, not PR'd.** + +Discovered while preparing the first handoff under this flow: a **docs-only +PR cannot merge** under the protection rules. `ci.yaml` `paths-ignore`s +`docs/**` and `**/*.md`, so a docs-only change posts **no `ci / gate` run**; +but D5 requires `ci / gate*` before merge — so the required check never +arrives and the PR stalls on "expected/waiting". Rather than weaken the gate +or add CI machinery, this trivial low-risk class (handoffs, session notes, +small docs fixes) rides the existing owner-direct-push carve-out: the owner +is already whitelisted, and a docs-only push to `main` is itself +`paths-ignore`d, so it burns no CI. + +Substantive changes — code, and the ADRs/docs that accompany code — still go +through a PR as normal (their non-docs files trigger the gate). **If +docs-via-PR is ever wanted** (e.g. a docs-only ADR through review), the clean +fix is a "skipped → success" gate shim (a job that reports `ci / gate` +success when the real gate is path-skipped) or dropping the docs +`paths-ignore`; until then, direct-push is the sanctioned path for docs-only +changes. diff --git a/docs/adr/README.md b/docs/adr/README.md index 4ad1479..505981c 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -71,4 +71,4 @@ This directory contains the project's ADRs, recorded per - [ADR-0056 — crates.io publish-readiness + `cargo binstall` metadata (D3)](0056-crates-io-and-cargo-binstall.md) — **Prepared 2026-06-17** (plan step 3a; tracked by plan + ADR). Makes the crate **ready to publish** to crates.io (user decision) and adds `cargo-binstall` metadata; the actual `cargo publish` is a **gated, irreversible maintainer step**. Manifest: drops `publish = false`; adds `homepage` (relplay.org), `keywords`, `categories`, and an `exclude` (`/website`,`/docs`,`/.gitea`,`/.codegraph`) trimming the crate from 585 files/8.3 MiB → **353/913 KiB compressed** (code-only). Authors **`README.md`** (engine-neutral, simple/advanced-mode wording; install via curl|sh/binstall/source/prebuilt) and **`LICENSE-MIT`** (© Lazy Evaluation Ltd — *confirm holder*); the canonical **`LICENSE-APACHE`** is deferred to the maintainer (don't ship retyped legal text) — the SPDX `license` field already satisfies crates.io. **binstall** (syntax verified vs cargo-binstall SUPPORT.md): `pkg-fmt = "bin"` (bare binaries), `pkg-url` spelled `v{ version }` (the placeholder omits the `v`), plus per-target **`overrides`** mapping the common host triples to the assets we ship — `*-linux-gnu` → the static `*-linux-musl` build, `*-pc-windows-msvc` → `*-gnu`/`-gnullvm` `.exe` (macOS matches directly; the docs promise no automatic fallback). **Ordering:** publish at a **new tagged version whose release exists**, after the release — **not `0.1.0`** (diverges from the already-released 0.1.0 binaries that predate `--version`). Verified: `cargo publish --dry-run` packages + verify-builds; `cargo metadata` confirms the binstall block + 4 overrides. **Unverified:** a real `cargo binstall` run (not a dep; nothing on crates.io yet) — validate at first publish. Rejected: cargo-dist (GitHub-centric). Maintainer follow-ups: confirm © holder, add canonical `LICENSE-APACHE`, real binstall validation. **Amendment 1 (2026-06-18):** `0.2.0` **published live** (crates.io; `cargo install` + `cargo binstall` verified — the unverified-overrides caveat is resolved), via a new **manual `workflow_dispatch`** workflow `.gitea/workflows/publish.yaml` (mirrors `release-macos.yaml`; `tag` input; `cargo publish` with a crate-scoped `CARGO_REGISTRY_TOKEN` secret). Publish stays **manual** by decision — irreversible (keeps the token off every tag push), the split release (tag Linux/Windows + dispatched macOS) makes a human the "all assets up" gate, and crates.io has no Gitea-Actions trusted-publishing path. Each registry is its **own idempotent job** (crates.io job no-ops if the version exists) so Scoop/Homebrew/winget can be added as sibling jobs without interfering. **Amendment 2 (2026-06-19):** **Scoop + Homebrew wired** (D3 §3b/§3c) as sibling `publish.yaml` jobs (`scoop-bucket`, `homebrew-tap`) that render manifests from the release `.sha256` sidecars and push to **org-level, multi-package** repos `lazyeval/scoop-bucket` + `lazyeval/homebrew-tap`. Credential: a scoped bot user **`lazyeval-ci`** (Gitea PATs scope by permission-category, not per-repo, so an `oli` token would over-reach to the main repo) on a `lazyeval` org team with Write to the package repos only; its PAT is the `LAZYEVAL_PKG_TOKEN` secret on `oli/rdbms-playground`. Render scripts (`scripts/render-{scoop-manifest,homebrew-formula}.sh`) are **dependency-free bash** (CI image `node:22-slim` has no jq/ruby), tested by `scripts/test-package-renders.sh`. Scoop: `#/`-rename fragment + `checkver`, no `autoupdate`. Homebrew: `on_macos`/`on_linux`×arch bare-binary formula, no Windows. **Unverified:** real `scoop`/`brew install`, the `HEAD:main` branch assumption, macOS Gatekeeper-via-brew (ad-hoc sign). **Remaining D3:** winget. **Amendment 3 (2026-06-19):** **Scoop + Homebrew validated end-to-end** on real Windows + macOS (install + run). Found + fixed a **presigned-URL/HEAD gotcha**: Gitea (≥1.25) 303-redirects release downloads to a **method-bound SigV4 presigned S3 URL**; Homebrew resolves via HEAD, captures the HEAD-signed URL, then GETs it → 403 (GET-only tools unaffected). Fix is a **server-side Caddy rule** (lives in the Gitea edge config, NOT this repo — record it: lost on a rebuild → brew 403s again) answering HEAD on `…/releases/download/…` directly (200, no redirect) so brew's download GET re-runs the redirect fresh. ad-hoc mac signature **runs** via brew; Developer-ID + notarization still parked on the Apple org conversion. **Remaining D3:** winget only. **Amendment 4 (2026-06-20):** **winget wired** (D3 §3d) — the 4th `publish.yaml` sibling job opens a PR to the central, human-gated `microsoft/winget-pkgs` via **komac** (pinned 2.16.0; `LazyEvaluation.RdbmsPlayground`, `portable`, x64+arm64). Async + Microsoft-validated, unlike the bucket/tap. Auth: a **classic `public_repo` PAT** (fine-grained can't open the cross-fork PR, komac #310) on a **dedicated GitHub bot** → `WINGET_GITHUB_TOKEN`, job-scoped, passed via curl config file (not argv). Idempotent via **two guards** (already-merged version + already-open PR) so re-dispatch is safe. Unsigned is fine to submit (portable; only MSIX needs signing) — may earn an AV/SmartScreen manual-review label first time. **One-time `komac new` bootstrap is manual** (interactive); CI `komac update` handles releases after. Completes the D3 package-manager set. - [ADR-0057 — Non-functional-requirement verification strategy](0057-nfr-verification-strategy.md) — **Accepted 2026-06-22.** How NFR-1..7 are verified now that public binaries ship. **Gated:** NFR-5/NFR-7 colour contrast — `src/theme.rs` unit tests assert every text foreground clears **WCAG-AA 4.5:1** on both themes, the advanced-mode border clears the **3:1** UI bar (plain border decorative-exempt, documented), and every syntax-token pair clears **CIEDE2000 ΔE2000 ≥ 15** (metric reference-validated). Writing these **caught two shipped light-theme defects** (`tok_string` 4.42:1, `tok_flag` 3.15:1) + two near-duplicate dark pairs — all fixed (`65eab71`); dev tool `scripts/palette-preview.py`. **Measured, generously bounded:** NFR-1 startup + NFR-3 idle RSS via the Tier-4 PTY harness (debug-binary gross-regression bounds, not a tight gate per user decision); recorded **release** figures — startup **~29 ms** (< 500 ms), idle RSS **~10 MB** (< 50 MB). **By argument:** NFR-2 off-thread responsiveness (worker thread ADR-0010 + separate input task). **Reviewer note:** NFR-4 distinctive design, NFR-6 cross-platform parity (CI matrix: Linux+macOS execute, Windows build-only; one documented divergence — true-colour quantisation on non-`Tc` terminals). Latent finding **issue #39** (fast DDL→insert vs stale schema cache) deferred. - [ADR-0058 — Clause-concept hints (`hint.concept.*` surfaced by cursor position)](0058-clause-concept-hints.md) — **Accepted + implemented 2026-06-23 (issue #37).** The deferred ADR-0053 extension: a third tier-3 surface, deeper than the per-form `hint.cmd.*` block but narrower than it, shown by **F1** when the cursor sits **inside a recognized clause** — referential actions (`on delete`/`on update`), `1:n`/`m:n` cardinality, primary key, unique, check, foreign key (seven topics). Layered **on top of** the per-form block (an "About this clause" sub-block), never replacing it. **Mechanism:** a new transparent `Node::Concept { topic, inner }` grammar wrapper records the clause's byte-span into `WalkContext::concept_spans` (append-only, **survives the clause being fully matched** — unlike `pending_hint_mode`, which clears on match, giving only slot-boundary awareness); `concept_topic_at_cursor` walks the full buffer and returns the **innermost** span containing the cursor (so a cursor on `on delete` inside a `references … on delete` resolves to the narrower `referential_actions`). No use of the dormant `WalkBound::Position`. **Two user forks:** detection is "anywhere inside the clause" (not just the slot boundary), and **all four clause families** ship in v1. **Mode-keyed examples** (`example.simple`/`example.advanced`) honour ADR-0053 D6's mode-correct-example rule for the topics reachable in both modes (referential actions, primary key, unique, check); `emit_tier3_block` picks by live mode. `/runda` caught two design gaps before build (the clause map missed the simple-mode constraint suffix; the single-`example` model collided with D6) — both fixed. **Comprehensiveness gate:** a recursive `Node::Concept` visitor cross-checks grammar wrappers ↔ `CONCEPT_TOPICS` ↔ catalogue blocks. 21 new tests (14 resolver, 3 gates, 3 F1 integration, 1 snapshot); suite green all tiers, `fmt`/`clippy` clean. First ADR numbered **reserve-first** (stable from creation; ADR-0059). -- [ADR-0059 — Branch-and-PR working method: worktrees, merge commits, reserve-first ADR numbering](0059-dev-workflow.md) — **Accepted 2026-06-23.** The trackable working method for the now-public repo. **PRs onto a protected `main`** (always-green; no direct pushes bar one carve-out), one logical change per branch, conventional branch/commit prefixes, the `/runda` review pasted into the PR. **One worktree per branch** (`-worktree-`, the existing convention) — never switch the primary checkout — via `scripts/wt-new.sh` / `wt-rm.sh` (the latter removes only the *named* worktree; no merged-detection sweep — long-lived branches like `website`/`ci` are merged into main too and must never be auto-removed). **Merge commits (`--no-ff`)**, never rebase/squash (the only strategy consistent with append-only history). **Reserve-first ADR numbering** (`scripts/adr-reserve.sh`): the fix for the real collision problem — a contiguous integer needs an allocator, plain git branches have none, so **`main` is the registry and an atomic `git push` is the lock** (CAS, retried on contention) recorded in an append-only ledger `docs/adr/RESERVATIONS.log`; the number is **stable from creation** (safe in immutable commit messages + cross-refs from commit #1), which `number-on-merge` is not. Supersedes ADR-0000's placeholder-until-merge default; subproject namespaces (`ADR-website/ci-NNN`) unchanged. **Branch protection:** require PR + the `ci / gate*` check + up-to-date-before-merge, with the **owner whitelisted for direct push** (the sole sanctioned direct commit — the reservation ledger line). **Push/merge stay human steps**; agents prepare but never push. Forks user-chosen: merge-commit; strict-PR; protection enforced; reserve-first integers (vs number-on-merge / issue-number ids / allocator bot); worktrees prescribed. Scripts ship with local-`origin` test harnesses (reserve 10/10, worktrees 15/15, all shellcheck-clean). First two reserve-first numbers: ADR-0058 + this one. (`wt-clean` auto-sweep → explicit `wt-rm ` shortly after, on review — see the fix PR.) +- [ADR-0059 — Branch-and-PR working method: worktrees, merge commits, reserve-first ADR numbering](0059-dev-workflow.md) — **Accepted 2026-06-23.** The trackable working method for the now-public repo. **PRs onto a protected `main`** (always-green; no direct pushes bar one carve-out), one logical change per branch, conventional branch/commit prefixes, the `/runda` review pasted into the PR. **One worktree per branch** (`-worktree-`, the existing convention) — never switch the primary checkout — via `scripts/wt-new.sh` / `wt-rm.sh` (the latter removes only the *named* worktree; no merged-detection sweep — long-lived branches like `website`/`ci` are merged into main too and must never be auto-removed). **Merge commits (`--no-ff`)**, never rebase/squash (the only strategy consistent with append-only history). **Reserve-first ADR numbering** (`scripts/adr-reserve.sh`): the fix for the real collision problem — a contiguous integer needs an allocator, plain git branches have none, so **`main` is the registry and an atomic `git push` is the lock** (CAS, retried on contention) recorded in an append-only ledger `docs/adr/RESERVATIONS.log`; the number is **stable from creation** (safe in immutable commit messages + cross-refs from commit #1), which `number-on-merge` is not. Supersedes ADR-0000's placeholder-until-merge default; subproject namespaces (`ADR-website/ci-NNN`) unchanged. **Branch protection:** require PR + the `ci / gate*` check + up-to-date-before-merge, with the **owner whitelisted for direct push** (the sole sanctioned direct commit — the reservation ledger line). **Push/merge stay human steps**; agents prepare but never push. Forks user-chosen: merge-commit; strict-PR; protection enforced; reserve-first integers (vs number-on-merge / issue-number ids / allocator bot); worktrees prescribed. Scripts ship with local-`origin` test harnesses (reserve 10/10, worktrees 15/15, all shellcheck-clean). First two reserve-first numbers: ADR-0058 + this one. (`wt-clean` auto-sweep → explicit `wt-rm ` shortly after, on review — see the fix PR.) **Amendment 1 (2026-06-25):** docs direct-push carve-out — handoff/session docs (and small docs amendments) are owner-direct-pushed, not PR'd, because a docs-only PR posts no `ci / gate` run (paths-ignored) and so stalls on the required check. diff --git a/docs/handoff/20260625-handoff-80.md b/docs/handoff/20260625-handoff-80.md new file mode 100644 index 0000000..edca3e0 --- /dev/null +++ b/docs/handoff/20260625-handoff-80.md @@ -0,0 +1,144 @@ +# Session handoff — 2026-06-25 (80) + +A long session. It began as the next open-issue item — **#37, clause-concept +hints** — but the act of cutting a branch for it surfaced that this +now-public repo had **no written, trackable working method**. So the bulk of +the session became establishing one (**ADR-0059**) and hardening it through +real use, with two follow-up fixes the dogfooding turned up. Both arcs are +fully merged; the tree is clean. + +## §1. State + +**Branch `main` at `78272e2`.** Everything below is merged; **no open PRs**; +worktrees are just the primary (`main`) + the long-lived `website`. All +feature/fix worktrees were cleaned up with `wt-rm`. + +**Suite green at #37's merge:** **1831 lib + 8 e2e_pty + 503 it + 200 typing +(2542 total), 0 failed, 1 ignored**; `fmt --check` + `clippy -D warnings` +clean (via `nix develop -c`). The new workflow scripts carry their own +local-`origin` harnesses: `test-adr-reserve.sh` **10/10**, `test-wt.sh` +**16/16**, all `shellcheck`-clean. + +**Issues:** closed this session — **#37** (done, ADR-0058) and **#38** +(won't-do, see §4). Still open — **#40** (winget release notes, deferred to +next release; see §4). (#36/#39 were closed in earlier sessions.) + +## §2. What shipped — #37 clause-concept hints (ADR-0058, merged #42) + +The deferred ADR-0053 extension: a tier-3 **`hint.concept.*`** layer shown by +**F1** when the cursor sits **inside a recognized clause**, layered under the +per-form `hint.cmd.*` block. Seven topics — referential actions, `1:n`/`m:n` +cardinality, primary key, unique, check, foreign key. + +- **Mechanism:** a new transparent `Node::Concept { topic, inner }` grammar + wrapper records the clause's byte span into `WalkContext::concept_spans` + (**append-only — survives the clause being fully matched**, unlike + `pending_hint_mode` which clears on match and so only knows the slot + boundary). `concept_topic_at_cursor` walks the full buffer and returns the + **innermost** containing span. No use of the dormant `WalkBound::Position`. +- **Two user forks:** detection = "anywhere inside the clause"; **all four + clause families** in v1. **Mode-keyed examples** (`example.simple` / + `example.advanced`) honour ADR-0053 D6 for topics reachable in both modes; + `emit_tier3_block` picks by live mode. +- **`/runda` caught two design gaps before any code** (clause map missed the + simple-mode constraint suffix; single-`example` model collided with D6) — + both fixed. **Comprehensiveness gate**: a recursive `Node::Concept` visitor + cross-checks grammar wrappers ↔ `CONCEPT_TOPICS` ↔ catalogue blocks. +- 21 new tests (14 resolver, 3 gates, 3 F1 integration, 1 snapshot). + +## §3. The working method (ADR-0059, merged #41; fixes #43, #44) + +The session's main artifact — the trackable flow for the public repo: + +- **PRs onto a protected `main`** (always-green; one direct-push carve-out, + §4), one logical change per branch, conventional prefixes, the `/runda`/DA + review pasted into each PR. **Merge commits (`--no-ff`)**; never + rebase/squash (append-only). +- **One worktree per branch** (`-worktree-`) — never switch the + primary checkout. `scripts/wt-new.sh ` (off `origin/main`, + `--no-track`) / `scripts/wt-rm.sh ` (removes only the **named** + worktree). +- **Reserve-first ADR numbering** — `scripts/adr-reserve.sh `. The fix + for the real collision problem: a contiguous integer needs an allocator and + plain git branches have none, so **`main` is the registry and an atomic + `git push` is the lock** (compare-and-swap, retried on contention), + recorded in the append-only ledger **`docs/adr/RESERVATIONS.log`**. The + number is **stable from creation** (safe in immutable commit messages + + cross-refs). Supersedes ADR-0000's placeholder-until-merge default; + subproject namespaces (`ADR-website/ci-NNN`) unchanged. +- **Branch protection** (you applied in Gitea): require PR + the `ci / gate*` + check + up-to-date-before-merge; **owner whitelisted for direct push** (the + reservation ledger line, now also handoff/session docs — §4). +- **Fixes found by dogfooding:** + - **#43** — `wt-clean` (auto-sweep of all merged worktrees) → explicit + **`wt-rm `**. The auto-sweep would have deleted long-lived + branches (`website`, `ci`) since they're merged into `main` too. Also + **`wt-new --no-track`**: branching off `origin/main` had set the new + branch's upstream to `origin/main`, so a bare `git push` errored on a + name-mismatch and suggested the dangerous `HEAD:main`. + - **#44** — CI **dedupe**: `push: branches: [main]` (was `['**']`) so a + push to a PR'd branch no longer runs the gate twice. On **Gitea** the + `push` and `pull_request` runs were byte-identical — Gitea has **no + merge-preview ref**; its `pull_request` checks out `refs/pull/N/head`, the + same commit a branch push would (`docs.gitea.com/usage/actions/faq`). + Keeping the gate on `pull_request` is forward-compatible: if Gitea ever + adds the merge ref, the runs upgrade to testing the merged result for free. + +## §4. Decisions + +- **#38 closed — won't build** the pre-submit-diagnostic tier-3 route. The + ADR-0053 D6 deferral reasons still hold: `Diagnostic` carries no class key + (a class field would have to thread through every diagnostic-creation + site — broad change) for marginal value (tier-2 already surfaces + diagnostics live; many classes duplicate the runtime-error/clause-concept + tiers). Reconsider only if a diagnostic class has genuinely unique teaching + value. Rationale recorded on the issue. +- **#40 deferred** (open): wire `CHANGELOG` into komac's winget + `--release-notes-url`. Best coupled to the **next `v*` release + first real + winget *update* test** — the initial winget PR to `microsoft/winget-pkgs` + is still unconfirmed after several days, so end-to-end validation needs a + confirmed package first. +- **Docs direct-push carve-out** (this handoff is the first to use it): + handoff / session docs (and the reservation ledger) are **owner + direct-pushed to `main`**, not PR'd. See §5 for *why* a PR doesn't work. + +## §5. Process lessons (now in ADR-0059 / CLAUDE.md) + +- **Update a branch in ONE lane** — locally (`git fetch && git merge + origin/main`), **not** the Gitea "Update branch" button when a conflict is + possible. The button silently mis-resolved the README clash on #42 + (dropped the `0059` index row) and, combined with a local merge, diverged + the PR branch; healed with an append-only merge (no force-push). +- **Primary checkout rests on `main`; feature work in worktrees.** Mid-session + the primary was stuck on `feat` (bootstrap artifact), which is what made + worktree cleanup awkward — there was no `main` checkout holding the + scripts. Resolved by switching the primary to `main` and moving `feat` to a + worktree. +- **Docs-only PRs are blocked by the required gate.** `paths-ignore` + (`docs/**`, `**/*.md`) means a docs-only change posts **no `ci / gate` + run**, and branch protection requires `ci / gate*` — so the required check + never arrives and the PR is stuck "expected/waiting." That is the concrete + reason handoff/session docs are direct-pushed (§4). If docs-via-PR is ever + wanted, add a "skipped → success" gate shim (or drop the paths-ignore). +- **Gitea CI specifics worth remembering:** no merge-preview ref (above); the + reserve script's CAS via atomic push; `--no-track` on branch creation to + avoid the inherited-`origin/main` upstream. + +## §6. Next + +- **Next session is free to pick a feature** — no specific item is queued; + consult `docs/requirements.md` for the remaining backlog (e.g. **TT4 / + Tier-4-in-CI** still not wired; **D3 packaging** — winget pending + confirmation; the larger deferred UX items: tutorial system, session-log + + markdown export V4, multi-line input I1, ER-diagram export V3). +- **#40** when the next release happens (with the first winget update test). +- **Use the new flow:** `wt-new` to start a branch, `adr-reserve` the moment + an ADR is needed, PR onto `main`, `wt-rm` when done. Push/merge stay your + steps; agents prepare but never push. + +## §7. Process pins + +- Commits user-confirmed, no AI attribution, append-only. **Push/merge are + the user's steps.** This handoff + the §4 carve-out doc amendments are + direct-pushed to `main` by the owner (docs-only, paths-ignored, + owner-whitelisted).