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
26 changes: 13 additions & 13 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,8 @@ jobs:
name: Lint the protobuf schema
command: make proto-lint

# Baseline is an ancestor of HEAD, never live `origin/main` (a merge landing meanwhile
# would read as deletions): the first parent on main, the previous release on a `v*` tag.
# Baseline is an ancestor of HEAD, never a live branch tip (a merge landing meanwhile would
# read as deletions): the first parent on main or develop, the previous release on a `v*` tag.
- run:
name: Check the protobuf schema for breaking changes
command: |
Expand Down Expand Up @@ -1510,46 +1510,46 @@ jobs:
workflows:
version: 2

# Build and test every merge into main; pull requests run .github/workflows/pr.yml instead.
# Build and test every merge into main or develop; pull requests run .github/workflows/pr.yml instead.
# The Go suite is the four `Go …` jobs, and everything downstream requires all of them.
build-test:
jobs:
- go-static:
name: Go static checks
filters: &main-only
filters: &integration-branches
branches:
only: main
only: [main, develop]
tags:
ignore: /.*/
- go-race-test:
name: Go race tests
filters: *main-only
filters: *integration-branches
- go-coverage:
name: Go coverage profile
filters: *main-only
filters: *integration-branches
- go-gates:
name: Go gates and binaries
filters: *main-only
filters: *integration-branches
- python-test:
name: Python client tests
requires: &go-suite
- Go static checks
- Go race tests
- Go coverage profile
- Go gates and binaries
filters: *main-only
filters: *integration-branches
- rust-test:
name: Rust client tests
requires: *go-suite
filters: *main-only
filters: *integration-branches
- java-test:
name: Java client tests
requires: *go-suite
filters: *main-only
filters: *integration-branches
- node-test:
name: Node client tests
requires: *go-suite
filters: *main-only
filters: *integration-branches
- scan:
name: SonarCloud scan
# Matched exactly, like PyPI below; this context holds SONAR_TOKEN.
Expand All @@ -1566,7 +1566,7 @@ workflows:
- Python client tests
- Java client tests
- Node client tests
filters: *main-only
filters: *integration-branches

# Build and release on tags. The suite runs here too: a tag can point at any
# commit, so a release is only published from a revision proven green.
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: PR

# The only CI a pull request runs. Pushes to main and tags are covered by the
# CircleCI config; this workflow mirrors its build-test workflow, not release.
# The only CI a pull request runs. Pushes to main and develop, and tags, are covered
# by the CircleCI config; this workflow mirrors its build-test workflow, not release.
on:
pull_request:

Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ It provides a hand-written lexer/parser, semantic engine, execution runtime, LSP
1. **Correctness over expedience.** No shortcuts, no stubs left behind, no lossy conversions. If a proper fix is large, do it properly or stop and flag it.
- **For features specifically: do not minimize code changes or dodge complexity.** Implement the feature fully and correctly even if it touches many files, adds new types, or requires refactoring. Completeness beats diff size. See §8.
2. **Root-cause first.** Before editing, confirm *why* something fails (read the code, add a temporary debug print, write a focused test). Then make the minimal correct change.
3. **Never regress.** `main` is green. Any test passing on `main` must still pass on your branch. Diff against `main` if unsure: `git stash && git checkout main && go test ./... ; git checkout - && git stash pop`.
3. **Never regress.** `develop` is green. Any test passing on `develop` must still pass on your branch. Diff against `develop` if unsure: `git stash && git checkout develop && go test ./... ; git checkout - && git stash pop`.
4. **Respect the architecture invariants** (see §4). The AST is immutable; semantics live in side tables; execution consumes lowered IR — do not bypass these.
5. **Tests are the contract.** Existing tests encode intended behavior (including *when* and *where* errors surface). Make code satisfy tests, not the reverse — unless the test is provably wrong, in which case explain before changing it.
6. **Leave no dead code.** Remove superseded helpers/structs. Run `go vet ./...` to catch it.
Expand Down Expand Up @@ -139,7 +139,7 @@ Then update `docs/project/spec-compliance.md` mapping: semantic rule → impleme

## 6. Development Workflow

1. **Understand first.** Grep/read the relevant package and its tests. Diff the branch against `main` to see what changed and why.
1. **Understand first.** Grep/read the relevant package and its tests. Diff the branch against `develop` to see what changed and why.
2. **Reproduce.** Run the failing test(s) and read the exact error before changing anything.
3. **Locate the root cause** in the correct layer (lexer vs parser vs lower vs runtime). Bugs in specialized layers are often upstream of where they surface.
4. **Implement the correct fix.** For bug fixes, keep edits minimal and scoped. For features, implement completely (see §8) — "minimal" means *no unrelated changes*, never *under-built*. Match existing style; keep imports at the top.
Expand Down
30 changes: 23 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ make proto # regenerate the Go, Java and Python stubs
make proto-buf # Go and Java stubs only
make python-proto # Python stubs only (needs grpcio-tools; PYTHON=... picks the interpreter)
make proto-lint # lint the schema, as CI does
make proto-breaking # reject wire-breaking changes against main, as CI does
make proto-breaking # reject wire-breaking changes against develop, as CI does

# Python gRPC bindings
make python-install # install opensysml package
Expand Down Expand Up @@ -144,14 +144,26 @@ docs: update Quick Start guide with new commands
test(semantics): add conformance checking test cases
```

## Branches

The repository follows git-flow with two long-lived branches:

- `develop` is the integration branch and the default branch. Every `feature/`, `fix/`, `docs/`,
`ci/` and `test/` branch is cut from `develop`, and its pull request targets `develop`.
- `main` is the release branch. It receives only `release/x.y.z` pull requests (cut from
`develop`, with the changelog fragments folded in) and `hotfix/` pull requests. Release tags —
`v*` and the client package tags — are created on `main`. After a release is tagged, `main`
is merged back into `develop` (a plain merge, no rebase) so hotfixes and the folded changelog
flow down. See [docs/project/releasing.md](docs/project/releasing.md).

## Pull Request Process

1. **Fork** the repository
2. **Create a branch** from `main`: `git checkout -b feat/my-feature`
2. **Create a branch** from `develop`: `git checkout -b feat/my-feature`
3. **Make changes** with clear commit messages
4. **Run tests**: `go test ./...`
5. **Push** to your fork
6. **Open a Pull Request** targeting `main`
6. **Open a Pull Request** targeting `develop`

### PR Guidelines

Expand All @@ -168,14 +180,17 @@ test(semantics): add conformance checking test cases
### Creating a Release

1. **Update version** (if needed in code)
2. **Tag the release:**
2. **Merge the `release/x.y.z` pull request** into `main` (see
[docs/project/releasing.md](docs/project/releasing.md))
3. **Tag the release** on `main`:
```bash
git tag -a v0.1.0 -m "Release v0.1.0: Initial public release"
git push origin v0.1.0
```
3. **CI automatically:**
4. **CI automatically:**
- Builds binaries for all platforms
- Publishes to GitHub Releases
5. **Merge `main` back into `develop`**

### Release Checklist

Expand All @@ -200,7 +215,8 @@ A release is a **PATCH** when everything the previous release accepted still beh
result into the one the Kernel Semantic Library derives; that is compatible and is listed under
*Fixed*.
- No CLI flag, REPL command, RPC or wire field is removed or renamed. The protobuf
wire-compatibility check, `make proto-breaking`, passes.
wire-compatibility check passes against the previous release's schema:
`make proto-breaking BUF_BREAKING_REF=origin/main` on the release branch.

New features, new flags, new capabilities and new wire fields are all patch material.

Expand Down Expand Up @@ -243,7 +259,7 @@ is over-tested rather than untested — teach the script about it, and add a cas

`.circleci/config.yml` runs after a merge and on tags, never on a pull request branch:

**On every push to `main`:**
**On every push to `main` or `develop`:**
- The same suite, gates, client tests and conformance runs as the pull-request workflow, over
the merged tree, plus the host binaries
- SonarCloud scan, fed by the Go and client coverage reports
Expand Down
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ GO_WINRES_VERSION := v0.3.3

# buf drives all protobuf codegen; override BUF to use an already-installed binary.
BUF ?= go run github.com/bufbuild/buf/cmd/buf@$(BUF_VERSION)
# Wire-compatibility baseline: the schema as it stands on the main branch.
BUF_BREAKING_REF ?= origin/main
# Wire-compatibility baseline: the schema as it stands on the develop branch.
BUF_BREAKING_REF ?= origin/develop
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.

# go-winres embeds a VERSIONINFO resource into the Windows binaries (a build
# tool only; nothing of it ships). The .syso it writes carries a _windows_amd64
Expand Down Expand Up @@ -253,7 +253,7 @@ proto-lint: ## Lint the protobuf schema
$(BUF) lint
@echo "✓ Proto lint passed"

proto-breaking: ## Check the protobuf schema for wire-breaking changes against main
proto-breaking: ## Check the protobuf schema for wire-breaking changes against develop
@# An archive, not the .git directory: buf would clone that, which a blobless (CI) checkout cannot serve.
baseline=$$(mktemp -t proto-baseline.XXXXXX) && trap 'rm -f "$$baseline"' EXIT && \
git archive --format=tar -o "$$baseline" '$(BUF_BREAKING_REF)' api/proto && \
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ github.com/Open-MBEE/OpenSysML
- **Grammar source:** OMG pilot Xtext grammars (`SysML.xtext` and `KerMLExpressions`)
- **Spec compliance:** [OMG SysML v2.1 Beta 1 / KerML 1.1](https://www.omg.org/spec/SysML/2.0) (2026-07 release)
- **Standard library:** 94 files from [SysML v2 Pilot Implementation 2026-07](https://github.com/Systems-Modeling/SysML-v2-Pilot-Implementation/releases/tag/2026-07), byte-identical, plus the non-normative `OpenSysML Libraries/OpenSysMLMathFunctions.kerml` extension
- **CI/CD:** GitHub Actions checks pull requests; CircleCI builds and tests `main` and publishes releases from tags
- **CI/CD:** GitHub Actions checks pull requests; CircleCI builds and tests `main` and `develop` and publishes releases from tags

## Releases

Expand Down
4 changes: 4 additions & 0 deletions changes/unreleased/git-flow-branches.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- Development moved to a `develop` integration branch; `main` now carries releases only.
Feature and fix pull requests target `develop`, releases reach `main` through
`release/x.y.z` pull requests and are tagged there, and CircleCI builds and tests both
branches. `make proto-breaking` compares against `origin/develop` by default.
52 changes: 46 additions & 6 deletions docs/project/releasing.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,47 @@ Then check the release-facing text:
and no compliance row claims more than the implementation does. Count first-level subtests:
a case that registers sub-subtests, like `variant_connection_per_owner`, otherwise counts twice.

## The release branch

Day-to-day work merges into `develop`; `main` carries releases only (see
[CONTRIBUTING.md § Branches](../../CONTRIBUTING.md#branches)). A release is a
branch that moves the integration state onto `main`:

1. Cut `release/x.y.z` from `develop`:

```bash
git checkout develop && git pull
git checkout -b release/0.0.5
```

2. Fold the changelog fragments on that branch — `python3 scripts/changelog.py release 0.0.5`,
as [Before tagging](#before-tagging) describes — and commit `CHANGELOG.md` together with the
deleted fragments. Anything else the release needs (a version string in code, a doc that
names the version) lands here too; a feature does not. Check the wire compatibility
against the released schema, not the branch's own source:
`make proto-breaking BUF_BREAKING_REF=origin/main` (the default baseline is
`origin/develop`; the pull-request workflow uses the base branch, so the PR to `main`
makes the same comparison).

3. Open a pull request from `release/x.y.z` to `main` and merge it once the
pull-request workflow is green. Merging into `main` runs CircleCI's
`build-test` workflow over the merged tree.

4. Tag `main` as [Tagging](#tagging) describes.

5. Merge `main` back into `develop` — a plain merge, no rebase — so the folded
changelog, and any hotfix that landed on `main` in the meantime, flow down:

```bash
git checkout develop && git pull
git merge main
git push origin develop
```

A `hotfix/` branch follows the same path from `main`: cut from `main`, pull
request to `main` (`make proto-breaking BUF_BREAKING_REF=origin/main` locally, as above),
tag, merge back into `develop`.

## Tagging

The tag is the version: CircleCI passes `CIRCLE_TAG` to the build as
Expand All @@ -83,12 +124,11 @@ git tag -a v0.0.5 -m "v0.0.5"
git push origin v0.0.5
```

The tag belongs on the repository the releases live on. v0.0.1–v0.0.7 are
releases of `Open-MBEE/OpenSysML`, while development happens on
`JPL-Devin/OpenSysML`, which has no tags at all — so cutting a release means
promoting `main` upstream first (v0.0.4 came through Open-MBEE PR #47) and
tagging there. Tagging the development repository would build a release nobody
consumes.
The tag belongs on `Open-MBEE/OpenSysML`, the repository the releases live on
and where development happens: every release from v0.0.1 on is tagged on its
`main`. The clients resolve releases from that repository
(`DEFAULT_GITHUB_REPO` in `clients/python/opensysml/binary.py`), so a tag pushed
to a fork builds a release nobody consumes.

Tags are matched by `/^v.*/` in `.circleci/config.yml`. A tag on a commit that
fails the suite fails the release workflow before anything is published.
Expand Down
Loading