From 58cd23c74149bf2e8955a5824d173f2aaac01436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=A0=CF=85=CE=B1=CE=B7=20=D7=A0=CF=85=CE=B1=CE=B7=D1=95?= =?UTF-8?q?=CF=83=CE=B7?= Date: Sat, 15 Aug 2026 10:51:10 -0700 Subject: [PATCH 1/8] refactor: consume the flat go module Renames go:: call sites to go- across the justfile, both workflows, CLAUDE.md and the docs site, and imports go/go.just instead of loading go.mod.just. This is what makes osapi's coverage target take effect. Its `export JUST_COVERAGE_TARGET := "99.9"` never reached the shim module -- env() resolves against the process environment at parse time -- so osapi ran against the default 100 and passed only because `go tool cover -func` rounds its 99.9359% to 100.0%. With a flat import the consumer assigns go_coverage_target directly: `just go-unit-cov-check` now reports "meets target 99.9%". Depends on osapi-justfiles#46. Co-Authored-By: Claude Opus 5 (1M context) --- .github/codecov.yml | 6 +++--- .github/workflows/go-int.yml | 4 ++-- .github/workflows/go.yml | 4 ++-- CLAUDE.md | 16 +++++++------- docs/docs/sidebar/development/development.md | 12 +++++------ docs/docs/sidebar/development/testing.md | 8 +++---- .../sidebar/development/ui-development.md | 2 +- justfile | 21 ++++++++++--------- 8 files changed, 37 insertions(+), 36 deletions(-) diff --git a/.github/codecov.yml b/.github/codecov.yml index d27eaa4ee..046d86e02 100644 --- a/.github/codecov.yml +++ b/.github/codecov.yml @@ -1,7 +1,7 @@ --- # Coverage target for this repository. # -# `target: 99.9%` is declared again as JUST_COVERAGE_TARGET in this repository's +# `target: 99.9%` is declared again as `go_coverage_target` in this repository's # justfile, which overrides the org-wide default of 100 from the shared go # module. osapi has 9 uncovered statements across 7 functions (99.9359%); raise # both to 100 once they are covered. Neither system can read the other's config, @@ -9,12 +9,12 @@ # # The threshold absorbs rounding, not regression. With precision 2 and round # down, a change in statement count can shift the reported figure and fail the -# status on an artifact. `just go::unit-cov-check` is the exact check; this +# status on an artifact. `just go-unit-cov-check` is the exact check; this # tolerance exists so Codecov's own rounding does not report a failure the # coverage does not have. # # There is deliberately no `ignore:` list. Exclusions are defined once in -# .coverignore and applied by `just go::unit-cov` before the profile is +# .coverignore and applied by `just go-unit-cov` before the profile is # uploaded, so excluded files never reach Codecov. A second list here would be # free to drift from that one. coverage: diff --git a/.github/workflows/go-int.yml b/.github/workflows/go-int.yml index 970eb8c57..f2cf38bae 100644 --- a/.github/workflows/go-int.yml +++ b/.github/workflows/go-int.yml @@ -28,11 +28,11 @@ jobs: run: just fetch - name: Deps run: | - just go::deps + just go-deps just react-deps - name: Build UI run: just react-build - name: Linux tuning run: just linux-tune - name: Integration - run: just go::unit-int + run: just go-unit-int diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 2a1666731..3ea30922e 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -28,8 +28,8 @@ jobs: run: just fetch - name: Deps run: | - just go::deps - just go::mod + just go-deps + just go-mod just react-deps - name: Test run: just test diff --git a/CLAUDE.md b/CLAUDE.md index 3fdb54417..aeea9d6b7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -26,10 +26,10 @@ Quick reference for common commands: just deps # Install all dependencies just build # Build production binary (React UI + Go) just test # Run all tests (lint + unit + coverage) -just go::unit # Run unit tests only -just go::unit-int # Run integration tests (requires running osapi) -just go::vet # Run golangci-lint -just go::fmt # Auto-format (gofumpt + golines) +just go-unit # Run unit tests only +just go-unit-int # Run integration tests (requires running osapi) +just go-vet # Run golangci-lint +just go-fmt # Auto-format (gofumpt + golines) go test -run TestName -v ./internal/job/... # Run a single test just react-dev # Start UI dev server (http://localhost:5173) @@ -772,8 +772,8 @@ service. Follow the same principles as the orchestrator examples: ```bash just generate # regenerate specs + code go build ./... # compiles -just go::unit # tests pass -just go::vet # lint passes +just go-unit # tests pass +just go-vet # lint passes ``` ## Code Standards (MANDATORY) @@ -793,12 +793,12 @@ func FunctionName( Three test layers: - **Unit tests** (`*_test.go`, `*_public_test.go`) — fast, mocked - dependencies, run with `just go::unit`. Includes `TestXxxHTTP` / + dependencies, run with `just go-unit`. Includes `TestXxxHTTP` / `TestXxxRBACHTTP` methods that send raw HTTP through real Echo middleware with mocked backends. - **Integration tests** (`test/integration/`) — build and start a real `osapi` binary, exercise CLI commands end-to-end. Guarded by - `//go:build integration` tag, run with `just go::unit-int`. New API + `//go:build integration` tag, run with `just go-unit-int`. New API domains should include a `{domain}_test.go` smoke suite. Write tests (mutations) must be guarded by `skipWrite(s.T())` so CI can run read-only tests by default (`OSAPI_INTEGRATION_WRITES=1` enables diff --git a/docs/docs/sidebar/development/development.md b/docs/docs/sidebar/development/development.md index b6a5aa926..a289da270 100644 --- a/docs/docs/sidebar/development/development.md +++ b/docs/docs/sidebar/development/development.md @@ -58,9 +58,9 @@ Go code should be formatted by [`gofumpt`][gofumpt] and linted using formatted and linted by [Prettier][]. This style is enforced by CI. ```bash -just go::fmt-check # Check formatting -just go::fmt # Auto-fix formatting -just go::vet # Run linter +just go-fmt-check # Check formatting +just go-fmt # Auto-fix formatting +just go-vet # Run linter ``` ## Running your changes @@ -106,15 +106,15 @@ recipes. ```bash just test # Run all tests (lint + unit + coverage) -just go::unit # Run unit tests only -just go::unit-int # Run integration tests (requires running osapi) +just go-unit # Run unit tests only +just go-unit-int # Run integration tests (requires running osapi) ``` Coverage is gated at 99.9%. `just test` fails if total coverage drops below it, so a change that adds untested code fails locally and in CI: ```bash -just go::unit-cov-check # Report coverage and fail below the target +just go-unit-cov-check # Report coverage and fail below the target ``` The target is declared in `.github/codecov.yml` and in the shared `go` justfile diff --git a/docs/docs/sidebar/development/testing.md b/docs/docs/sidebar/development/testing.md index c81a09267..a1e97b7b8 100644 --- a/docs/docs/sidebar/development/testing.md +++ b/docs/docs/sidebar/development/testing.md @@ -15,8 +15,8 @@ $ just deps Unit tests run with mocked dependencies and require no external services: ```bash -$ just go::unit # Run unit tests -$ just go::unit-cov # Run with coverage report +$ just go-unit # Run unit tests +$ just go-unit-cov # Run with coverage report $ just test # Run all checks (lint + unit + coverage) ``` @@ -33,7 +33,7 @@ API server, agent), and exercise CLI commands end-to-end. They are guarded by a `//go:build integration` tag and located in `test/integration/`: ```bash -$ just go::unit-int # Run integration tests +$ just go-unit-int # Run integration tests ``` The test harness allocates random ports, generates a JWT, and starts the server @@ -45,7 +45,7 @@ commands with `--json` output. Auto format code: ```bash -$ just go::fmt +$ just go-fmt ``` ## Listing Recipes diff --git a/docs/docs/sidebar/development/ui-development.md b/docs/docs/sidebar/development/ui-development.md index f8627092f..ce7f6c481 100644 --- a/docs/docs/sidebar/development/ui-development.md +++ b/docs/docs/sidebar/development/ui-development.md @@ -70,7 +70,7 @@ just build ``` This is the top-level build recipe. It runs `just react-build` first (to -populate `ui/dist/` with static assets), then `just go::build` to produce the Go +populate `ui/dist/` with static assets), then `just go-build` to produce the Go binary with the assets embedded via the `//go:embed` directive in `ui/embed.go`. The controller API serves these assets at runtime from the embedded filesystem — no separate web server is required. diff --git a/justfile b/justfile index e53e7f32c..cdbd6d851 100644 --- a/justfile +++ b/justfile @@ -1,3 +1,5 @@ +set allow-duplicate-variables := true + # Optional modules: mod? allows `just fetch` to work before .just/remote/ exists. # Recipes below use `just` subcommands instead of dependency syntax because just @@ -6,13 +8,13 @@ # statements across 7 functions (99.9359%). Raise to 100 once they are covered; # this holds the current level so it cannot decay in the meantime. Mirrored in # .github/codecov.yml — change both together. -export JUST_COVERAGE_TARGET := "99.9" +go_coverage_target := "99.9" # The React application lives in ui/, not at the repository root. The flat # react module requires the importing justfile to declare it. react_dir := "ui" -mod? go '.just/remote/go.mod.just' +import? '.just/remote/go.just' mod? docs '.just/remote/docs.mod.just' mod? just '.just/remote/just.mod.just' mod? docker '.just/remote/docker.mod.just' @@ -24,8 +26,7 @@ import? '.just/remote/react.just' # Fetch shared justfiles from osapi-justfiles fetch: mkdir -p .just/remote - curl -sSfL https://raw.githubusercontent.com/osapi-io/osapi-justfiles/refs/heads/main/go.mod.just -o .just/remote/go.mod.just - curl -sSfL https://raw.githubusercontent.com/osapi-io/osapi-justfiles/refs/heads/main/go.just -o .just/remote/go.just + curl -sSfL https://raw.githubusercontent.com/osapi-io/osapi-justfiles/refs/heads/main/go/go.just -o .just/remote/go.just curl -sSfL https://raw.githubusercontent.com/osapi-io/osapi-justfiles/refs/heads/main/docs.mod.just -o .just/remote/docs.mod.just curl -sSfL https://raw.githubusercontent.com/osapi-io/osapi-justfiles/refs/heads/main/docs.just -o .just/remote/docs.just curl -sSfL https://raw.githubusercontent.com/osapi-io/osapi-justfiles/refs/heads/main/just.mod.just -o .just/remote/just.mod.just @@ -38,8 +39,8 @@ fetch: # Install all dependencies deps: - just go::deps - just go::mod + just go-deps + just go-mod just docs::deps just react-deps @@ -52,12 +53,12 @@ build: test: linux-tune just just::fmt-check just react-build - just go::test + just go-test # Generate code generate: redocly join --prefix-tags-with-info-prop title -o internal/controller/api/gen/api.yaml internal/controller/api/*/gen/api.yaml internal/controller/api/node/*/gen/api.yaml - just go::generate + just go-generate just docs::generate cp internal/controller/api/gen/api.yaml ui/src/sdk/gen/api.yaml just react-generate @@ -67,8 +68,8 @@ ready: just generate just just::fmt just docs::fmt - just go::fmt - just go::vet + just go-fmt + just go-vet just react-fmt just react-lint just react-build From 7e41c50ef3c487fbd6e18c6b6fcca9589393e19b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=A0=CF=85=CE=B1=CE=B7=20=D7=A0=CF=85=CE=B1=CE=B7=D1=95?= =?UTF-8?q?=CF=83=CE=B7?= Date: Sat, 15 Aug 2026 11:10:18 -0700 Subject: [PATCH 2/8] fix: declare the coverage target in the justfile The go module no longer ships a default, so the consuming justfile declares go_coverage_target. Drops set allow-duplicate-variables, which osapi-io/specs now forbids: it suspends the duplicate check for every variable in the file to override one. Co-Authored-By: Claude Opus 5 (1M context) --- justfile | 12 +++++++----- ui/justfile | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/justfile b/justfile index cdbd6d851..df9a0330b 100644 --- a/justfile +++ b/justfile @@ -1,20 +1,22 @@ -set allow-duplicate-variables := true - # Optional modules: mod? allows `just fetch` to work before .just/remote/ exists. # Recipes below use `just` subcommands instead of dependency syntax because just - # validates dependencies at parse time, which would fail when modules aren't loaded. # Coverage target. Below the org-wide 100% because osapi has 9 uncovered # statements across 7 functions (99.9359%). Raise to 100 once they are covered; # this holds the current level so it cannot decay in the meantime. Mirrored in # .github/codecov.yml — change both together. -go_coverage_target := "99.9" - # The React application lives in ui/, not at the repository root. The flat # react module requires the importing justfile to declare it. + react_dir := "ui" +# Minimum total coverage. Declared again in .github/codecov.yml — +# change both together. + +go_coverage_target := "99.9" + import? '.just/remote/go.just' + mod? docs '.just/remote/docs.mod.just' mod? just '.just/remote/just.mod.just' mod? docker '.just/remote/docker.mod.just' diff --git a/ui/justfile b/ui/justfile index ef9507c88..98c252fea 100644 --- a/ui/justfile +++ b/ui/justfile @@ -1,4 +1,5 @@ # The React application is this directory. + react_dir := "." # Optional modules: mod? allows `just fetch` to work before .just/remote/ exists. From 09df9a8817cd2f363ff96f0368adf773ecfcce71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=A0=CF=85=CE=B1=CE=B7=20=D7=A0=CF=85=CE=B1=CE=B7=D1=95?= =?UTF-8?q?=CF=83=CE=B7?= Date: Sat, 15 Aug 2026 11:17:38 -0700 Subject: [PATCH 3/8] fix: tidy the justfile variable declarations Earlier edits left the old JUST_COVERAGE_TARGET comment orphaned above react_dir, describing a variable that no longer exists, and a second comment for the same thing below it. One comment each, and the coverage note now says why osapi sits below 100%: the nine uncovered statements are unreachable guards, not missing tests. Co-Authored-By: Claude Opus 5 (1M context) --- justfile | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/justfile b/justfile index df9a0330b..f007f8b71 100644 --- a/justfile +++ b/justfile @@ -1,17 +1,14 @@ # Optional modules: mod? allows `just fetch` to work before .just/remote/ exists. # Recipes below use `just` subcommands instead of dependency syntax because just # validates dependencies at parse time, which would fail when modules aren't loaded. -# Coverage target. Below the org-wide 100% because osapi has 9 uncovered -# statements across 7 functions (99.9359%). Raise to 100 once they are covered; -# this holds the current level so it cannot decay in the meantime. Mirrored in -# .github/codecov.yml — change both together. # The React application lives in ui/, not at the repository root. The flat # react module requires the importing justfile to declare it. react_dir := "ui" -# Minimum total coverage. Declared again in .github/codecov.yml — -# change both together. +# Minimum total coverage. Below the org-wide 100% because nine statements are +# unreachable guards that cannot execute. Declared again in .github/codecov.yml +# — change both together. go_coverage_target := "99.9" From 8a2e2332601535ef735193ee6b6ade08a65c798c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=A0=CF=85=CE=B1=CE=B7=20=D7=A0=CF=85=CE=B1=CE=B7=D1=95?= =?UTF-8?q?=CF=83=CE=B7?= Date: Sat, 15 Aug 2026 12:28:01 -0700 Subject: [PATCH 4/8] refactor: reassign module defaults Sets allow-duplicate-variables so the react and go module defaults can be reassigned: react_dir to ui, go_coverage_target to 99.9. Verified all three invocation styles agree -- run by name, reached through another recipe, and overridden on the command line. Co-Authored-By: Claude Opus 5 (1M context) --- justfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/justfile b/justfile index f007f8b71..08ac67b4e 100644 --- a/justfile +++ b/justfile @@ -1,8 +1,10 @@ +set allow-duplicate-variables := true + # Optional modules: mod? allows `just fetch` to work before .just/remote/ exists. # Recipes below use `just` subcommands instead of dependency syntax because just # validates dependencies at parse time, which would fail when modules aren't loaded. -# The React application lives in ui/, not at the repository root. The flat -# react module requires the importing justfile to declare it. +# The React application lives in ui/, not at the repository root, so the react +# module's default of "." is reassigned above the import. react_dir := "ui" From 6884de6ad6514f81e0d09e81b631c8611c65dc33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=A0=CF=85=CE=B1=CE=B7=20=D7=A0=CF=85=CE=B1=CE=B7=D1=95?= =?UTF-8?q?=CF=83=CE=B7?= Date: Sat, 15 Aug 2026 12:32:29 -0700 Subject: [PATCH 5/8] fix: format the setting the way current just writes it just 1.58 formats a boolean setting as `set allow-duplicate-variables` and 1.45 formats it as `set allow-duplicate-variables := true`. There is no form both accept: each rejects the other's. CI runs the newer one, so the file matches it. Both run it identically -- the override resolves to 99.9 under either. Co-Authored-By: Claude Opus 5 (1M context) --- justfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/justfile b/justfile index 08ac67b4e..199872176 100644 --- a/justfile +++ b/justfile @@ -1,4 +1,4 @@ -set allow-duplicate-variables := true +set allow-duplicate-variables # Optional modules: mod? allows `just fetch` to work before .just/remote/ exists. # Recipes below use `just` subcommands instead of dependency syntax because just From af72cfcd926cb9b774db3b2daf94c5272370aa48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=A0=CF=85=CE=B1=CE=B7=20=D7=A0=CF=85=CE=B1=CE=B7=D1=95?= =?UTF-8?q?=CF=83=CE=B7?= Date: Sat, 15 Aug 2026 12:37:04 -0700 Subject: [PATCH 6/8] ci: record the just version Applies standardize-repository-layout task 5.1a. .mise.toml can only declare a version that matches CI once we know what the setup action installs, and nothing prints it today. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/just-lint.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/just-lint.yml b/.github/workflows/just-lint.yml index 74a2ee343..f8f043c72 100644 --- a/.github/workflows/just-lint.yml +++ b/.github/workflows/just-lint.yml @@ -16,5 +16,7 @@ jobs: uses: extractions/setup-just@v4 - name: Fetch justfiles run: just fetch + - name: Record just version + run: just --version - name: Lint justfiles run: just just::fmt-check From 784831fafcf8aef6dcb204237c632c66bdd19d17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=A0=CF=85=CE=B1=CE=B7=20=D7=A0=CF=85=CE=B1=CE=B7=D1=95?= =?UTF-8?q?=CF=83=CE=B7?= Date: Sat, 15 Aug 2026 12:39:03 -0700 Subject: [PATCH 7/8] chore: declare just in .mise.toml just was not declared, so mise had nothing to resolve and the shell fell through to Homebrew 1.45.0 while CI installs 1.58.0. That split is what made this branch fail its justfile format check. 1.58.0 verified from the version step added to just-lint. Applies standardize-repository-layout task 5.1. Co-Authored-By: Claude Opus 5 (1M context) --- .mise.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/.mise.toml b/.mise.toml index 53aecf161..af65944a2 100644 --- a/.mise.toml +++ b/.mise.toml @@ -1,4 +1,5 @@ [tools] go = "1.25" +just = "1.58.0" node = "22" bun = "latest" From 60282e61f3fba7ed549b48779cd03c8250a1fdc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=A0=CF=85=CE=B1=CE=B7=20=D7=A0=CF=85=CE=B1=CE=B7=D1=95?= =?UTF-8?q?=CF=83=CE=B7?= Date: Sat, 15 Aug 2026 12:43:46 -0700 Subject: [PATCH 8/8] chore: float just to latest Nothing maintains a pin in .mise.toml and the workflow setup action floats, so pinning here would diverge at the next release. Both resolve to 1.58.0 today. Co-Authored-By: Claude Opus 5 (1M context) --- .mise.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mise.toml b/.mise.toml index af65944a2..738fa1d27 100644 --- a/.mise.toml +++ b/.mise.toml @@ -1,5 +1,5 @@ [tools] go = "1.25" -just = "1.58.0" +just = "latest" node = "22" bun = "latest"