Artifact 9fa561b89d20b3b1fc102cdad2dfb351ef30e178a291492a2a59b38933f6afa1:
- File
docs/RELEASE-0.1.0-PLAN.md
— part of check-in
[122998a428]
at
2026-07-18 20:12:07
on branch release-0.1
— Add BSD-2-Clause LICENSE, ship it in .paths, drop scratch file, ignore the pattern
A release without a license grants nobody any rights, so this is the legally gating step of the 0.1.0 sequence. zit is an independent reimplementation from the Fossil RFCs rather than a derivation of Fossil source, so the choice was open; BSD-2-Clause matches the Fossil heritage and the systems-Zig ecosystem.
What changed:
- LICENSE at the repo root, BSD 2-Clause, copyright Daniel Mestas 2026. - build.zig.zon .paths now names LICENSE, so the file actually ships inside a fetched package instead of only existing in the checkout. - The leftover commit-description-413190fb92be991f.txt scratch file is gone and .fossil-settings/ignore-glob carries commit-description-* so the class of file cannot drift back in. - src/packaging_test.zig pins the above as executable facts: LICENSE content, LICENSE named inside the manifest's brace-matched .paths block, a line-anchored ignore-glob pin, and a negative-space pin asserting every repo-root path build.zig embeds is also named in .paths. These acceptance criteria are file-structure facts, which rot silently because nothing executes them; the battery alone cannot catch a .paths regression. - build.zig grows build_unit_test_module: the pinned repository files attach as anonymous imports to a test-only compile of root.zig, never to the exported zit module. Attaching them to zit made every consumer's build depend on files outside .paths and a fetched package failed on a missing .fossil-settings/ignore-glob before compiling a line. The negative-space pin exists to catch exactly that recurrence. - docs/RELEASE-0.1.0-PLAN.md, the plan of record for the 0.1.0 release, is committed alongside the first step it describes.
Test evidence: zig build and zig build test green in the working checkout. This commit is additionally gated on a clean-checkout proof — fossil open into a fresh temp directory, then zig build and zig build test there — which is the check that catches a file referenced but never added.
No borrowed techniques in this change, so no attribution is owed. (user: dmestas, size: 25969) [annotate] [blame] [check-ins using]
zit 0.1.0 — Release Plan
STATUS: FINAL (armed — the release workflow may run. The
workflow preflight refuses to run against a DRAFT plan. Flipping to FINAL also
ratifies the two decisions embedded here: the BSD-2-Clause license choice and
the creation of a private GitHub mirror named zit for CI. (Operator
decision, 2026-07-18: BSD-2-Clause confirmed; the mirror is PRIVATE —
publishing the repository publicly is a separate, later, explicitly-operator-
gated decision. Nothing in this plan may make the code public.)
Source of truth for findings: docs/PRE-RELEASE-READINESS.md (F1–F7, S1–S7,
N1–N4). Executor: /Users/dmestas/zit-plans/release-0.1.0/release.workflow.js.
0. Release thesis
Ship 0.1.0 as a library-first release with an honest-caveats CLI in
roughly one focused week. Do not hold for fossil parity. The claim we release
on: an independent, conformance-checked implementation of the four Fossil
RFCs with an embeddable Zig API — carried by the smoke step running in CI
against the real fossil binary. Seven blockers stand between here and that
tag; nothing else does. The main.zig split is explicitly not on the
path (post-release, N1) — the architecture is otherwise genuinely
deep-module and a pre-release reorg buys users nothing and invites merge
churn against concurrent sessions.
One framing correction carried into this plan: zit status not reporting
edited files is a documented, deliberate deferral ("honestly deferred to
commit/diff (B-status-16), stated in --help", main.zig:1080-1086) —
not a silent lie. It stays a blocker because users don't read --help before
running status, but it is a UX/completeness gap, and the fix is framed as
completing the verb, not correcting dishonesty.
1. What "0.1.0 released" concretely means
All of the following, in this order of finality:
- All seven blockers (F1–F7) closed on the
release-0.1branch, each with its required tests/fuzz/e2e in tree. - Full local battery green on the converged branch:
zig fmt --check .·zig build·zig build test·zig build e2e·zig build dst·zig build smoke. release-0.1merged to trunk; CI green on the mirror for the merge commit.build.zig.zonversion0.0.0→0.1.0;LICENSEpresent and listed in.paths.README.mdcarries an honest caveats table (see §3, P5b).docs/RELEASE-NOTES-0.1.0.md: what it is, what's proven (incl. the exactfossilversion smoke passed against — S7), what's deliberately NOT done.- Tag
v0.1.0on the trunk merge commit (fossil tag + git tag on the mirror), release notes written todocs/RELEASE-NOTES-0.1.0.mdand attached to a release on the private mirror. NOTE: "released" here means tagged + noted on the private mirror — NOT a public announcement. Going public is a separate operator decision, deliberately out of scope. - Cleanup: release worktrees removed, scratch files gone, mirror in sync.
The definition-of-done checklist in §8 is the mechanical form of this list.
2. Phase plan and ordering rationale
P1 License & hygiene (hours)
└► P2 CI bootstrap (~1 day)
├────────────► P3 CLI cliffs ┐ three parallel worktrees:
│ F3 clone→open (1–2d) │ F3 ∥ F4 ∥ F5
│ F4 add/rm rec. (~1d) │
│ F5 status edits (½–1d)┘
└────────────► P4 Fuzz hardening ─ one worktree, F6 → F7 serialized
F6 transport/serve (~1d), F7 merge3 (½d)
P3 + P4 both complete ─► P5 Release surface (help audit → docs/version)
└► P6 Converge & ship
Why this order:
- P1 first — LICENSE is minutes of work, legally gating (a release with no license grants nobody any rights), and has zero conflict surface. It also carries the trivial hygiene item S6 and commits this plan document.
- P2 second, before any code fix — CI is the multiplier: once the mirror
pipeline runs
test+e2e+dst+smoke, every subsequent fix lands with an automated gate, and the smoke conformance claim becomes continuously enforced rather than milestone-manual. Bootstrap subtlety: P1 and P2 themselves have no CI to gate on — the local verify battery is the gate for them; from P3 onward every commit additionally gates on mirror CI. (An aggressive schedule could overlap P2 with P3/P4; we deliberately serialize — it costs at most a day and buys the CI gate for every code fix.) - P3 ∥ P4 fan-out — the three CLI cliffs and the two fuzz targets are
mutually independent. P4 touches only
fuzz_tests.zig+ new*_fuzzfiles +build.zig(disjoint frommain.zig), so it runs fully parallel to P3. Within P3, F3/F4/F5 touch distinct regions ofmain.zig(~:2537+, ~:452/:679, ~:1080-1160) plus per-verb spots incli.zigande2e.zig— line-based fossil merges converge cleanly; each trackfossil updates before committing to absorb siblings. Within P4, F6 and F7 both edit thefuzz_tests.zigregistration table → serialized. - P5 after P3+P4 — the help audit (S2) must describe the post-fix verb
set (
openexists only after F3), and the caveats table / release notes must describe final behavior. Writing them earlier documents a moving target. - P6 strictly last — trunk re-merge, full battery, single merge to trunk, tag, publish, cleanup.
3. Per-change specifications
P1 — License & packaging hygiene (F1 + S6) — hours, trivial risk
| Scope | Add LICENSE (BSD-2-Clause, copyright Daniel Mestas 2026). zit is an independent reimplementation from the RFCs, not derived from fossil source, so any license is legally available; BSD-2-Clause matches the Fossil heritage and the systems-Zig ecosystem. (MIT would be equally defensible — this is the one taste call embedded in the FINAL flip.) Add LICENSE to build.zig.zon .paths. Delete commit-description-413190fb92be991f.txt and add an ignore-glob for the pattern (S6). Commit this plan doc. |
| Acceptance | LICENSE at repo root; named in .paths; scratch file gone; ignore-glob in .fossil-settings/ignore-glob; battery green. |
| Tests | Amended from "none new — battery only" (explicit scope ack, not silent drift). P1 adds src/packaging_test.zig: structural pins over the shipped distribution — LICENSE content, LICENSE named inside the manifest's brace-matched .paths block, a line-anchored ignore-glob pin, and a negative-space pin asserting every repo-root path build.zig embeds is named in .paths. Justification: the P1 acceptance criteria are all file-structure facts, which rot silently because nothing executes them; the battery alone cannot catch a .paths regression. Caveat recorded because this addition was itself the vector for a packaging blocker — the embeds must attach to the test-only module (build_unit_test_module), never to the exported zit module, or a consumer fetching the package fails on a file outside .paths. The negative-space pin exists to catch exactly that recurrence. |
| Risk / size | Trivial / minutes–hours. |
P2 — CI bootstrap (F2) — ~1 day, medium risk (infra unknowns)
| Scope | (a) Establish a PRIVATE git mirror of the fossil repo at github.com/<owner>/zit via fossil git export (create with gh repo create --private if absent — the --private flag is MANDATORY; a public mirror is out of scope for 0.1.0 and requires a separate operator decision), with a scripted export step so later phases can push deterministically. (b) .github/workflows/ci.yml: on push (all branches) + PR — pin Zig 0.16.0, install fossil (for smoke), run zig fmt --check ., zig build, zig build test, zig build e2e, zig build dst, zig build smoke. Single ubuntu-latest gating job for 0.1 (macOS job is 0.2 material). Do not change local step semantics — e2e staying compile-only under zig build test is a good inner-loop design; CI runs the steps explicitly. |
| Acceptance | First fully green Actions run on the mirror for release-0.1, including smoke against a real installed fossil. Export step is one command, rerunnable. |
| Tests | The pipeline is the test; green run required. |
| Risk / size | Medium — runner environment (fossil version, Zig install, smoke's spawned-server behavior in CI) is the unknown; budget the day for iteration. ~1 day. |
P3-F3 — Clone → working tree: zit open — 1–2 days, highest risk
| Scope | Recommended shape (final call belongs to this step's Ousterhout round): implement a zit open verb — fossil-parity (fossil clone + fossil open is exactly fossil's own UX) and the deeper module (opens any repo file, not just fresh clones). open takes a repo path + workdir, writes the checkout record and managed set, and materializes the tip of trunk reusing the existing checkout.zig/update.zig machinery. runClone stays repo-only. Alternative if review prefers it: clone writes the checkout bootstrap itself. Register the verb (cli.zig Verb enum + dispatch + help). |
| Acceptance | e2e proof chain: clone (from zit serve) → open → files on disk byte-match the source tree → update works in the opened tree → a commit in the opened tree round-trips. Smoke scenario: clone from a real fossil-served repo → open → file bytes match. open appears in help with an e2e pin. |
| Tests | The e2e chain above (this is the missing proof the assessment called out — the existing clone test asserts digest-set equality only, e2e.zig:10209), plus the smoke scenario. |
| Risk / size | Highest of the release — whether update works against a fresh clone's absent checkout record is unproven; expect to fix what the new e2e exposes. 1–2 days. |
P3-F4 — add/rm directory recursion — ~1 day, low-medium risk
| Scope | Implement recursion at main.zig:452 / :679, honoring the existing extras.sweep exclusion walk — the exact pattern addremove (f0dc5f4e2a) already established: one scan, mutations only through ManagedSet.insert/remove/write. No second walker. Replace the "directory recursion is not yet supported" diagnostics and retire their e2e pins (e2e.zig:645,1034,1164). |
| Acceptance | zit add . adds every non-excluded extra under the tree; zit add <dir> scoped correctly; zit rm <dir> removes tracked files under dir; control files / ignore-glob matches never added; --dry-run semantics if present stay consistent with addremove. |
| Tests | e2e: nested dirs, exclusion globs honored, add . at root and in subdir, rm of a partially-tracked dir; updated diagnostics tests. |
| Risk / size | Low-medium (proven pattern to copy). ~1 day. |
P3-F5 — status reports edited files — ½–1 day, medium risk
| Scope | Complete B-status-16: full edited-file detection — hash tracked files against the current check-in, reusing the dirty-scan machinery commit already has. Add an EDITED row class to the render loop (~main.zig:1155-1160). Update --help to drop the deferral text. Frame: completing a documented deferral, not fixing a lie. |
| Acceptance | Edit a tracked file → status lists it as edited; unchanged files not listed; added/missing behavior unchanged; help text updated. No performance claims without a benchmark (rule 7) — if the notes want to say anything about status speed, cite a measurement or say nothing. |
| Tests | e2e: edit→status shows; touch-without-change (mtime bump, same bytes) → not shown; interaction with missing and added states. |
| Fallback of record | If the track overruns its budget: ship the minimum honest version — a trailing notice line ("edits not shown; see zit diff") — and move full detection to 0.2.0 top-of-list. The workflow treats this as a legitimate DONE_WITH_CONCERNS outcome, recorded in the release notes. |
| Risk / size | Medium. ½–1 day. |
P4-F6 — Transport/serve fuzz targets — ~1 day, low risk
| Scope | transport_frame_garbage and serve_request_garbage seeded fuzz targets for the only surfaces reachable by an untrusted remote peer (transport.zig 469 L, serve.zig 593 L). sync_parsers_adversarial covers the layer above; these hit the HTTP framing itself. Register in the fuzz_tests.zig:21-46 table exactly like the existing 24; replayable seeds. |
| Acceptance | Targets run in the standard fuzz invocation and in CI; N-iteration seeded run clean (no crash/leak/UB); any bug found is fixed in this step with a regression test pinning the seed. |
| Risk / size | Low for the targets; unknown for what they find (that's the point). ~1 day. |
P4-F7 — merge3 property fuzz — ½ day, low risk
| Scope | merge3_properties target with the four algebraic oracles: merge(b,x,b)==x, merge(b,b,y)==y, merge(b,x,x)==x, and no-invented-lines (every output line ∈ some input). Silent merge corruption is the worst VCS failure mode; this is the cheapest insurance on the list. Serialized after F6 (shared fuzz_tests.zig table). |
| Acceptance | Same bar as F6: registered, seeded, CI-run, clean at N iterations, findings fixed with pinned-seed regressions. |
| Risk / size | Low. ½ day. |
P5a — Help-text audit (S2) — hours, trivial risk
| Scope | Every dispatched verb appears in shipped help: name sync (currently a live dispatch arm deliberately absent from help, cli.zig:2355-2357 — fine mid-development, wrong in a release), and audit clone/pull/push/remote/pack/open. |
| Acceptance | e2e test asserting each dispatched Verb-enum member appears in zit help output (a structural pin, so the audit can't rot). |
| Risk / size | Trivial. Hours. Must run after F3 (open exists). |
P5b — Version, README caveats, release notes — ½ day, low risk
| Scope | build.zig.zon 0.0.0 → 0.1.0. README honest-caveats table: status/diff limits (rev-vs-rev diff absent — diff is working-tree vs current check-in only; status fallback if F5 shipped minimal), placeholder sync identity, deferred R/T/U/W card semantics, verbs missing vs fossil (stash, grep, ui, settings, rev-diff). docs/RELEASE-NOTES-0.1.0.md in the honest-diagnostic voice the codebase already has (it's a release asset): what's implemented, what the conformance claim rests on (smoke in CI against the real fossil binary — name the exact fossil version, S7), what's deliberately deferred and where each deferral is documented. Any performance number quoted (e.g. the pack/re-deltification sizes) must cite its existing measurement (bab9303056) — no unbenchmarked claims. |
| Acceptance | Version stamped; caveats table complete against the final shipped behavior; notes reviewed at the design tier for voice and honesty; battery green. |
| Risk / size | Low. ½ day. Strictly after P3+P4+P5a. |
P6 — Converge & ship — ½ day, medium risk (concurrency)
| Scope | (1) Re-merge trunk → release-0.1 (trunk advances from concurrent sessions; expect and absorb their commits). (2) Full local battery incl. smoke on the merged tree. (3) GO/NO-GO judgment against the §8 checklist. (4) Merge release-0.1 → trunk (SQLITE_BUSY retry; re-merge again if trunk moved). (5) Mirror export; wait for CI green on the merge commit. (6) Tag v0.1.0 (fossil tag on trunk tip + git tag on the private mirror), publish the release with its notes on the private mirror only — no public announcement, no visibility change; going public is a separate operator decision. (7) Cleanup: remove /Users/dmestas/zit-rel/* worktrees, verify fossil extras clean, mirror in sync. |
| Acceptance | §8 checklist fully checked. |
| Risk / size | Medium — merge races with concurrent sessions; the retry+re-merge loop is the mitigation. ½ day. |
4. Dependency graph & parallelism
Serialize: P1 → P2. Fan out: P3 (three worktrees) ∥ P4 (one worktree). Join: P5a → P5b → P6.
Worktree map (house pattern: parallel tracks are separate worktrees on the SAME branch, converging on the branch, then one merge to trunk):
| Worktree | Track | Files touched (conflict surface) |
|---|---|---|
/Users/dmestas/zit (trunk checkout) |
P1, P2, P5, P6 | root files, .github/, docs, build.zig.zon, cli.zig help |
/Users/dmestas/zit-rel/open |
F3 | main.zig ~:2537+, cli.zig Verb/help, checkout.zig, e2e.zig, smoke.zig |
/Users/dmestas/zit-rel/addrm |
F4 | main.zig :452/:679, extras.zig (read), e2e.zig |
/Users/dmestas/zit-rel/status |
F5 | main.zig ~:1080-1160, e2e.zig |
/Users/dmestas/zit-rel/fuzz |
F6→F7 | fuzz_tests.zig, new *_fuzz files, build.zig |
P1/P2/P5/P6 run in the trunk-side checkout but commit to release-0.1
(sequential phases — no self-conflict). Every track fossil updates
immediately before committing to absorb sibling commits; if the update pulls
nontrivial changes, re-run zig build test before committing. Existing
zit-storage / zit-nextverbs worktrees are left alone — they belong to
other lines of work.
5. Branch strategy
Single fossil branch release-0.1, cut from trunk tip at preflight. The
phases are interdependent (help audit and notes describe the post-fix verb
set), so a coherent branch lets CI validate the set together.
Continuous integration to trunk (operator decision, 2026-07-18). Every
increment lands on trunk as soon as it passes its own gates — not one
big-bang merge at P6. After a step commits on release-0.1, runStep
immediately runs a land-on-trunk gate:
- Driven from the trunk worktree (
/Users/dmestas/zit), never from the step's worktree — so parallel P3/P4 tracks don't each steer trunk. fossil update trunk→ require a clean tree (a dirty trunk carrying another session's WIP blocks; never revert or stash someone else's work).fossil merge release-0.1→ any conflict or<<<<<<<marker blocks for human resolution; no silent semantic merges.- Re-verify the merged tree (
fmt/build/test, plussmokeon interop-relevant steps). Green-on-the-branch does not imply green-on-the-merge, because trunk advances under us. - Commit the merge (guard enforced, SQLITE_BUSY/guard-flake retries, never bypassed). If trunk moved mid-merge, restart the sequence (bounded, 3×).
Rationale: smaller, reviewable merges; minimal divergence from a trunk that
concurrent sessions keep advancing; each increment independently landed and
revertible; conflicts surface at one-increment size instead of accumulating to
release-sized. A failed land does not lose work — the increment stays
committed on release-0.1 and the step reports landed: false.
By P6 trunk should already contain every increment; P6's merge becomes a formality (plus the final re-verify, GO/NO-GO, and tag). Tag goes on the trunk tip.
Concurrency rules (standing): SQLITE_BUSY on any fossil op → bounded retry
with backoff; never inherit rule-violating files from concurrent sessions
across a merge (inspect what the re-merge brings in); the zit-commit-guard
pre-commit hook builds the main checkout and runs test/dst — it may flake
under concurrent writers; retry, never bypass, never --no-verify.
6. Scope decisions — SHOULD-FIX / NICE-TO-HAVE disposition
| Item | In 0.1.0? | Rationale |
|---|---|---|
S2 help-text audit (sync et al.) |
Yes (P5a) | Cheap; a hidden verb is wrong in a release. |
| S6 scratch-file removal | Yes (P1) | Minutes. |
| S7 fossil version in notes | Yes (P5b) | The conformance claim needs it. |
| Version stamp + tag + caveats table | Yes (P5b/P6) | Is the release. |
| S1 working-tree crash-consistency DST sweep | 0.2 — first item | Biggest post-release safety win (this is where a user's power-loss lands) and the harness (sim/faulty_file.zig) already exists — but no user-visible cliff, and the week budget belongs to the seven cliffs. Deliberately top of 0.2. |
| Delta/repo-state RFC vectors | 0.2 | Smoke-in-CI (P2) covers the conformance substance with stronger evidence (validation against fossil's own code); vectors are defense-in-depth that runs without a fossil binary. |
| S3 seam-coverage matrix (~14 "deferred to manifest assembly" promises) | 0.2 | Converts informal promises into one enforced invariant; valuable, not user-facing, not gating. |
S4 parse-garbage fuzz (managed/undo/repocache) |
0.2 | On-disk-state hardening; pairs naturally with S1. |
| S5 artifact fuzz alphabet → R/T/U/W/Z | 0.2 | Those card semantics are themselves deferred; fuzz them when they land. |
| Extended smoke scenarios (bidirectional sync, delta-heavy) | 0.2 | Marginal conformance dollar goes furthest here — after the tag. |
N1 main.zig split |
Post-release, explicitly deferred | Shallow god-file, real debt — but a reorg buys users nothing pre-tag and invites merge churn. Seam and target shape already documented in the assessment. |
N2 kcov cov in CI + floor |
0.2 | The kcov plan already exists (queued post-CLI); wire it once CI is stable. |
N3 separate test-aggregation root · N4 repostate_crosslink_garbage |
Backlog | No release relevance. |
7. Quality bar (per step — the workflow enforces this; do not thin it)
Every P1–P6 step runs the full gauntlet built over the storage lever:
- Ousterhout design review (design tier, bounded ≤3 rounds): shallow module / leaky interface / pass-through check; complexity pushed down, not up to callers; lighter-mechanism check; premise check.
- Implement, TDD: failing test first (shown failing), then to green.
- STANDALONE TigerStyle audit — its own gate with its own agent, never folded into code review (bounded ≤3 audit→fix rounds).
- DST/property + seeded fuzz where the step touches simulated or fuzzed
surfaces (F6/F7 are themselves this; F3/F4/F5 must keep
zig build dstgreen and extend e2e). - Full local verify battery:
zig fmt --check .·zig build·zig build test·zig build e2e·zig build dst·zig build smokewhere interop-relevant (F3, P6 always; others when they touch sync/serve). - Commit discipline (the pack.zig lesson): check
fossil extras,fossil addevery new file, commit (SQLITE_BUSY retry), then verify a clean checkout of the new commit builds (fossil openinto a temp dir →zig build+zig build test). Guard hook: never bypass. - From P3 onward: mirror export + CI green on the branch is an additional gate per commit.
- Attribution: borrowed techniques cite author + codebase/paper in the code comment AND the commit message. No AI attribution anywhere.
- Rule 7: no performance claim without a benchmark, in code comments, commit messages, or release notes.
8. Definition-of-done checklist (P6 GO/NO-GO input)
- [ ] F1:
LICENSE(BSD-2-Clause) at root and in.paths - [ ] F2: mirror CI green running fmt-check/build/test/e2e/dst/smoke, Zig 0.16.0 pinned, fossil installed
- [ ] F3: e2e clone→open→files-on-disk→update→commit chain green; smoke scenario vs real fossil green
- [ ] F4:
zit add ./zit rm <dir>recursive, exclusion-sweep-honoring, e2e-covered - [ ] F5:
statusreports edited files (or recorded fallback: notice line + 0.2 deferral in notes) - [ ] F6: transport/serve fuzz targets registered, seeded, CI-run, clean
- [ ] F7: merge3 property target (4 oracles) registered, seeded, CI-run, clean
- [ ] S2: every dispatched verb in help, structurally pinned by e2e
- [ ] S6: scratch file removed, pattern ignored
- [ ] Version
0.1.0inbuild.zig.zon - [ ] README caveats table matches shipped behavior
- [ ]
docs/RELEASE-NOTES-0.1.0.mdcomplete, incl. exact fossil version (S7); no unbenchmarked perf claims - [ ] Trunk re-merged into
release-0.1; full battery green on converged tree - [ ]
release-0.1merged to trunk; CI green on merge commit - [ ]
v0.1.0tagged (fossil + mirror git tag); release published with notes on the PRIVATE mirror (repo visibility unchanged — still private) - [ ]
fossil extrasclean on trunk; release worktrees removed; mirror in sync
9. Risks & contingencies
| Risk | Mitigation |
|---|---|
| F3 exposes deeper checkout/update breakage than 1–2 days absorbs | It's the first track dispatched (longest pole). If it balloons: keep open minimal (materialize tip + records; defer flags), and let the e2e chain define "enough". If still blocked, the workflow halts that track and surfaces it — 0.1 does not ship without F3. |
| CI environment fights back (smoke in Actions) | Budgeted into P2's day; smoke's server-spawn is the likely friction. If a runner-specific smoke issue can't be fixed same-day, gate on test/e2e/dst and file the smoke-in-CI gap as a named caveat + 0.2 item — an explicitly surfaced downgrade, not a silent one. |
| Concurrent sessions race trunk | Re-merge before finalizing; SQLITE_BUSY retries; inspect merged-in content; guard-hook flakes get retried, never bypassed. |
| F6/F7 fuzz finds real bugs | That's success. Fix-with-pinned-seed inside the step; if a finding is structural (e.g. a protocol flaw), the workflow halts the track and surfaces it rather than papering over. |
| F5 full detection overruns | Recorded fallback: notice line + 0.2 deferral (see P3-F5). |