diff --git a/changelog.d/fixes/15682-basereds-r2-membership-test.md b/changelog.d/fixes/15682-basereds-r2-membership-test.md new file mode 100644 index 000000000000..d9cd0e0c64d0 --- /dev/null +++ b/changelog.d/fixes/15682-basereds-r2-membership-test.md @@ -0,0 +1 @@ +- **fix(ci):** the quality-rail membership guard (G0) pins `cycles` in the fast-gates `ratchet_gates` array, completing the #15590 landing whose squash omitted the matching test update — every PR off `release/v3.8.52` was red on `Unit Tests (3/8)` + `fast-path (3/4)` over the stale gate-membership needle (#15682) diff --git a/changelog.d/maintenance/15682-basereds-r2-skills-mirrors.md b/changelog.d/maintenance/15682-basereds-r2-skills-mirrors.md new file mode 100644 index 000000000000..3d6e6137102f --- /dev/null +++ b/changelog.d/maintenance/15682-basereds-r2-skills-mirrors.md @@ -0,0 +1 @@ +- **chore(skills):** refresh the `omni-auth` OIDC allowlist contract and `omni-settings` partial-update endpoint reference; these two mirror corrections do not claim to resolve unrelated generated-skill drift (#15682). diff --git a/docs/architecture/QUALITY_GATES.md b/docs/architecture/QUALITY_GATES.md index 95e1b969c71d..357ef634e47b 100644 --- a/docs/architecture/QUALITY_GATES.md +++ b/docs/architecture/QUALITY_GATES.md @@ -102,7 +102,7 @@ Runs on every PR to `main`. Blocks merge on failure. | Script (`npm run ...`) | Validates | Blocking | | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | | `check:node-runtime` | Node.js version is within the supported range | Yes | -| `check:cycles` | Circular imports across all of `src/` + `open-sse/` (AST-based, tsconfig `paths` resolved). Bare = advisory, lists the cycles. `check:cycles:ratchet` (what CI runs) blocks when the count exceeds the `metrics.cycles` ceiling in `quality-baseline.json` — currently 14, `direction: down`, so it can only fall (#15159 G-01/G-02) | Yes (ratchet) | +| `check:cycles` | Circular imports across all of `src/` + `open-sse/` (AST-based, tsconfig `paths` resolved). Bare exits 1 whenever any cycle exists (fail-closed since #15281) and lists the SCCs. `check:cycles:ratchet` (what CI runs) blocks when the count exceeds the `metrics.cycles` ceiling in `quality-baseline.json` — currently 14, `direction: down`, so it can only fall (#15159 G-01/G-02) | Yes (ratchet) | | `check:route-validation:t06` | Zod schemas present on all routes (Tier 6 policy) | Yes | | `check:any-budget:t11` | `@ts-expect-error // any` count does not exceed budget (Tier 11 catraca) | Yes | | `check:provider-consistency` | Every provider in `providers.ts` has a matching entry in `providerRegistry.ts` (and vice-versa, within the allowlist) | Yes | diff --git a/docs/ops/RELEASE_CHECKLIST.md b/docs/ops/RELEASE_CHECKLIST.md index 84ff4a7c5973..b93cb1f8ce38 100644 --- a/docs/ops/RELEASE_CHECKLIST.md +++ b/docs/ops/RELEASE_CHECKLIST.md @@ -137,7 +137,7 @@ matrix automatically, without any label. - [ ] `npm run lint` — 0 errors (warnings are pre-existing) - [ ] `npm run typecheck:core` — clean - [ ] `npm run typecheck:noimplicit:core` — clean (strict) -- [ ] `npm run check:cycles` — no circular deps +- [ ] `npm run check:cycles:ratchet` — within the frozen `metrics.cycles` ceiling (bare `check:cycles` exits 1 on any cycle, #15281) - [ ] `npm run check:any-budget:t11` — within budget - [ ] `npm run check:route-validation:t06` — clean - [ ] `npm run check:node-runtime` — supported runtime floor met (`>=22.22.2 <23`, `>=24.0.0 <27`, per `SUPPORTED_NODE_RANGE` in `src/shared/utils/nodeRuntimeSupport.ts`; aligned with `package.json` `engines`) diff --git a/scripts/check/check-cycles.mjs b/scripts/check/check-cycles.mjs index ad8476370a43..68652878ab7f 100644 --- a/scripts/check/check-cycles.mjs +++ b/scripts/check/check-cycles.mjs @@ -27,7 +27,9 @@ // counting them invents cycles that do not exist at runtime). // // Cycle count is a ratchet, not a hard zero: see config/quality/quality-baseline.json -// → metrics.cycles (G-02). `check:cycles` alone is advisory, `--ratchet` blocks. +// → metrics.cycles (G-02). Zero cycles exits 0 in every mode. With cycles present, +// plain mode exits 1 and `--ratchet` exits 1 above the ceiling or when the baseline +// is missing/invalid. import fs from "node:fs"; import path from "node:path"; @@ -437,7 +439,7 @@ export function analyzeCycles(roots, cwd = process.cwd()) { /** * Read the `cycles` ceiling from quality-baseline.json. - * Missing/invalid baseline ⇒ null (advisory, no ceiling). + * Missing/invalid baseline ⇒ null (main() then exits 1 whenever any cycle exists). * * @param {string} [baselinePath] * @returns {number | null} diff --git a/skills/omni-auth/SKILL.md b/skills/omni-auth/SKILL.md index 817a0c449406..544a907e77b7 100644 --- a/skills/omni-auth/SKILL.md +++ b/skills/omni-auth/SKILL.md @@ -58,9 +58,9 @@ curl https://localhost:20128/api/auth/oidc/login \ Complete OIDC login for the dashboard admin gate Validates the `state` cookie, exchanges the authorization `code` for tokens, -verifies the ID token against the issuer's JWKS (audience = client id), and — -if `oidcAllowedSubjects` is configured — checks the token's `sub`/`email` against -that allowlist. On success it mints the same 30-day `auth_token` dashboard-session +verifies the ID token against the issuer's JWKS (audience = client id), and +checks the token's `sub`/`email` against `oidcAllowedSubjects`, which must hold at +least one entry (an empty list ends in `not_configured`). On success it mints the same 30-day `auth_token` dashboard-session JWT used by password login and redirects to `/dashboard`. diff --git a/skills/omni-settings/references/endpoints.md b/skills/omni-settings/references/endpoints.md index 0b0045674a08..20c0f9aad509 100644 --- a/skills/omni-settings/references/endpoints.md +++ b/skills/omni-settings/references/endpoints.md @@ -277,6 +277,8 @@ curl https://localhost:20128/api/settings/compression \ Update global compression settings +Partial update: only the sent top-level keys change. `engines` merges by engine id — an entry overwrites only the fields it sends, engines left out are kept as-is, and until an engines row is stored the merge base is the map derived from the legacy per-engine settings. + ```bash curl -X PUT https://localhost:20128/api/settings/compression \ -H "Authorization: Bearer $OMNIROUTE_TOKEN" \ diff --git a/stryker.conf.json b/stryker.conf.json index f6f50cf297e1..510ffdcd1e25 100644 --- a/stryker.conf.json +++ b/stryker.conf.json @@ -161,6 +161,7 @@ "tests/unit/capability-filter.test.ts", "tests/unit/cc-bridge-openai-image-7777.test.ts", "tests/unit/cc-compatible-provider.test.ts", + "tests/unit/characterization-oauth.test.ts", "tests/unit/chat-adaptive-admission-binding.test.ts", "tests/unit/chat-combo-live-test.test.ts", "tests/unit/chat-context-relay.test.ts", @@ -361,6 +362,7 @@ "tests/unit/mark-account-unavailable-numeric-epoch-guard.test.ts", "tests/unit/masked-200-exhaustion-fallback-6427.test.ts", "tests/unit/mcp-connect-scope.test.ts", + "tests/unit/measure-boundary.test.ts", "tests/unit/memory-embedding-remote.test.ts", "tests/unit/memory-embedding-transformers.test.ts", "tests/unit/metered-budget-must-not-disable-flat-rate.test.ts", @@ -460,6 +462,7 @@ "tests/unit/route-guard-cursor-refresh.test.ts", "tests/unit/route-guard-forge-jcode-settings-local-only.test.ts", "tests/unit/route-guard-grok-build-settings-local-only.test.ts", + "tests/unit/route-guard-local-only-sweep.test.ts", "tests/unit/route-guard-middleware-local-only.test.ts", "tests/unit/route-guard-plugins-local-only.test.ts", "tests/unit/route-guard-private-lan.test.ts", diff --git a/tests/unit/quality-rail-gate-membership.test.ts b/tests/unit/quality-rail-gate-membership.test.ts index 3662b07b4a1d..2379127c7a16 100644 --- a/tests/unit/quality-rail-gate-membership.test.ts +++ b/tests/unit/quality-rail-gate-membership.test.ts @@ -50,15 +50,29 @@ test("fast-gates carries the deterministic ratchets and security scanners from t const block = jobBlock("fast-gates"); // #8542: all gates run inside a single aggregation step's bash loop. // Check that the gate names appear in the arrays or the loop body. + // #15306: `cycles` moved to ratchet_gates — check-cycles.mjs exits 1 on ANY cycle + // without --ratchet (#15281), so fast-gates must run it with the frozen ceiling in + // quality-baseline.json, same as ci.yml's check:cycles:ratchet. for (const needle of [ - "cycles lockfile duplication dead-code type-coverage compression-budget", - "secrets vuln-ratchet workflows openapi-breaking", + "lockfile duplication dead-code type-coverage compression-budget", + "secrets vuln-ratchet workflows openapi-breaking cycles", "typecheck:core", "check:dashboard-typecheck", "check:ts7-diagnostics-ratchet", ]) { assert.ok(block.includes(needle), `fast-gates must contain "${needle}"`); } + // The ratchet_gates move must be exclusive: a plain `cycles` entry would run + // check-cycles.mjs without --ratchet, which exits 1 on ANY cycle and fails + // every PR at the frozen 14-SCC ceiling (#15306). Pin the whole gates=(...) + // array, not just its current line, so a re-entry on any line trips the guard. + const plainGates = /\n(\s+)gates=\(([\s\S]*?)\n\1\)/.exec(block); + assert.ok(plainGates, "fast-gates must still carry the deterministic plain gates array"); + assert.doesNotMatch( + plainGates[2], + /(^|\s)cycles(\s|$)/, + "cycles must not re-enter the plain gates array — it would run without --ratchet" + ); assert.ok( block.includes( "BASE_REF: ${{ github.base_ref && format('origin/{0}', github.base_ref) || '' }}"