Skip to content

[JUM-841][CI] Verify npm org access before publishing - #407

Merged
web2solutions merged 1 commit into
devfrom
kimi/ci/JUM-841-npm-publish-wiring
Sep 21, 2026
Merged

web2solutions merged 1 commit into
devfrom
kimi/ci/JUM-841-npm-publish-wiring

Conversation

@web2solutions

@web2solutions web2solutions commented Sep 21, 2026 •

Copy link
Copy Markdown
Owner

Summary

Wires the npm publish path end to end: the npm-publish GitHub environment now exists (created via API, matching the pin in npm-package-release.test.ts), the NPM_CI_CD repository secret is in place, and the publish job gains a first-class Verify npm org access step (JUM-859 check: absolute npm resolution + whoami/org ls) so a missing or under-scoped token fails before any artifact work. The stale unmasked NPM_JUMENTIX_CI_CD environment variable on env vars was removed (superseded by the repo secret; plain variables are not log-masked).

Problem Statement

Project Tracking (Required)

Branch Promotion Path (Required)

  • Source branch: kimi/ci/JUM-841-npm-publish-wiring
  • Target branch: dev
  • Required PR title format: [JUM-XXXX][Nature] <concise outcome>
  • The leading JUM-XXXX matches the single Linear Issue declared above.
  • This task PR targets dev.
  • This PR is not a direct task/topic branch promotion to main.

Bidirectional Traceability (Required)

  • Every linked issue already contains this PR URL.
  • Every linked issue already contains commit hash/range evidence.
  • PR description includes mapping of task -> commit(s).
  • Task -> commit(s) mapping:

Scope of Change

Adapters / Infrastructure

  • .github/workflows/npm-publish.yml: new Verify npm org access step before artifact validation, with NODE_AUTH_TOKEN: ${{ secrets.NPM_CI_CD }}.

Architecture and Design Alignment

  • No architectural impact; matches the existing pinned markers (environment: npm-publish, secrets.NPM_CI_CD, no token echo).

Security Impact

  • Security impact: positive — removes an unmasked token variable; the org check fails closed before publish on bad credentials.
  • Secrets handling reviewed: [x] Yes
  • Input/output sanitization reviewed: [x] N/A
  • AuthN/AuthZ impact: [ ] Yes [x] No
  • Data exposure risk: [ ] Yes [x] No
  • Sonar security findings addressed or unaffected: [x] Yes

Data and Migration Impact

  • Data model impact: none. Migration: [x] No.

Breaking Changes

None.

Acceptance Criteria

  • Publish workflow resolves the token and verifies org access before any artifact step.

Test Plan (Evidence)

  • bun x jest ci-cd/test/npm-package-release.test.ts ci-cd/test/check-npm-org-integration.test.ts ci-cd/test/check-ci-provider.test.ts — 45 pass
  • pre-commit ci:gate:branch passed (commit 085b1f2)

Coverage

  • Project coverage >= 95%: [x] Yes (workflow-only)
  • Patch coverage >= 95%: [x] Yes
  • Codecov status passing: pending CI

SonarQube Cloud

  • Quality Gate passing: pending CI
  • New vulnerabilities introduced: [ ] Yes [x] No
  • New security hotspots reviewed: [x] N/A

Performance / Reliability Impact

Adds ~5s (whoami + org ls) to a manual publish run.

Observability

  • Logs updated: [x] Yes (the org check prints the authenticated user)

Deployment and Rollout

Risks and Mitigations

  1. Risk: the org check consumes an npm API round trip on every publish run.
    Mitigation: manual workflow; seconds of latency; fails closed on scope loss which is the point.

Documentation Updates

  • README updated (not needed)
  • Additional docs updated (not needed)
  • Changelog untouched; GitHub Actions synchronizes it after the validated dev merge

Reviewer Checklist

  • Changes are clear and scoped.
  • Acceptance criteria are testable and satisfied.
  • Tests are sufficient for risk level.
  • Security and data impacts are addressed.
  • CI checks pass fully. (in progress)

Note

Low Risk
Workflow-only change that adds a fail-fast credential gate; no application or auth logic changes.

Overview
The npm-publish workflow now runs Verify npm org access immediately after dependency install and before artifact validation or any publish step.

That step sets NODE_AUTH_TOKEN from secrets.NPM_CI_CD and runs bun run npm:org:check:jumentix (the existing JUM-859 org/whoami check). A missing or under-scoped token fails the job early instead of surfacing errors later during package checks or npm publish.

Reviewed by Cursor Bugbot for commit 085b1f2. Bugbot is set up for automated code reviews on this repo. Configure here.

The npm-publish job binds the (now created) npm-publish environment and
reads the NPM_CI_CD repository secret, but jumped straight from install
to artifact validation to npm publish. Run the org access check
(JUM-859, absolute npm resolution + whoami/org ls) as a first-class step
so a missing or under-scoped token fails before any artifact work.
Environment variable NPM_JUMENTIX_CI_CD on 'env vars' was removed: it
duplicated the repository secret and, as a plain variable, was not
masked in logs.
@cursor

cursor Bot commented Sep 21, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_3f34ce17-9871-4507-8c69-4cb91f807542)

@sonarqubecloud

Copy link
Copy Markdown

@web2solutions
web2solutions merged commit d76896f into dev Sep 21, 2026
29 checks passed
web2solutions added a commit that referenced this pull request Sep 22, 2026
…h readiness, CI governance (#409)

* feat(frontend): domain dashboards from OAS metrics

JUM-811…814: widget grid, OAS metrics widgets, Users examples, axe, docs.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(ci): analyse main and dev on sonar and codecov (#355)

Clear Sonar reliability bugs, replace the broken coverage measure badge,
run the coverage job (Codecov upload + Sonar) on main and dev, and embed
the Codecov grid graph in the READMEs (JUM-823).

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(latent): clear bugs documented during JUM-821 promotion rounds (JUM-839) (#356)

- monitoringCharts drawStackedArea: guard null series in the totals
  reduce, matching the neighboring guards (TypeError latent)
- RestAPI getHandlerFactory: typeof guard on the handler default, matching
  RealtimeAPIBase; truthy non-function defaults now fall through to the
  next framework candidate instead of throwing 'not a function'
- UserService: drop dead newData ?? {} (newData is always an object)
- purgeTombstones parseInstant: document the owner decision — numeric
  epoch deletedAt is not an accepted representation and is intentionally
  never purged (contract: ISO string or Date)
- CommercialPages: update the relationship snippet to the string-named
  decorator syntax

Validated: 371 tests across 33 suites green under bun:test --isolate,
RestAPI.nonFunctionDefault 1/1 on both runners, lint clean.

* [JUM-840][Governance] Retire superseded governance material (#357)

* docs: retire superseded governance material

* fix(ci): resolve git binary for governance docs check

* style(docs): remove trailing blank lines

* chore(governance): restore suite and tooling ownership (JUM-824)

Add Req 137 and arch:check-ownership-placement; move SM suites, tooling
proof suites, and component scripts into owner homes; delete dual-home
package clones; wire the gate into ci:gate and branch preflight.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(ci): enforce public quality reporting (#359)

* fix: empty ownership allow-list and clear Sonar debt

Refine Req 137 heuristics so comments and ci-cd fixtures stop false
positives, keep SM-api @src composition, document suite homes, and harden
CLI path joins against traversal findings.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: drop ownership --root CLI to clear Sonar S8707

CLI always scans process.cwd(); programmatic callers still pass a root
for fixtures. Use path.relative containment before every filesystem join.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs: align Codecov grids (#360)

* docs: restore public project badges (#361)

* fix: clear Sonar reliability bug and ownership regex smells

Use isEntryPoint in frontend coverage CLI (S3403) and drop super-linear
regexes in the ownership gate so PR security and reliability stay at A.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs: [JUM-844] make product setup CLI-first

* chore: clear ownership path freeze leftovers for JUM-834 (#362)

Update requirement evidence and comments to the post-move homes, and
rewrite stale suite paths in the branch-quality-gate artifact.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat: [JUM-841] prepare npm package publication

* ci: retarget coverage jobs to packages/cana browser scripts

Coverage steps still called removed ci-cd/ paths after JUM-836 moved the
runners under packages/cana/scripts (JUM-842).

* chore: sync changelog for JUM-842 coverage path retarget

* test(JUM-857): restore branch coverage to >= 98% for the release gate (#367)

The release-gate coverage job on promotion PR #366 failed (branches
97.51% < 98%, Requirements 020/063) because the gate only runs on
promotions and the deficit accumulated on dev since promotion #353.

Add functional unit tests covering 40 previously uncovered in-scope
branch paths across backend-template, service-management (UI, state,
vendor sync scripts), service-management-api Catalogs, ci-cd tooling
and designer-core. Local gate: branches 98.53%.

Also fix the agent-registry CLI package root path broken by the JUM-824
ownership move (bin/ relocated from ci-cd/ without updating the
relative path), which made agent-registry:register/heartbeat fail.

* test(JUM-858): cover JUM-811 dashboard metrics lines for the patch-coverage gate (#368)

The promotion gate on PR #366 advanced past full branch coverage (JUM-857)
and failed the next gate: patch coverage 93.31% (265/284) < 99%. The
uncovered changed lines came from JUM-811 (PR #354):
apps/frontend/src/components/dashboard/loadMetrics.ts (offline/Cana path)
and apps/frontend/src/contracts/metricsSchema.ts (two branches).

Add a bun:test suite for loadMetrics driving a real Cana test DB
(openCana/wipeCanaDatabase precedent from the localRepository suite):
localRecords with and without since, the Cana-open loadMetrics branch
(count and groupBy variants), and countPendingLocal open/closed. Extend
metricsSchema.test.ts with the interval-preservation and
unknown-operation-id cases. All named lines now hit per lcov.

* fix(JUM-859): resolve npm by absolute path in check-npm-org-integration (#369)

Valid Sonar finding (javascript:S4036, code-scanning alert #114) on
promotion PR #366: execFileSync('npm', ...) resolved the credential-check
CLI through PATH, where a writable earlier entry can shadow the real npm
and answer the authentication questions as an impostor.

Follow the repo precedent from ci-cd/lib/git-binary.js: resolve an absolute
invocation from npm's own self-report (npm_execpath/npm_node_execpath,
validated against bun's script-compat self-report), then the npm bundled
next to the running node binary, then fixed install locations, and fail
closed otherwise. Extract checkNpmOrgAccess with an injectable runner so
the failure and parse branches are covered without touching npm; main()
stays a thin entry-point wrapper. 13 unit tests.

* fix(JUM-860): enforce Sonar reliability against the analyzed branch (#370)

The promotion gate on PR #366 failed 'Enforce SonarCloud reliability A'
against a stale analysis: on a dev->main promotion PR the scanner submits
a pull-request analysis, which never refreshes the base branch measures,
so the check read the pre-promotion main rating (4.0) even though every
one of its 36 bugs is already fixed on dev (78ba64f, PR #355).

- ci-cd/check-npm-package-release.js: replace the inline
  'require.main === module' guard (Sonar S3403, the exact pattern
  ci-cd/lib/entry-point.js exists for) with isEntryPoint(module) — the
  one real open BUG on dev.
- .github/workflows/ci.yml: resolve SONAR_BRANCH from
  github.head_ref || github.ref_name so promotion PRs enforce against
  the head branch (analyzed on every push to dev) instead of the stale
  base branch; the workflow comment records the skew mechanics.

* docs(governance): rewrite Req 037 as factory generator CLI v2

Normative rules for init/add/upgrade/doctor, packaged templates,
freshness gate, and generated-project contract before CLI core work.

* refactor(cli-init): add TS command router, prompts and init config

Ship jumentix init|add|upgrade|doctor help surface with TypeScript
build to dist, legacy --service-type mapping, and jumentix.init.json
round-trip (JUM-844).

* fix(cli-init): build dist before suites when missing

Jest gate loads cli-init tests without pretest; ensure dist exists so
require('../dist/...') resolves in CI (JUM-844).

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(JUM-865): enforce PR feedback and Sonar reliability gates

* fix(JUM-865): fail closed Bun installation in CI

* ci(JUM-862): synchronize changelog through a PR instead of pushing to dev (#372)

Branch protection rejects the direct push to dev (GH006) and allow_auto_merge
is off, so the sync-changelog job now opens chore/changelog-sync-<sha>, waits
for required checks with gh pr checks --watch --fail-fast, and squash-merges.
Failures after the push print the PR URL and exit 1, leaving it for manual
handling. check-ci-provider now pins the PR-based markers instead of the
removed direct push.

* fix(JUM-863): make versionless catalog delete unconditional and unshadow deletedAt (#374)

CatalogDataRepository.delete passed expectedVersion ?? -1 into a literal
staleness comparison, so delete(id) without a version always conflicted
(expected -1, current is 1). An absent expectedVersion is now the
unconditional-delete sentinel: the staleness check only guards
optimistic-concurrency deletes, and the service forwards the undefined
through deleteCatalogById instead of coercing -1. The Deleted integration
event now carries the post-tombstone version (current.version + 1) instead
of the incoherent (expectedVersion ?? -1) + 1, which emitted 0 for
unconditional deletes.

Catalog's getter-only deletedAt shadowed BaseModel's accessor pair, so
external assignment threw a TypeError and the getter hid a null tombstone
behind ''. The shadow is removed: Catalog inherits string | null accessors,
ICatalog/CatalogFactory widen deletedAt accordingly, and the constructor
keeps normalizing null to '' so persisted documents keep the convention
the active-feed filter relies on.

* fix(JUM-864): validate keyPath segments at the point of use in writePath (#375)

The __proto__/constructor/prototype guard ran as a separate loop before
the write loops, so CodeQL js/prototype-pollution-utility (alert #33) did
not recognize it as a sanitizer for the recursive writes. The guard now
runs immediately before each segment is used to index or assign, in a
single traversal, with the same canaError InvalidRequest message and the
throw still naming the offending segment. Cypress regression coverage
extends the prototype-chain keyPath test to constructor and prototype
segments.

* ci(JUM-862): grant pull-requests write to sync-changelog (#378)

The PR-based changelog sync pushed its branch and then failed at
gh pr create: the job token only had contents:write, and PR creation
requires pull-requests:write (GraphQL: Resource not accessible by
integration).

* chore: synchronize changelog (#380)

* chore: synchronize changelog

* chore: synchronize changelog (signed)

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* feat(cli-init): package backend/frontend seeds with freshness gate

Bundle lean template slices under packages/cli-init/templates and fail
ci:gate when they drift from apps seeds (JUM-845). Size: 5.0M.
Exclude packaged templates from root build:dev typecheck.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(release): make @jumentix packages and cli-init publishable

Expand the public npm cohort for generated-project dependencies, fix package
dist emission for publishable entrypoints, and keep release dry-run gates green
without claiming a live registry publish while NPM_TOKEN is unavailable.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(cli-init): resolve sources into GenerationPlan

Load designer export, OAS, catalog URL, or Users preset into one
validated GenerationPlan for factory init (JUM-846).

Co-authored-by: Cursor <cursoragent@cursor.com>

* ci(JUM-862): open changelog PRs with a PAT and poll mergeability (#385)

Two follow-ups from the first live runs of the PR-based changelog sync:

- PRs opened with GITHUB_TOKEN never trigger pull_request_target
  workflows, and dev's protection now requires their contexts
  (pr-feedback, sonar-reliability) - a bot-opened PR can never satisfy
  them. The job now creates the PR with the CHANGELOG_GH_TOKEN secret
  (fine-grained PAT, contents rw + pull-requests rw, this repo only) so
  the required checks actually run; fail closed with manual
  instructions when the secret is absent.
- 'gh pr checks --watch --fail-fast' aborts on any failing check,
  including non-required ones that fail on every PR (code-scanning AI
  findings). Replaced with a mergeStateStatus poll (CLEAN/UNSTABLE/HAS_HOOKS)
  which reflects exactly the required-context state.

* chore: synchronize changelog (#383)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Eduardo Almeida <eduardo@xpertminds.dev>

* feat(cli-init): generate backend services from GenerationPlan

Slice templates/backend per service, inject hexagonal domains, and
render env/package metadata for factory init (JUM-847).

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(cli-init): sanitize npm name segments without ReDoS regex

Replace quantified character-class replaces with a linear scan so CodeQL
polynomial-regex findings on package scope/service id sanitization clear.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(cli-init): generate frontend seed from GenerationPlan

Wire generateFrontend for hybrid/frontend modes (JUM-848): copy the
packaged frontend template, bake merged OAS contracts, emit one module
per domain with entity configs from OAS operation ids and
x-list-capabilities, write Core/service .env URLs, and honor --offline
for the Cana layer.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(cli-init): slugify identifiers without ReDoS regex

Linear-scan slugify/camelCase for frontend module names so CodeQL
character-class quantifier findings stay clear on the stack tip.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(cli-init): assemble generated workspace root and manifests

Wire JUM-849 root assembly after backend/frontend generation: Bun workspaces,
docker-compose, README, .jumentix project/manifest, init answers, --git/--install.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(cli-init): add domain|service|frontend to generated projects

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(cli-init): upgrade generated projects with three-way merge

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(cli-init): doctor env and project diagnostics

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(cli-init): add generation e2e matrix harness

JUM-854: timed CLI generation matrix; Docker cells gated by
CLI_INIT_E2E_DOCKER=1.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(cli-init): link designer-core for spawned e2e CLI

Cold CI often lacks the nested workspace symlink. ensure-built now builds
designer-core and recreates the link so bun bin/jumentix.js can resolve it.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs(cli-init): factory getting-started and bootstrap EN/PT

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs(cli-init): req 094 epic closure record for factory v1

Co-authored-by: Cursor <cursoragent@cursor.com>

* [JUM-866][Fix] Restore long-lived CI health (#393)

* [JUM-866][Fix] Restore long-lived CI health

* fix: [JUM-866] harden task CI prerequisites

* fix: [JUM-866] bootstrap Bun for browser matrix

* fix: [JUM-866] order workspace package builds

* fix: [JUM-866] enforce Sonar PR reliability

* fix: [JUM-866] keep Sonar PR analysis unprivileged

* fix: [JUM-866] avoid manifest error disclosure

* docs(cli-init): fill factory epic closure merge evidence

Record C5-C14 PR URLs and merge SHAs EN/PT. Note live npm still
needs NPM_TOKEN (Req 130).

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: synchronize changelog

* ci(JUM-862): bind sync-changelog to the env vars environment (#399)

CHANGELOG_GH_TOKEN was created as an environment secret under 'env vars'
(the same environment the coverage job already uses), which repository
jobs cannot read without an explicit environment binding. The job
otherwise degrades to the manual-instructions path on every drift cycle.

check-ci-provider's environment-scoped-secrets test stripped only the
first 'environment: env vars' line; with two jobs bound to the
environment that left the check green and the assertion vacuous — it now
strips every binding.

* [JUM-870][Fix] Restore npm pack gate and map NPM_CI_CD (#398)

* fix(ci-cd): allow template envs and pack with bun

cli-init ships seed .env under templates/, and npm pack left workspace:*
ranges that break consumer install. Gate now allows templates/.env* and
uses bun pm pack so published deps resolve.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(ci-cd): restore npm pack gate and map NPM_CI_CD

Allow templates/.env seeds, pack with bun pm so workspace:* rewrites,
and wire the npm-publish workflow to secrets.NPM_CI_CD.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: synchronize changelog (#402)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* [JUM-862][CI] Treat UNKNOWN merge state as retryable in the changelog sync poll (#401)

* ci(JUM-862): treat UNKNOWN merge state as retryable in sync poll

The first fully-automated changelog run created its PR with the PAT and
then aborted: mergeStateStatus is UNKNOWN for the first seconds after
PR creation while GitHub computes mergeability lazily, and the poll
treated it as fatal. UNKNOWN now stays in the retry loop (first live
evidence: run on push 8a1e1af, PR #400).

* fix(JUM-866): exempt SonarCloud quality-gate decorations from the PR feedback gate

The gate demands a resolution marker for every general PR comment that
is neither a marker nor a Cursor usage-limit notice. SonarCloud posts
its Quality Gate banner on every analyzed PR (and updates it in place),
so every PR was accumulating a failing pr-feedback context - first seen
blocking the changelog automation's own PR (#400) and this PR (#401).
The banner carries no human feedback; it is now exempt alongside the
Cursor notice, with the same author-plus-content pairing so a human
impersonating the bot does not slip through.

* chore: synchronize changelog (#404)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* ci(JUM-841): verify npm org access before publishing (#407)

The npm-publish job binds the (now created) npm-publish environment and
reads the NPM_CI_CD repository secret, but jumped straight from install
to artifact validation to npm publish. Run the org access check
(JUM-859, absolute npm resolution + whoami/org ls) as a first-class step
so a missing or under-scoped token fails before any artifact work.
Environment variable NPM_JUMENTIX_CI_CD on 'env vars' was removed: it
duplicated the repository secret and, as a plain variable, was not
masked in logs.

* [JUM-821][Chore] Reconcile main squash ancestry into dev (#408)

* [JUM-821][Release] Promote dev to main (#366)

* feat(frontend): domain dashboards from OAS metrics

JUM-811…814: widget grid, OAS metrics widgets, Users examples, axe, docs.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(ci): analyse main and dev on sonar and codecov (#355)

Clear Sonar reliability bugs, replace the broken coverage measure badge,
run the coverage job (Codecov upload + Sonar) on main and dev, and embed
the Codecov grid graph in the READMEs (JUM-823).

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(latent): clear bugs documented during JUM-821 promotion rounds (JUM-839) (#356)

- monitoringCharts drawStackedArea: guard null series in the totals
  reduce, matching the neighboring guards (TypeError latent)
- RestAPI getHandlerFactory: typeof guard on the handler default, matching
  RealtimeAPIBase; truthy non-function defaults now fall through to the
  next framework candidate instead of throwing 'not a function'
- UserService: drop dead newData ?? {} (newData is always an object)
- purgeTombstones parseInstant: document the owner decision — numeric
  epoch deletedAt is not an accepted representation and is intentionally
  never purged (contract: ISO string or Date)
- CommercialPages: update the relationship snippet to the string-named
  decorator syntax

Validated: 371 tests across 33 suites green under bun:test --isolate,
RestAPI.nonFunctionDefault 1/1 on both runners, lint clean.

* [JUM-840][Governance] Retire superseded governance material (#357)

* docs: retire superseded governance material

* fix(ci): resolve git binary for governance docs check

* style(docs): remove trailing blank lines

* chore(governance): restore suite and tooling ownership (JUM-824)

Add Req 137 and arch:check-ownership-placement; move SM suites, tooling
proof suites, and component scripts into owner homes; delete dual-home
package clones; wire the gate into ci:gate and branch preflight.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(ci): enforce public quality reporting (#359)

* fix: empty ownership allow-list and clear Sonar debt

Refine Req 137 heuristics so comments and ci-cd fixtures stop false
positives, keep SM-api @src composition, document suite homes, and harden
CLI path joins against traversal findings.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: drop ownership --root CLI to clear Sonar S8707

CLI always scans process.cwd(); programmatic callers still pass a root
for fixtures. Use path.relative containment before every filesystem join.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs: align Codecov grids (#360)

* docs: restore public project badges (#361)

* fix: clear Sonar reliability bug and ownership regex smells

Use isEntryPoint in frontend coverage CLI (S3403) and drop super-linear
regexes in the ownership gate so PR security and reliability stay at A.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs: [JUM-844] make product setup CLI-first

* chore: clear ownership path freeze leftovers for JUM-834 (#362)

Update requirement evidence and comments to the post-move homes, and
rewrite stale suite paths in the branch-quality-gate artifact.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat: [JUM-841] prepare npm package publication

* ci: retarget coverage jobs to packages/cana browser scripts

Coverage steps still called removed ci-cd/ paths after JUM-836 moved the
runners under packages/cana/scripts (JUM-842).

* chore: sync changelog for JUM-842 coverage path retarget

* test(JUM-857): restore branch coverage to >= 98% for the release gate (#367)

The release-gate coverage job on promotion PR #366 failed (branches
97.51% < 98%, Requirements 020/063) because the gate only runs on
promotions and the deficit accumulated on dev since promotion #353.

Add functional unit tests covering 40 previously uncovered in-scope
branch paths across backend-template, service-management (UI, state,
vendor sync scripts), service-management-api Catalogs, ci-cd tooling
and designer-core. Local gate: branches 98.53%.

Also fix the agent-registry CLI package root path broken by the JUM-824
ownership move (bin/ relocated from ci-cd/ without updating the
relative path), which made agent-registry:register/heartbeat fail.

* test(JUM-858): cover JUM-811 dashboard metrics lines for the patch-coverage gate (#368)

The promotion gate on PR #366 advanced past full branch coverage (JUM-857)
and failed the next gate: patch coverage 93.31% (265/284) < 99%. The
uncovered changed lines came from JUM-811 (PR #354):
apps/frontend/src/components/dashboard/loadMetrics.ts (offline/Cana path)
and apps/frontend/src/contracts/metricsSchema.ts (two branches).

Add a bun:test suite for loadMetrics driving a real Cana test DB
(openCana/wipeCanaDatabase precedent from the localRepository suite):
localRecords with and without since, the Cana-open loadMetrics branch
(count and groupBy variants), and countPendingLocal open/closed. Extend
metricsSchema.test.ts with the interval-preservation and
unknown-operation-id cases. All named lines now hit per lcov.

* fix(JUM-859): resolve npm by absolute path in check-npm-org-integration (#369)

Valid Sonar finding (javascript:S4036, code-scanning alert #114) on
promotion PR #366: execFileSync('npm', ...) resolved the credential-check
CLI through PATH, where a writable earlier entry can shadow the real npm
and answer the authentication questions as an impostor.

Follow the repo precedent from ci-cd/lib/git-binary.js: resolve an absolute
invocation from npm's own self-report (npm_execpath/npm_node_execpath,
validated against bun's script-compat self-report), then the npm bundled
next to the running node binary, then fixed install locations, and fail
closed otherwise. Extract checkNpmOrgAccess with an injectable runner so
the failure and parse branches are covered without touching npm; main()
stays a thin entry-point wrapper. 13 unit tests.

* fix(JUM-860): enforce Sonar reliability against the analyzed branch (#370)

The promotion gate on PR #366 failed 'Enforce SonarCloud reliability A'
against a stale analysis: on a dev->main promotion PR the scanner submits
a pull-request analysis, which never refreshes the base branch measures,
so the check read the pre-promotion main rating (4.0) even though every
one of its 36 bugs is already fixed on dev (78ba64f, PR #355).

- ci-cd/check-npm-package-release.js: replace the inline
  'require.main === module' guard (Sonar S3403, the exact pattern
  ci-cd/lib/entry-point.js exists for) with isEntryPoint(module) — the
  one real open BUG on dev.
- .github/workflows/ci.yml: resolve SONAR_BRANCH from
  github.head_ref || github.ref_name so promotion PRs enforce against
  the head branch (analyzed on every push to dev) instead of the stale
  base branch; the workflow comment records the skew mechanics.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(release): drop duplicate pre-commit check from main reconcile

The squash ancestry merge auto-inserted a second identical
preCommitPath guard; keep a single check.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>

* ci(JUM-866): guard the patch-report frontend coverage step to PRs (#410)

'Produce frontend coverage for the patch report' ran unconditionally in
the coverage job, while the step that consumes it (Enforce patch
coverage) already guards on pull_request. On dev push runs where the
coverage job is selected, the producer failed after ~13m (no PR patch
context), failing the whole job despite the full-suite thresholds
passing (branches 98.22%).

* fix(JUM-872): address PR #409 review findings on dev (#411)

Patch coverage (Codecov 81.59% -> 100% lines on the changed files):
- packages/cli-init/scripts/check-template-freshness.js: 24 uncovered
  lines driven by 13 new functional cases in the existing suite (seed
  walk errors, manifest drift shapes, entry-point guard/catch).
- packages/cli-init/scripts/build-templates.js: 13 uncovered lines
  driven by 6 new cases (resolveSourceCommit with/without git, missing
  seed, stripExcludedFromTree, direct run, entry-point success/catch).

Sonar S4036 (PATH resolution) in cli-init tooling:
- ensure-built.js: process.execPath instead of bare 'bun'.
- run-generation-matrix.ts: fixed-candidate absolute docker resolution,
  failing closed to 'not available' (git-binary.js precedent).
- legacy/bootstrap.ts runCommand: explicit absolute-path registry for
  git/bun/node; absolute paths pass through; unknown bare commands
  refused (fail closed).

Entry-point tests are runner-dual: full execution under jest (the
coverage runner) and an honest require-only assertion under bun:test
(where require.main is absent on test workers).

* ci(JUM-862): bind bot-token jobs to the consolidated secrets environment (#412)

All bot tokens were consolidated into the GitHub 'secrets' environment
(CHANGELOG_GH_TOKEN, NPM_CI_CD, NPM_JUMENTIX_CI_CD now live there):
- sync-changelog: environment env vars -> secrets (CHANGELOG_GH_TOKEN).
- npm-publish: environment npm-publish -> secrets (NPM_CI_CD); the empty
  npm-publish environment is superseded.
- npm-package-release gate: pins the new environment name.

* chore: synchronize changelog (#413)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* [JUM-871][Fix] Build workspace packages in topological level order (#414)

* fix(JUM-871): build workspace packages in topological level order

The parallel 'bun run --filter' build let a dependent package's tsc race
its workspace dependencies' dist emission, failing intermittently with
TS2307 (sdk-grpc-client vs shared-contracts observed repeatedly on the
promotion gate). New ci-cd/build-workspace-packages.js discovers
packages, builds the workspace dependency graph, and runs Kahn levels:
parallel within a level, sequential across levels, spawned via the
running interpreter. Cycles and empty workspaces fail closed; a build
failure aborts later levels naming the package.

Also fixes a latent jest.config.js bug this exposed:
modulePathIgnorePatterns '.build' treated the dot as regex-any, silently
crawling out any path containing <anychar>build; scoped to <rootDir>/
\.build etc. (479 -> 480 test files discovered, full gate green).

* fix(JUM-871): deterministic sort comparators in the topological builder

Sonar S2871 on the two level-sort calls: add an explicit comparator
preserving default UTF-16 code-unit order so level output is
deterministic across runtimes.

* chore: synchronize changelog (#415)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix(cli-init): [JUM-821] restore coverage setup (#416)

* fix(ci): [JUM-821] bootstrap promotion gates (#417)

* chore: synchronize changelog (#418)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix(cli-init): [JUM-821] resolve Bun in Actions (#419)

* chore: synchronize changelog (#420)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix(ci): build workspaces topologically (#421)

* fix(ci): [JUM-821] build workspaces topologically

* fix(ci): [JUM-821] sync changelog only on main

* fix(ci): [JUM-821] build dependencies before workspace tests (#422)

* fix(ci): [JUM-821] harden isolated promotion jobs (#423)

* fix(ci): retry transient Redis registry failures (#424)

* fix(ci): retry database compose startup (#425)

* test(backend): cover paging fallbacks (#426)

* fix(ci): prepare frontend coverage dependencies (#427)

* fix(ci): scope release patch coverage to dev baseline (#428)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
web2solutions added a commit that referenced this pull request Sep 22, 2026
* feat(frontend): domain dashboards from OAS metrics

JUM-811…814: widget grid, OAS metrics widgets, Users examples, axe, docs.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(ci): analyse main and dev on sonar and codecov (#355)

Clear Sonar reliability bugs, replace the broken coverage measure badge,
run the coverage job (Codecov upload + Sonar) on main and dev, and embed
the Codecov grid graph in the READMEs (JUM-823).

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(latent): clear bugs documented during JUM-821 promotion rounds (JUM-839) (#356)

- monitoringCharts drawStackedArea: guard null series in the totals
  reduce, matching the neighboring guards (TypeError latent)
- RestAPI getHandlerFactory: typeof guard on the handler default, matching
  RealtimeAPIBase; truthy non-function defaults now fall through to the
  next framework candidate instead of throwing 'not a function'
- UserService: drop dead newData ?? {} (newData is always an object)
- purgeTombstones parseInstant: document the owner decision — numeric
  epoch deletedAt is not an accepted representation and is intentionally
  never purged (contract: ISO string or Date)
- CommercialPages: update the relationship snippet to the string-named
  decorator syntax

Validated: 371 tests across 33 suites green under bun:test --isolate,
RestAPI.nonFunctionDefault 1/1 on both runners, lint clean.

* [JUM-840][Governance] Retire superseded governance material (#357)

* docs: retire superseded governance material

* fix(ci): resolve git binary for governance docs check

* style(docs): remove trailing blank lines

* chore(governance): restore suite and tooling ownership (JUM-824)

Add Req 137 and arch:check-ownership-placement; move SM suites, tooling
proof suites, and component scripts into owner homes; delete dual-home
package clones; wire the gate into ci:gate and branch preflight.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(ci): enforce public quality reporting (#359)

* fix: empty ownership allow-list and clear Sonar debt

Refine Req 137 heuristics so comments and ci-cd fixtures stop false
positives, keep SM-api @src composition, document suite homes, and harden
CLI path joins against traversal findings.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: drop ownership --root CLI to clear Sonar S8707

CLI always scans process.cwd(); programmatic callers still pass a root
for fixtures. Use path.relative containment before every filesystem join.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs: align Codecov grids (#360)

* docs: restore public project badges (#361)

* fix: clear Sonar reliability bug and ownership regex smells

Use isEntryPoint in frontend coverage CLI (S3403) and drop super-linear
regexes in the ownership gate so PR security and reliability stay at A.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs: [JUM-844] make product setup CLI-first

* chore: clear ownership path freeze leftovers for JUM-834 (#362)

Update requirement evidence and comments to the post-move homes, and
rewrite stale suite paths in the branch-quality-gate artifact.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat: [JUM-841] prepare npm package publication

* ci: retarget coverage jobs to packages/cana browser scripts

Coverage steps still called removed ci-cd/ paths after JUM-836 moved the
runners under packages/cana/scripts (JUM-842).

* chore: sync changelog for JUM-842 coverage path retarget

* test(JUM-857): restore branch coverage to >= 98% for the release gate (#367)

The release-gate coverage job on promotion PR #366 failed (branches
97.51% < 98%, Requirements 020/063) because the gate only runs on
promotions and the deficit accumulated on dev since promotion #353.

Add functional unit tests covering 40 previously uncovered in-scope
branch paths across backend-template, service-management (UI, state,
vendor sync scripts), service-management-api Catalogs, ci-cd tooling
and designer-core. Local gate: branches 98.53%.

Also fix the agent-registry CLI package root path broken by the JUM-824
ownership move (bin/ relocated from ci-cd/ without updating the
relative path), which made agent-registry:register/heartbeat fail.

* test(JUM-858): cover JUM-811 dashboard metrics lines for the patch-coverage gate (#368)

The promotion gate on PR #366 advanced past full branch coverage (JUM-857)
and failed the next gate: patch coverage 93.31% (265/284) < 99%. The
uncovered changed lines came from JUM-811 (PR #354):
apps/frontend/src/components/dashboard/loadMetrics.ts (offline/Cana path)
and apps/frontend/src/contracts/metricsSchema.ts (two branches).

Add a bun:test suite for loadMetrics driving a real Cana test DB
(openCana/wipeCanaDatabase precedent from the localRepository suite):
localRecords with and without since, the Cana-open loadMetrics branch
(count and groupBy variants), and countPendingLocal open/closed. Extend
metricsSchema.test.ts with the interval-preservation and
unknown-operation-id cases. All named lines now hit per lcov.

* fix(JUM-859): resolve npm by absolute path in check-npm-org-integration (#369)

Valid Sonar finding (javascript:S4036, code-scanning alert #114) on
promotion PR #366: execFileSync('npm', ...) resolved the credential-check
CLI through PATH, where a writable earlier entry can shadow the real npm
and answer the authentication questions as an impostor.

Follow the repo precedent from ci-cd/lib/git-binary.js: resolve an absolute
invocation from npm's own self-report (npm_execpath/npm_node_execpath,
validated against bun's script-compat self-report), then the npm bundled
next to the running node binary, then fixed install locations, and fail
closed otherwise. Extract checkNpmOrgAccess with an injectable runner so
the failure and parse branches are covered without touching npm; main()
stays a thin entry-point wrapper. 13 unit tests.

* fix(JUM-860): enforce Sonar reliability against the analyzed branch (#370)

The promotion gate on PR #366 failed 'Enforce SonarCloud reliability A'
against a stale analysis: on a dev->main promotion PR the scanner submits
a pull-request analysis, which never refreshes the base branch measures,
so the check read the pre-promotion main rating (4.0) even though every
one of its 36 bugs is already fixed on dev (78ba64f, PR #355).

- ci-cd/check-npm-package-release.js: replace the inline
  'require.main === module' guard (Sonar S3403, the exact pattern
  ci-cd/lib/entry-point.js exists for) with isEntryPoint(module) — the
  one real open BUG on dev.
- .github/workflows/ci.yml: resolve SONAR_BRANCH from
  github.head_ref || github.ref_name so promotion PRs enforce against
  the head branch (analyzed on every push to dev) instead of the stale
  base branch; the workflow comment records the skew mechanics.

* docs(governance): rewrite Req 037 as factory generator CLI v2

Normative rules for init/add/upgrade/doctor, packaged templates,
freshness gate, and generated-project contract before CLI core work.

* refactor(cli-init): add TS command router, prompts and init config

Ship jumentix init|add|upgrade|doctor help surface with TypeScript
build to dist, legacy --service-type mapping, and jumentix.init.json
round-trip (JUM-844).

* fix(cli-init): build dist before suites when missing

Jest gate loads cli-init tests without pretest; ensure dist exists so
require('../dist/...') resolves in CI (JUM-844).

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(JUM-865): enforce PR feedback and Sonar reliability gates

* fix(JUM-865): fail closed Bun installation in CI

* ci(JUM-862): synchronize changelog through a PR instead of pushing to dev (#372)

Branch protection rejects the direct push to dev (GH006) and allow_auto_merge
is off, so the sync-changelog job now opens chore/changelog-sync-<sha>, waits
for required checks with gh pr checks --watch --fail-fast, and squash-merges.
Failures after the push print the PR URL and exit 1, leaving it for manual
handling. check-ci-provider now pins the PR-based markers instead of the
removed direct push.

* fix(JUM-863): make versionless catalog delete unconditional and unshadow deletedAt (#374)

CatalogDataRepository.delete passed expectedVersion ?? -1 into a literal
staleness comparison, so delete(id) without a version always conflicted
(expected -1, current is 1). An absent expectedVersion is now the
unconditional-delete sentinel: the staleness check only guards
optimistic-concurrency deletes, and the service forwards the undefined
through deleteCatalogById instead of coercing -1. The Deleted integration
event now carries the post-tombstone version (current.version + 1) instead
of the incoherent (expectedVersion ?? -1) + 1, which emitted 0 for
unconditional deletes.

Catalog's getter-only deletedAt shadowed BaseModel's accessor pair, so
external assignment threw a TypeError and the getter hid a null tombstone
behind ''. The shadow is removed: Catalog inherits string | null accessors,
ICatalog/CatalogFactory widen deletedAt accordingly, and the constructor
keeps normalizing null to '' so persisted documents keep the convention
the active-feed filter relies on.

* fix(JUM-864): validate keyPath segments at the point of use in writePath (#375)

The __proto__/constructor/prototype guard ran as a separate loop before
the write loops, so CodeQL js/prototype-pollution-utility (alert #33) did
not recognize it as a sanitizer for the recursive writes. The guard now
runs immediately before each segment is used to index or assign, in a
single traversal, with the same canaError InvalidRequest message and the
throw still naming the offending segment. Cypress regression coverage
extends the prototype-chain keyPath test to constructor and prototype
segments.

* ci(JUM-862): grant pull-requests write to sync-changelog (#378)

The PR-based changelog sync pushed its branch and then failed at
gh pr create: the job token only had contents:write, and PR creation
requires pull-requests:write (GraphQL: Resource not accessible by
integration).

* chore: synchronize changelog (#380)

* chore: synchronize changelog

* chore: synchronize changelog (signed)

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* feat(cli-init): package backend/frontend seeds with freshness gate

Bundle lean template slices under packages/cli-init/templates and fail
ci:gate when they drift from apps seeds (JUM-845). Size: 5.0M.
Exclude packaged templates from root build:dev typecheck.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(release): make @jumentix packages and cli-init publishable

Expand the public npm cohort for generated-project dependencies, fix package
dist emission for publishable entrypoints, and keep release dry-run gates green
without claiming a live registry publish while NPM_TOKEN is unavailable.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(cli-init): resolve sources into GenerationPlan

Load designer export, OAS, catalog URL, or Users preset into one
validated GenerationPlan for factory init (JUM-846).

Co-authored-by: Cursor <cursoragent@cursor.com>

* ci(JUM-862): open changelog PRs with a PAT and poll mergeability (#385)

Two follow-ups from the first live runs of the PR-based changelog sync:

- PRs opened with GITHUB_TOKEN never trigger pull_request_target
  workflows, and dev's protection now requires their contexts
  (pr-feedback, sonar-reliability) - a bot-opened PR can never satisfy
  them. The job now creates the PR with the CHANGELOG_GH_TOKEN secret
  (fine-grained PAT, contents rw + pull-requests rw, this repo only) so
  the required checks actually run; fail closed with manual
  instructions when the secret is absent.
- 'gh pr checks --watch --fail-fast' aborts on any failing check,
  including non-required ones that fail on every PR (code-scanning AI
  findings). Replaced with a mergeStateStatus poll (CLEAN/UNSTABLE/HAS_HOOKS)
  which reflects exactly the required-context state.

* chore: synchronize changelog (#383)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Eduardo Almeida <eduardo@xpertminds.dev>

* feat(cli-init): generate backend services from GenerationPlan

Slice templates/backend per service, inject hexagonal domains, and
render env/package metadata for factory init (JUM-847).

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(cli-init): sanitize npm name segments without ReDoS regex

Replace quantified character-class replaces with a linear scan so CodeQL
polynomial-regex findings on package scope/service id sanitization clear.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(cli-init): generate frontend seed from GenerationPlan

Wire generateFrontend for hybrid/frontend modes (JUM-848): copy the
packaged frontend template, bake merged OAS contracts, emit one module
per domain with entity configs from OAS operation ids and
x-list-capabilities, write Core/service .env URLs, and honor --offline
for the Cana layer.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(cli-init): slugify identifiers without ReDoS regex

Linear-scan slugify/camelCase for frontend module names so CodeQL
character-class quantifier findings stay clear on the stack tip.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(cli-init): assemble generated workspace root and manifests

Wire JUM-849 root assembly after backend/frontend generation: Bun workspaces,
docker-compose, README, .jumentix project/manifest, init answers, --git/--install.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(cli-init): add domain|service|frontend to generated projects

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(cli-init): upgrade generated projects with three-way merge

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(cli-init): doctor env and project diagnostics

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(cli-init): add generation e2e matrix harness

JUM-854: timed CLI generation matrix; Docker cells gated by
CLI_INIT_E2E_DOCKER=1.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(cli-init): link designer-core for spawned e2e CLI

Cold CI often lacks the nested workspace symlink. ensure-built now builds
designer-core and recreates the link so bun bin/jumentix.js can resolve it.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs(cli-init): factory getting-started and bootstrap EN/PT

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs(cli-init): req 094 epic closure record for factory v1

Co-authored-by: Cursor <cursoragent@cursor.com>

* [JUM-866][Fix] Restore long-lived CI health (#393)

* [JUM-866][Fix] Restore long-lived CI health

* fix: [JUM-866] harden task CI prerequisites

* fix: [JUM-866] bootstrap Bun for browser matrix

* fix: [JUM-866] order workspace package builds

* fix: [JUM-866] enforce Sonar PR reliability

* fix: [JUM-866] keep Sonar PR analysis unprivileged

* fix: [JUM-866] avoid manifest error disclosure

* docs(cli-init): fill factory epic closure merge evidence

Record C5-C14 PR URLs and merge SHAs EN/PT. Note live npm still
needs NPM_TOKEN (Req 130).

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: synchronize changelog

* ci(JUM-862): bind sync-changelog to the env vars environment (#399)

CHANGELOG_GH_TOKEN was created as an environment secret under 'env vars'
(the same environment the coverage job already uses), which repository
jobs cannot read without an explicit environment binding. The job
otherwise degrades to the manual-instructions path on every drift cycle.

check-ci-provider's environment-scoped-secrets test stripped only the
first 'environment: env vars' line; with two jobs bound to the
environment that left the check green and the assertion vacuous — it now
strips every binding.

* [JUM-870][Fix] Restore npm pack gate and map NPM_CI_CD (#398)

* fix(ci-cd): allow template envs and pack with bun

cli-init ships seed .env under templates/, and npm pack left workspace:*
ranges that break consumer install. Gate now allows templates/.env* and
uses bun pm pack so published deps resolve.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(ci-cd): restore npm pack gate and map NPM_CI_CD

Allow templates/.env seeds, pack with bun pm so workspace:* rewrites,
and wire the npm-publish workflow to secrets.NPM_CI_CD.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: synchronize changelog (#402)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* [JUM-862][CI] Treat UNKNOWN merge state as retryable in the changelog sync poll (#401)

* ci(JUM-862): treat UNKNOWN merge state as retryable in sync poll

The first fully-automated changelog run created its PR with the PAT and
then aborted: mergeStateStatus is UNKNOWN for the first seconds after
PR creation while GitHub computes mergeability lazily, and the poll
treated it as fatal. UNKNOWN now stays in the retry loop (first live
evidence: run on push 8a1e1af, PR #400).

* fix(JUM-866): exempt SonarCloud quality-gate decorations from the PR feedback gate

The gate demands a resolution marker for every general PR comment that
is neither a marker nor a Cursor usage-limit notice. SonarCloud posts
its Quality Gate banner on every analyzed PR (and updates it in place),
so every PR was accumulating a failing pr-feedback context - first seen
blocking the changelog automation's own PR (#400) and this PR (#401).
The banner carries no human feedback; it is now exempt alongside the
Cursor notice, with the same author-plus-content pairing so a human
impersonating the bot does not slip through.

* chore: synchronize changelog (#404)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* ci(JUM-841): verify npm org access before publishing (#407)

The npm-publish job binds the (now created) npm-publish environment and
reads the NPM_CI_CD repository secret, but jumped straight from install
to artifact validation to npm publish. Run the org access check
(JUM-859, absolute npm resolution + whoami/org ls) as a first-class step
so a missing or under-scoped token fails before any artifact work.
Environment variable NPM_JUMENTIX_CI_CD on 'env vars' was removed: it
duplicated the repository secret and, as a plain variable, was not
masked in logs.

* [JUM-821][Chore] Reconcile main squash ancestry into dev (#408)

* [JUM-821][Release] Promote dev to main (#366)

* feat(frontend): domain dashboards from OAS metrics

JUM-811…814: widget grid, OAS metrics widgets, Users examples, axe, docs.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(ci): analyse main and dev on sonar and codecov (#355)

Clear Sonar reliability bugs, replace the broken coverage measure badge,
run the coverage job (Codecov upload + Sonar) on main and dev, and embed
the Codecov grid graph in the READMEs (JUM-823).

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(latent): clear bugs documented during JUM-821 promotion rounds (JUM-839) (#356)

- monitoringCharts drawStackedArea: guard null series in the totals
  reduce, matching the neighboring guards (TypeError latent)
- RestAPI getHandlerFactory: typeof guard on the handler default, matching
  RealtimeAPIBase; truthy non-function defaults now fall through to the
  next framework candidate instead of throwing 'not a function'
- UserService: drop dead newData ?? {} (newData is always an object)
- purgeTombstones parseInstant: document the owner decision — numeric
  epoch deletedAt is not an accepted representation and is intentionally
  never purged (contract: ISO string or Date)
- CommercialPages: update the relationship snippet to the string-named
  decorator syntax

Validated: 371 tests across 33 suites green under bun:test --isolate,
RestAPI.nonFunctionDefault 1/1 on both runners, lint clean.

* [JUM-840][Governance] Retire superseded governance material (#357)

* docs: retire superseded governance material

* fix(ci): resolve git binary for governance docs check

* style(docs): remove trailing blank lines

* chore(governance): restore suite and tooling ownership (JUM-824)

Add Req 137 and arch:check-ownership-placement; move SM suites, tooling
proof suites, and component scripts into owner homes; delete dual-home
package clones; wire the gate into ci:gate and branch preflight.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(ci): enforce public quality reporting (#359)

* fix: empty ownership allow-list and clear Sonar debt

Refine Req 137 heuristics so comments and ci-cd fixtures stop false
positives, keep SM-api @src composition, document suite homes, and harden
CLI path joins against traversal findings.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: drop ownership --root CLI to clear Sonar S8707

CLI always scans process.cwd(); programmatic callers still pass a root
for fixtures. Use path.relative containment before every filesystem join.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs: align Codecov grids (#360)

* docs: restore public project badges (#361)

* fix: clear Sonar reliability bug and ownership regex smells

Use isEntryPoint in frontend coverage CLI (S3403) and drop super-linear
regexes in the ownership gate so PR security and reliability stay at A.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs: [JUM-844] make product setup CLI-first

* chore: clear ownership path freeze leftovers for JUM-834 (#362)

Update requirement evidence and comments to the post-move homes, and
rewrite stale suite paths in the branch-quality-gate artifact.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat: [JUM-841] prepare npm package publication

* ci: retarget coverage jobs to packages/cana browser scripts

Coverage steps still called removed ci-cd/ paths after JUM-836 moved the
runners under packages/cana/scripts (JUM-842).

* chore: sync changelog for JUM-842 coverage path retarget

* test(JUM-857): restore branch coverage to >= 98% for the release gate (#367)

The release-gate coverage job on promotion PR #366 failed (branches
97.51% < 98%, Requirements 020/063) because the gate only runs on
promotions and the deficit accumulated on dev since promotion #353.

Add functional unit tests covering 40 previously uncovered in-scope
branch paths across backend-template, service-management (UI, state,
vendor sync scripts), service-management-api Catalogs, ci-cd tooling
and designer-core. Local gate: branches 98.53%.

Also fix the agent-registry CLI package root path broken by the JUM-824
ownership move (bin/ relocated from ci-cd/ without updating the
relative path), which made agent-registry:register/heartbeat fail.

* test(JUM-858): cover JUM-811 dashboard metrics lines for the patch-coverage gate (#368)

The promotion gate on PR #366 advanced past full branch coverage (JUM-857)
and failed the next gate: patch coverage 93.31% (265/284) < 99%. The
uncovered changed lines came from JUM-811 (PR #354):
apps/frontend/src/components/dashboard/loadMetrics.ts (offline/Cana path)
and apps/frontend/src/contracts/metricsSchema.ts (two branches).

Add a bun:test suite for loadMetrics driving a real Cana test DB
(openCana/wipeCanaDatabase precedent from the localRepository suite):
localRecords with and without since, the Cana-open loadMetrics branch
(count and groupBy variants), and countPendingLocal open/closed. Extend
metricsSchema.test.ts with the interval-preservation and
unknown-operation-id cases. All named lines now hit per lcov.

* fix(JUM-859): resolve npm by absolute path in check-npm-org-integration (#369)

Valid Sonar finding (javascript:S4036, code-scanning alert #114) on
promotion PR #366: execFileSync('npm', ...) resolved the credential-check
CLI through PATH, where a writable earlier entry can shadow the real npm
and answer the authentication questions as an impostor.

Follow the repo precedent from ci-cd/lib/git-binary.js: resolve an absolute
invocation from npm's own self-report (npm_execpath/npm_node_execpath,
validated against bun's script-compat self-report), then the npm bundled
next to the running node binary, then fixed install locations, and fail
closed otherwise. Extract checkNpmOrgAccess with an injectable runner so
the failure and parse branches are covered without touching npm; main()
stays a thin entry-point wrapper. 13 unit tests.

* fix(JUM-860): enforce Sonar reliability against the analyzed branch (#370)

The promotion gate on PR #366 failed 'Enforce SonarCloud reliability A'
against a stale analysis: on a dev->main promotion PR the scanner submits
a pull-request analysis, which never refreshes the base branch measures,
so the check read the pre-promotion main rating (4.0) even though every
one of its 36 bugs is already fixed on dev (78ba64f, PR #355).

- ci-cd/check-npm-package-release.js: replace the inline
  'require.main === module' guard (Sonar S3403, the exact pattern
  ci-cd/lib/entry-point.js exists for) with isEntryPoint(module) — the
  one real open BUG on dev.
- .github/workflows/ci.yml: resolve SONAR_BRANCH from
  github.head_ref || github.ref_name so promotion PRs enforce against
  the head branch (analyzed on every push to dev) instead of the stale
  base branch; the workflow comment records the skew mechanics.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(release): drop duplicate pre-commit check from main reconcile

The squash ancestry merge auto-inserted a second identical
preCommitPath guard; keep a single check.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>

* ci(JUM-866): guard the patch-report frontend coverage step to PRs (#410)

'Produce frontend coverage for the patch report' ran unconditionally in
the coverage job, while the step that consumes it (Enforce patch
coverage) already guards on pull_request. On dev push runs where the
coverage job is selected, the producer failed after ~13m (no PR patch
context), failing the whole job despite the full-suite thresholds
passing (branches 98.22%).

* fix(JUM-872): address PR #409 review findings on dev (#411)

Patch coverage (Codecov 81.59% -> 100% lines on the changed files):
- packages/cli-init/scripts/check-template-freshness.js: 24 uncovered
  lines driven by 13 new functional cases in the existing suite (seed
  walk errors, manifest drift shapes, entry-point guard/catch).
- packages/cli-init/scripts/build-templates.js: 13 uncovered lines
  driven by 6 new cases (resolveSourceCommit with/without git, missing
  seed, stripExcludedFromTree, direct run, entry-point success/catch).

Sonar S4036 (PATH resolution) in cli-init tooling:
- ensure-built.js: process.execPath instead of bare 'bun'.
- run-generation-matrix.ts: fixed-candidate absolute docker resolution,
  failing closed to 'not available' (git-binary.js precedent).
- legacy/bootstrap.ts runCommand: explicit absolute-path registry for
  git/bun/node; absolute paths pass through; unknown bare commands
  refused (fail closed).

Entry-point tests are runner-dual: full execution under jest (the
coverage runner) and an honest require-only assertion under bun:test
(where require.main is absent on test workers).

* ci(JUM-862): bind bot-token jobs to the consolidated secrets environment (#412)

All bot tokens were consolidated into the GitHub 'secrets' environment
(CHANGELOG_GH_TOKEN, NPM_CI_CD, NPM_JUMENTIX_CI_CD now live there):
- sync-changelog: environment env vars -> secrets (CHANGELOG_GH_TOKEN).
- npm-publish: environment npm-publish -> secrets (NPM_CI_CD); the empty
  npm-publish environment is superseded.
- npm-package-release gate: pins the new environment name.

* chore: synchronize changelog (#413)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* [JUM-871][Fix] Build workspace packages in topological level order (#414)

* fix(JUM-871): build workspace packages in topological level order

The parallel 'bun run --filter' build let a dependent package's tsc race
its workspace dependencies' dist emission, failing intermittently with
TS2307 (sdk-grpc-client vs shared-contracts observed repeatedly on the
promotion gate). New ci-cd/build-workspace-packages.js discovers
packages, builds the workspace dependency graph, and runs Kahn levels:
parallel within a level, sequential across levels, spawned via the
running interpreter. Cycles and empty workspaces fail closed; a build
failure aborts later levels naming the package.

Also fixes a latent jest.config.js bug this exposed:
modulePathIgnorePatterns '.build' treated the dot as regex-any, silently
crawling out any path containing <anychar>build; scoped to <rootDir>/
\.build etc. (479 -> 480 test files discovered, full gate green).

* fix(JUM-871): deterministic sort comparators in the topological builder

Sonar S2871 on the two level-sort calls: add an explicit comparator
preserving default UTF-16 code-unit order so level output is
deterministic across runtimes.

* chore: synchronize changelog (#415)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix(cli-init): [JUM-821] restore coverage setup (#416)

* fix(ci): [JUM-821] bootstrap promotion gates (#417)

* chore: synchronize changelog (#418)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix(cli-init): [JUM-821] resolve Bun in Actions (#419)

* chore: synchronize changelog (#420)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix(ci): build workspaces topologically (#421)

* fix(ci): [JUM-821] build workspaces topologically

* fix(ci): [JUM-821] sync changelog only on main

* fix(ci): [JUM-821] build dependencies before workspace tests (#422)

* fix(ci): [JUM-821] harden isolated promotion jobs (#423)

* fix(ci): retry transient Redis registry failures (#424)

* fix(ci): retry database compose startup (#425)

* test(backend): cover paging fallbacks (#426)

* fix(ci): prepare frontend coverage dependencies (#427)

* fix(ci): scope release patch coverage to dev baseline (#428)

* fix(ci): allow generated changelog release PRs (#430)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant