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.
8.2 KiB
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 intoWalkContext::concept_spans(append-only — survives the clause being fully matched, unlikepending_hint_modewhich clears on match and so only knows the slot boundary).concept_topic_at_cursorwalks the full buffer and returns the innermost containing span. No use of the dormantWalkBound::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_blockpicks by live mode. /rundacaught two design gaps before any code (clause map missed the simple-mode constraint suffix; single-examplemodel collided with D6) — both fixed. Comprehensiveness gate: a recursiveNode::Conceptvisitor 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 (
<repo>-worktree-<segment>) — never switch the primary checkout.scripts/wt-new.sh <branch>(offorigin/main,--no-track) /scripts/wt-rm.sh <branch>(removes only the named worktree). - Reserve-first ADR numbering —
scripts/adr-reserve.sh <slug>. The fix for the real collision problem: a contiguous integer needs an allocator and plain git branches have none, somainis the registry and an atomicgit pushis the lock (compare-and-swap, retried on contention), recorded in the append-only ledgerdocs/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) → explicitwt-rm <branch>. The auto-sweep would have deleted long-lived branches (website,ci) since they're merged intomaintoo. Alsowt-new --no-track: branching offorigin/mainhad set the new branch's upstream toorigin/main, so a baregit pusherrored on a name-mismatch and suggested the dangerousHEAD:main. - #44 — CI dedupe:
push: branches: [main](was['**']) so a push to a PR'd branch no longer runs the gate twice. On Gitea thepushandpull_requestruns were byte-identical — Gitea has no merge-preview ref; itspull_requestchecks outrefs/pull/N/head, the same commit a branch push would (docs.gitea.com/usage/actions/faq). Keeping the gate onpull_requestis forward-compatible: if Gitea ever adds the merge ref, the runs upgrade to testing the merged result for free.
- #43 —
§4. Decisions
- #38 closed — won't build the pre-submit-diagnostic tier-3 route. The
ADR-0053 D6 deferral reasons still hold:
Diagnosticcarries 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
CHANGELOGinto komac's winget--release-notes-url. Best coupled to the nextv*release + first real winget update test — the initial winget PR tomicrosoft/winget-pkgsis 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 the0059index 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 onfeat(bootstrap artifact), which is what made worktree cleanup awkward — there was nomaincheckout holding the scripts. Resolved by switching the primary tomainand movingfeatto a worktree. - Docs-only PRs are blocked by the required gate.
paths-ignore(docs/**,**/*.md) means a docs-only change posts noci / gaterun, and branch protection requiresci / 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-trackon branch creation to avoid the inherited-origin/mainupstream.
§6. Next
- Next session is free to pick a feature — no specific item is queued;
consult
docs/requirements.mdfor 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-newto start a branch,adr-reservethe moment an ADR is needed, PR ontomain,wt-rmwhen 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
mainby the owner (docs-only, paths-ignored, owner-whitelisted).