Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: levelcodeai/levelcode
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 4e6593b
Choose a base ref
...
head repository: levelcodeai/levelcode
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 4e4175b
Choose a head ref
  • 2 commits
  • 4 files changed
  • 1 contributor

Commits on Aug 14, 2026

  1. ci: automate the release — draft notes, sign in CI, publish behind ap…

    …proval
    
    Replaces the hybrid model (CI builds unsigned, you sign on your laptop, then
    hand-juggle six `gh` commands) with three chained workflows. The only manual
    steps left are the two that need judgement: writing the prose, and deciding to
    ship.
    
      prepare-release.yml  →  you edit the PR  →  tag-on-merge.yml  →  release.yml
      (drafts the notes)      (the prose)         (pushes the tag)     (builds, signs,
                                                                        notarizes, waits)
    
    **Notes.** `draft-release-notes.mjs` already filled in every fact and left TODO
    markers where judgement is needed — its header argues that a changelog generated
    from commit subjects is why most release notes go unread. So the workflow opens a
    PR with that draft rather than committing it, and `tag-on-merge.yml` refuses to
    tag while a TODO or the scaffolding block survives, or when the first line doesn't
    name the version being tagged. Automation cannot ship scaffolding, and it cannot
    ship last release's notes either.
    
    **Signing.** `notarize.sh` already took APPLE_ID + TEAM_ID + APP_SPECIFIC_PASSWORD
    as the CI alternative to a local keychain profile, so no build script changed. The
    workflow imports the Developer ID cert into a temporary keychain in RUNNER_TEMP,
    runs the existing `make-dmg.sh`, verifies with codesign + stapler + spctl, and
    deletes the keychain in an `always()` step. Two details that are load-bearing:
    `set-key-partition-list` (without it codesign blocks on a GUI prompt nobody can
    click and the job hangs to timeout) and a 6h keychain lock timeout (the 5-minute
    default re-locks mid-notarization and the next codesign fails with a misleading
    "user interaction is not allowed").
    
    Also `fetch-depth: 0` on the build checkout: `build-macos.sh` stamps the version
    from `git describe --tags`, and its failure mode is silent — it warns and ships a
    build whose About box reads 1.126.0, the Code-OSS base.
    
    **The gate.** Publishing is deploying: the Squirrel updater installs a published
    release on every existing install at its next check, with no staged rollout, and
    the rollback pin cannot un-update anyone who already took it. So the publish job
    sits in a `release` Environment with required reviewers. Everything before it is
    reversible — a branch, a tag, a draft. That step is not. After publishing it polls
    the update feed and warns (not fails — the release is already correct) if the feed
    hasn't picked it up.
    
    The draft job also refuses to publish unless all four assets are present. Losing
    only the x64 job would otherwise strand every Intel user silently, since the feed
    serves per-arch.
    
    RELEASING.md §7 rewritten: the six secrets, the environment setup (called out
    hard — GitHub creates a missing environment with NO protection rules, so skipping
    it makes the gate decorative), the new flow, and the trade-off the old §7 named
    when it described this as the road not taken: the signing identity now lives in
    the cloud. Revocation path and blast-radius limits documented, along with how to
    go back.
    
    Verified: actionlint (which shellchecks every run: block) clean on all three.
    The notes gate was extracted from the workflow and exercised — real v1.0.4 notes
    pass; a real generated draft fails on TODOs and scaffolding; TODOs-removed-but-
    scaffolding-left still fails; v1.0.4 notes presented as v1.0.5 fail as stale; and
    generate → fill → delete scaffolding passes.
    ndemianc committed Aug 14, 2026
    Configuration menu
    Copy the full SHA
    3dde0f9 View commit details
    Browse the repository at this point in the history
  2. ci: address PR #63 review — tag the merge commit, narrow the TODO gate

    **Tag the merge commit, by SHA.** `tag-on-merge.yml` checked out `base.ref`, which
    resolves to whatever develop points at when the job starts — so anything merged in
    the window after the release PR got swept into the tag. Since the build stamps its
    version from `git describe --tags`, that ships code the release notes do not
    describe, silently. Now checks out `pull_request.merge_commit_sha`.
    
    **Narrow the TODO gate to the generator's marker.** It grepped for the bare word
    `TODO`, so prose legitimately containing it — describing a known gap, quoting a
    code comment — would block a finished release with no fix available except
    rewording. It now matches `<!-- TODO`, which is the question the gate is actually
    asking: did you fill in the placeholders draft-release-notes.mjs left?
    
    **Refuse to prepare a release off develop.** The Run-workflow dropdown accepts any
    ref, and the PR targets whatever you picked — but tag-on-merge.yml only listens for
    PRs into develop, so a release PR opened elsewhere merges cleanly and then never
    tags. A dead end with no error. Fails fast now, and RELEASING.md §7 says so.
    
    **`list-keychains`, plural.** The review said the singular form "isn't a valid
    subcommand" and that signing "will fail before codesign runs" — that part is not
    right: `security` accepts unambiguous subcommand prefixes, and `security
    list-keychain -d user` exits 0 today. Changed anyway, because prefix-matching is
    not a name: one more Apple subcommand starting `list-keychain…` and it breaks.
    
    Gate re-verified, six cases, harness fixed (the previous run generated drafts from
    outside the repo, so the generator correctly refused and wrote an empty file —
    which failed the first-line check for the wrong reason):
    
      real v1.0.4 notes @ v1.0.4        pass
      same notes claimed as v1.0.5      fail — stale
      raw generated draft               fail — TODOs + scaffolding
      filled + scaffolding removed      pass
      prose containing the word TODO    pass   ← was blocked before this change
      a real <!-- TODO --> marker       fail
    
    actionlint clean.
    ndemianc committed Aug 14, 2026
    Configuration menu
    Copy the full SHA
    4e4175b View commit details
    Browse the repository at this point in the history
Loading