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
36 changes: 36 additions & 0 deletions .agent/memory/active/napkin.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,41 @@
# Napkin

## Session: 2026-06-18 (final+) — continuous release on merge (PR #44)

### What Was Done

- Replaced the release-PR/`--auto` pattern with **continuous release on merge**
via the Oak Semantic Release Bot (app 2995796, ruleset bypass actor): trigger
on `workflow_run` after CI succeeds on main; `create-github-app-token`; compute
increment; `cz bump`; push bump+tag straight to protected main; publish Release.
Added `prevent_accidental_major` commit-msg hook (majors stay manual). Retired
#43 + `release/next`.

### Surprises & corrections (critically assess — incl. sub-agents AND analysers)

- **The literal CI-skip token in a feature commit/PR message skips CI on the
squash-merge.** My `feat` commit body *described* the loop-guard token in prose,
so #44's merge skipped CI → no `workflow_run` → no release; main stayed 0.3.0.
Keep the literal token out of feature messages. Documented in dev-tooling.
- **SonarCloud is a source to critically assess too.** It flagged `S8707` (argv
path → file read = path injection) on the commit-msg hook. Real impact is ~nil
(git supplies the path; 1-bit output), but fix-at-source beat suppression:
confined the path to the worktree-aware git dir with an `allowed_base` test
seam. Query Sonar via the MCP (`get_project_quality_gate_status` /
`search_sonar_issues_in_projects`, projectKey `oaknational_oak-python-starter`).
- **Critically rejected two reviewer findings** (premises wrong): pin checkout to
`workflow_run.head_sha` would make the bump push non-fast-forward under
concurrent merges (incompatible with direct-push); `create-github-app-token`
already defaults to current-repo scope, so it is not over-scoped.
- **`git add -A` swept untracked IDE dirs** (`.sonarlint/`, `.vscode/`) into the
commit — amended them out and gitignored them. Stage explicit paths.
- **ruff `--ignore-noqa` + B009 autofix:** a `getattr(x, "literal")` is rewritten
to `x.literal` (then pyright reportPrivateUsage fails). Use a *variable* attr
name: `name = "_fn"; getattr(x, name)`.
- The harness auto-mode classifier **blocks `gh workflow run Release -f
increment=...`** — agent-forced release version. Rely on the computed increment
from a real merge.

## Session: 2026-06-18 (final) — program COMPLETE: F6 + Tier 3 + Tier 2 + deps + v0.3.0

### What Was Done
Expand Down
43 changes: 28 additions & 15 deletions .agent/memory/operational/repo-continuity.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
# Repo Continuity

**Last refreshed**: 2026-06-18 (final) — **the "highest proportionate bar"
program is COMPLETE; `v0.3.0` is cut** (tag + GitHub Release with wheel + sdist).
`main` is green. Landed this session: **F6** agent-hook hardening (#37, owner
**Last refreshed**: 2026-06-18 (final+) — the "highest proportionate bar" program
is COMPLETE (`v0.3.0` cut). **NEW: the release model is now CONTINUOUS release on
merge (PR #44)** — the release-PR/`--auto` pattern is retired. After CI passes on
`main`, the Oak Semantic Release Bot (app 2995796, a ruleset bypass actor) bumps +
tags + pushes to `main` and publishes the Release; every qualifying merge advances
the version. **Not yet live-verified:** PR #44's own merge skipped CI (its squash
message contained the literal CI-skip token in prose), so no release fired and
`main` is still `0.3.0`. The next clean merge (message free of the CI-skip token)
will cut the first continuous release (**v0.4.0**, the computed minor from #44's
feat) and verify the bot's push-to-protected-main. Do NOT force it via
`workflow_dispatch` — the harness blocks an agent-forced increment, and the owner
wants the computed one.

(Earlier this session, pre-#44:) `main` is green. Landed: **F6** agent-hook hardening (#37, owner
chose recurse-and-check), **Tier 3** branch coverage + floor 86 (#38), Hypothesis
property tests (#39), single-version ADR-0002 (#40), **Tier 2** governance
checklist `docs/repository-governance.md` (#41), **Dependabot** #29 (actions) +
Expand Down Expand Up @@ -114,18 +125,20 @@ over-block). Full state in the

## Next Safe Step

- **The program is complete — no queued program work remains.** If resuming:
(1) the only outstanding items are **owner-only GitHub settings** in
`docs/repository-governance.md` (required status checks, release-PR token, Code
Quality preview, `v*` tag protection) — I cannot do these; (2) **F6 residuals**
(glued shell operators like `ok|git`, bare subshells `(...)`, and heredoc-prose
over-block) are documented and deferred to a future owner-authorised session —
fixing the glued-operator one needs a quote-aware raw tokeniser, a
safety-critical change; (3) **Tier 4** (SBOM, SLSA, Scorecard, mutation testing)
stays deferred unless the owner asks. Steady-state: a new `chore(release)` PR
will accrue future feat/fix — merge it with `gh pr merge <n> --squash --auto`
(bot PR sits UNSTABLE; `code_quality` is the only required check). Normal PRs
merge with `gh pr merge <n> --squash --delete-branch` once green.
- **Verify the first continuous release.** When this closeout PR (or any clean
merge) lands, watch the `Release` `workflow_run` run: it should bump to
**v0.4.0**, push the bump commit + tag to `main`, and publish the Release. If
it fails, the likely cause is the bot app lacking `Contents: write` (the one
unverified prerequisite) — main stays intact; fix the app perms and re-merge.
- **Remaining work otherwise:** (1) **owner-only GitHub settings** in
`docs/repository-governance.md` (required status checks, Code Quality preview,
`v*` tag protection — the release-bot secrets + bypass actor are already set);
(2) **F6 residuals** (glued shell operators like `ok|git`, bare subshells, and
heredoc-prose over-block) — deferred, the glued-operator one needs a quote-aware
raw tokeniser; (3) **PyPI publishing guide** for template adopters (owner asked;
docs-only, deferred — see Open Side-Tasks); (4) **Tier 4** stays deferred.
Normal PRs merge with `gh pr merge <n> --squash --delete-branch` once green —
keep the literal CI-skip token out of the message or the release won't fire.

## Open Side-Tasks

Expand Down
5 changes: 5 additions & 0 deletions docs/dev-tooling.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,11 @@ uv run cz check --message "docs: explain the Commitizen workflow"
- the version stays committed in the tree; releases publish to GitHub Releases
only (no PyPI). `audit_release_workflow` keeps the workflow (trigger, `cz bump`,
the increment tool, the `[skip ci]` loop guard) and the bump policy honest
- **gotcha:** because the loop guard relies on GitHub's CI-skip marker, a feature
commit or PR title/body that contains that literal marker in prose will make a
squash-merge skip CI too — so no `workflow_run` fires and no release is cut.
Keep the literal marker out of feature commit/PR messages; only the bump commit
should carry it

## Hydration guidance

Expand Down