Validation and linting
This page describes selected commands from the pinned APEX product. Run them in
that checkout, not apex-docs. The current package.json, hook configuration,
and CI files determine exact coverage.
The owner retired APEX .github/hooks/ runtime hooks in the October 18 migration.
Do not restore them or introduce replacement hooks to satisfy an older validation
recipe. validate:hooks and test:hooks below are historical pinned commands,
not current setup requirements. Source-caller retirement belongs to the product
change and is not verified by this docs update. Git Lefthook, pre-commit checks,
secret scanning, other validators, and CI remain separate. See the
retirement record for the lost protection and permission limits.
For this documentation site, use npm run build, npm run check:links,
npm test, and npm run test:browser. The build uses the Linux toolchain and
prepared pinned product metadata. The link checker validates routes and fragments.
Use npm run check:external-links separately for external destinations.
Jump to: Architecture · Lefthook Hooks · Validation Scripts · CI Workflows · Running Locally
Validation architecture
Section titled “Validation architecture”Stabilization checks
Section titled “Stabilization checks”CodeGen proceeds in dependency-ordered batches of up to three new source files, with focused validation after each edit and a root check at each batch boundary. Routine next-file permission is not required. Explicit user stop requests, unresolved errors, ownership changes and human approval gates still stop progression.
Use these read-only commands from the repository root:
node tools/scripts/resolve-deployment-inputs.mjs --input approved-discovery-snapshot.jsonnode tools/scripts/validate-iac-handoff.mjs --tree-hash infra/bicep/examplenode tools/scripts/summarize-deployment-preview.mjs --input preview.json --tool bicep --expected-ids expected.jsonnode tools/scripts/validate-policy-precheck.mjs precheck.json --preview preview.json --expected-ids expected.jsonnode tools/scripts/validate-provider-payload.mjs --input resolved-resources.json --s2-max-bytes 268435456000The input resolver consumes approved values and read-only discovery snapshots; it performs no Azure calls or identity mutations. Its default report omits resolved values. See the input snapshot contract. An unset environment variable is not a reason to ask again for an already approved value.
Capture Bicep what-if with --no-pretty-print --output json. The summarizer returns exit 0 for checked evidence,
2 for required review and 1 for invalid or blocked evidence. Expected IDs come from approved resource bindings,
including child resources, not from copying the observed result. A passing preview never grants apply permission.
For unexpected Bicep Ignore records only, both preview commands support --ignored-evidence bundle/ignored.json.
The ignored-resource evidence contract binds exact preview/expected-ID hashes to saved
parent/child observations. It supports private-endpoint NICs, SQL master and Storage-linked system topics,
with exact IDs and reasons, not wildcard exclusions. The records remain visible in the summary. Changed actions,
missing managed resources and unknown coverage still block; relationship evidence does not confer apply approval.
Provider-payload checks cover known SQL S2 and App Service Plan regressions only. Supply a concrete resource array extracted from generated payloads with recorded provenance; unresolved expressions remain unverified. The example SQL byte size must be checked against the target region’s capabilities and approved configuration before use. Compilation, provider validation, preview and successful deployment are distinct outcomes.
Validation runs at three stages, catching issues progressively earlier:
flowchart LR
A["Pre-Commit<br/>(lefthook)"] --> B["Pre-Push<br/>(lefthook)"]
B --> C["CI<br/>(GitHub Actions)"]
style A fill:#e8f5e9,stroke:#4caf50,color:#000
style B fill:#fff3e0,stroke:#ff9800,color:#000
style C fill:#ffebee,stroke:#f44336,color:#000
- Pre-commit runs configured checks. Publication Markdown/artifact checks use the staged index.
- Pre-push selects domain checks for changed files.
- CI runs the suites and filters declared by the current workflow.
Lefthook hooks
Section titled “Lefthook hooks”The Git hooks listed here are defined in lefthook.yml at the repository root.
Pre-commit hooks
Section titled “Pre-commit hooks”Markdown and artifact checks run through node tools/scripts/check-publication-scope.mjs markdown|artifacts.
They materialize an isolated index snapshot, so partially staged files are checked as committed. Unrelated untracked
projects cannot block publication. Template, artifact-guidance and validator changes still run H2/template and review
presence checks across all tracked artifacts in that snapshot. Markdown uses the installed local executable; failures
propagate without filtering away exit codes. These checks never format, stage or rewrite project files.
| Hook | Trigger (glob) | Purpose |
|---|---|---|
markdown-lint | *.md | markdownlint on staged markdown files |
artifact-validation | Staged artifacts, templates, guidance and validators | H2/template and review presence checks on tracked snapshot |
agents | **/*.agent.md, **/*.prompt.md | Agent frontmatter, model alignment, body size |
instructions | **/*.instructions.md, agents, skills | Instruction frontmatter and cross-reference validity |
secrets-baseline | (all staged files) | gitleaks secret scan (soft-skip if not installed) |
python-lint | tools/mcp-servers/**/*.py | Ruff linter on Python files |
terraform-fmt | *.tf | Terraform formatting check |
terraform-validate | *.tf | Terraform validation per project |
iac-security-baseline | infra/bicep/**/*.bicep, infra/terraform/**/*.tf | TLS 1.2, HTTPS-only, no public blob, managed identity |
Commit-msg hook
Section titled “Commit-msg hook”| Hook | Purpose |
|---|---|
commitlint | Enforce Conventional Commits format |
Pre-push hooks
Section titled “Pre-push hooks”| Hook | Purpose |
|---|---|
branch-naming | Validate branch name uses an approved prefix |
branch-scope | Validate domain branches only modify in-scope files |
diff-based-check | Run domain-scoped validators for changed file types |
Validation scripts
Section titled “Validation scripts”All scripts are in the tools/scripts/ directory. Run via npm run <command>.
Architecture and registry validators
Section titled “Architecture and registry validators”| npm Command | Script | Purpose |
|---|---|---|
validate:agents | validate-agents.mjs | Agent frontmatter, body size, model alignment |
validate:skills | validate-skills.mjs | Skill format, affinity, references, stale refs |
validate:skill-checks | validate-skill-checks.mjs | Skill size (≤500 lines) and references |
validate:instruction-checks | validate-instruction-checks.mjs | Instruction frontmatter and applyTo patterns |
validate:agent-registry | validate-agent-registry.mjs | Agent registry consistency |
validate:workflow-graph | validate-workflow-graph.mjs | DAG integrity (no orphans, no cycles) |
Artifact and template validators
Section titled “Artifact and template validators”| npm Command | Script | Purpose |
|---|---|---|
validate:artifacts | validate-artifacts.mjs | H2 sync, template compliance, and auto-fix (with --fix) |
Governance and compliance validators
Section titled “Governance and compliance validators”| npm Command | Script | Purpose |
|---|---|---|
lint:governance-refs | validate-governance-refs.mjs | Governance guardrails integrity |
validate:no-hardcoded-counts | validate-no-hardcoded-counts.mjs | Prevent hardcoded entity counts |
lint:deprecated-refs | validate-no-deprecated-refs.mjs | Block deprecated API/pattern references |
validate:iac-security-baseline | validate-iac-security-baseline.mjs | IaC security baseline (TLS, HTTPS, blob, identity, SQL auth) |
Session and state validators
Section titled “Session and state validators”| npm Command | Script | Purpose |
|---|---|---|
validate:session-state | validate-session-state.mjs | Schema validation + deprecated lock/claim field detection |
validate:challenger-presence | validate-challenger-presence.mjs | Required review findings exist for each review-mandated step; for projects with Step 2 complete, no *.tmp.md or FAILED cost files remain at the top level |
validate:challenger-findings | validate-challenger-findings.mjs | Review findings schema and freshness; rejects mutable parent-owned files (sku-manifest.json, 00-handoff.md, README.md, recall state, *-decisions.json) as supporting inputs |
Quality and cross-reference validators
Section titled “Quality and cross-reference validators”| npm Command | Script | Purpose |
|---|---|---|
lint:glob-audit | validate-glob-audit.mjs | Detect overly broad glob patterns |
lint:orphaned-content | validate-orphaned-content.mjs | Detect unreferenced skills/content |
lint:docs-freshness | check-docs-freshness.mjs | Documentation staleness detection |
validate:retirement-scan | audit-retirement-candidates.mjs | Tracked-file census and schema checks |
lint:version-sync | validate-version-sync.mjs | Version consistency across files |
Configuration validators
Section titled “Configuration validators”| npm Command | Script | Purpose |
|---|---|---|
validate:vscode | validate-vscode-config.mjs | VS Code settings completeness |
validate:hooks | validate-hooks.mjs | Historical runtime-hook check; not a setup requirement after retirement |
test:hooks | test-hooks.sh | Historical runtime-hook tests; do not recreate deleted hooks to run them |
lint:mcp-config | validate-mcp-config.mjs | MCP server configuration validity |
Code and format linters
Section titled “Code and format linters”| npm Command | Tool | Purpose |
|---|---|---|
lint:md | markdownlint-cli2 | Markdown formatting and style |
format:check | Prettier | Code formatting (JS/JSON/CSS; markdown via markdownlint) |
lint:links | check-repository-links.mjs | Product repository link checks |
lint:json | lint-json.mjs | JSON/JSONC syntax validation |
lint:python | ruff | Python code quality (tools/apex-recall/) |
lint:terraform-fmt | terraform fmt | Terraform formatting compliance |
lint:bicep-fmt | bicep format | Bicep formatting compliance (no-op when no projects) |
validate:terraform | terraform validate | Terraform validation per project |
Aggregate commands
Section titled “Aggregate commands”| npm Command | Purpose |
|---|---|
validate:all | Run cache-aware Node validators plus external validators |
validate:_node | Node validators in one cache-sharing process; bounded children for Python, ESLint, and tests |
validate:_external | All external tool validators in parallel |
validate:agents | Agent frontmatter, body, model alignment |
validate:artifacts | H2 sync, template compliance, auto-fix |
validate:skills | Skill format, affinity, references, stale |
audit:quarterly | Quarterly context audit checks |
audit:retirement | Generate or inspect the whole-repository retirement census |
validate:_externalis a local-developer aggregate (run all external-tool linters in one shot). In CI its members are gated individually so coverage does not depend on the aggregate:lint:mdandformat:checkrun inci.yml,lint:pythonruns in theci.ymlexternal-tests job. Inspect current workflow steps for the remaining external checks; do not assume a retirediac-checks.ymlstill runs them. Site checks belong to the separate apex-docs repository.
validate:_node:legacy and validate:_node-ci:legacy retain the former
unbounded run-p aggregates as rollback and benchmark baselines.
Agent-invoked IaC validators (runtime, not CI)
Section titled “Agent-invoked IaC validators (runtime, not CI)”These validators are run by agents during the workflow against generated
artifacts (Steps 4–6), not by lefthook or CI. They have no committed inputs on
main, so they are intentionally absent from the aggregates above.
| npm Command | Invoked by | Validates |
|---|---|---|
validate:iac-contract | 05-IaC Planner | 04-iac-contract.json schema/DAG |
validate:iac-contract-consistency | 05-IaC Planner | Contract ↔ implementation plan |
validate:iac-handoff | 06b/06t CodeGen | 05-iac-handoff.json + tree hash |
validate:environment-manifest | 05-IaC Planner | 04-environment-manifest.json |
validate:policy-property-map | 05-IaC Planner | 04-policy-property-map.json |
sync:draft-contract-hashes | 05-IaC Planner | Refreshes plan_ref and l1m_ref digests of an unapproved draft contract; keeps formatting; --write replaces the file atomically |
Contract validator rules
Section titled “Contract validator rules”validate:iac-contract --readiness --stage deploy|post-deploy|go-live(defaultdeploy) fails an unresolved required capability only when its optionalblockslist includes that stage or an earlier one. Withoutblocksa capability blocks every stage.- A
phaseordeployment_phaseparameter may not declare adefault. - Resources may declare
phase,consumes(resources reached over a private path) and, on private endpoints,target. Adepends_oninto a later phase fails, and a consumer mustdepends_ona private endpoint that targets what it consumes. Contracts without these fields are not checked. validate:iac-contract-consistencyrequires every resource without an AVM module entry to appear in the plan’s### Raw Resource Exceptionssection when that section exists.validate:policy-property-mapacceptsstatusper policy:satisfied,pending,not-applicable(needsnot_applicable_reason) andunsatisfiable(fails).
CI workflows
Section titled “CI workflows”All workflows are in .github/workflows/.
This table describes the pinned product configuration, not proof that migration callers have been retired. Its historical runtime-hook checks do not authorize hook restoration or disabling unrelated CI.
| Workflow | File | Trigger | Purpose |
|---|---|---|---|
| CI | ci.yml | PR to main, push to main | Full validation suite (markdown, Prettier, agents, skills, hooks, bats tests, MCP, VS Code config) + Python ruff in the external-tests job |
| Branch Enforcement | branch-enforcement.yml | PR to main | Branch naming convention and scope validation |
| Consumer Template Checks | consumer-template-checks.yml | Configured template checks | Validate consumer-template behavior |
| Dev Container Base Validation | validate-devcontainer-base.yml | Relevant PR changes or manual dispatch | Compare candidate container bases on native architectures |
| Upstream Skill Drift | upstream-skill-drift.yml | Weekly (Monday 06:00 UTC) or manual dispatch | Compare the reviewed microsoft/azure-skills tag with the latest release (npm run report:upstream-skills) and keep one labelled issue up to date; never edits skills |
The apex-docs repository owns the site’s build and publishing workflows. Product validation does not publish documentation.
Running validations locally
Section titled “Running validations locally”# Run everythingnpm run validate:all
# Run a specific categorynpm run lint:md # Markdown onlynpm run validate:agents # Agent definitions onlynpm run validate:session-state # Session state only
# Auto-fix where supportednpm run lint:md:fix # Fix markdown issuesnpm run fix:artifacts -- <file> --apply # Fix artifact H2 headingsnpm run lint:python:fix # Fix Python lint issues