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
99 changes: 99 additions & 0 deletions .claude/skills/release/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Release Skill

Executes a full release cycle for the riddl project. Follow each
step in order. **STOP immediately** if any assertion fails and
report the problem.

## Arguments

The user should provide a version number (e.g., `1.10.1`). If
not provided, analyze changes since the last tag and recommend
a version bump per semver (MAJOR/MINOR/PATCH), then wait for
the user to confirm.

## Pre-Flight Checks

1. Assert current branch is `main`:
```
git branch --show-current
```
If not on `main`, ask the user before switching. **Never
publish from `development` or feature branches.**

2. Assert working tree is clean:
```
git status --porcelain
```
If dirty, list the uncommitted files and ask the user how
to proceed.

3. Unset GITHUB_TOKEN to avoid auth conflicts:
```
unset GITHUB_TOKEN
```

4. Verify the version tag does not already exist:
```
git tag -l <VERSION>
```

## Release Steps

5. Run the full test suite and confirm all tests pass:
```
sbt clean test
```

6. Create an annotated git tag:
```
git tag -a <VERSION> -m "Release <VERSION>"
```

7. Push the tag to origin:
```
git push origin <VERSION>
```

8. Publish all modules to GitHub Packages:
```
sbt clean test publish
```
Verify the published version matches `<VERSION>` in the sbt
output (sbt-dynver derives version from the tag).

9. Create a GitHub release:
```
gh release create <VERSION> --title "Release <VERSION>" \
--generate-notes
```
This triggers the Release Artifacts workflow (native builds,
Homebrew formula update) and the npm-publish workflow
automatically.

## Post-Release Verification

10. Run `git status` to confirm the working tree is still clean.

11. Confirm the release exists:
```
gh release view <VERSION>
```

12. Switch back to `development` and merge the tag forward:
```
git checkout development
git merge main
git push
```

13. Report a summary: tag, commit SHA, release URL, and any
CI workflows triggered.

## If Something Fails

- If tests fail in step 5: fix and re-run. Do NOT proceed.
- If tag push fails in step 7: check if the tag exists remotely.
- If publish fails in step 8: check credentials and retry.
- If `gh release create` fails in step 9: the tag is already
pushed, so the release can be created manually or retried.
- **Never force-push tags** without explicit user approval.
26 changes: 7 additions & 19 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ jobs:
- os: macos-latest
artifact: riddlc-macos-arm64
arch: arm64
- os: macos-13
artifact: riddlc-macos-x86_64
arch: x86_64
- os: ubuntu-latest
artifact: riddlc-linux-x86_64
arch: x86_64
Expand Down Expand Up @@ -175,7 +172,6 @@ jobs:
id: hashes
run: |
echo "macos_arm64=$(shasum -a 256 artifacts/riddlc-macos-arm64/riddlc-macos-arm64.zip | cut -d' ' -f1)" >> "$GITHUB_OUTPUT"
echo "macos_x86=$(shasum -a 256 artifacts/riddlc-macos-x86_64/riddlc-macos-x86_64.zip | cut -d' ' -f1)" >> "$GITHUB_OUTPUT"
echo "linux_x86=$(shasum -a 256 artifacts/riddlc-linux-x86_64/riddlc-linux-x86_64.zip | cut -d' ' -f1)" >> "$GITHUB_OUTPUT"
echo "jvm=$(shasum -a 256 artifacts/riddlc-jvm/riddlc.zip | cut -d' ' -f1)" >> "$GITHUB_OUTPUT"

Expand All @@ -190,7 +186,6 @@ jobs:
env:
TAG: ${{ github.event.release.tag_name || github.event.inputs.tag }}
SHA_MACOS_ARM64: ${{ steps.hashes.outputs.macos_arm64 }}
SHA_MACOS_X86: ${{ steps.hashes.outputs.macos_x86 }}
SHA_LINUX_X86: ${{ steps.hashes.outputs.linux_x86 }}
SHA_JVM: ${{ steps.hashes.outputs.jvm }}
run: |
Expand All @@ -209,10 +204,7 @@ jobs:
if OS.mac? && Hardware::CPU.arm?
url "https://github.com/ossuminc/riddl/releases/download/#{version}/riddlc-macos-arm64.zip"
sha256 "${SHA_MACOS_ARM64}"
elsif OS.mac? && Hardware::CPU.intel?
url "https://github.com/ossuminc/riddl/releases/download/#{version}/riddlc-macos-x86_64.zip"
sha256 "${SHA_MACOS_X86}"
elsif OS.linux?
elsif OS.linux? && Hardware::CPU.intel?
url "https://github.com/ossuminc/riddl/releases/download/#{version}/riddlc-linux-x86_64.zip"
sha256 "${SHA_LINUX_X86}"
else
Expand All @@ -222,19 +214,15 @@ jobs:
end

def install
if OS.mac? || OS.linux?
if !Hardware::CPU.type.to_s.start_with?("arm") || !OS.mac?
# x86_64 native or Linux native
bin.install "bin/riddlc"
else
# macOS ARM64 native
bin.install "bin/riddlc"
end
if (OS.mac? && Hardware::CPU.arm?) || (OS.linux? && Hardware::CPU.intel?)
# Native binary - Homebrew strips the single top-level "bin/" dir
bin.install "riddlc"
else
# JVM fallback
# JVM version - needs wrapper script
rm "bin/riddlc.bat"
libexec.install "lib"
libexec.install "bin"

(bin/"riddlc").write <<~EOS
#!/bin/bash
export JAVA_HOME="#{Formula["openjdk@21"].opt_prefix}"
Expand All @@ -244,7 +232,7 @@ jobs:
end

def caveats
if OS.mac? || OS.linux?
if (OS.mac? && Hardware::CPU.arm?) || (OS.linux? && Hardware::CPU.intel?)
<<~EOS
riddlc is installed as a native binary. No JDK required.

Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ target
/node_modules
*.bak
language/input/everything.bast
.claude/
.claude/*
!.claude/skills/
language/jvm/src/test/python/.venv/
__pycache__/
13 changes: 11 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -691,8 +691,17 @@ Then add to root aggregation: `.aggregate(..., mymodule, mymoduleJS, mymoduleNat
27. **riddlLibJS tests now work** - Fixed by overriding `Test / scalaJSLinkerConfig` to `CommonJSModule` in `build.sbt`. Production bundle stays ESModule. 8 shared `RiddlLibTest` tests run on both JVM and JS
28. **NEVER put `import '`, `import "`, or `import(` in shared string literals** - ESM shim plugins scan the JS bundle and rewrite these patterns. Use string concatenation (`"im" + "port"`) or rephrase the message. `ESMSafetyTest` in `riddlLib/jvm/src/test/` enforces this by scanning the fullLinkJS bundle
29. **Container.flatten() extension** - Recursively removes Include/BASTImport wrappers in-place. Lives in `language/shared/.../Contents.scala`. FlattenPass delegates to `root.flatten()`. Use base `Pass` not `DepthFirstPass` β€” mutating contents during traversal corrupts ArrayBuffer iteration
30. **release.yml automates multi-platform builds** - Triggered by `gh release create`. Builds native riddlc on macOS ARM64, macOS x86_64, Linux x86_64, plus JVM. Auto-updates homebrew-tap formula with SHA256 hashes
31. **Homebrew formula supports native + JVM fallback** - macOS ARM64 gets native binary (no JDK). Other platforms get JVM version with openjdk@21 dependency. Formula at `../homebrew-tap/Formula/riddlc.rb`
30. **release.yml automates multi-platform builds** - Triggered
by `gh release create`. Builds native riddlc on macOS ARM64
and Linux x86_64, plus JVM universal. Auto-updates
homebrew-tap formula with SHA256 hashes. macOS x86_64
dropped (GitHub deprecated `macos-13` runners; Intel Macs
fall back to JVM version)
31. **Homebrew formula supports native + JVM fallback** - macOS
ARM64 and Linux x86_64 get native binaries (no JDK). All
other platforms (including Intel Macs) get JVM version with
openjdk@21 dependency. Formula at
`../homebrew-tap/Formula/riddlc.rb`
32. **RiddlLib shared trait** - `riddlLib/shared/.../RiddlLib.scala` provides cross-platform API (parseString, flattenAST, validateString, getOutline, getTree). `object RiddlLib extends RiddlLib` has default implementations. RiddlAPI.scala is now a thin JS facade delegating to RiddlLib
33. **parseString returns opaque Root in JS** - As of 1.5.0, `RiddlAPI.parseString()` returns the actual Scala `Root` object (opaque to JS). Use `getDomains(root)` or `inspectRoot(root)` to access data. TypeScript type is branded `RootAST`
34. **Schema is in NonDefinitionValues** - Schema extends Leaf (Definition) but is also in the `NonDefinitionValues` union type. Its match case in `ValidationPass.process()` must appear BEFORE `case _: NonDefinitionValues`. Similarly, Relationship extends Leaf and must be matched before `case _: Definition`
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ RUN curl -fsSL https://github.com/sbt/sbt/releases/download/v1.10.7/sbt-1.10.7.t
WORKDIR /app

# Copy project files for sbt dependency resolution (cached layer)
COPY project/build.properties project/plugins.sbt project/Dep.scala project/
COPY project/build.properties project/plugins.sbt project/Dependencies.scala project/
COPY build.sbt ./

# Pre-fetch dependencies (this layer is cached if build files don't change)
Expand Down
71 changes: 64 additions & 7 deletions NOTEBOOK.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,16 +248,73 @@ The `pseudoCodeBlock` parser now allows comments before and/or after `???`:

---

## Changes Since v1.9.0

- BAST reader metadata flag fix, deserialization edge cases
- BASTWriter node tracking improvements
- BinaryFormat header enhancements, new BAST node type tags
- Pass.scala updates for BAST integration
- SharedBASTTest coverage for deserialization edge cases
## Changes Since v1.10.0

- Fixed Dockerfile `Dep.scala` β†’ `Dependencies.scala` reference
- Dropped deprecated `macos-13` x86_64 from release.yml (GitHub
retired the runner; Intel Macs fall back to JVM version)
- Updated generated Homebrew formula in release.yml to match
actual homebrew-tap structure
- Added `/release` skill (`.claude/skills/release/SKILL.md`)
- Updated CLAUDE.md notes #30, #31 for dropped x86_64 target
- Updated `../CLAUDE.md` with workflow discipline rules from
insights analysis (scope discipline, single-purpose commits,
post-commit verification, publish-from-main, GITHUB_TOKEN
caveat, dependency locality)

## Session Log

### February 14, 2026 (CI Fixes & Insights)

**Focus**: Fix pre-existing CI failures, apply insights
suggestions to CLAUDE.md files, create `/release` skill.

**Work Completed**:
1. **Fixed Dockerfile** β€” `Dep.scala` β†’ `Dependencies.scala`
(file was renamed but Dockerfile never updated)
2. **Dropped `macos-13` x86_64 from release.yml** β€” GitHub
deprecated `macos-13` runners. Removed matrix entry, SHA
computation, and updated generated Homebrew formula to
match actual `homebrew-tap` structure (macOS ARM64 native,
Linux x86_64 native, JVM fallback for everything else)
3. **Applied insights suggestions to `../CLAUDE.md`** (general,
all ossuminc projects):
- Scope discipline (don't expand without asking)
- `unset GITHUB_TOKEN` before `gh` commands
- Publish from `main` only
- Dependency locality (prefer local packages)
- Single-purpose commits
- Post-commit verification (`git status` after commit)
4. **Updated `./CLAUDE.md`** β€” notes #30 and #31 for dropped
macOS x86_64 target
5. **Created `/release` skill** at
`.claude/skills/release/SKILL.md` β€” encodes full release
workflow with pre-flight checks, publish steps, and
post-release verification
6. **Un-ignored `.claude/skills/`** in `.gitignore` so skills
are tracked in git (other `.claude/` contents stay ignored)

**CI Failure Analysis**:
- Docker: Fixed (Dockerfile)
- Release Artifacts: Fixed (dropped `macos-13`)
- RiddlModelsRoundTripTest: Known chicken-egg problem β€” needs
.bast files regenerated with 1.10.0 in riddl-models. Not
actionable from this repo.

**Files Created**:
- `.claude/skills/release/SKILL.md`

**Files Modified**:
- `Dockerfile`
- `.github/workflows/release.yml`
- `.gitignore`
- `CLAUDE.md`

**Cross-project**:
- `../CLAUDE.md` β€” workflow discipline rules

---

### February 14, 2026 (RiddlResult ADT)

**Focus**: Add cross-platform `RiddlResult[T]` result type to
Expand Down
Loading