Skip to content

Project governance for React teams

lattice governance assess returns a project-level verdict for managed Next.js, Vite + React and React apps. Version 0.5.0 evaluates eight defined domains: inventory, direct dependency policy, source architecture, dependency security, code quality, code security, browser/mobile compatibility and accessibility. A pass covers those configured controls; it is not a certification of every enterprise control.

Install @anhcodo13/lattice@0.5.0 with Node.js 24+ to run the eight-domain assessment. Version 0.4.0 provided seven domains; 0.5.0 adds conditional library floors and accessibility evidence.

Domain Evidence Default gate
Inventory Exact path/profile set Every discovered app is declared
Dependency policy Manifest ranges, source imports, npm/pnpm importers and locked versions Required framework and used managed-library versions meet approved floors
Architecture Local import graph, boundaries and score Score ≥75, no error finding or module cycle
Dependency security Native npm/pnpm audit of the lockfile No high or critical advisory
Code quality ESLint, TypeScript, Vitest and V8 line coverage No lint error; typecheck passes; tests pass; coverage ≥70%
Code security Semgrep p/ci and Gitleaks No high/critical SAST finding or detected secret
Compatibility Playwright browser projects and mobile emulation Chromium, Firefox, WebKit, Android Chrome and iPhone Safari emulation; two viewport widths and browser version per project
Accessibility Axe results from rendered Playwright pages Desktop Chromium and Android Chrome scans with WCAG 2.1 A/AA tags, no violation or unresolved check

Place .nklattice-apps.json at the directory passed to governance assess:

{
"schemaVersion": 1,
"apps": [
{ "path": "apps/next", "profile": "next" },
{ "path": "apps/vite", "profile": "vite-react" },
{ "path": "apps/react", "profile": "react" }
]
}

A standalone app uses "path": ".". Paths are relative to the scan root, unique and confined to it. Discovery scans package.json and infers a profile from next, vite plus react, or react; an explicit "nklattice": { "profile": "react" } wins. The exact path/profile set must equal the discovered set. A missing, substituted, newly discovered or reprofiled app produces incomplete. --expect-apps N adds a count check; it cannot replace inventory. Packages without a supported profile are outside this managed set, so review inventory when adding packages.

governance/policy.json retains schema 2 and has policy version 5.0.0. Its profiles set mandatory framework floors, while managedPackages adds conditional minima for libraries declared or imported by an app. See Managed React libraries. For example, "react": ">=19.3.1" accepts exact 19.3.1 or ^19.3.1 because every allowed version meets that floor. ^19.2.0 fails even if today’s lockfile resolves to 19.3.1. The checker also requires the npm/pnpm lockfile importer specifier to equal the declaration and the locked version to satisfy both ranges. An unbounded floor can admit a future major; teams still review compatibility.

assessment.architecture defines minimumScore, maximumErrors, blockedRuleIds, and central analysis thresholds, weights and import boundaries. The checked-in defaults require score ≥75, zero error findings and no module-cycle. A blocked ID must name a built-in rule or enabled central boundary. The app’s .nklattice.json cannot lower these gates during assessment. It still controls local lattice analyze exploration.

{
"assessment": {
"architecture": {
"minimumScore": 75,
"maximumErrors": 0,
"blockedRuleIds": ["module-cycle"],
"analysis": {
"thresholds": {},
"weights": { "architecture": 40, "imports": 25, "components": 20, "complexity": 15 },
"policies": [],
"aliases": {}
}
}
}
}

Review both files like code. policyVersion is a human label; SHA-256 hashes in the report identify the exact policy and inventory contents.

assessment.evidence additionally requires a fresh advisory scan, zero high/critical advisories, zero ESLint errors, a passing TypeScript check when TypeScript source is present, nonzero passing tests, no failed tests, line coverage ≥70%, zero high/critical SAST findings and zero detected secrets. The Playwright matrix requires chromium-desktop, firefox-desktop, webkit-desktop, android-chrome and iphone-safari, with at least two tests and two viewport widths per project. minimumTestedBrowserVersions and minimumEmulatedOsVersions set reviewed floors for the test environment; a lower measured value fails the gate. Mobile OS values come from user-agent emulation, not tested physical OS releases, and the floors do not prove support for older versions. Missing, stale or malformed scanner output is incomplete, never a pass.

The reusable workflow installs app dependencies, Semgrep 1.136.0, Gitleaks 8.30.1 and Playwright browser engines. Consumer lockfiles must provide ESLint, TypeScript, Vitest with V8 coverage and Playwright tests/configuration and @axe-core/playwright with an annotated accessibility scan in desktop Chromium and Android Chrome. See Accessibility evidence. After installing these tools in the consumer, collect evidence outside the scan root before assessment:

Terminal window
pnpm dlx @anhcodo13/lattice@0.5.0 governance run examples/governance \
--policy governance/policy.json --expect-apps 3 \
--evidence /tmp/nklattice-governance-evidence.json

For a standalone app, use examples/standalone-react and --expect-apps 1. For a workspace subtree, --workspace-root permits a shared lockfile in an ancestor. --inventory names another inventory inside the scan root. --output selects the report directory; default is .nklattice-governance/ under the scan root. The command writes assessment.json and self-contained report.html. They show domain statuses, findings, score, scanner versions, coverage, compatibility matrix, axe scans and route paths, policy/inventory/input hashes, scan commit and excluded controls. The workflow uploads normalized evidence and reports even when the gate fails; raw secret values are not included.

Exit Meaning Typical reason
0 pass Every required domain has fresh evidence and meets its reviewed threshold.
7 fail A measured policy breach, such as an advisory, secret, failed test or browser failure.
3 incomplete or command error Missing app, stale evidence, scanner outage, skipped source file, missing browser project or invalid policy.

Architecture scans supported JS/TS source, including hidden source directories, under each app. It excludes node_modules, .git, .next, dist, build, out, coverage, generated tool directories and .d.ts. It follows static imports, literal import() and literal require() calls. Nonliteral dynamic imports, malformed source and unresolved local imports make the result incomplete. Existing CSS/JSON and other non-code assets can be imported without becoming graph nodes. Vite aliases must match a validated central analysis.aliases mapping or tsconfig.paths; unverifiable alias targets make the result incomplete. Third-party package resolution is outside this local-import check. The score is a deterministic review aid, not a guarantee that an app builds or runs. Invalid policy syntax stops before a report can be created; CI logs still show the error.

The reusable workflow checks out one reviewed full core-ref SHA and builds CLI and policy from it. Copy the consumer example, replace both SHA placeholders with the same commit, commit the inventory, and make deployment depend on governance. The caller must keep its workflow uses: ref equal to core-ref; the called job validates the latter but cannot prove equality from inside the workflow. Make governance a required merge check in the consumer repository.

Changing core policy does not automatically start CI in another repository. Consumers update their pinned SHA and rerun their gates. A green NKLattice sample proves the sample, not an enterprise-wide rollout.

The assessment now queries known dependency advisories through npm/pnpm audit, scans code with Semgrep and Gitleaks, and runs tests and browser projects. A pnpm workspace audit covers the shared lockfile; its result is repeated for each app as a conservative workspace-level gate, not an app-attributed advisory claim. The advisory service receives package/version information; NKLattice itself does not upload source code to it. Semgrep p/ci is a remotely maintained ruleset whose contents can change between runs despite the pinned Semgrep executable. Playwright mobile projects emulate browsers and do not prove behavior on a particular physical Android/iOS release. The browser matrix verifies configured engines and mobile context, while the usefulness of app-authored tests still depends on their review. Accessibility checks cover only routes tested with axe and do not replace manual WCAG review. Test authors can omit routes or forge annotations; protect CI and review test changes.

The evidence JSON is a normalized artifact, not a cryptographically authenticated attestation. Its timestamp, hashes and commit catch accidental drift; a caller able to alter the artifact or control the CI runner can forge a local result. The reusable workflow uses governance run, which collects and assesses in one process without rereading the artifact. Treat a pass as authoritative only in a protected workflow on a trusted runner with protected report artifacts. Licenses, runtime performance, repository access, branch protection and cross-repository adoption remain outside this verdict. It is a technical baseline, not certification under TCVN 11930:2017 or Circular 12/2022/TT-BTTTT. The dependency-only lattice governance check remains for existing schema 2 consumers.

See the Vietnam web governance baseline for a control-by-control mapping, accessibility scope and evaluated integrations.