Gates
Gates are automated quality checks that must pass before a WU can be completed. They replace manual code review with consistent, automated enforcement.
Why Gates?
Section titled “Why Gates?”Traditional review:
- Human bottleneck (waiting for reviewers)
- Inconsistent (different reviewers, different standards)
- Slow feedback (review happens after code is written)
Gates:
- Instant (run automatically)
- Consistent (same checks every time)
- Fast feedback (run locally before pushing)
Config-Driven Gates
Section titled “Config-Driven Gates”Define your gate commands in workspace.yaml under software_delivery.gates:
Optional Migration Verification
Section titled “Optional Migration Verification”Projects with manual database deploy steps can add an explicit migration-state verifier:
When migration_verify is configured, pnpm gates and pnpm wu:prep run it only when the
working diff touches schema or migration paths such as db/schema/**, prisma/schema.prisma,
supabase/schema.sql, or migration directories.
Use this for commands that check whether the target database is up to date. Do not use it to run migrations automatically.
This approach works with any language and toolchain.
Automated Test Diff Evidence
Section titled “Automated Test Diff Evidence”wu:prep can enforce an extra proof step: if a WU changes code, it must also touch at least one
automated test file in the same diff. This policy is configured under
software_delivery.gates.tdd_diff_evidence.
Defaults come from software_delivery.methodology.testing:
tddsetssoftware_delivery.gates.tdd_diff_evidence.mode: blocktest-aftersetssoftware_delivery.gates.tdd_diff_evidence.mode: offnonesetssoftware_delivery.gates.tdd_diff_evidence.mode: offapplies_to_typesdefaults tofeatureandbugexempt_pathsdefaults to[]test_file_patternsdefaults to TS/JS globs (**/*.test.{ts,tsx,js,jsx,mjs},**/*.spec.{ts,tsx,js,jsx,mjs},**/__tests__/**,**/*.test-utils.*,**/*.mock.*)code_file_extensionsdefaults to TS/JS extensions (.ts,.tsx,.js,.jsx,.cjs,.mts,.cts)
mode supports block, warn, and off. wu:prep only blocks when the mode is block; teams
that want the policy disabled can set warn or off and still document their intent in config.
Configuring for non-TS/JS toolchains
Section titled “Configuring for non-TS/JS toolchains”test_file_patterns and code_file_extensions make the gate language-agnostic. Override either
field to teach the gate which files count as tests vs production code in your workspace. Overrides
replace the defaults — supply only your toolchain’s patterns.
C# (xUnit / NUnit / MSTest):
Python (pytest / unittest):
Go:
Use this gate when you want changed-test evidence for specific WU types or runtime paths. It is not a requirement to force every team into test-first development.
For one-off exceptions, document the reason in the WU notes with:
Native Delivery Review
Section titled “Native Delivery Review”The Software Delivery pack also exposes a native delivery_review gate for completion review. This
capability is public and vendor-agnostic:
- It lives under
software_delivery.gates.delivery_review enabled: trueregisters it for every agent/client runtimeauto_run: truemakeswu:preprun it for applicable WU types- It runs through native gate execution and
wu:prep, not through a vendor-specific skill path - It does not depend on lumenflow-cloud or any hosted control plane
pnpm gates runs delivery_review whenever the global gate is enabled. pnpm wu:prep auto-runs
it when both enabled: true and auto_run: true are set, unless the current WU type matches
skip_types. The same public contract is catalogued in the
Gates Reference.
For source-code delivery changes, delivery_review requires automated test evidence or meaningful
manual verification evidence. A non-empty tests.manual entry is not enough by itself:
placeholders and negative values such as todo, n/a, screenshot: n/a, and not run are
treated as missing evidence and fail the gate. Use concrete manual entries that name the surface,
action, observed result, and artifact path when visual or manual QA is the right evidence.
Set block_partial: true when the repo wants delivery-review uncertainty to block rather than
warn. Set verifier_command when native evidence-shape checks should be followed by project-owned
truth checks. The command runs from the repository root, receives
LUMENFLOW_DELIVERY_REVIEW_WU_ID=<WU-ID>, and blocks the gate when it exits non-zero.
Client-specific config can still exist for adapter UX, hooks, or prompt surfacing, but it is not the enforcement switch:
For one release, legacy client-scoped features.delivery_review.auto_run: true is still honored
when the global gate is enabled and global auto_run is omitted. LumenFlow emits a migration
warning pointing to software_delivery.gates.delivery_review.auto_run. Client-scoped
features.delivery_review.enabled: false does not disable the core gate; disable or skip the gate
through the normal global gate config or auditable gate-skip mechanism.
Delivery Review Output Contract
Section titled “Delivery Review Output Contract”delivery_review produces a stable JSON artifact at
.lumenflow/artifacts/delivery-review/<WU-ID>.json. Hosts and products can consume the result
without assuming a specific vendor runtime.
Verdict behavior:
PASSmeans the review found sufficient delivery evidencePARTIALmeans the review completed with uncertainty or lower-severity findings; it warns by default and blocks whensoftware_delivery.gates.delivery_review.block_partialistrueFAILmeans the review found blocking gaps or risks and gates fail
The native review inspects the current WU spec, changed files, acceptance criteria, and delivery
risks. It is intentionally separate from wu:verify, which keeps its existing lifecycle meaning.
Conditional Commands
Section titled “Conditional Commands”Define pattern-triggered commands alongside your standard gates:
| Field | Type | Required | Description |
| ------------------ | ---------- | -------- | -------------------------------------------------------- |
| trigger_patterns | string[] | Yes | Glob patterns matched against changed files |
| command | string | Yes | Shell command to execute when patterns match |
| severity | string | No | error (default, blocks gates), warn, or off (skip) |
| guidance | string | No | Actionable text shown when the command fails |
| guidance_ref | string | No | File path whose content is appended to guidance |
How it works:
- When
pnpm gatesorwu:prepruns, changed files are compared against each command’strigger_patternsusing glob matching - Only commands with matching patterns execute — unmatched commands are silently skipped
- If a matching command fails with severity
error, gates fail. With severitywarn, a warning is logged but gates continue
Registering via the CLI (Constraint-9 compatible):
workspace.yaml must not be edited by hand. Two sanctioned paths exist:
-
gate:conditional(recommended, per-rule) — mirrorsgate:co-change:The
namefield is how--remove/--editaddress a specific entry. It is optional in the underlying schema (existing unnamed entries continue to work) but required for CLI-managed entries. -
config:set --json-value(escape hatch) — writes the whole array verbatim when you need a shape the flags above don’t cover:
Both paths validate against ConditionalCommandConfigSchema and commit atomically
via micro-worktree.
Using Presets
Section titled “Using Presets”For common languages, use a preset to get sensible defaults:
Available presets: node, python, go, rust, dotnet, java, ruby, php
Path-scoped tests.unit execution is preset-aware. When the active preset supports scoped
execution, wu:prep can use the current WU’s tests.unit entries to narrow the test gate. When a
preset does not support path-scoped execution, such as dotnet, LumenFlow falls back to the
configured default test command for that preset instead of attempting a JavaScript-specific runner.
One test plan per gate run
Section titled “One test plan per gate run”The immutable safety-critical-test gate owns the shared test plan. It runs
declared tests.unit paths when they can be scoped safely; otherwise it runs
the configured test_incremental command. The normal test gate reuses that
exact result, so the same test process does not execute twice during one
wu:prep.
The planner falls back to test_full when broader coverage is required:
- main-snapshot comparison probes;
--full-testsor--full-coverage;- test-runner configuration changes;
- unavailable change detection or untracked code; and
- a missing, blank, or full-equivalent
test_incrementalcommand.
These fallbacks also execute once across the safety and normal test gates. Full CI remains the final whole-repository authority.
Preset Defaults
Section titled “Preset Defaults”| Preset | Format | Lint | Typecheck | Test |
| -------- | ------------------------ | --------------- | -------------- | ------------- |
| node | prettier --check . | eslint . | tsc --noEmit | npm test |
| python | ruff format --check . | ruff check . | mypy . | pytest |
| go | gofmt -l . | golangci-lint | go vet ./... | go test |
| rust | cargo fmt --check | cargo clippy | cargo check | cargo test |
| dotnet | dotnet format --verify | dotnet build | - | dotnet test |
| java | spotless:check | checkstyle | mvn compile | mvn test |
| ruby | rubocop | rubocop | - | rspec |
| php | php-cs-fixer | phpstan | - | phpunit |
Running Gates
Section titled “Running Gates”Dependency Isolation Preflight
Section titled “Dependency Isolation Preflight”Before gate context, telemetry, or any gate command starts, LumenFlow inspects the active checkout’s
dependency roots and @lumenflow workspace-package links. Each workspace dependency must resolve
inside the active checkout. Package managers may materialize shared content into a checkout-local
virtual store via hardlinks, reflinks, or copies, but a direct workspace link to an external store is
never accepted. Store-looking substrings do not establish trust. Every intermediate scope/package
component is realpath-checked, including directory junctions. Missing/non-directory dependency
roots, missing declared workspace packages, and paths into main or another worktree all fail closed.
The diagnostic includes both the exact contaminated link and its resolved target:
Remove only the listed link, run the configured frozen install inside the active worktree, and then rerun gates. Do not relink to main and do not skip the check: no gate result is trustworthy when module resolution can read another branch.
A worktree gates invocation also requires its own CLI dist. It never falls back to main’s CLI dist,
so a --skip-setup checkout cannot bypass this preflight by bootstrapping the gate runner from a
different checkout.
Main-snapshot comparison probes follow the same boundary. Each temporary probe performs its own frozen install and blocks classification if installation or isolation verification fails.
If any gate fails, wu:prep fails and you fix issues in the worktree before completion.
For migration verification failures, the expected fix is:
- Apply the pending migrations using your project’s normal process
- Re-run the configured verification command manually if needed
- Re-run
pnpm wu:prep --id WU-XXX
Gate Flags
Section titled “Gate Flags”| Flag | Description |
| -------------- | --------------------------------------------------------------------------- |
| --docs-only | Run only docs-related gates (skip format/lint/typecheck/test) |
| --full-tests | Force one full test_full execution instead of scoped or incremental tests |
| --full-lint | Run full lint pass instead of scoped lint |
Command Options
Section titled “Command Options”Commands can be strings or objects with options:
Language Examples
Section titled “Language Examples”Node.js / TypeScript
Section titled “Node.js / TypeScript”Python
Section titled “Python”Java / JVM
Section titled “Java / JVM”How Gates Work Under the Hood
Section titled “How Gates Work Under the Hood”Each gate maps to a policy rule in the Software Delivery Pack:
| Gate | Policy ID | Trigger |
| ------------ | ---------------------------------- | --------------- |
| Format check | software-delivery.gate.format | on_completion |
| Lint | software-delivery.gate.lint | on_completion |
| Type check | software-delivery.gate.typecheck | on_completion |
| Test | software-delivery.gate.test | on_completion |
When wu:prep or wu:done runs, the kernel evaluates these policies. A deny from any gate makes the completion decision final — the deny-wins invariant applies. The result is recorded in the evidence store for audit.
Gate Behavior
Section titled “Gate Behavior”On Claim
Section titled “On Claim”When you wu:claim:
- Worktree is created
- Gates status is “pending”
During Work
Section titled “During Work”Run pnpm gates frequently:
On Prep and Done
Section titled “On Prep and Done”When you wu:prep:
- Gates run automatically in the worktree
- If any fail, the WU stays
in_progressuntil you fix and rerunwu:prep
When you wu:done:
- The WU merges to main
- The stamp is created
- The worktree is cleaned up
Gate Failures
Section titled “Gate Failures”Fix and retry:
Skip Flags
Section titled “Skip Flags”There is no bare pnpm gates --skip-<gate> flag. Skip a specific, named gate through wu:done
instead — both --reason and --fix-wu are required, and only gates marked skippable: true can
be named this way:
See Constraints — Gates and Named Gate Skips for the gates that are immutable and can never be skipped this way.
Or in configuration:
CI Integration
Section titled “CI Integration”Use the LumenFlow Gates GitHub Action:
The action reads your software_delivery.gates.execution config automatically. See GitHub Action docs for details.
Backwards Compatibility
Section titled “Backwards Compatibility”If no software_delivery.gates.execution config is present, LumenFlow falls back to auto-detecting your project type based on files present and uses preset defaults.
Next Steps
Section titled “Next Steps”- Policy Engine — How gates are evaluated as deny-wins policies
- Evidence Store — How gate results are recorded for audit
- Configuration Reference — Full gates schema
- CLI Reference — All gate commands