diff --git a/.github/workflows/release-notes.yml b/.github/workflows/release-notes.yml new file mode 100644 index 0000000..e591e06 --- /dev/null +++ b/.github/workflows/release-notes.yml @@ -0,0 +1,31 @@ +name: Release notes + +# Regenerates a release's notes on demand, for any tag. New releases don't +# need this: their notes run as a separate job, so "Re-run failed jobs" +# retries them. It's for releases cut before that split (0.2.9 and earlier), +# where the notes step ran after `npm publish` in the same job and a re-run +# would try to publish the same version again. +on: + workflow_dispatch: + inputs: + tag: + description: Release tag to regenerate notes for (e.g. v0.2.9) + required: true + +permissions: + contents: write + +jobs: + notes: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + with: + fetch-depth: 0 + fetch-tags: true + - name: Generate AI release notes + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + RELEASE_TAG: ${{ inputs.tag }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: bash .github/scripts/ai-release-notes.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8868621..6e2bfe7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,7 +36,7 @@ jobs: if: ${{ needs.release-please.outputs.release_created == 'true' }} runs-on: ubuntu-latest permissions: - contents: write # edit the GitHub Release with AI-generated notes + contents: read id-token: write # npm publish provenance steps: - name: Checkout @@ -71,10 +71,24 @@ jobs: env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - # Best-effort: replace the release body with human-readable notes written by - # Claude. If it fails, the release keeps release-please's default notes. + # Replaces the release body with human-readable notes. Its own job, after + # publish, so a failure (e.g. an empty API credit balance) shows red without + # touching the release, and "Re-run failed jobs" retries just this - never + # npm publish. If it stays failed, the release keeps release-please's notes. + notes: + needs: [release-please, publish] + if: ${{ needs.release-please.outputs.release_created == 'true' }} + runs-on: ubuntu-latest + permissions: + contents: write # edit the GitHub Release + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true + - name: Generate AI release notes - continue-on-error: true env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} RELEASE_TAG: ${{ needs.release-please.outputs.tag_name }} diff --git a/docs/agent/log.md b/docs/agent/log.md index 3b542b7..1243344 100644 --- a/docs/agent/log.md +++ b/docs/agent/log.md @@ -24,6 +24,8 @@ conventional commits, what needs a device — are in ## Runs +- **2026-10-08** — **Shipped 0.2.9** (the #36 `onDimensions` fix) to npm with provenance. npm's homepage now points at the site. The Release workflow's AI-notes step failed with `credit balance is too low` from the Anthropic API. It's `continue-on-error`, so the publish went through, but the release kept release-please's plain notes. Re-running the Release job can't fix that: the notes step comes after `npm publish`, which refuses a version that already exists. Fixed two ways. In `release.yml` the notes now run as their own `notes` job after `publish`, without `continue-on-error`: a failure shows red without touching the release, and "Re-run failed jobs" retries only the notes. `publish` drops to `contents: read`. Added `.github/workflows/release-notes.yml` (manual dispatch with a `tag` input) for releases cut before the split: `gh workflow run release-notes.yml -f tag=v0.2.9`. + - **2026-10-07** — **Public site and demo video** (`website/`, deployed by `.github/workflows/pages.yml`; README GIF closes #28). Design and plan: [`plans/2026-10-07-public-website-and-demo-video.md`](plans/2026-10-07-public-website-and-demo-video.md). Re-cut the video with `website/scripts/make-demo.sh `. The source recordings aren't in the repo, and the capture recording's own ending shows pre-#50 sizes, which the script cuts. Cloudflare Web Analytics beacon in the page. It reports only from `tristanheilman.github.io`, so localhost shows a CORS error, which is expected. A final review found two Important issues: the size tile disagreed with the video, and `og:image` was relative. Both fixed, plus 320 px overflow (upgraded from Minor because Display Zoom iPhones use 320). **Deferred minors, for the owner:** the tile label says `onDimensions` where the public API is `addDimensionsListener`; the copy-fallback label 'Press ⌘C' assumes a Mac; 'Expo works too' could read as Expo Go (it needs prebuild/dev client); `make-demo.sh` has no usage message and its `stat -f%z` is macOS-only. - **2026-10-07** — **#36 verified and fixed: `onDimensions` reported the capture volume, not the object.** Scanned a tissue box measured at ~22 × 11 × 12.5 cm. The USDZ was right (22.8 × 12.8 × 13.5 via `usdcat` and ModelIO), and native and JS agreed exactly, so the bridge was fine. But the value itself was 44.5 × 22.2 × 28.9: it came from the `.bounds` request, which returns the detection box plus padding. Now measured from the written model with `MDLAsset(url:).boundingBox`, and verified on device: 23.1 × 12.5 × 13.2. Handy: `swift` scripts can run ModelIO on the Mac against a USDZ pulled with `devicectl device copy from`, which checks a measurement before any device run. **Watch for: a RealityKit crash** — SIGTRAP, `assertion failure: (m_size > 0) Queue is empty` in `re::AssetManager::updateLoadRequests`, while the scan screen first renders (right after session state `ready`). No library frames on the stack. It hit 2 of about 6 launches on the fix build, with the phone at ~12% battery (Low Power Mode likely on). It didn't reproduce on 3 opens of the previous build, or later on the fix build once charged. If it recurs, record battery and Low Power state, and pull `systemCrashLogs` with `devicectl` to compare signatures.