From f62c67d517ef8fbfe3e4160e721e39ae77400926 Mon Sep 17 00:00:00 2001 From: fullsend-code <278716306+fullsend-ai-coder[bot]@users.noreply.github.com> Date: Fri, 25 Sep 2026 11:09:11 +0000 Subject: [PATCH 1/2] docs: add RHDH domain context to AGENTS.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add version resolution, offline/air-gap, and error handling documentation to Key Conventions. Document the 3-tier version resolution engine and check-versions command in Architecture. Add version-related file references to Pattern References. These additions give the review agent domain context about RHDH release semantics, the RHDH-to-Backstage version mapping model, and the offline vs air-gapped distinction — knowledge gaps that caused the review agent to miss design-level findings on PR #176. Closes #199 Assisted-by: claude-opus-4-6 --- AGENTS.md | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 0bf4a52..ade232a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -38,6 +38,28 @@ import prefix, typescript:S4624 nested template literals) before they accumulate its own `.command('action')` with only the flags that apply to it. See `plugin dev` in `src/commands/index.ts` and `src/commands/dev/` for the reference implementation. +- **RHDH-to-Backstage version mapping**: RHDH versions (e.g. `2.1.0`) are + not Backstage versions. The CLI resolves RHDH versions to Backstage + release versions via a 3-tier strategy: (1) remote metadata from the + RHDH GitHub release branch, (2) a static compatibility matrix + (`RHDH_COMPATIBILITY_MATRIX` in `src/lib/rhdhVersion.ts`), (3) error if + neither resolves. Bare version numbers like `1.54.0` that do not match a + known RHDH release are rejected — users must prefix with `backstage:` to + target a Backstage version directly (e.g. `backstage:1.54.0`). The static + matrix must be updated manually each RHDH release cycle. +- **Offline vs air-gapped**: `RHDH_OFFLINE=true` (or `--offline`) skips + the GitHub metadata lookup (tier 1) and falls back to the static + compatibility matrix (tier 2), but the Backstage release manifest still + fetches from `versions.backstage.io`. For true air-gapped use, users must + also supply `--manifest-file ` (or set `BACKSTAGE_MANIFEST_FILE`) + pointing to a local copy of the Backstage release manifest JSON. +- **Error handling in plugin commands**: Plugin command functions (under + `src/commands/`) signal non-zero exit by throwing `ExitCodeError` from + `src/lib/errors.ts`. The `lazy()` wrapper in `src/commands/index.ts` + catches it and calls `process.exit(error.code)`. This keeps command + functions testable — tests can catch the error without `process.exit()` + killing the test runner. Intent-based action commands use + `handleCommandError` from `intent-errors.ts` instead. ## CLI UX Design Conventions @@ -170,6 +192,58 @@ subprocess error. as symlinks in the staged copy rather than followed, which would cause a self-copy error on repeated `update` runs. +### Version resolution engine + +`src/lib/rhdhVersion.ts` is the core abstraction that maps RHDH version +queries to Backstage release versions and their package manifests. All +commands that depend on a target RHDH version (`check-versions`, `upgrade`, +`new`) call `resolveRhdhVersion()` as their entry point. + +**3-tier resolution:** + +1. **Remote metadata (tier 1)** — fetches `build-metadata.json` from the + RHDH GitHub repository's release branch (e.g. `release-2.0` for RHDH + `2.0.x`). Extracts the Backstage version from the `card` object. + Skipped when `RHDH_OFFLINE=true` or `{ offline: true }`. +2. **Static compatibility matrix (tier 2)** — `RHDH_COMPATIBILITY_MATRIX` + maps known RHDH releases to Backstage versions. Used as fallback when + remote lookup fails, times out, or is skipped. This matrix must be + updated manually each RHDH release cycle. +3. **Backstage release manifest (tier 3)** — once a Backstage version is + determined (by tier 1 or 2), the manifest is fetched from + `versions.backstage.io` (or from `BACKSTAGE_VERSIONS_BASE_URL` / + `--manifest-file`) to get concrete package versions for dependency + alignment. + +**Caching:** Resolved versions are cached by a composite key of +`normalizedVersion + manifestFile + versionsBaseUrl + offline` so +different resolution contexts (e.g. different base URLs) produce +separate cache entries. + +Key files: + +- `src/lib/rhdhVersion.ts` — RHDH version normalization, GitHub ref + mapping, remote metadata fetch, static matrix lookup, and the main + `resolveRhdhVersion` entry point. +- `src/lib/backstageVersion.ts` — Backstage manifest fetching, + `backstage:^` protocol resolution, `backstage.json` version detection. + +### `check-versions` — dependency alignment command + +`src/commands/check-versions/` owns `rhdh-cli plugin check-versions`. It +audits a plugin's `package.json` dependencies against the Backstage release +manifest for a target RHDH version. Dependency status is one of: `match`, +`mismatch`, `unmanifested` (a `@backstage/` package not in the manifest), +or `unverifiable` (`backstage:^` peer dependencies that cannot be resolved +without `backstage.json`). + +Key files: + +- `command.ts` — `checkPluginDependencies()` audit logic, human-readable + tabular output, and JSON mode. +- `command.test.ts` — test patterns using `setupFetchMock` to mock both + the RHDH metadata endpoint and the Backstage manifest endpoint. + ## Pattern References - New command group: `src/commands/intent-based-actions/catalog.ts` @@ -177,6 +251,10 @@ self-copy error on repeated `update` runs. - Human/JSON output formatting: `src/commands/intent-based-actions/format.ts` - Structured CLI errors: `src/commands/intent-based-actions/intent-errors.ts` - Repeatable `key=value` and JSON input parsing: `src/commands/intent-based-actions/kv.ts` +- Version-aware CLI command: `src/commands/check-versions/command.ts` +- RHDH-to-Backstage version resolution: `src/lib/rhdhVersion.ts` +- Test patterns with mocked fetch responses: `src/lib/rhdhVersion.test.ts` +- Backstage manifest and `backstage:^` resolution: `src/lib/backstageVersion.ts` ## CI & Packaging From 6a6e6f207de55faa87578be417d74885f7db00c1 Mon Sep 17 00:00:00 2001 From: fullsend-fix <278716306+fullsend-ai-coder[bot]@users.noreply.github.com> Date: Mon, 28 Sep 2026 12:45:47 +0000 Subject: [PATCH 2/2] fix: address review feedback on AGENTS.md documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix 3-tier strategy description: tier 3 is Backstage release manifest fetch, not an error condition (algorithm-logic-consistency) - Remove non-existent `--offline` CLI flag reference (api-contract) - Rename heading to follow `identifier — noun phrase` pattern (code-organization) - Fix command.test.ts description: uses jest.mock, not setupFetchMock (technical-accuracy) Addresses #221 Assisted-by: claude-sonnet-4-6 --- AGENTS.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index ade232a..dce93eb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -42,12 +42,14 @@ import prefix, typescript:S4624 nested template literals) before they accumulate not Backstage versions. The CLI resolves RHDH versions to Backstage release versions via a 3-tier strategy: (1) remote metadata from the RHDH GitHub release branch, (2) a static compatibility matrix - (`RHDH_COMPATIBILITY_MATRIX` in `src/lib/rhdhVersion.ts`), (3) error if - neither resolves. Bare version numbers like `1.54.0` that do not match a + (`RHDH_COMPATIBILITY_MATRIX` in `src/lib/rhdhVersion.ts`), (3) Backstage + release manifest fetch from `versions.backstage.io`. If neither tier 1 + nor tier 2 resolves a Backstage version, an error is raised. Bare + version numbers like `1.54.0` that do not match a known RHDH release are rejected — users must prefix with `backstage:` to target a Backstage version directly (e.g. `backstage:1.54.0`). The static matrix must be updated manually each RHDH release cycle. -- **Offline vs air-gapped**: `RHDH_OFFLINE=true` (or `--offline`) skips +- **Offline vs air-gapped**: `RHDH_OFFLINE=true` skips the GitHub metadata lookup (tier 1) and falls back to the static compatibility matrix (tier 2), but the Backstage release manifest still fetches from `versions.backstage.io`. For true air-gapped use, users must @@ -192,7 +194,7 @@ subprocess error. as symlinks in the staged copy rather than followed, which would cause a self-copy error on repeated `update` runs. -### Version resolution engine +### `rhdhVersion.ts` — version resolution engine `src/lib/rhdhVersion.ts` is the core abstraction that maps RHDH version queries to Backstage release versions and their package manifests. All @@ -241,8 +243,9 @@ Key files: - `command.ts` — `checkPluginDependencies()` audit logic, human-readable tabular output, and JSON mode. -- `command.test.ts` — test patterns using `setupFetchMock` to mock both - the RHDH metadata endpoint and the Backstage manifest endpoint. +- `command.test.ts` — test patterns using `jest.mock` to stub + `resolveRhdhVersion` at the module boundary, allowing unit tests of + audit logic and CLI output without triggering any network calls. ## Pattern References