From e064bfa5f21d56844c04b13b4e2372e155669d54 Mon Sep 17 00:00:00 2001 From: Tommy Hughes Date: Thu, 13 Aug 2026 10:43:16 -0500 Subject: [PATCH 1/5] OSAC-4006: Relocate protobuf-conventions rule to fulfillment-service scope, sync cli-ux verb list Add .claude/rules/protobuf-conventions.md at fulfillment-service scope (was workspace-only in osac-workspace despite being fulfillment-service- specific content) as a short pointer to AGENTS.md's API Design Guidelines and docs/API.md, rather than a restatement. Fix cli-ux.md's stale/inaccurate verb list and path qualifier: - Add the missing scale/tenant verbs (both real internal/cmd/cli/ subcommands, already present in osac-workspace's soon-to-be-retired copy). - Remove lookup, which was wrong in *both* copies -- verified against root_cmd.go's actual AddCommand calls and a real `--help` run: lookup.Find() is an internal helper consumed by scale/get/describe, never a registered top-level command. - Correct the intro line's path qualifier to a bare internal/cmd/cli/, appropriate for a file that already lives inside fulfillment-service. Assisted-by: Claude Code Signed-off-by: Tommy Hughes --- .../.claude/rules/protobuf-conventions.md | 11 +++++++++++ .../internal/cmd/cli/.claude/rules/cli-ux.md | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 fulfillment-service/.claude/rules/protobuf-conventions.md diff --git a/fulfillment-service/.claude/rules/protobuf-conventions.md b/fulfillment-service/.claude/rules/protobuf-conventions.md new file mode 100644 index 0000000000..0428ce152f --- /dev/null +++ b/fulfillment-service/.claude/rules/protobuf-conventions.md @@ -0,0 +1,11 @@ +# Protocol Buffer Conventions + +See [AGENTS.md § API Design Guidelines](../../AGENTS.md#api-design-guidelines) before adding or modifying any `.proto` file — [`docs/API.md`](../../docs/API.md) is the authoritative source for all API conventions (object structure, naming, services, request/response patterns, REST transcoding, enums, conditions, references, and documentation requirements). + +OSAC follows [Kubernetes API conventions](https://github.com/kubernetes/community/blob/main/contributors/devel/sig-architecture/api-conventions.md) adapted for protobuf. + +## Workflow + +- Always run `buf lint` before committing proto changes +- Regenerate code by running `buf generate` after proto changes +- `SERVICE_SUFFIX` lint rule is intentionally excluded in `buf.yaml` diff --git a/fulfillment-service/internal/cmd/cli/.claude/rules/cli-ux.md b/fulfillment-service/internal/cmd/cli/.claude/rules/cli-ux.md index 980eed004a..6c4d80adbc 100644 --- a/fulfillment-service/internal/cmd/cli/.claude/rules/cli-ux.md +++ b/fulfillment-service/internal/cmd/cli/.claude/rules/cli-ux.md @@ -1,6 +1,6 @@ # CLI UX Guidelines -The OSAC CLI is a tenant-facing tool for managing infrastructure resources. It is NOT a Kubernetes admin tool - end users should not need to know k8s. +The OSAC CLI (`internal/cmd/cli/`) is a tenant-facing tool for managing infrastructure resources. It is NOT a Kubernetes admin tool - end users should not need to know k8s. ## Design Inspiration @@ -10,7 +10,7 @@ The OSAC CLI is a tenant-facing tool for managing infrastructure resources. It i ## Existing Verbs -`create`, `get`, `describe`, `edit`, `delete`, `annotate`, `label`, `login`, `logout`, `lookup`, `console`, `whoami`, `version` +`create`, `get`, `describe`, `edit`, `delete`, `annotate`, `label`, `login`, `logout`, `console`, `scale`, `tenant`, `whoami`, `version` ## When Adding New CLI Commands From dd93a7cbfcaa4176df25eb48d16ffe8fa48ef1c8 Mon Sep 17 00:00:00 2001 From: Tommy Hughes Date: Thu, 13 Aug 2026 11:53:02 -0500 Subject: [PATCH 2/5] OSAC-4006: fold protobuf-conventions.md into AGENTS.md, add cli-ux.md pointer Review follow-up: fulfillment-service/.claude/rules/protobuf-conventions.md turned out to be almost entirely redundant with AGENTS.md once cross-checked line by line -- its buf-lint reminder was stale (AGENTS.md already documents the correct `uv run dev.py lint proto` invocation, which is what CodeRabbit's review flagged this file for missing), its SERVICE_SUFFIX note was already verbatim in AGENTS.md, and its AGENTS.md/docs/API.md pointer duplicated a path this repo's own "Where to Find Information" table already provides directly. The one non-duplicated sentence (OSAC's protobuf conventions being adapted from the Kubernetes API conventions doc) is folded into AGENTS.md's existing "API Design Guidelines" section instead of keeping a second, driftable copy. cli-ux.md is the opposite case -- it holds real, non-duplicated CLI design guidance -- but was missing from AGENTS.md's "Where to Find Information" table entirely, so nothing pointed an agent at it. Added that entry. Assisted-by: Claude Code Signed-off-by: Tommy Hughes --- .../.claude/rules/protobuf-conventions.md | 11 ----------- fulfillment-service/AGENTS.md | 5 ++++- 2 files changed, 4 insertions(+), 12 deletions(-) delete mode 100644 fulfillment-service/.claude/rules/protobuf-conventions.md diff --git a/fulfillment-service/.claude/rules/protobuf-conventions.md b/fulfillment-service/.claude/rules/protobuf-conventions.md deleted file mode 100644 index 0428ce152f..0000000000 --- a/fulfillment-service/.claude/rules/protobuf-conventions.md +++ /dev/null @@ -1,11 +0,0 @@ -# Protocol Buffer Conventions - -See [AGENTS.md § API Design Guidelines](../../AGENTS.md#api-design-guidelines) before adding or modifying any `.proto` file — [`docs/API.md`](../../docs/API.md) is the authoritative source for all API conventions (object structure, naming, services, request/response patterns, REST transcoding, enums, conditions, references, and documentation requirements). - -OSAC follows [Kubernetes API conventions](https://github.com/kubernetes/community/blob/main/contributors/devel/sig-architecture/api-conventions.md) adapted for protobuf. - -## Workflow - -- Always run `buf lint` before committing proto changes -- Regenerate code by running `buf generate` after proto changes -- `SERVICE_SUFFIX` lint rule is intentionally excluded in `buf.yaml` diff --git a/fulfillment-service/AGENTS.md b/fulfillment-service/AGENTS.md index 8a65d76f06..34e1b32773 100644 --- a/fulfillment-service/AGENTS.md +++ b/fulfillment-service/AGENTS.md @@ -19,6 +19,7 @@ This file contains only frequently-needed commands and non-obvious rules. For de - Public/private server delegation - Builder pattern for server configuration - **Testing patterns**: See `*_suite_test.go` files for Ginkgo/Gomega setup +- **CLI design guidelines**: [`internal/cmd/cli/.claude/rules/cli-ux.md`](internal/cmd/cli/.claude/rules/cli-ux.md) - **Dev tooling**: [dev/README.md](dev/README.md) for extending `dev.py` - **Linter configuration**: - Go: `.golangci.yml` @@ -241,7 +242,9 @@ Before making any API design or implementation decision (adding or modifying `.p services, messages, or REST transcoding), read [docs/API.md](docs/API.md). That document contains the full set of conventions and rules for the API, including object structure, naming, services, request/response patterns, REST transcoding, enums, conditions, object references, and -documentation requirements. +documentation requirements. OSAC follows [Kubernetes API +conventions](https://github.com/kubernetes/community/blob/main/contributors/devel/sig-architecture/api-conventions.md) +adapted for protobuf. ## Validation Constraints From ce86bf16109526664db767f83ac6e9537010fc8f Mon Sep 17 00:00:00 2001 From: Tommy Hughes Date: Thu, 13 Aug 2026 12:01:22 -0500 Subject: [PATCH 3/5] OSAC-4006: fix broken bare buf-lint hooks in fulfillment-service settings.json While checking fulfillment-service's broader .claude/ surface for conflicts with the cli-ux.md AGENTS.md pointer, found both Claude Code hooks in .claude/settings.json invoke bare `buf lint` -- the same staleness bug CodeRabbit caught in docs (dd93a7cb), except here it's an executable automation that actually breaks: $ buf lint Failure: plugin "bin/buf-plugin-osac-lint" failed: fork/exec bin/buf-plugin-osac-lint: no such file or directory buf.yaml's OSAC_OBJECT_SHAPE lint rule requires bin/buf-plugin-osac-lint, which only `uv run dev.py lint proto` builds first. Both hooks (auto-lint after editing a .proto file, and the git-commit/gh-pr-create pre-flight gate) would fail on a fresh checkout, or any time the plugin binary is stale/absent. Swapped both to `uv run dev.py lint proto`, matching AGENTS.md, the pre-commit config, and every other correct reference to this command. Verified: `uv run dev.py lint proto` now exits 0. Assisted-by: Claude Code Signed-off-by: Tommy Hughes --- fulfillment-service/.claude/settings.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fulfillment-service/.claude/settings.json b/fulfillment-service/.claude/settings.json index b7ee533a50..c0ac1865a5 100644 --- a/fulfillment-service/.claude/settings.json +++ b/fulfillment-service/.claude/settings.json @@ -6,7 +6,7 @@ "hooks": [ { "type": "command", - "command": "file_path=$(cat - | jq -r '.tool_input.file_path // .tool_input.filePath // empty') && case \"$file_path\" in *.proto) cd \"$CLAUDE_PROJECT_DIR\" && buf lint && buf generate ;; *go.mod) cd \"$CLAUDE_PROJECT_DIR\" && go mod tidy ;; esac" + "command": "file_path=$(cat - | jq -r '.tool_input.file_path // .tool_input.filePath // empty') && case \"$file_path\" in *.proto) cd \"$CLAUDE_PROJECT_DIR\" && uv run dev.py lint proto && buf generate ;; *go.mod) cd \"$CLAUDE_PROJECT_DIR\" && go mod tidy ;; esac" } ] } @@ -17,7 +17,7 @@ "hooks": [ { "type": "command", - "command": "cmd=$(cat - | jq -r '.tool_input.command // empty') && case \"$cmd\" in *'git commit'*) cd \"$CLAUDE_PROJECT_DIR\" && buf lint ;; *'gh pr create'*) cd \"$CLAUDE_PROJECT_DIR\" && gofmt -s -w . && test -z \\\"$(git diff --name-only)\\\" && buf lint && ginkgo run -r internal ;; esac" + "command": "cmd=$(cat - | jq -r '.tool_input.command // empty') && case \"$cmd\" in *'git commit'*) cd \"$CLAUDE_PROJECT_DIR\" && uv run dev.py lint proto ;; *'gh pr create'*) cd \"$CLAUDE_PROJECT_DIR\" && gofmt -s -w . && test -z \\\"$(git diff --name-only)\\\" && uv run dev.py lint proto && ginkgo run -r internal ;; esac" } ] } From e53879b0ad85b9a5a6037005cbcf9059e4e8eec7 Mon Sep 17 00:00:00 2001 From: Tommy Hughes Date: Thu, 13 Aug 2026 12:13:36 -0500 Subject: [PATCH 4/5] OSAC-4006: fix over-escaped quoting in fulfillment-service settings.json PR-create gate While actually simulating the settings.json hooks end-to-end (piping realistic Claude Code stdin payloads through the exact extracted command strings, per review feedback -- the prior commit had only tested the underlying `uv run dev.py lint proto` command in isolation, not the hook script itself), found the gh-pr-create branch's git-diff empty-check was broken independently of the buf-lint issue: test -z \"$(git diff --name-only)\" decodes (after JSON unescaping) to a literal backslash+quote around the substitution, i.e. `test -z '""'` at runtime -- a 2-character string, never empty, so this check always fails regardless of whether gofmt actually changed anything: $ bash -x -c 'test -z \"$(git diff --name-only)\"' + test -z '""' (exit 1, always, even on a clean tree) Fixed to single-escaped `\"..\"`, matching every other quoted variable reference in this same file. Verified end-to-end by extracting the live command from settings.json and piping realistic PostToolUse/PreToolUse JSON payloads through it: .proto edit -> lint+generate (exit 0), go.mod edit -> go mod tidy (exit 0), unrelated file/command -> no-op (exit 0), git-commit command -> lint proto (exit 0), gh-pr-create command on a clean tree -> gate passes and proceeds to ginkgo (verified via bash -x trace reaching that point, not run to completion given repo-wide test runtime). Assisted-by: Claude Code Signed-off-by: Tommy Hughes --- fulfillment-service/.claude/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fulfillment-service/.claude/settings.json b/fulfillment-service/.claude/settings.json index c0ac1865a5..46b909a2ac 100644 --- a/fulfillment-service/.claude/settings.json +++ b/fulfillment-service/.claude/settings.json @@ -17,7 +17,7 @@ "hooks": [ { "type": "command", - "command": "cmd=$(cat - | jq -r '.tool_input.command // empty') && case \"$cmd\" in *'git commit'*) cd \"$CLAUDE_PROJECT_DIR\" && uv run dev.py lint proto ;; *'gh pr create'*) cd \"$CLAUDE_PROJECT_DIR\" && gofmt -s -w . && test -z \\\"$(git diff --name-only)\\\" && uv run dev.py lint proto && ginkgo run -r internal ;; esac" + "command": "cmd=$(cat - | jq -r '.tool_input.command // empty') && case \"$cmd\" in *'git commit'*) cd \"$CLAUDE_PROJECT_DIR\" && uv run dev.py lint proto ;; *'gh pr create'*) cd \"$CLAUDE_PROJECT_DIR\" && gofmt -s -w . && test -z \"$(git diff --name-only)\" && uv run dev.py lint proto && ginkgo run -r internal ;; esac" } ] } From b797c1b0f43b57041c19fef8b1d99bd392ee0d59 Mon Sep 17 00:00:00 2001 From: Tommy Hughes Date: Thu, 13 Aug 2026 13:07:59 -0500 Subject: [PATCH 5/5] OSAC-4006: Fix stale bare buf lint references in AGENTS.md AGENTS.md's quick-reference block, Linting and Code Generation section, and two proto-change reminders still told readers to run bare `buf lint`, which fails without first building bin/buf-plugin-osac-lint (the same staleness bug already fixed in .claude/settings.json's hooks and the now-deleted protobuf-conventions.md). The Automated Hooks section already correctly referenced `uv run dev.py lint proto`, so these were an internal inconsistency within the same file. Point all four at the working command. Assisted-by: Claude Code Signed-off-by: Tommy Hughes --- fulfillment-service/AGENTS.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fulfillment-service/AGENTS.md b/fulfillment-service/AGENTS.md index 34e1b32773..069ee963f8 100644 --- a/fulfillment-service/AGENTS.md +++ b/fulfillment-service/AGENTS.md @@ -63,7 +63,7 @@ ginkgo run -r internal --skip="database" uv run dev.py lint # Proto: lint and generate -buf lint +uv run dev.py lint proto buf generate # Run all tests including integration (requires kind cluster) @@ -98,7 +98,7 @@ Requires `/etc/hosts` entries: uv run dev.py lint # Lint proto files -buf lint +uv run dev.py lint proto # Generate Go code from proto buf generate @@ -113,7 +113,7 @@ uv run ruff check go mod tidy ``` -**CRITICAL**: Always run `buf lint && buf generate` after any `.proto` file change. Generated code lands in `internal/api/` (never edit manually). Buf is installed via `buf-action` in CI (see the root-level `.github/workflows/check-pull-request.yaml`); for local use, install buf separately following the [official installation guide](https://buf.build/docs/installation). +**CRITICAL**: Always run `uv run dev.py lint proto && buf generate` after any `.proto` file change. Generated code lands in `internal/api/` (never edit manually). Buf is installed via `buf-action` in CI (see the root-level `.github/workflows/check-pull-request.yaml`); for local use, install buf separately following the [official installation guide](https://buf.build/docs/installation). For extending `dev.py` with new commands, see [dev/README.md](dev/README.md). @@ -277,7 +277,7 @@ To override embedded message validation (e.g., Projects allowing dots in names w Do not implement validation in Go code that can be expressed declaratively in proto. -As with any proto change, run `buf lint && buf generate` afterward (see [Linting and Code Generation](#linting-and-code-generation)). +As with any proto change, run `uv run dev.py lint proto && buf generate` afterward (see [Linting and Code Generation](#linting-and-code-generation)). ## Common Pitfalls @@ -286,7 +286,7 @@ As with any proto change, run `buf lint && buf generate` afterward (see [Linting - CI timeout: 1 hour for unit and integration test runs - Integration test logs uploaded as `logs-helm` and `logs-kustomize` artifacts (always, even on failure) -See [Linting and Code Generation](#linting-and-code-generation) for the required `buf lint && buf generate` step, and [Files Requiring Extra Caution](#files-requiring-extra-caution) for generated paths that must never be hand-edited. +See [Linting and Code Generation](#linting-and-code-generation) for the required `uv run dev.py lint proto && buf generate` step, and [Files Requiring Extra Caution](#files-requiring-extra-caution) for generated paths that must never be hand-edited. ## Files Requiring Extra Caution