diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51e052e74..597d55442 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,9 +1,9 @@ # PR + main-branch quality gate. # # Runs lint + typecheck + test on both workspaces, plus a schema smoke -# that applies all 9 migrations against a real pgvector container. Audit -# enforces a high-severity ceiling so a CVE-bumping dep can't slip in -# unnoticed. +# that applies every migration in the repo against a real pgvector +# container. Audit enforces a high-severity ceiling so a CVE-bumping +# dep can't slip in unnoticed. # # Naming-independent — no secrets, no GHCR/npm push. Release-flow lives # in release.yml (currently placeholder; activates once OB-30 Block 2 @@ -12,8 +12,12 @@ name: CI on: + # Pull-request trigger accepts any base branch so that cluster-fix + # PRs stacked on the test-suite resurrection branch (#35 / #37) + # still run CI. Once #35 merges and the cluster work is done, this + # can return to `branches: [main]`. pull_request: - branches: [main] + branches: ['**'] push: branches: [main] @@ -41,7 +45,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '22' cache: 'npm' cache-dependency-path: middleware/package-lock.json @@ -75,7 +79,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '22' cache: 'npm' cache-dependency-path: web-ui/package-lock.json @@ -92,8 +96,11 @@ jobs: run: npm run test # ------------------------------------------------------------------ - # Schema smoke: apply all 9 migrations against pgvector. Catches - # SQL-only regressions before they hit prod-or-OSS-demo deploys. + # Schema smoke: apply every migration in the repo against pgvector. + # Catches SQL-only regressions before they hit prod-or-OSS-demo + # deploys. Domains are listed explicitly in dependency order; files + # inside a domain are applied in lexical (numbered) order, so newly + # added migrations are picked up automatically. # ------------------------------------------------------------------ schema: name: schema (migrations on pgvector) @@ -112,6 +119,17 @@ jobs: --health-interval 5s --health-timeout 3s --health-retries 20 + env: + # Schema domains in apply order. Within each domain, files apply + # in lexical (file-name) order — which matches the numbered + # migration convention. Newline-separated so the shell loop can + # iterate cleanly. + MIGRATION_DOMAINS: | + middleware/packages/harness-knowledge-graph-neon/src/migrations + middleware/src/auth/migrations + middleware/src/plugins/routines/migrations + middleware/src/profileSnapshots/migrations + middleware/src/profileStorage/migrations steps: - uses: actions/checkout@v4 @@ -120,45 +138,30 @@ jobs: PGPASSWORD=omadia-ci psql -h localhost -U omadia -d omadia \ -c "CREATE EXTENSION IF NOT EXISTS vector;" - - name: Apply 9 migrations in order + - name: Apply all migrations run: | set -euo pipefail - declare -a MIGRATIONS=( - "middleware/packages/harness-knowledge-graph-neon/src/migrations/0001_graph_init.sql" - "middleware/src/services/graph/migrations/0002_user_scoping.sql" - "middleware/packages/harness-knowledge-graph-neon/src/migrations/0003_agentic_graph.sql" - "middleware/src/services/graph/migrations/0004_turn_fts.sql" - "middleware/packages/harness-knowledge-graph-neon/src/migrations/0005_turn_embeddings_768.sql" - "middleware/packages/harness-knowledge-graph-neon/src/migrations/0006_embedding_backfill_state.sql" - "middleware/src/services/graph/migrations/0007_verifier_tables.sql" - "middleware/src/services/graph/migrations/0008_teams_attachments.sql" - "middleware/src/plugins/routines/migrations/0001_routines.sql" - ) - for m in "${MIGRATIONS[@]}"; do - echo "--- applying $(basename "$m")" - PGPASSWORD=omadia-ci psql -h localhost -U omadia -d omadia \ - -v ON_ERROR_STOP=1 -f "$m" - done + while IFS= read -r dir; do + [ -z "$dir" ] && continue + echo "==> domain: $dir" + for f in "$dir"/*.sql; do + echo " applying $(basename "$f")" + PGPASSWORD=omadia-ci psql -h localhost -U omadia -d omadia \ + -v ON_ERROR_STOP=1 -f "$f" + done + done <<< "$MIGRATION_DOMAINS" - name: Re-apply migrations (idempotency check) run: | set -euo pipefail - declare -a MIGRATIONS=( - "middleware/packages/harness-knowledge-graph-neon/src/migrations/0001_graph_init.sql" - "middleware/src/services/graph/migrations/0002_user_scoping.sql" - "middleware/packages/harness-knowledge-graph-neon/src/migrations/0003_agentic_graph.sql" - "middleware/src/services/graph/migrations/0004_turn_fts.sql" - "middleware/packages/harness-knowledge-graph-neon/src/migrations/0005_turn_embeddings_768.sql" - "middleware/packages/harness-knowledge-graph-neon/src/migrations/0006_embedding_backfill_state.sql" - "middleware/src/services/graph/migrations/0007_verifier_tables.sql" - "middleware/src/services/graph/migrations/0008_teams_attachments.sql" - "middleware/src/plugins/routines/migrations/0001_routines.sql" - ) - for m in "${MIGRATIONS[@]}"; do - PGPASSWORD=omadia-ci psql -h localhost -U omadia -d omadia \ - -v ON_ERROR_STOP=1 -f "$m" > /dev/null - echo "✓ idempotent: $(basename "$m")" - done + while IFS= read -r dir; do + [ -z "$dir" ] && continue + for f in "$dir"/*.sql; do + PGPASSWORD=omadia-ci psql -h localhost -U omadia -d omadia \ + -v ON_ERROR_STOP=1 -f "$f" > /dev/null + echo "✓ idempotent: $(basename "$f")" + done + done <<< "$MIGRATION_DOMAINS" # ------------------------------------------------------------------ # Dependency audit. Enforces a "no high or critical" floor — moderate @@ -182,7 +185,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '22' cache: 'npm' cache-dependency-path: ${{ matrix.workspace }}/package-lock.json diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 329937552..fe63521a2 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -9,6 +9,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- 2026-05-17 — byte5ai engineering-standards bootstrap (PR #31). Repo is now + on `status: applied` against `byte5ai/engineering-standards`: + - `.github/engineering-standards.yml` as the explicit marker. + - `.hooks/pre-push` blocks direct pushes to `main`/`master` locally. + - `script/setup` enables the hook and runs the npm bootstrap in one step. + - AGENTS.md gained a "Git Workflow & Engineering Standards" section. + - CONTRIBUTING.md documents the pre-push guard and forbids + `Co-Authored-By:` trailers for AI agents. + - Branch protection on `main` is enforced server-side: PR required, + force-push and deletion blocked, all four CI workflows (five contexts + including the `audit` matrix) wired up as required status checks. + + GitHub Actions were disabled on the repo since 2026-05-11 and were + reactivated as part of this rollout. The first post-reactivation CI run + surfaced three pre-existing pipeline bugs that had been masked while + Actions were off — they're fixed in the same wave, see *Fixed* below. + +### Fixed + +- 2026-05-17 — Three pre-existing bugs in the CI pipeline, surfaced once + Actions were reactivated: + - `.github/workflows/ci.yml` pinned `setup-node@v4` to `node-version: '20'` + in three places, but `middleware/package.json` declares + `engines.node ">=22 <23"`. `npm ci` failed with `EBADENGINE` in the + `middleware` and `audit (middleware)` jobs. Bumped to `'22'`. + - The `schema (migrations on pgvector)` job applied a hardcoded list of + nine migrations, four of which had moved or been renumbered as the + knowledge-graph schema grew (`harness-knowledge-graph-neon` now ships + 13 migrations, two more domains were added — `auth/`, + `profileSnapshots/`, `profileStorage/`). Replaced the array with a + glob over five migration domains, applied in lexical order. Coverage + grew from 9 to 20 migrations. + - `middleware/src/index.ts:398` triggered `prefer-const` because + eslint's reassignment analysis doesn't trace the forward-reference + assignment ~1300 lines later in `main()`. Documented the intent and + suppressed the rule on that one line. + ### Changed - `docs/CHANGELOG.md` reformatted to follow the Keep-a-Changelog convention. diff --git a/middleware/profiles/minimal-dev.yaml b/middleware/profiles/minimal-dev.yaml index bded25074..67abedb7f 100644 --- a/middleware/profiles/minimal-dev.yaml +++ b/middleware/profiles/minimal-dev.yaml @@ -3,8 +3,8 @@ id: minimal-dev name: Minimal Dev description: In-memory knowledge graph, no verifier. Embeddings are included because orchestrator-extras requires embeddingClient@^1. Add channel plugins via the admin UI after the profile applies. plugins: - - @omadia/memory - - @omadia/knowledge-graph-inmemory - - @omadia/embeddings - - @omadia/orchestrator-extras - - @omadia/orchestrator + - "@omadia/memory" + - "@omadia/knowledge-graph-inmemory" + - "@omadia/embeddings" + - "@omadia/orchestrator-extras" + - "@omadia/orchestrator" diff --git a/middleware/profiles/production.yaml b/middleware/profiles/production.yaml index 5c4c9f11e..50d298ff6 100644 --- a/middleware/profiles/production.yaml +++ b/middleware/profiles/production.yaml @@ -3,9 +3,11 @@ id: production name: Recommended Production description: Postgres-backed knowledge graph + verifier + full orchestrator stack. Operator sets DATABASE_URL + ANTHROPIC_API_KEY before profile apply, then installs channel plugins via the admin UI. plugins: - - @omadia/memory - - @omadia/knowledge-graph-neon - - @omadia/embeddings - - @omadia/orchestrator-extras - - @omadia/verifier - - @omadia/orchestrator + - "@omadia/memory" + - "@omadia/knowledge-graph-neon" + - "@omadia/embeddings" + - "@omadia/orchestrator-extras" + - "@omadia/verifier" + - "@omadia/orchestrator" + - "de.byte5.channel.teams" + - "de.byte5.channel.telegram" diff --git a/middleware/src/index.ts b/middleware/src/index.ts index 304a1aebf..bceeb5161 100644 --- a/middleware/src/index.ts +++ b/middleware/src/index.ts @@ -394,7 +394,10 @@ async function main(): Promise { // Forward reference for the channel registry — constructed later in boot // (after the channel-SDK adapters are wired up). The install hooks below // close over this variable so post-install activations dispatched to a - // channel-kind plugin reach the right runtime once it exists. + // channel-kind plugin reach the right runtime once it exists. The + // assignment happens further down in main() once the channel runtime + // is wired; eslint's prefer-const doesn't trace through that depth. + // eslint-disable-next-line prefer-const let channelRegistryRef: ChannelRegistry | undefined; const installService = new InstallService({ diff --git a/middleware/test/profileLoader.test.ts b/middleware/test/profileLoader.test.ts index 62d9702ec..b7fa5cb18 100644 --- a/middleware/test/profileLoader.test.ts +++ b/middleware/test/profileLoader.test.ts @@ -103,8 +103,8 @@ describe('profileLoader / object-form entries with config', () => { 'name: With Config', 'description: Mixed string and object plugin entries', 'plugins:', - ' - @omadia/memory', - ' - id: @omadia/knowledge-graph-neon', + ' - "@omadia/memory"', + ' - id: "@omadia/knowledge-graph-neon"', ' config:', ' graph_tenant_id: my-tenant', '', @@ -193,8 +193,8 @@ describe('profileLoader / invalid inputs', () => { 'name: x', 'description: x', 'plugins:', - ' - @omadia/memory', - ' - @omadia/memory', + ' - "@omadia/memory"', + ' - "@omadia/memory"', ].join('\n'), ); await assert.rejects(loadProfile(file), /duplicate plugin id/); diff --git a/middleware/test/profilesRouter.test.ts b/middleware/test/profilesRouter.test.ts index 64aa19346..45980f01b 100644 --- a/middleware/test/profilesRouter.test.ts +++ b/middleware/test/profilesRouter.test.ts @@ -102,8 +102,8 @@ describe('/api/v1/profiles router', () => { 'name: Production', 'description: Full stack', 'plugins:', - ' - @omadia/memory', - ' - @omadia/embeddings', + ' - "@omadia/memory"', + ' - "@omadia/embeddings"', '', ].join('\n'), ); @@ -116,7 +116,7 @@ describe('/api/v1/profiles router', () => { 'name: Minimal', 'description: Minimal stack', 'plugins:', - ' - @omadia/memory', + ' - "@omadia/memory"', '', ].join('\n'), ); @@ -129,7 +129,7 @@ describe('/api/v1/profiles router', () => { 'name: With Config', 'description: Object-form entries', 'plugins:', - ' - id: @omadia/memory', + ' - id: "@omadia/memory"', ' config:', ' retention_days: 30', '',