From edda14251f7bb5a3df387ec1aa1181e9831dd584 Mon Sep 17 00:00:00 2001 From: Rafael Costa Date: Sun, 17 May 2026 09:58:13 -0300 Subject: [PATCH 1/3] fix: rebrand internal .aiox-core/package.json + add namespace drift gate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes the Bug 2 follow-up from #739 (@gabrielolio): the internal `.aiox-core/package.json` manifest still declared the legacy `@aiox-fullstack/core@4.31.1` namespace while the surface package moved to `@aiox-squads/core@5.x` long ago. The drift went undetected because no pre-publish check was looking at this internal file, and it ships inside every release of `@aiox-squads/core`. ## Changes to `.aiox-core/package.json` Renamed and clarified its role: * `name`: `@aiox-fullstack/core` → `@aiox-squads/core-internal` (the `-internal` suffix + `private: true` make it explicit this is NOT a separately-published package — it ships inside the parent surface) * `version`: `4.31.1` → `5.2.6` (now tracks parent surface) * `private: true` added (defensively prevents accidental separate publish in case someone runs `npm publish` from `.aiox-core/`) * `description` rewritten to explain the file's actual role * Dropped `peerDependencies` block — all four `@aiox-fullstack/*` peers referenced packages that never made the namespace migration and do not exist on npm * Dropped publish-only fields that don't apply to an internal manifest: `module`, `types`, `bin`, `files`, `exports`, `publishConfig` * Repository directory hint added so anyone inspecting the file knows the SOT location * Retained the runtime `dependencies` block (consumed by scripts under `.aiox-core/development/scripts/` — validated by `scripts/validate-aiox-core-deps.js`) ## New pre-publish gate `scripts/validate-aiox-core-namespace.js` enforces five rules: 1. `.aiox-core/package.json` exists 2. `name` ends with `-internal` (forbids drifting back to a published namespace) 3. `private: true` 4. `version` matches root `package.json` version exactly (single source of truth — root drives the framework version) 5. No `@aiox-fullstack/*` peer deps re-introduced The validator is wired into `validate:publish` (which `prepublishOnly` chains), so a release that drifts again is blocked before it ships. Also exposed as `npm run validate:aiox-core-namespace` for ad-hoc runs. ## Why the `-internal` suffix instead of just using `@aiox-squads/core` Two packages with the same name on the same npm registry — even if one is `private: true` — confuses tooling that resolves by name (the installer itself, lockfile resolution, dependency graphs, `npm ls` output). The suffix is a defensive disambiguation: the internal file ships inside the parent surface but never appears in dependency graphs as a competing entry. ## Impact on existing installs Running `aiox install --update` (or any flow that calls `applyUpgrade(..., { includeModified: true })`) will pull the corrected file from the next release. Students who hit the namespace drift before this lands can also hand-patch `.aiox-core/package.json` locally — the file is not load-bearing for runtime; it informs tooling and the operator-facing `aiox info` chain. Co-Authored-By: Claude Opus 4.7 (1M context) --- .aiox-core/install-manifest.yaml | 8 +-- .aiox-core/package.json | 81 +++------------------- bin/utils/validate-publish.js | 21 ++++++ package.json | 3 +- scripts/validate-aiox-core-namespace.js | 89 +++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 75 deletions(-) create mode 100755 scripts/validate-aiox-core-namespace.js diff --git a/.aiox-core/install-manifest.yaml b/.aiox-core/install-manifest.yaml index 2750ab68ad..3741d34173 100644 --- a/.aiox-core/install-manifest.yaml +++ b/.aiox-core/install-manifest.yaml @@ -8,7 +8,7 @@ # - File types for categorization # version: 5.2.6 -generated_at: "2026-05-17T12:22:51.608Z" +generated_at: "2026-05-17T12:58:14.317Z" generator: scripts/generate-install-manifest.js file_count: 1128 files: @@ -1297,7 +1297,7 @@ files: type: data size: 9590 - path: data/entity-registry.yaml - hash: sha256:7a1dc65b0661069cdccf8babb7c3320320281f10a8e5258a3cba26b8953df5ad + hash: sha256:910cf52ea4d999bccf255c431db5648663d2de5a871a18068fc443adaab3379c type: data size: 572193 - path: data/learned-patterns.yaml @@ -3697,9 +3697,9 @@ files: type: monitor size: 818 - path: package.json - hash: sha256:049326a853153ea930a49c1d083d5fa9a5eb5d05c3198f0322dbd831fe151b2e + hash: sha256:d1cc33f580e68ec3c3e5dfb95f152852d587472d086d55fa643e8aabd0c29f77 type: other - size: 2529 + size: 1445 - path: product/checklists/accessibility-wcag-checklist.md hash: sha256:56126182b25e9b7bdde43f75315e33167eb49b1f9a9cb0e9a37bc068af40aeab type: checklist diff --git a/.aiox-core/package.json b/.aiox-core/package.json index ea49119f36..d9a79ce12a 100644 --- a/.aiox-core/package.json +++ b/.aiox-core/package.json @@ -1,34 +1,11 @@ { - "name": "@aiox-fullstack/core", - "version": "4.31.1", - "description": "AIOX-FullStack Core - Meta-agent and component generation system", + "name": "@aiox-squads/core-internal", + "version": "5.2.6", + "description": "Internal package manifest for AIOX framework — declares runtime dependencies consumed by scripts under .aiox-core/. This is NOT published independently; it ships inside @aiox-squads/core (the top-level package). Kept name-distinct from the parent (`-internal` suffix) to avoid npm registry confusion. Version follows the parent package.", + "private": true, "main": "index.js", - "module": "index.esm.js", - "types": "index.d.ts", - "bin": { - "aiox-core": "bin/aiox-core.js" - }, - "files": [ - "lib/", - "bin/", - "templates/", - "utils/", - "tasks/", - "docs/", - "elicitation/", - "index.js", - "index.esm.js", - "index.d.ts", - "README.md", - "LICENSE" - ], "scripts": { - "build": "node ../tools/build-core.js", - "test": "npm run test:unit && npm run test:integration", - "test:unit": "jest tests/unit", - "test:integration": "jest tests/integration", - "lint": "eslint .", - "typecheck": "tsc --noEmit" + "test": "echo 'Use parent package test scripts'" }, "dependencies": { "ajv": "^8.17.1", @@ -47,39 +24,19 @@ "tar": "^7.5.7", "validator": "^13.15.15" }, - "peerDependencies": { - "@aiox-fullstack/memory": "^4.31.0", - "@aiox-fullstack/security": "^4.31.0", - "@aiox-fullstack/performance": "^4.31.0", - "@aiox-fullstack/telemetry": "^4.31.0" - }, - "peerDependenciesMeta": { - "@aiox-fullstack/memory": { - "optional": true - }, - "@aiox-fullstack/security": { - "optional": true - }, - "@aiox-fullstack/performance": { - "optional": true - }, - "@aiox-fullstack/telemetry": { - "optional": true - } - }, "keywords": [ "aiox", - "meta-agent", - "component-generation", + "aiox-squads", + "framework", "ai-orchestration", - "fullstack", - "development-tools" + "internal-manifest" ], - "author": "AIOX Fullstack Team", + "author": "AIOX Squads", "license": "MIT", "repository": { "type": "git", - "url": "git+https://github.com/SynkraAI/aiox-core.git" + "url": "git+https://github.com/SynkraAI/aiox-core.git", + "directory": ".aiox-core" }, "bugs": { "url": "https://github.com/SynkraAI/aiox-core/issues" @@ -88,21 +45,5 @@ "engines": { "node": ">=18.0.0", "npm": ">=9.0.0" - }, - "publishConfig": { - "access": "public", - "registry": "https://registry.npmjs.org/" - }, - "exports": { - ".": { - "types": "./index.d.ts", - "import": "./index.esm.js", - "require": "./index.js" - }, - "./templates": "./templates/", - "./utils": "./utils/", - "./tasks": "./tasks/", - "./docs": "./docs/", - "./elicitation": "./elicitation/" } } diff --git a/bin/utils/validate-publish.js b/bin/utils/validate-publish.js index e041aebcda..6c99a40907 100644 --- a/bin/utils/validate-publish.js +++ b/bin/utils/validate-publish.js @@ -132,6 +132,27 @@ try { passed = false; } +// Check 5 (#739 Bug 2 follow-up): .aiox-core/package.json namespace + version sync +console.log(''); +console.log('--- Internal Manifest Namespace Sync (Issue #739) ---\n'); +try { + const nsValidatorPath = path.join(PROJECT_ROOT, 'scripts', 'validate-aiox-core-namespace.js'); + if (fs.existsSync(nsValidatorPath)) { + execSync(`node "${nsValidatorPath}"`, { + encoding: 'utf8', + cwd: PROJECT_ROOT, + timeout: 10000, + stdio: 'inherit', + }); + } else { + console.log('SKIP: scripts/validate-aiox-core-namespace.js not found'); + } +} catch (_nsErr) { + console.error('FAIL: .aiox-core/package.json namespace/version drift detected'); + console.error(' Fix: Run "node scripts/validate-aiox-core-namespace.js" to see details'); + passed = false; +} + // Summary console.log(''); if (passed) { diff --git a/package.json b/package.json index 101b52776d..2cd19e9520 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,8 @@ "sync:ide:cursor": "node .aiox-core/infrastructure/scripts/ide-sync/index.js sync --ide cursor", "validate:publish": "node bin/utils/validate-publish.js", "prepublishOnly": "node bin/utils/validate-publish.js && npm run generate:manifest && npm run validate:manifest", - "prepare": "husky" + "prepare": "husky", + "validate:aiox-core-namespace": "node scripts/validate-aiox-core-namespace.js" }, "dependencies": { "@clack/prompts": "^0.11.0", diff --git a/scripts/validate-aiox-core-namespace.js b/scripts/validate-aiox-core-namespace.js new file mode 100755 index 0000000000..6fe307858e --- /dev/null +++ b/scripts/validate-aiox-core-namespace.js @@ -0,0 +1,89 @@ +#!/usr/bin/env node +/** + * .aiox-core/package.json namespace + version sync validator + * + * Story #739 (Bug 2 follow-up): the internal `.aiox-core/package.json` + * manifest drifted to the legacy `@aiox-fullstack/core@4.31.1` namespace + * while the surface package moved to `@aiox-squads/core@5.x`. Several + * releases shipped stale internal metadata that confused tooling and + * misled operators investigating upgrade issues. + * + * This validator runs in the pre-publish surface to catch the drift + * before it ships again. + * + * Validation rules: + * 1. `.aiox-core/package.json` MUST exist. + * 2. `name` MUST end with `-internal` (it is NOT a published package on + * its own — `private: true` + suffix avoids npm registry confusion + * with the parent surface). + * 3. `private` MUST be true. + * 4. `version` MUST equal the root `package.json` version (single source + * of truth: the parent surface drives the framework version). + * 5. No `peerDependencies` referencing the legacy `@aiox-fullstack/*` + * namespace. + * + * Exit codes: 0 = PASS, 1 = FAIL + * Usage: node scripts/validate-aiox-core-namespace.js + */ + +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +const ROOT = path.resolve(__dirname, '..'); +const INTERNAL_PKG = path.join(ROOT, '.aiox-core', 'package.json'); +const ROOT_PKG = path.join(ROOT, 'package.json'); + +function fail(msg) { + console.error(`FAIL: ${msg}`); + process.exit(1); +} + +function main() { + if (!fs.existsSync(INTERNAL_PKG)) { + fail('.aiox-core/package.json not found'); + } + if (!fs.existsSync(ROOT_PKG)) { + fail('root package.json not found'); + } + + const internal = JSON.parse(fs.readFileSync(INTERNAL_PKG, 'utf8')); + const root = JSON.parse(fs.readFileSync(ROOT_PKG, 'utf8')); + + if (!internal.name) { + fail('.aiox-core/package.json missing `name` field'); + } + if (!internal.name.endsWith('-internal')) { + fail( + `.aiox-core/package.json name "${internal.name}" must end with "-internal" ` + + '(internal manifest, not a separately-published package — see Story #739)', + ); + } + if (internal.private !== true) { + fail('.aiox-core/package.json must declare `"private": true` (internal-only)'); + } + if (internal.version !== root.version) { + fail( + `version drift: .aiox-core/package.json version "${internal.version}" ` + + `does not match root package.json version "${root.version}". ` + + 'They must move in lockstep — root is SOT.', + ); + } + + const peerDeps = internal.peerDependencies || {}; + const legacyPeers = Object.keys(peerDeps).filter((d) => d.startsWith('@aiox-fullstack/')); + if (legacyPeers.length > 0) { + fail( + `legacy @aiox-fullstack/* peerDependencies in .aiox-core/package.json: ${legacyPeers.join(', ')}. ` + + 'These packages do not exist; drop the peerDependencies block or rename to the current namespace.', + ); + } + + console.log( + `PASS: .aiox-core/package.json is in sync with root (name=${internal.name}, version=${internal.version})`, + ); + process.exit(0); +} + +main(); From 7d4fd5eab6bad08a333d75b7066142544eafdda4 Mon Sep 17 00:00:00 2001 From: Rafael Costa Date: Sun, 17 May 2026 10:15:45 -0300 Subject: [PATCH 2/3] fix: address CodeRabbit feedback on PR #746 + sync install-manifest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three real issues caught: 1. **execFileSync over execSync (nitpick)** — Replaced shell-based `execSync('node "${path}"', ...)` with `execFileSync('node', [path], ...)` for the two validator invocations in `validate-publish.js`. Eliminates shell parsing entirely, defense-in-depth even though the paths are hardcoded. 2. **Fail-closed for missing namespace validator (actionable)** — The previous code SKIP'd silently if `validate-aiox-core-namespace.js` was missing. That's the exact silent-fall pattern that allowed the namespace drift to ship for several releases. Now an absent validator fails the publish gate with a clear message that the file is required and was introduced specifically for Issue #739 Bug 2. Trying to ship without the gate is now blocked. 3. **Scope check in namespace validator (actionable)** — The `-internal` suffix alone allowed names like `@any-scope/foo-internal` to pass. Added a `startsWith('@aiox-squads/')` check before the suffix check, with a message that calls out `@aiox-fullstack/*` as the legacy scope to reject. Now both conditions must hold: `@aiox-squads/-internal`. Also: regenerated `.aiox-core/install-manifest.yaml` — the new validator script + the modified `validate-publish.js` changed hash, and `validate:manifest` was failing in CI because the manifest was stale relative to the working tree. After regen, manifest validation passes. Co-Authored-By: Claude Opus 4.7 (1M context) --- .aiox-core/install-manifest.yaml | 6 ++--- bin/utils/validate-publish.js | 31 +++++++++++++++---------- scripts/validate-aiox-core-namespace.js | 7 ++++++ 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/.aiox-core/install-manifest.yaml b/.aiox-core/install-manifest.yaml index 3741d34173..0dfe06141f 100644 --- a/.aiox-core/install-manifest.yaml +++ b/.aiox-core/install-manifest.yaml @@ -8,7 +8,7 @@ # - File types for categorization # version: 5.2.6 -generated_at: "2026-05-17T12:58:14.317Z" +generated_at: "2026-05-17T13:13:35.812Z" generator: scripts/generate-install-manifest.js file_count: 1128 files: @@ -1297,9 +1297,9 @@ files: type: data size: 9590 - path: data/entity-registry.yaml - hash: sha256:910cf52ea4d999bccf255c431db5648663d2de5a871a18068fc443adaab3379c + hash: sha256:5dac372c022f1da390b923a2ce2c719deb2ed3916464925be788b26596f31fdf type: data - size: 572193 + size: 574327 - path: data/learned-patterns.yaml hash: sha256:24ac0b160615583a0ff783d3da8af80b7f94191575d6db2054ec8e10a3f945dc type: data diff --git a/bin/utils/validate-publish.js b/bin/utils/validate-publish.js index 6c99a40907..6b03783a10 100644 --- a/bin/utils/validate-publish.js +++ b/bin/utils/validate-publish.js @@ -16,7 +16,7 @@ const fs = require('fs'); const path = require('path'); -const { execSync } = require('child_process'); +const { execSync, execFileSync } = require('child_process'); const PROJECT_ROOT = path.join(__dirname, '..', '..'); const MIN_FILE_COUNT = 50; @@ -116,7 +116,7 @@ console.log('--- Dependency Completeness (INS-4.12) ---\n'); try { const depValidatorPath = path.join(PROJECT_ROOT, 'scripts', 'validate-aiox-core-deps.js'); if (fs.existsSync(depValidatorPath)) { - execSync(`node "${depValidatorPath}"`, { + execFileSync('node', [depValidatorPath], { encoding: 'utf8', cwd: PROJECT_ROOT, timeout: 30000, @@ -133,24 +133,31 @@ try { } // Check 5 (#739 Bug 2 follow-up): .aiox-core/package.json namespace + version sync +// +// Fail-closed: this validator is required, not optional. If it's missing +// from the working tree we ABORT the publish — historically the silent-skip +// pattern is what let the namespace drift ship in the first place. console.log(''); console.log('--- Internal Manifest Namespace Sync (Issue #739) ---\n'); -try { - const nsValidatorPath = path.join(PROJECT_ROOT, 'scripts', 'validate-aiox-core-namespace.js'); - if (fs.existsSync(nsValidatorPath)) { - execSync(`node "${nsValidatorPath}"`, { +const nsValidatorPath = path.join(PROJECT_ROOT, 'scripts', 'validate-aiox-core-namespace.js'); +if (!fs.existsSync(nsValidatorPath)) { + console.error('FAIL: scripts/validate-aiox-core-namespace.js is required but not found'); + console.error(' This validator was introduced for Issue #739 Bug 2 and is mandatory.'); + console.error(' Restore the file or revert the deletion that removed it.'); + passed = false; +} else { + try { + execFileSync('node', [nsValidatorPath], { encoding: 'utf8', cwd: PROJECT_ROOT, timeout: 10000, stdio: 'inherit', }); - } else { - console.log('SKIP: scripts/validate-aiox-core-namespace.js not found'); + } catch (_nsErr) { + console.error('FAIL: .aiox-core/package.json namespace/version drift detected'); + console.error(' Fix: Run "node scripts/validate-aiox-core-namespace.js" to see details'); + passed = false; } -} catch (_nsErr) { - console.error('FAIL: .aiox-core/package.json namespace/version drift detected'); - console.error(' Fix: Run "node scripts/validate-aiox-core-namespace.js" to see details'); - passed = false; } // Summary diff --git a/scripts/validate-aiox-core-namespace.js b/scripts/validate-aiox-core-namespace.js index 6fe307858e..4320d16960 100755 --- a/scripts/validate-aiox-core-namespace.js +++ b/scripts/validate-aiox-core-namespace.js @@ -54,6 +54,13 @@ function main() { if (!internal.name) { fail('.aiox-core/package.json missing `name` field'); } + const EXPECTED_SCOPE = '@aiox-squads/'; + if (!internal.name.startsWith(EXPECTED_SCOPE)) { + fail( + `.aiox-core/package.json name "${internal.name}" must start with "${EXPECTED_SCOPE}" ` + + '(current org scope — names like `@aiox-fullstack/*` are legacy, see Story #739)', + ); + } if (!internal.name.endsWith('-internal')) { fail( `.aiox-core/package.json name "${internal.name}" must end with "-internal" ` + From 1f4cb2b672413fb4af9e97693c21ddf1672f8d7c Mon Sep 17 00:00:00 2001 From: Rafael Costa Date: Sun, 17 May 2026 10:49:44 -0300 Subject: [PATCH 3/3] chore(sync): propagate devops.md release-procedure section to IDE projections Mirror of the same sync commit on PR #747. The release-procedure section added to devops.md by PR #745 was not synced to the four IDE projections before #745 merged, so this branch also inherits the drift from main and fails CI's Compatibility Parity Gate. Files: - .claude/skills/AIOX/agents/devops/SKILL.md - .codex/agents/devops.md - .gemini/rules/AIOX/agents/devops.md - .kimi/skills/aiox-devops/SKILL.md --- .claude/skills/AIOX/agents/devops/SKILL.md | 13 +++++++++++++ .codex/agents/devops.md | 13 +++++++++++++ .gemini/rules/AIOX/agents/devops.md | 13 +++++++++++++ .kimi/skills/aiox-devops/SKILL.md | 13 +++++++++++++ 4 files changed, 52 insertions(+) diff --git a/.claude/skills/AIOX/agents/devops/SKILL.md b/.claude/skills/AIOX/agents/devops/SKILL.md index bfc7f81715..c180143768 100644 --- a/.claude/skills/AIOX/agents/devops/SKILL.md +++ b/.claude/skills/AIOX/agents/devops/SKILL.md @@ -589,6 +589,19 @@ Type `*help` to see all commands. - ❌ Creating PR before quality gates pass - ❌ Skipping CodeRabbit CRITICAL issues +### Release Procedure (NON-NEGOTIABLE Reference) + +When invoked with `*release`, `*push` followed by version-bump intent, or any task that ends with a tag push to `@aiox-squads/*`, **load and follow `docs/guides/release-procedure.md` as the canonical SOP before touching anything**. It is the authoritative playbook — the task templates `publish-npm.md` and `release-management.md` are thin wrappers around it. + +The SOP captures lessons paid for in 11 patches across 30 days: +- Two-system branch protection on `main` (modern ruleset id `13330052` + legacy `required_pull_request_reviews`); `gh pr merge --admin` bypasses neither alone — you must relax both and restore both atomically with `trap EXIT` + sanitized payloads (raw GitHub API responses include read-only fields that PUT rejects). +- 4-site version bump coordination (`package.json`, `compat/aiox-core/package.json` + its dep, `packages/installer/package.json`, `package-lock.json` + `CHANGELOG.md`). +- The `publish_legacy_aiox_core` job depends on `publish` completing (compat wrapper transitively depends on the scoped package — race against npm CDN propagation has bitten us). +- npm propagation budget for the legacy smoke (240s with dual visibility check). +- Windows path escape in workflow `node -e` interpolations of `${{ github.workspace }}` (use env vars). + +Skipping the SOP because "it's just a patch release" is how the next 30-day patch storm starts. + ### Related Agents - **@dev (Dex)** - Delegates push operations to me diff --git a/.codex/agents/devops.md b/.codex/agents/devops.md index 41fca70e16..a6576998ee 100644 --- a/.codex/agents/devops.md +++ b/.codex/agents/devops.md @@ -579,6 +579,19 @@ Type `*help` to see all commands. - ❌ Creating PR before quality gates pass - ❌ Skipping CodeRabbit CRITICAL issues +### Release Procedure (NON-NEGOTIABLE Reference) + +When invoked with `*release`, `*push` followed by version-bump intent, or any task that ends with a tag push to `@aiox-squads/*`, **load and follow `docs/guides/release-procedure.md` as the canonical SOP before touching anything**. It is the authoritative playbook — the task templates `publish-npm.md` and `release-management.md` are thin wrappers around it. + +The SOP captures lessons paid for in 11 patches across 30 days: +- Two-system branch protection on `main` (modern ruleset id `13330052` + legacy `required_pull_request_reviews`); `gh pr merge --admin` bypasses neither alone — you must relax both and restore both atomically with `trap EXIT` + sanitized payloads (raw GitHub API responses include read-only fields that PUT rejects). +- 4-site version bump coordination (`package.json`, `compat/aiox-core/package.json` + its dep, `packages/installer/package.json`, `package-lock.json` + `CHANGELOG.md`). +- The `publish_legacy_aiox_core` job depends on `publish` completing (compat wrapper transitively depends on the scoped package — race against npm CDN propagation has bitten us). +- npm propagation budget for the legacy smoke (240s with dual visibility check). +- Windows path escape in workflow `node -e` interpolations of `${{ github.workspace }}` (use env vars). + +Skipping the SOP because "it's just a patch release" is how the next 30-day patch storm starts. + ### Related Agents - **@dev (Dex)** - Delegates push operations to me diff --git a/.gemini/rules/AIOX/agents/devops.md b/.gemini/rules/AIOX/agents/devops.md index 41fca70e16..a6576998ee 100644 --- a/.gemini/rules/AIOX/agents/devops.md +++ b/.gemini/rules/AIOX/agents/devops.md @@ -579,6 +579,19 @@ Type `*help` to see all commands. - ❌ Creating PR before quality gates pass - ❌ Skipping CodeRabbit CRITICAL issues +### Release Procedure (NON-NEGOTIABLE Reference) + +When invoked with `*release`, `*push` followed by version-bump intent, or any task that ends with a tag push to `@aiox-squads/*`, **load and follow `docs/guides/release-procedure.md` as the canonical SOP before touching anything**. It is the authoritative playbook — the task templates `publish-npm.md` and `release-management.md` are thin wrappers around it. + +The SOP captures lessons paid for in 11 patches across 30 days: +- Two-system branch protection on `main` (modern ruleset id `13330052` + legacy `required_pull_request_reviews`); `gh pr merge --admin` bypasses neither alone — you must relax both and restore both atomically with `trap EXIT` + sanitized payloads (raw GitHub API responses include read-only fields that PUT rejects). +- 4-site version bump coordination (`package.json`, `compat/aiox-core/package.json` + its dep, `packages/installer/package.json`, `package-lock.json` + `CHANGELOG.md`). +- The `publish_legacy_aiox_core` job depends on `publish` completing (compat wrapper transitively depends on the scoped package — race against npm CDN propagation has bitten us). +- npm propagation budget for the legacy smoke (240s with dual visibility check). +- Windows path escape in workflow `node -e` interpolations of `${{ github.workspace }}` (use env vars). + +Skipping the SOP because "it's just a patch release" is how the next 30-day patch storm starts. + ### Related Agents - **@dev (Dex)** - Delegates push operations to me diff --git a/.kimi/skills/aiox-devops/SKILL.md b/.kimi/skills/aiox-devops/SKILL.md index 5ebdcb1218..8e79b9e047 100644 --- a/.kimi/skills/aiox-devops/SKILL.md +++ b/.kimi/skills/aiox-devops/SKILL.md @@ -663,6 +663,19 @@ Type `*help` to see all commands. - ❌ Creating PR before quality gates pass - ❌ Skipping CodeRabbit CRITICAL issues +### Release Procedure (NON-NEGOTIABLE Reference) + +When invoked with `*release`, `*push` followed by version-bump intent, or any task that ends with a tag push to `@aiox-squads/*`, **load and follow `docs/guides/release-procedure.md` as the canonical SOP before touching anything**. It is the authoritative playbook — the task templates `publish-npm.md` and `release-management.md` are thin wrappers around it. + +The SOP captures lessons paid for in 11 patches across 30 days: +- Two-system branch protection on `main` (modern ruleset id `13330052` + legacy `required_pull_request_reviews`); `gh pr merge --admin` bypasses neither alone — you must relax both and restore both atomically with `trap EXIT` + sanitized payloads (raw GitHub API responses include read-only fields that PUT rejects). +- 4-site version bump coordination (`package.json`, `compat/aiox-core/package.json` + its dep, `packages/installer/package.json`, `package-lock.json` + `CHANGELOG.md`). +- The `publish_legacy_aiox_core` job depends on `publish` completing (compat wrapper transitively depends on the scoped package — race against npm CDN propagation has bitten us). +- npm propagation budget for the legacy smoke (240s with dual visibility check). +- Windows path escape in workflow `node -e` interpolations of `${{ github.workspace }}` (use env vars). + +Skipping the SOP because "it's just a patch release" is how the next 30-day patch storm starts. + ### Related Agents - **@dev (Dex)** - Delegates push operations to me