Complete reference for all xtask CLI commands.
JSON Output Support: The following commands support --json flag for agent/portal integration:
ac-status --json- AC coverage report as structured JSONac-history --format json- Time-series history of AC snapshotsac-slo --format json- SLO check result with thresholdsfriction-list --json- Friction entries with statisticsquestions-list --json- Questions with statisticsfork-list --json- Fork registry with kernel version breakdownversion --json- Kernel and template version informationissues-search --json- Cross-artifact search results with relevance scores
Quick Index:
- dev-up - One-command environment setup
- status - Governance status dashboard
- check - Format, lint, test
- bdd - Run BDD acceptance tests
- ac-status - Generate AC status report
- ac-coverage - Show AC coverage and unknown ACs
- ac-report - Human-readable AC governance reports
- ac-history - Time-series analysis of AC coverage
- ac-slo - SLO gate for AC coverage
- ac-suggest-scenarios - Generate BDD scenario stub
- policy-test - Test Rego policies
- bundle - Generate LLM context
- release-bundle - Generate release evidence bundle
- skills-fmt - Normalize SKILL.md files
- skills-lint - Validate Skills definitions
- quickstart - First-run validation
- selftest - Comprehensive 12-step validation suite
- idp-check - Validate IDP/portal integration surface
- contracts-check - Validate governed facts match docs
- contracts-fmt - Sync governed facts to docs
- ui-contract-check - Validate UI contract and DOM anchors
- check-api-diff - Check contract crates for API breaking changes
- check-openapi-diff - Check OpenAPI contract for breaking changes
- check-json-schemas - Check CLI JSON output schemas
- check-layering - Enforce dependency layering rules
- issues-search - Search across friction, questions, and tasks
- friction-gh-create - Create GitHub issue from friction entry
- friction-gh-link - Link existing GitHub issue to friction entry
- friction-resolve - Resolve a friction entry
- question-new - Create a new question artifact
- question-resolve - Resolve a question
One-command environment setup and health check.
cargo run -p xtask -- dev-up
# Or in Nix shell
nix develop -c cargo run -p xtask -- dev-upPerforms a comprehensive environment setup and validation:
- Dependency check: Verifies required tools (cargo, rustc, conftest, etc.)
- Platform health: Checks if HTTP server is running (
http://localhost:8080/platform/status) - Governance validation: Parses specs and verifies structure
- Core checks: Runs
xtask check(fmt, clippy, tests) - BDD tests: Runs acceptance scenarios
- Guidance: Shows next steps and helpful URLs
0: Environment ready- Non-zero: Setup issues detected
- First time - After cloning the repository
- After environment changes - Tool updates, config changes
- Daily standup - Quick "am I ready to code?" check
- For agents - Automated environment verification
======================================
Dev Environment Setup
======================================
[1/6] Checking dependencies...
✓ cargo 1.91.0
✓ rustc 1.91.0
✓ conftest 0.52.0
[2/6] Checking platform health...
✓ Platform running at http://localhost:8080
✓ /platform/status responding
[3/6] Validating governance...
✓ spec_ledger.yaml parsed
✓ tasks.yaml parsed
[4/6] Running core checks...
✓ Format check passed
✓ Clippy passed
✓ Tests passed
[5/6] Running BDD tests...
✓ All scenarios passed
[6/6] Checking commands...
✓ All xtask commands available
======================================
✓ Environment ready!
Next steps:
• View governance: http://localhost:8080/ui
• Check status: cargo xtask status
• List tasks: cargo xtask tasks-list
• Run selftest: cargo xtask selftest
======================================
Platform not running:
# Start the platform first
cargo run -p app-http &
# Then run dev-up
cargo xtask dev-upMissing dependencies:
# Enter Nix shell (recommended)
nix develop
# Or install tools manually
brew install conftest # macOSChecks fail:
- Run
cargo xtask checkseparately to see detailed errors - Fix issues and re-run
dev-up
Show governance status dashboard (CLI summary).
cargo run -p xtask -- status
# Or with alias
xt statusDisplays a quick governance health snapshot:
- Reads
specs/spec_ledger.yamlto count Stories, Requirements, ACs - Reads
specs/tasks.yamlto count tasks by status (Todo, InProgress, Review, Done) - Shows template version from ledger metadata
- Provides helpful next-step commands
0: Always succeeds (read-only operation)
- Quick orientation - "What's the state of this cell?"
- Morning standup - Check task counts without opening UI
- Agent workflows - Lightweight status check before planning work
- CI reporting - Include in build logs for visibility
======================================
Rust-as-Spec – 2.4.0
======================================
Governance:
Stories: 3
Requirements: 23
ACs: 46
Tasks:
Todo: 3
InProgress: 2
Review: 1
Done: 15
Next steps:
• View tasks: cargo xtask tasks-list
• Run selftest: cargo xtask selftest
• Start platform: cargo run -p app-http
• View UI: http://localhost:8080/ui
======================================
- Read-only: Never modifies files or state
- Fast: Parses YAML files only, no network calls
- No dependencies: Works even if platform is offline
- Complements
/platform/status: CLI equivalent of HTTP endpoint
| Feature | xtask status |
/platform/status |
|---|---|---|
| Type | CLI tool | HTTP API |
| Data source | YAML files | In-memory runtime state |
| Requires platform | No | Yes |
| Use case | Quick CLI check | Programmatic access |
Run all code quality checks: formatting, linting, and tests.
cargo run -p xtask -- check
# Or in Nix shell
nix develop -c cargo run -p xtask -- checkRuns three checks in sequence:
- Format check:
cargo fmt --all -- --check - Lint check:
cargo clippy --all-targets --all-features -- -D warnings - Unit tests:
cargo test --workspace --exclude acceptance
Stops at first failure.
0: All checks passed- Non-zero: One or more checks failed
- Before every commit - Ensure code quality
- In pre-commit hooks - Automatic validation
- In CI - Required check for pull requests
Running format check...
Running clippy...
Running tests...
Running unittests src/lib.rs (target/debug/deps/core-...)
Running unittests src/lib.rs (target/debug/deps/model-...)
✓ All checks passed
Format check fails:
# Fix by running
cargo fmt --allClippy warnings:
# See specific warnings
cargo clippy --all-targets --all-featuresTests fail:
# Run tests with output
cargo test --workspace --exclude acceptance -- --nocaptureRun BDD acceptance tests with JUnit XML output.
cargo run -p xtask -- bdd- Runs
cargo test -p acceptance --test acceptance - Generates JUnit XML at
target/junit/acceptance.xml - Prints scenario results to console
0: All scenarios passed- Non-zero: One or more scenarios failed
target/junit/acceptance.xml- JUnit test results for CI
- After implementing AC - Verify scenario passes
- Before pull request - Ensure acceptance criteria met
- In CI - Validate behavioral requirements
Running acceptance tests...
Feature: Platform Status
Scenario: Platform status returns governance health
✔ Given the service is running
✔ When I GET /platform/status
✔ Then I receive 200 with governance data
[Summary]
1 feature
1 scenario (1 passed)
3 steps (3 passed)
✓ Acceptance tests passed
JUnit output: target/junit/acceptance.xml
Scenario fails:
- Check step definitions in
crates/acceptance/src/steps/ - Verify feature file syntax in
specs/features/ - Run with verbose output:
cargo test -p acceptance -- --nocapture
JUnit XML not generated:
- Check
target/junit/directory exists - Verify path in
crates/acceptance/tests/acceptance.rs
Generate AC status report from acceptance test results.
cargo run -p xtask -- ac-status
# Output as JSON for agent/portal integration
cargo run -p xtask -- ac-status --json
# Show details for a single AC
cargo run -p xtask -- ac-status --ac AC-KERN-001
# Single AC as JSON (useful for debugging)
cargo run -p xtask -- ac-status --ac AC-KERN-001 --json
# Or in Nix shell
nix develop -c cargo run -p xtask -- ac-status| Flag | Description |
|---|---|
--json |
Output structured JSON instead of generating markdown |
--ac <ID> |
Show details for a single AC (e.g., AC-KERN-001) |
--summary |
Print concise summary to stdout |
- Reads
specs/spec_ledger.yamlto extract all AC definitions - Primary: Parses AC coverage JSONL (
target/ac/coverage.jsonl) written by the BDD harness- Streams results, resilient to
std::process::exit()(cucumber-rs issue) - See
docs/design/ac-coverage-format.mdfor format specification
- Streams results, resilient to
- Fallback 1: JSON report (
target/ac_report.json) if coverage.jsonl unavailable - Fallback 2 (legacy): JUnit XML + feature file parsing if JSON unavailable
- Parses
specs/features/**/*.featurefor@AC-####tags - Parses
target/junit/acceptance.xmlfor test results - May be unreliable due to cucumber-rs exit() behavior
- Parses
- Maps scenarios → ACs based on
@AC-####tags - Computes status for each AC (pass/fail/unknown)
- Generates
docs/feature_status.mdwith status table
Note: The coverage.jsonl path is the recommended approach. JUnit fallback is for backward compatibility and may be removed in a future major version.
When --json is specified, outputs structured JSON instead of generating the markdown file.
Full schema reference: See ac-status-json-schema.md for the complete v2.0 schema with TypeScript types and migration guidance.
Schema version 2.0 uses must_have_ac metadata for AC classification instead of prefix-based heuristics:
{
"schema_version": "2.0",
"timestamp": "2025-12-05T12:00:00Z",
"must_have_acs": {
"total": 48,
"passing": 46,
"failing": 1,
"unknown": 1
},
"optional_acs": {
"total": 17,
"passing": 15,
"failing": 0,
"unknown": 2
},
"coverage_percent": 93.8,
"acs": [
{
"id": "AC-TPL-001",
"story_id": "US-TPL-001",
"req_id": "REQ-TPL-HEALTH",
"text": "Doctor command validates environment",
"status": "pass",
"source": "coverage",
"must_have_ac": true,
"scenarios": ["Doctor detects missing tools"],
"tests": [...],
"tests_total": 1,
"tests_executed": 1
}
]
}| Field | Type | Description |
|---|---|---|
schema_version |
string | Schema version (currently "2.0"). Bump on breaking changes. |
timestamp |
string | ISO 8601 timestamp of report generation |
must_have_acs |
object | Stats for ACs with must_have_ac=true (strictly enforced in selftest) |
optional_acs |
object | Stats for ACs with must_have_ac=false (informational) |
coverage_percent |
number | Overall coverage: (passing ACs / total ACs) × 100 |
acs |
array | Array of individual AC status objects |
Per-AC Fields:
| Field | Type | Description |
|---|---|---|
id |
string | AC identifier (e.g., AC-KERN-001) |
story_id |
string | Parent user story ID |
req_id |
string | Parent requirement ID |
text |
string | Human-readable AC description |
status |
string | "pass", "fail", or "unknown" |
source |
string | Primary result source (see below) |
must_have_ac |
boolean | Whether AC participates in strict coverage gate |
scenarios |
array | BDD scenario names mapped to this AC |
tests |
array | Test mappings from ledger |
tests_total |
number | Total mapped tests declared in ledger |
tests_executed |
number | Tests that actually ran |
Source Values:
| Source | Description |
|---|---|
"coverage" |
Result from coverage.jsonl (streaming BDD, preferred) |
"junit" |
Result from JUnit XML fallback |
"json" |
Result from Cucumber JSON fallback |
"inferred" |
No test results; status is ledger-only (Unknown) |
must_have_ac Semantics:
The must_have_ac flag uses AND semantics between requirement and AC:
- If
REQ.must_have_ac=trueANDAC.must_have_ac=true→ effectivemust_have_ac=true - If either is
false→ effectivemust_have_ac=false - Both default to
trueif not specified inspec_ledger.yaml
When XTASK_STRICT_AC_COVERAGE=1 is set, selftest fails if any must_have_ac=true AC has status=unknown.
0: All ACs passed or unknown- Non-zero: One or more ACs failed
docs/feature_status.md- AC status table with pass/fail/unknown indicators (not generated when --json is used)
- After running BDD tests - Check which ACs are covered
- In CI - Verify AC coverage
- During development - Understand test-to-AC mapping
- Before releases - Ensure all ACs have passing tests
Parsing ledger: specs/spec_ledger.yaml
Found 3 ACs
Parsing JSON report: target/ac_report.json
Found 3 scenarios
Found results for 3 ACs
Generating status: docs/feature_status.md
✓ Generated docs/feature_status.md
✓ All ACs passed
Legacy fallback output (if JSON not available):
Parsing ledger: specs/spec_ledger.yaml
Found 3 ACs
JSON report not found: target/ac_report.json
Falling back to JUnit + feature parsing (legacy)
Found 3 scenarios
Found results for 3 ACs
...
- Pass (✅): All mapped testcases passed
- Fail (❌): Any mapped testcase failed
- Unknown (❓): AC has no mapped scenarios or testcases
No JUnit XML found:
- Run
cargo run -p xtask -- bddfirst to generate test results - Check that
target/junit/acceptance.xmlexists
ACs show as unknown:
- Verify feature files have
@AC-####tags - Check that tag IDs match ledger AC IDs
- Ensure scenarios are actually running in BDD tests
Unmapped scenarios:
- Scenario has
@AC-####tag that doesn't exist in ledger - Check ledger for typos in AC IDs
- Add missing ACs to
specs/spec_ledger.yaml
- Normalizes testcase names by removing
(row N)and(example N)suffixes - Reports unmapped ACs (no scenarios) and unmapped scenarios (invalid AC refs)
- Used by
xtask selftestand CI workflows
Show AC coverage report grouped by requirement.
cargo run -p xtask -- ac-coverage
# Show only ACs with Unknown status (coverage backlog)
cargo run -p xtask -- ac-coverage --todo
# Show only kernel (must_have_ac=true) ACs with Unknown status
cargo run -p xtask -- ac-coverage --todo --must-have
# Or with alias
xt ac-coverage| Flag | Description |
|---|---|
--todo |
Show only ACs with Unknown status (coverage backlog checklist) |
--must-have |
When used with --todo, filter to only kernel ACs (must_have_ac=true) |
Displays AC coverage summary and identifies which ACs need BDD scenarios:
- Reads
specs/spec_ledger.yamlfor all AC definitions - Parses feature files in
specs/features/to find@AC-####tags - Reads test results from JSON or JUnit (same as
ac-status) - Groups unknown ACs by requirement
- Displays pass/fail/unknown counts and actionable next steps
The --must-have flag filters to only show "kernel" ACs where must_have_ac=true in the spec ledger. These are the ACs that selftest enforces coverage for.
0: Always succeeds (read-only operation)
- During AC development - Identify which ACs still need scenarios
- Sprint planning - See coverage gaps at a glance (
--todo) - Before releases - Ensure all kernel ACs have coverage (
--todo --must-have) - Onboarding new features - Understand what's missing
📊 Computing AC coverage...
📋 AC Coverage Summary
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ 18 passing
✗ 0 failing
? 22 unknown (no BDD scenarios)
📍 Unknown ACs (Need BDD scenarios)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
REQ-PLT-ONBOARDING: AC-PLT-001, AC-PLT-002, AC-PLT-003, AC-PLT-018
REQ-PLT-DESIGN-SCAFFOLDING: AC-PLT-004, AC-PLT-005
REQ-PLT-RELEASE-SAFETY: AC-PLT-011, AC-PLT-012, AC-PLT-013
🎯 Suggested Next Steps
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. Generate scenario stub for AC-PLT-001:
$ cargo xtask ac-suggest-scenarios AC-PLT-001
2. Edit specs/features/your_feature.feature:
$ vim specs/features/your_feature.feature
3. Run BDD tests:
$ cargo xtask bdd
4. Check coverage again:
$ cargo xtask ac-coverage
| Feature | ac-coverage |
ac-status |
|---|---|---|
| Purpose | Quick coverage summary | Detailed AC status table |
| Output | Terminal summary | Markdown file |
| Use case | Sprint planning | CI/comprehensive validation |
| Unknown ACs | Grouped by REQ | Listed with text |
- Groups unknown ACs by requirement ID for easy navigation
- Provides direct command suggestions for next steps
- No side effects (read-only operation)
- Fast execution (parses YAML + feature files)
Human-readable AC governance reports. Downstream consumer of ac-status --json.
cargo run -p xtask -- ac-report
# Kernel-only view (must_have_ac=true)
cargo run -p xtask -- ac-report --must-have
# Filter by status
cargo run -p xtask -- ac-report --status unknown
cargo run -p xtask -- ac-report --status fail
# Combine filters
cargo run -p xtask -- ac-report --must-have --status unknown
# Group by story instead of requirement
cargo run -p xtask -- ac-report --by-story
# Output formats
cargo run -p xtask -- ac-report --format text # Default: colored terminal
cargo run -p xtask -- ac-report --format markdown # For PRs/Notion
cargo run -p xtask -- ac-report --format html # For portals
cargo run -p xtask -- ac-report --format json # Passthrough of ac-status --json| Flag | Description |
|---|---|
--must-have |
Only show ACs with must_have_ac=true (kernel ACs) |
--status <STATUS> |
Filter by status: pass, fail, or unknown |
--by-story |
Group output by story instead of requirement |
--format <FORMAT> |
Output format: text (default), markdown, html, or json |
- Calls
cargo xtask ac-status --jsoninternally to get AC data - Validates schema version (expects
2.0) - Filters ACs based on
--must-haveand--statusflags - Groups ACs by requirement or story
- Renders output in the requested format
0: Report generated successfully- Non-zero: Failed to load AC data or invalid format
| Format | Stability | Use Case |
|---|---|---|
text |
Informational; may change | Terminal review, debugging |
markdown |
Stable structure | PRs, Notion, documentation |
html |
Stable classes | Dashboards, portals |
json |
Identical to ac-status --json (schema v2.0) |
Programmatic access |
Markdown output includes:
- Summary table (Must-have vs Optional counts)
- Coverage percentage
- Blockers section (failing ACs)
- Missing coverage section (unknown ACs)
HTML output includes:
- CSS classes:
.pass,.fail,.unknown,.kernel - No JavaScript dependencies
- Self-contained, portable document
- PR descriptions - Generate markdown summary:
cargo xtask ac-report --format markdown - Sprint reviews - Show kernel coverage:
cargo xtask ac-report --must-have - Debugging - Find failing ACs:
cargo xtask ac-report --status fail - Dashboards - Generate HTML:
cargo xtask ac-report --format html > report.html - Coverage backlog - List missing kernel coverage:
cargo xtask ac-report --must-have --status unknown
AC Governance Report
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Summary:
Must-have ACs: 48 total (46 passing, 1 failing, 1 unknown)
Optional ACs: 17 total (15 passing, 0 failing, 2 unknown)
Coverage: 93.8%
📋 Filtered by: all ACs
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Requirement REQ-KERN-HEALTH
[✓] AC-KERN-001 🔒
Health endpoint returns OK
[✗] AC-KERN-002 🔒
Metrics endpoint exposes counts
→ cargo xtask test-ac AC-KERN-002
Requirement REQ-KERN-STATUS
[?] AC-KERN-003 🔒
Status shows version info
→ cargo xtask ac-suggest-scenarios AC-KERN-003
Next Steps:
1. Fix 1 failing AC(s): cargo xtask test-ac AC-KERN-002
2. Add coverage for 1 AC(s): cargo xtask ac-suggest-scenarios AC-KERN-003
## AC Coverage Report
| Category | Total | Pass | Fail | Unknown |
|----------|-------|------|------|---------|
| Must-have | 48 | 46 | 1 | 1 |
| Optional | 17 | 15 | 0 | 2 |
**Coverage:** 93.8%
### Blockers (Failing ACs)
- **AC-KERN-002** (fail): Metrics endpoint exposes counts
- Requirement: REQ-KERN-HEALTH
- Source: coverage
### Missing Coverage (Kernel)
- **AC-KERN-003** 🔒: Status shows version info| Command | Purpose | Data Source |
|---|---|---|
ac-status |
Generate JSON + markdown file | Spec ledger + test results |
ac-coverage |
Quick terminal summary | Spec ledger + test results |
ac-report |
Formatted views (human-readable) | ac-status --json output |
ac-report is a pure consumer - it never reads spec files or test results directly. This separation ensures:
- Schema versioning is respected
- Format changes don't break the report
- Easy to test rendering independently
"Unknown schema version" warning:
- The
ac-status --jsonoutput has a newer schema than expected - Update
ac-reportto handle new fields, or downgradeac-status
No ACs match filter:
- The combination of
--must-haveand--statusreturned empty set - This is success (e.g., no failing kernel ACs)
JSON format is empty:
- Ensure
ac-status --jsonruns successfully first - Check for BDD test failures that prevent JSON generation
- Downstream consumer: Depends on
ac-status --json(schema v2.0) - Read-only: Never modifies files or state
- Fast: Single subprocess call to ac-status, then in-memory filtering
- Testable: Rendering logic is separated from data loading
Analyze AC coverage trends from CI-generated snapshots.
# Summarize history from downloaded CI artifacts
cargo run -p xtask -- ac-history --dir ./artifacts/ac-status
# Export as CSV for charting
cargo run -p xtask -- ac-history --dir ./artifacts/ac-status --format csv
# Focus on kernel ACs only
cargo run -p xtask -- ac-history --dir ./artifacts/ac-status --must-have
# JSON output for programmatic access
cargo run -p xtask -- ac-history --dir ./artifacts/ac-status --format json| Flag | Description |
|---|---|
--dir <PATH> |
Directory containing ac-status-*.json snapshot files (default: artifacts/ac-status) |
--format <FORMAT> |
Output format: text (default), markdown, csv, or json |
--must-have |
Only show must_have_ac=true ACs (kernel ACs) |
- Scans directory for
ac-status-<sha>.jsonfiles - Parses snapshots (validates schema v2.0)
- Extracts commit SHA from filename
- Sorts by timestamp from JSON
- Computes deltas between consecutive snapshots (new/resolved blockers, coverage change)
- Renders output in the requested format
The tier1-selftest.yml workflow generates snapshots:
- name: Generate AC status snapshot (JSON)
run: |
mkdir -p artifacts/ac-status
cargo xtask ac-status --json > artifacts/ac-status/ac-status-${GITHUB_SHA}.json
- name: Upload AC status snapshot
uses: actions/upload-artifact@v4
with:
name: ac-status-${{ github.ref_name }}
path: artifacts/ac-status/
retention-days: 30To analyze history:
- Download artifacts from CI
- Extract to a local directory
- Run
cargo xtask ac-history --dir ./path/to/artifacts
0: Report generated successfully- Non-zero: Failed to load snapshots or invalid format
| Format | Stability | Use Case |
|---|---|---|
text |
Informational; may change | Terminal review |
markdown |
Stable structure | PRs, documentation |
csv |
Stable columns | Spreadsheets, charting |
json |
Schema v1.0 | Programmatic access |
AC Coverage History
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2 snapshots analyzed
Date range: 2025-12-01T10:00:00Z → 2025-12-02T10:00:00Z
All ACs:
Commit Date Cov% Pass Fail Unk
────────────────────────────────────────────────────────────
abc123 2025-12-01 73.3 11 2 2
def456 2025-12-02 93.3 14 0 1
Notable Changes:
↑ def456 – Resolved: AC-KERN-002, AC-KERN-003
Latest Snapshot:
Commit: def456
Coverage: 93.3%
[OK] No kernel blockers
## AC Coverage History
**Snapshots:** 2
**Date range:** 2025-12-01T10:00:00Z → 2025-12-02T10:00:00Z
| Commit | Date | Cov% | Pass | Fail | Unknown |
|--------|------|------|------|------|---------|
| abc123 | 2025-12-01 | 73.3% | 11 | 2 | 2 |
| def456 | 2025-12-02 | 93.3% | 14 | 0 | 1 |
### Notable Changes
- **def456** ✅ Resolved: AC-KERN-002, AC-KERN-003commit,timestamp,coverage_percent,total,passing,failing,unknown,kernel_blockers
abc123,2025-12-01T10:00:00Z,73.33,15,11,2,2,"AC-KERN-002;AC-KERN-003"
def456,2025-12-02T10:00:00Z,93.33,15,14,0,1,""{
"snapshot_count": 2,
"date_range": ["2025-12-01T10:00:00Z", "2025-12-02T10:00:00Z"],
"snapshots": [
{
"commit": "abc123",
"timestamp": "2025-12-01T10:00:00Z",
"must_have_total": 10,
"must_have_passing": 7,
"must_have_failing": 2,
"must_have_unknown": 1,
"optional_total": 5,
"optional_passing": 4,
"optional_failing": 0,
"optional_unknown": 1,
"coverage_percent": 73.3,
"kernel_blockers": ["AC-KERN-002", "AC-KERN-003"]
}
],
"deltas": [
{
"commit": "def456",
"new_blockers": [],
"resolved_blockers": ["AC-KERN-002", "AC-KERN-003"],
"coverage_delta": 20.0
}
]
}| Command | Purpose | Data Source |
|---|---|---|
ac-status |
Generate JSON + markdown file | Spec ledger + test results |
ac-report |
Formatted views (human-readable) | ac-status --json output |
ac-history |
Time-series analysis | Directory of ac-status --json snapshots |
Empty directory:
- Ensure CI artifacts have been downloaded
- Check file extension is
.json - Verify filename format:
ac-status-<sha>.json
Schema version warning:
- Snapshots have older or newer schema version
- Output may be incomplete for incompatible versions
No deltas shown:
- Deltas only appear when blockers change or coverage shifts >0.5%
- Single snapshot has no previous to compare against
- CI integration: Designed to consume artifacts from
tier1-selftest.yml - Read-only: Never modifies files or state
- Offline: Works entirely on local files after artifact download
- Extensible: JSON output can feed dashboards or BI tools
Check if AC coverage meets Service Level Objective (SLO) thresholds. This is the governance gate for pipelines.
# Basic usage - check against default thresholds (80% coverage, 0 blockers)
cargo run -p xtask -- ac-slo --dir ./artifacts/ac-status
# Custom thresholds
cargo run -p xtask -- ac-slo --dir ./artifacts/ac-status --min-coverage 95 --max-blockers 0
# Strict mode (any unknown counts as failure)
cargo run -p xtask -- ac-slo --dir ./artifacts/ac-status --max-unknown 0
# JSON output for CI pipelines
cargo run -p xtask -- ac-slo --dir ./artifacts/ac-status --format json| Flag | Description | Default |
|---|---|---|
--dir <PATH> |
Directory containing ac-status-*.json snapshot files |
artifacts/ac-status |
--min-coverage <PERCENT> |
Minimum required coverage percentage | 80.0 |
--max-blockers <COUNT> |
Maximum allowed kernel blockers (failing must_have_ac ACs) | 0 |
--max-unknown <COUNT> |
Maximum allowed unknown status ACs (no limit if omitted) | No limit |
--format <FORMAT> |
Output format: text or json |
text |
- Loads snapshots from the specified directory (same as
ac-history) - Selects the latest snapshot (by timestamp)
- Evaluates SLO conditions:
coverage_percent >= min_coveragekernel_blockers.len() <= max_blockers- If
max_unknownis set:unknown_count <= max_unknown
- Returns exit code based on SLO result
0: SLO met (all conditions satisfied)- Non-zero: SLO violated (one or more conditions failed)
SLO Passed:
[SLO OK] AC SLO OK: coverage 95.0% (>=80%), 0 kernel blockers (<=0)
Commit: abc123def456
Timestamp: 2025-12-05T10:00:00Z
Coverage: 95.0% (threshold: 80%)
Blockers: 0 (threshold: 0)
SLO Violated:
[SLO VIOLATED] AC SLO VIOLATED: coverage 53.3% (<80%), 2 kernel blockers (>0): AC-KERN-002, AC-KERN-003
Commit: abc123def456
Timestamp: 2025-12-05T10:00:00Z
Coverage: 53.3% (threshold: 80%)
Blockers: 2 (threshold: 0)
AC-KERN-002, AC-KERN-003
{
"schema_version": "1.0",
"passed": false,
"commit": "abc123def456",
"timestamp": "2025-12-05T10:00:00Z",
"coverage_percent": 53.3,
"min_coverage": 80.0,
"coverage_ok": false,
"kernel_blockers": 2,
"max_blockers": 0,
"blockers_ok": false,
"blocker_ids": ["AC-KERN-002", "AC-KERN-003"],
"unknown_count": 3,
"max_unknown": null,
"unknown_ok": true,
"summary": "AC SLO VIOLATED: coverage 53.3% (<80%), 2 kernel blockers (>0): AC-KERN-002, AC-KERN-003"
}| Field | Type | Description |
|---|---|---|
schema_version |
string | Schema version (currently "1.0") |
passed |
boolean | Whether all SLO conditions were met |
commit |
string | Commit SHA of evaluated snapshot |
timestamp |
string | ISO 8601 timestamp of snapshot |
coverage_percent |
number | Actual coverage percentage |
min_coverage |
number | Required minimum coverage (SLO threshold) |
coverage_ok |
boolean | Whether coverage threshold was met |
kernel_blockers |
number | Count of failing must_have_ac ACs |
max_blockers |
number | Maximum allowed blockers (SLO threshold) |
blockers_ok |
boolean | Whether blockers threshold was met |
blocker_ids |
array | List of failing kernel AC IDs |
unknown_count |
number | Count of unknown status ACs |
max_unknown |
number/null | Maximum allowed unknowns (null = no limit) |
unknown_ok |
boolean | Whether unknown threshold was met |
summary |
string | Human-readable summary message |
| Command | Purpose | Data Source |
|---|---|---|
ac-status |
Point-in-time AC status | Ledger + tests |
ac-report |
Human report of one snapshot | ac-status --json |
ac-history |
Time-series of snapshots | ac-status snapshots on disk |
ac-slo |
Pass/fail gate on latest | ac-history / snapshots |
Protected branch / release pipeline:
- name: Download AC status artifacts
uses: actions/download-artifact@v4
with:
pattern: ac-status-*
path: artifacts/ac-status
- name: Check AC governance SLO
run: |
cargo xtask ac-slo \
--dir artifacts/ac-status \
--min-coverage 95.0 \
--max-blockers 0Nightly job on main (looser SLO):
- name: Check AC governance SLO (nightly)
run: |
cargo xtask ac-slo \
--dir artifacts/ac-status \
--min-coverage 80.0 \
--max-blockers 0 \
--max-unknown 5- Release gates: Ensure minimum quality bar before cutting releases
- Protected branches: Block merges that degrade coverage below threshold
- Nightly health checks: Monitor trends with slightly relaxed thresholds
- Post-merge validation: Fail loudly if coverage regresses
No snapshots found:
- Ensure CI artifacts have been downloaded
- Check file naming: must match
ac-status-<sha>.json - Verify the directory path is correct
SLO unexpectedly fails:
- Check
--min-coveragethreshold (default is 80%) - Review blocker IDs to understand which ACs are failing
- Use
ac-report --status failto see details
Exit code 1 but need to continue:
- Use
|| truein shell to ignore failure:cargo xtask ac-slo ... || true - Consider loosening thresholds for non-blocking checks
- Governance gate: Use as hard gate in release pipelines
- Complements selftest: Selftest checks correctness; ac-slo checks aggregate health
- Latest snapshot only: Evaluates most recent snapshot, not historical average
- Read-only: Never modifies files or state
- Fast: Single pass through snapshot directory
Generate BDD scenario stub for an acceptance criterion.
cargo run -p xtask -- ac-suggest-scenarios <AC-ID>
# Examples
cargo run -p xtask -- ac-suggest-scenarios AC-PLT-001
cargo run -p xtask -- ac-suggest-scenarios AC-TPL-002
# With alias
xt ac-suggest-scenarios AC-PLT-001- Reads
specs/spec_ledger.yamlto find the AC text - Analyzes the AC text to suggest scenario structure
- Generates a BDD scenario stub with appropriate Given/When/Then
- Provides guidance for customization
<AC-ID>- Acceptance Criterion ID (e.g.,AC-PLT-001)
0: Scenario stub generated successfully- Non-zero: AC not found or invalid ID format
- After creating a new AC - Generate scenario template quickly
- Before writing BDD tests - Get a starting point
- Batch scenario creation - Streamline multiple ACs
🔧 Generating BDD scenario stub...
✓ Found AC: AC-PLT-001
Suggested BDD Scenario (add to specs/features/*.feature):
@AC-PLT-001
Scenario: xtask doctor validates Rust, Nix, conftest
When I run the command
Then [assertion about outcome]
Next steps:
1. Copy the scenario above
2. Edit specs/features/your_feature.feature
3. Paste and customize the scenario:
- Update When/Then steps to match the AC
- Add specific test data or assertions
4. Run: cargo xtask bdd
5. Run: cargo xtask ac-status
The command suggests steps based on AC text patterns:
| AC Text Contains | Suggested Step |
|---|---|
| "GET /health" | When I make a GET request |
| "POST /api" | When I make a request |
| "returns" | Then the response should be valid |
| "success" | Then the operation should succeed |
| "validates" or "checks" | Both Given and When suggested |
| "run" or "execute" | When I run the command |
- Copy the stub - The output is ready to paste into feature files
- Customize assertions - Replace
[...]placeholders with specific checks - Use step definitions - Check existing steps in
crates/acceptance/src/steps/ - Keep it focused - Each scenario should test one behavior
- Run immediately - Test with
cargo xtask bddto validate syntax
# 1. Create an AC
cargo xtask ac-new AC-MY-001 "GET /api returns data" \
--story US-MY-001 \
--requirement REQ-MY-FEATURE
# 2. Generate scenario stub
cargo xtask ac-suggest-scenarios AC-MY-001
# 3. Edit the feature file and paste the stub
vim specs/features/my_feature.feature
# 4. Customize the scenario with real steps
# Edit: Given, When, Then to match the AC
# 5. Run BDD tests
cargo xtask bdd
# 6. Check coverage
cargo xtask ac-coverageAC ID not found:
- Verify AC exists in
specs/spec_ledger.yaml - Check ID format: must start with
AC- - Use exact case as in ledger
Wrong scenario type suggested:
- Template is a starting point only
- Always customize to match your specific AC
- Add multiple steps if needed
Steps don't match AC:
- Edit the Given/When/Then after pasting
- Add more specific assertions
- Reference actual API endpoints or commands
- Template-based - Suggestion uses pattern matching, always review
- Non-destructive - Only outputs to terminal, no file changes
- Quick iteration - Regenerate with different AC ID easily
- Pairing tool - Works well with
ac-coveragefor batch flows
Test Rego policies with conftest.
cargo run -p xtask -- policy-test
# Or in Nix shell
nix develop -c cargo run -p xtask -- policy-testRuns conftest policy tests for all policy areas:
- Ledger Policy (
policy/ledger.rego) - Ensures every AC has tests - Features Policy (
policy/features.rego) - Validates feature-AC references - Flags Policy (
policy/flags.rego) - Validates flag ownership and rollouts - Privacy Policy (
policy/privacy.rego) - Ensures PII fields have owners and retention
Each policy is tested against fixtures in policy/testdata/:
{area}_valid.json- Should pass{area}_invalid.json- Should fail{area}_missing_tests.json- Should fail (for ledger){area}_unknown_ac.json- Should fail (for features)
0: All policy tests passed- Non-zero: One or more policy tests failed or conftest not available
- During development - Validate policy changes
- Before commits - Ensure policies still pass
- In CI - Governance validation
- After adding ACs/flags/PII - Verify metadata is complete
Testing Rego policies...
Ledger Policy (policy/ledger.rego):
✓ ledger_valid.json (correctly passed)
✓ ledger_missing_tests.json (correctly failed)
Features Policy (policy/features.rego):
✓ features_valid.json (correctly passed)
✓ features_unknown_ac.json (correctly failed)
Flags Policy (policy/flags.rego):
✓ flags_valid.json (correctly passed)
✓ flags_invalid.json (correctly failed)
Privacy Policy (policy/privacy.rego):
✓ privacy_valid.json (correctly passed)
✓ privacy_invalid.json (correctly failed)
✓ All 8 policy tests passed!
Requires conftest to be available on PATH:
Install options:
- Nix:
nix develop(recommended - automatically available) - macOS:
brew install conftest - Linux: See https://www.conftest.dev/install/
- Container:
docker run --rm openpolicyagent/conftest
"conftest not found on PATH":
- Enter Nix shell:
nix develop - Or install conftest manually for your platform
Policy test fails unexpectedly:
- Check fixture files in
policy/testdata/ - Verify policy file syntax in
policy/*.rego - Run manually:
conftest test -p policy/ledger.rego policy/testdata/ledger_valid.json
No test fixtures found:
- Check that
policy/testdata/{area}_valid.jsonexists - Policy will skip if no fixtures found
- Part of
xtask selftestbut gracefully degrades if conftest unavailable - Each policy area is tested independently
- Fixtures use realistic data structures from actual specs
Generate LLM context bundle for a specific task.
cargo run -p xtask -- bundle <task>
# Examples
cargo run -p xtask -- bundle implement_ac
cargo run -p xtask -- bundle implement_feature
cargo run -p xtask -- bundle debug_tests- Reads
.llm/contextpack.yamlfor task configuration - Resolves
includeglob patterns viagit ls-files - Respects
.llm/.llmignoreexclusions (using gitignore syntax) - Enforces
max_byteslimit - Generates markdown bundle at
.llm/bundle/<task>.md
<task>- Task name defined in.llm/contextpack.yaml
0: Bundle generated successfully- Non-zero: Task not found or bundling failed
.llm/bundle/<task>.md- Generated context bundle
- Before LLM coding session - Get focused context
- When implementing AC - Provide specs + tests + code
- When debugging - Include relevant test failures
Generating LLM context bundle for task: implement_ac
Building context bundle: implement_ac
Max size: 250000 bytes
Description: Context for implementing an AC: ledger, specs, features, and core code
Files included: 6
Bundle size: 2708 bytes
Bundle written to: /path/to/.llm/bundle/implement_ac.md
✓ Bundle generated: .llm/bundle/implement_ac.md
Task not found:
- Check
.llm/contextpack.yamlhas task defined - Verify task name spelling
Bundle too large:
- Reduce
max_bytesin contextpack.yaml - Make
includepatterns more specific
Missing files:
- Files must be tracked by git (
git ls-files) - Check
.llm/.llmignoreisn't excluding needed files (uses gitignore syntax)
Edit .llm/contextpack.yaml:
tasks:
my_task:
max_bytes: 150000
include:
- specs/spec_ledger.yaml
- crates/core/src/**/*.rs
description: "Custom task description"Generate a structured release evidence bundle for a given version.
cargo run -p xtask -- release-bundle <version>
# Example
cargo run -p xtask -- release-bundle 3.3.6Creates a comprehensive evidence file at release_evidence/v<version>.md containing:
- Tasks Completed - All tasks with status "done" from
specs/tasks.yaml - Acceptance Criteria & Requirements - Linked REQs/ACs from
specs/spec_ledger.yaml - Architecture Decisions - List of ADRs from
docs/adr/ - Git Changelog - Commit log since last git tag
- Governance Status - Selftest results and policy status
- Resolved Friction - Entries marked as resolved in
FRICTION_LOG.md
<version>- Version number (e.g.,3.3.6) - format should beX.Y.Z
0: Evidence bundle generated successfully- Non-zero: Invalid version format or generation failed
release_evidence/v<version>.md- Complete evidence bundle for the release
- Before cutting a release - Generate evidence to review what's included
- For changelog generation - Feed evidence file to LLM for Keep a Changelog format
- For release notes - Use as source material for GitHub releases
- For compliance - Provide auditable evidence of what changed
- Post-release - Commit evidence file for historical tracking
📦 Generating release evidence bundle for 3.3.6...
📋 Collecting evidence...
✓ Evidence bundle written to: /path/to/release_evidence/v3.3.6.md
Next steps:
1. Review evidence: cat release_evidence/v3.3.6.md
2. Feed to LLM for changelog generation
3. Update CHANGELOG.md with generated content
The generated markdown file includes:
# Release Evidence: v3.3.6
**Generated:** 2025-01-21 10:30:00
---
## Tasks Completed
**Total completed:** 3 tasks
### TASK-TPL-REL-BUNDLE-3-3-6
**Title:** Implement release-bundle command
**Requirement:** REQ-TPL-REL-BUNDLE
**ACs:** AC-TPL-REL-EVIDENCE, AC-TPL-REL-CHANGELOG
...
## Acceptance Criteria & Requirements
### REQ-TPL-REL-BUNDLE - Release evidence bundle generation
**Story:** US-TPL-PLT-001 - Platform: Developer Experience & Governance
**Tags:** platform, release, devex
...
## Architecture Decisions
**Total ADRs:** 7
- 0001-adopt-hexagonal-architecture.md
- 0002-nix-first-development.md
...
## Git Changelog
**Since tag:** v2.4.0
- abc1234 feat: add release-bundle command (Agent)
- def5678 docs: update roadmap for v3.3.x (User)
...
## Governance Status
### Selftest Status
**Status:** ✅ PASSED
[7/7] Validating graph invariants... ✓ Graph invariants validated
### Policy Status
```json
{"status": "pass", "tests": 8, "failures": 0}
Total resolved entries: 2
...
### Integration with Release Workflow
Typical release workflow:
```bash
# 1. Prepare release (update versions)
cargo xtask release-prepare 3.3.6
# 2. Generate evidence bundle
cargo xtask release-bundle 3.3.6
# 3. Review evidence and generate changelog
cat release_evidence/v3.3.6.md
# Feed to LLM: "Generate Keep a Changelog entry from this evidence"
# 4. Update CHANGELOG.md with LLM-generated content
# 5. Verify release readiness
cargo xtask release-verify
# 6. Commit and tag
git add .
git commit -m "Release v3.3.6"
git tag -a v3.3.6 -m "Release 3.3.6"
git push && git push --tags
The evidence bundle is designed to be fed to an LLM with a prompt like:
Given this release evidence bundle, generate a CHANGELOG.md entry
in Keep a Changelog format (Added/Changed/Fixed/Removed sections).
Focus on user-visible changes and group related items logically.
[Paste evidence bundle content]
The LLM can then:
- Group tasks by category (Added/Changed/Fixed/Removed)
- Convert technical AC language to user-friendly descriptions
- Identify breaking changes from git log
- Generate concise bullet points
- Add links to issues/PRs if present in git log
No completed tasks found:
- Ensure tasks in
specs/tasks.yamlhavestatus: done(lowercase) - Check that tasks were completed for this release
- Manually mark tasks as done if needed
Git log empty:
- Ensure you've made commits since the last tag
- Check that git repository has at least one tag
- First release: git log will show all commits
Selftest fails during evidence generation:
- Evidence bundle will still be created, but governance status will show failure
- Fix selftest issues before releasing
- Run
cargo xtask selftestseparately to diagnose
Policy status not found:
- Run
cargo xtask policy-testto generatetarget/policy_status.json - Policy status section will note if file is missing
- Idempotent: Running multiple times overwrites the evidence file
- Version-agnostic tasks: Currently filters by status, not version field
- Git-dependent: Requires git repository with at least one tag for changelog
- Selftest integration: Runs selftest in low-resource mode for status
- Historical record: Commit evidence files for audit trail
Normalize Agent Skills definitions in .claude/skills/*/SKILL.md.
cargo run -p xtask -- skills-fmtApplies repository-wide formatting rules to Skills definitions:
- Locates all
SKILL.mdfiles under.claude/skills/ - Parses YAML frontmatter with
serde_yaml - Normalizes field order, required fields, and spacing
- Ensures consistent formatting across all Skills
0: All Skills formatted successfully- Non-zero: Formatting failed or invalid Skills found
- Before committing Skills changes - Ensure consistency
- After creating/editing Skills - Normalize formatting
- In pre-commit hooks - Automatic formatting
🎨 Formatting Agent Skills...
Formatted:
✓ .claude/skills/governed-feature-dev/SKILL.md
✓ .claude/skills/governed-maintenance/SKILL.md
✓ .claude/skills/governed-release/SKILL.md
✓ 3 Skills formatted
Permission errors:
- Ensure Skills files are writable
- Check file permissions in
.claude/skills/
Invalid YAML:
- Fix YAML syntax in frontmatter
- Verify frontmatter is enclosed in
---delimiters
- Idempotent: Safe to run multiple times
- Preserves content: Only formats, doesn't change meaning
- Part of governance: Skills are governed artifacts
Lint Agent Skills definitions for structural and governance correctness.
cargo run -p xtask -- skills-lintValidates Skills definitions against repository standards:
- Required frontmatter fields -
name,descriptionexist - Name conventions - Kebab-case, max length
- Description quality - Includes "what" and "when to use"
- References - Links to flows (
ac_first,onboarding) and/or xtask commands - Location - Skills live under
.claude/skills/only
0: All Skills valid- Non-zero: One or more Skills invalid; errors printed
- Before committing Skills changes - Validate structure
- In CI - Prevent invalid Skills from landing
- When adding/refactoring Skills - Ensure compliance
- In pre-commit hooks - Automatic validation
🔍 Linting Agent Skills...
Checking:
✓ .claude/skills/governed-feature-dev/SKILL.md
✓ .claude/skills/governed-maintenance/SKILL.md
✗ .claude/skills/governed-release/SKILL.md
→ Missing description in frontmatter
→ Description must include "when to use"
✗ 1/3 Skills failed validation
Missing frontmatter fields:
- Add required fields:
name,description - Ensure frontmatter is valid YAML
Invalid name format:
- Use kebab-case:
governed-feature-dev, notGovernedFeatureDev - Keep names concise (max 50 characters)
Description issues:
- Include both what the Skill does and when to use it
- Reference flows from
specs/devex_flows.yaml
No workflow references:
- Link to flows:
ac_first,onboarding, etc. - Or reference xtask commands:
cargo xtask check
Part of cargo xtask docs-check:
# Runs as part of documentation validation
cargo run -p xtask -- docs-check
# Output includes Skills check:
# Skills definitions... ✓ Valid- Non-invasive: Read-only, doesn't modify files
- Use with skills-fmt: Run
skills-fmtto fix formatting first - Governance integration: Skills are governed artifacts like docs
Quick validation of template functionality (first-run check).
cargo run -p xtask -- quickstart- Checks environment (cargo, rustc versions)
- Runs
xtask check - Runs
xtask bdd - Runs
xtask bundle implement_ac - Reports results with colored output
0: All validation passed- Non-zero: One or more validation steps failed
- First time - After cloning template
- After setup changes - Verify environment still works
- Quick health check - Lighter than
selftest
======================================
Rust Template Quick Start
======================================
[1/5] Checking environment...
✓ cargo 1.91.0
✓ rustc 1.91.0
[2/5] Running xtask check...
✓ Format check passed
✓ Clippy passed
✓ Tests passed
[3/5] Running BDD acceptance tests...
✓ BDD scenarios passed
✓ JUnit output created
[4/5] Testing LLM context bundler...
✓ Bundle command executed
✓ Bundle created (2708 bytes)
[5/5] Testing helper commands...
✓ Core commands validated
======================================
✓ Template validation passed!
Next steps:
• See docs/how-to/new-service-from-template.md for adoption guide
• See TEMPLATE_API.md for stable interface documentation
• See docs/tutorials/first-ac-change.md for AC-first development
======================================
| Feature | quickstart | selftest |
|---|---|---|
| Environment check | ✓ | ✓ |
| Core checks | ✓ | ✓ |
| BDD tests | ✓ | ✓ |
| AC status | ✗ | ✓ |
| Policy tests | ✗ | ✓ (if available) |
| Use case | First run | CI/comprehensive |
Complete template self-test suite (used in CI). This is the governance gate - if selftest passes, your changes are valid.
cargo run -p xtask -- selftest
# Low-resource mode (for CI/constrained environments)
XTASK_LOW_RESOURCES=1 cargo run -p xtask -- selftest
# Verbose mode
cargo run -p xtask -- selftest -v
# Strict AC coverage mode (fails on Unknown kernel ACs)
XTASK_STRICT_AC_COVERAGE=1 cargo run -p xtask -- selftest| Variable | Description |
|---|---|
XTASK_LOW_RESOURCES=1 |
Reduce parallelism and skip resource-intensive checks |
XTASK_SKIP_BDD=1 |
Skip BDD tests (internal/harness use; leave unset for normal selftest) |
XTASK_STRICT_AC_COVERAGE=1 |
Fail selftest if kernel (must_have_ac=true) ACs have Unknown status (no BDD coverage) |
Comprehensive validation in 12 steps:
- Core checks: format, clippy, tests
- BDD tests: acceptance scenarios + JUnit XML
- AC/ADR mapping: Validates traceability (tests → ACs, REQs → ADRs)
- LLM bundler: Validates context generation
- Policy tests: Runs Rego policies (if conftest available)
- DevEx contract: Verifies required commands exist
- Graph invariants: Validates structural integrity (no orphaned REQs, missing ACs)
0: All self-tests passed- Non-zero: One or more test suites failed
target/junit/acceptance.xml- JUnit test resultsdocs/feature_status.md- AC status mapping.llm/bundle/implement_ac.md- LLM context bundle
- In CI/CD - Comprehensive validation
- Before releases - Full health check
- After major changes - Verify nothing broke
======================================
Template Self-Test Suite
======================================
[1/7] Running core checks (fmt, clippy, tests)...
✓ Core checks passed
[2/7] Running BDD acceptance tests...
✓ BDD scenarios passed
[3/7] Checking AC/ADR mapping...
✓ AC status mapping verified
✓ ADR references validated
[4/7] Testing LLM context bundler...
✓ Bundle generated (2708 bytes)
[5/7] Running policy tests...
✓ Ledger policy passed
✓ LLM policy passed
[6/7] Checking DevEx contract...
✓ DevEx contract satisfied
[7/7] Validating graph invariants...
✓ Graph invariants validated
======================================
✓ All 7 steps passed!
======================================
When running with XTASK_LOW_RESOURCES=1:
[1/7] Core checks...
✓ passed
[2/7] BDD...
✓ passed (summary output suppressed)
[3/7] AC/ADR mapping...
✓ passed
[4/7] LLM bundler...
✓ passed
[5/7] Policy tests...
✓ passed
[6/7] DevEx contract...
✓ passed
[7/7] Graph invariants...
✓ passed
======================================
✓ All 7 steps passed!
======================================
Low-resource mode benefits:
- Reduced output (less logging from BDD runner)
- Same validation rigor
- Faster in CI environments
- Easier to parse for automation
Used in .github/workflows/ci-template-selftest.yml:
- name: Run template self-test suite
run: nix develop -c cargo run -p xtask -- selftest- AC status failures are warnings (informational)
- Policy tests skip if conftest unavailable
- Only core checks and BDD are hard requirements
Validate IDP integration surface (OpenAPI lint + Backstage plugin checks).
cargo run -p xtask -- idp-check
# Verbose output
cargo run -p xtask -- idp-check -vRuns focused validation for IDP/portal integration:
- OpenAPI lint: Runs Redocly linting on
specs/openapi/openapi.yaml - Backstage plugin checks: Runs
pnpm run checkinexamples/backstage-plugin/ - TypeScript config validation: Validates tsconfig.json against governance rules
- PlatformClient tests: Runs TypeScript tests for API contract compliance
0: All IDP checks passed- Non-zero: One or more checks failed
- After OpenAPI changes: Verify schema is still valid and TypeScript types compile
- After platform endpoint changes: Ensure Backstage plugin still type-checks
- Before releases: Validate the IDP surface is healthy
- During Backstage integration work: Quick feedback loop
🔍 Validating IDP integration surface...
[1/3] Running OpenAPI lint...
✓ specs/openapi/openapi.yaml valid
[2/3] Running Backstage plugin checks...
✓ TypeScript compilation passed
✓ Type tests passed
[3/3] Validating TypeScript config...
✓ No deprecated moduleResolution
✓ No ignoreDeprecations flags
✓ IDP surface validation passed
- Non-kernel: This is an ergonomic helper for IDP integration, not a kernel requirement
- Requires pnpm: Backstage plugin checks need pnpm installed
- Complements selftest: Use
selftestfor full governance; useidp-checkfor focused IDP validation
Validate that governed facts in documentation match their sources.
cargo run -p xtask -- contracts-checkValidates governed facts against their sources:
-
Computes facts from code and specs:
- Selftest step count (from
[N/M]patterns inselftest.rs) - AC counts by classification (kernel/template/meta from
spec_ledger.yaml) - Platform endpoints (from
openapi.yaml) - Required checks (from
devex_flows.yaml)
- Selftest step count (from
-
Loads patterns from
specs/contracts_manifest.yaml -
Scans documentation for patterns that contain governed numbers
-
Reports drift if any documented numbers don't match computed values
0: All documented facts match sources- Non-zero: Drift detected (documented value differs from source)
- Before PR merge: Ensure docs are synchronized
- After changing selftest steps: Verify step counts are updated
- After AC changes: Verify AC counts are updated
- In CI: Automated drift detection
📋 Checking contract governance...
Computed facts from source:
• Selftest steps: 11
• AC counts: total=116, kernel=61, template=37, meta=18
• Platform endpoints: 15
• Required checks: 4
✓ All contract facts are synchronized
When drift is detected:
📋 Checking contract governance...
Computed facts from source:
• Selftest steps: 11
• AC counts: total=116, kernel=61, template=37, meta=18
Contract drift detected:
README.md:42
Contract: selftest_step_count
- An 10-step selftest gate
+ An 12-step selftest gate
Error: contracts-check found 1 edit(s) across 1 file(s). Run `cargo xtask contracts-fmt` to fix.
Drift after adding selftest step:
- You added a step to
selftest.rsbut didn't update docs - Run
cargo xtask contracts-fmtto auto-fix
AC count mismatch:
- You changed ACs in
spec_ledger.yamlbutfeature_status_notes.mdis stale - Run
cargo xtask contracts-fmtto auto-fix
Pattern not matching:
- The regex in
contracts_manifest.yamldoesn't match the doc format - Update the regex or adjust the documentation format
Synchronize governed facts from sources to documentation.
cargo run -p xtask -- contracts-fmtUpdates documentation to match computed facts:
- Computes current values from sources (same as
contracts-check) - Loads patterns from
specs/contracts_manifest.yaml - Applies edits to each file where documented values differ
- Reports changes made
This is the "fix" command that pairs with contracts-check.
0: All files updated successfully (or no changes needed)- Non-zero: Failed to apply edits
- After selftest step changes: Update all step count references
- After AC changes: Update all AC count references
- Before commits: Auto-fix drift as part of workflow
- In pre-commit hooks: Automatic synchronization
When no changes needed:
📋 Synchronizing contract facts...
Computed facts from source:
• Selftest steps: 11
• AC counts: total=116, kernel=61, template=37, meta=18
• Platform endpoints: 15
• Required checks: 4
✓ All contract facts are synchronized
When changes are applied:
📋 Synchronizing contract facts...
Computed facts from source:
• Selftest steps: 11
• AC counts: total=116, kernel=61, template=37, meta=18
✓ README.md
✓ docs/feature_status_notes.md
✓ Applied 2 contract updates
Patterns are defined in specs/contracts_manifest.yaml:
contracts:
selftest_step_count:
source: "crates/xtask/src/commands/selftest.rs"
description: "Number of steps in the selftest governance gate"
patterns:
- file: "README.md"
regex: '(\d+)-step selftest gate'
template: "{n}-step selftest gate"- regex: Pattern to find the current value (capture group extracts number)
- template: Replacement text with
{n}substituted
Edit specs/contracts_manifest.yaml to add new patterns:
contracts:
my_fact:
source: "path/to/source/file"
description: "What this fact represents"
patterns:
- file: "docs/some-doc.md"
regex: 'has (\d+) widgets'
template: "has {n} widgets"
required: false # Don't fail if file doesn't existPattern doesn't match:
- Regex is too strict or doc format changed
- Test regex against the actual line in the file
- Update
contracts_manifest.yamlpattern
Write permission denied:
- Ensure documentation files are writable
- Check git isn't locking the files
- Idempotent: Safe to run multiple times
- Atomic writes: Uses temp file + rename to avoid partial writes
- Part of docs-check:
cargo xtask docs-checkrunscontracts-checkinternally
Validate UI contract specification and DOM anchors.
cargo run -p xtask -- ui-contract-checkValidates the UI contract system end-to-end:
- YAML Parse: Loads
specs/ui_contract.yamland verifies structure - Schema Validation: Checks unique screen IDs, unique region IDs per screen, required fields
- Region Kind Refs: Verifies all regions reference defined kinds in
region_kinds - DOM Validation: Runs integration tests to verify HTML has matching
data-uiidattributes
0: All UI contract checks passed- Non-zero: One or more checks failed
- After changing
/uipages: Verify DOM still matches contract - After editing
ui_contract.yaml: Validate contract structure - In CI: Part of selftest step 9 (Governance graph & UI)
- Before releases: Ensure UI contract is synchronized
🎨 Validating UI contract...
[1/4] UI contract YAML ✓
[2/4] Schema validation ✓
[3/4] Region kind refs ✓
[4/4] DOM validation tests ✓
UI contract validation PASSED
When validation fails:
🎨 Validating UI contract...
[1/4] UI contract YAML ✓
[2/4] Schema validation ✓
[3/4] Region kind refs ✓
[4/4] DOM validation tests ✗
UI contract validation FAILED
✗ DOM validation: Dashboard is missing data-uiid attributes for regions: ["dashboard.metrics"]
Fix the contract (specs/ui_contract.yaml) or HTML templates to match.
The contract is defined in specs/ui_contract.yaml:
schema_version: "1.0"
template_version: "v3.3.6"
screens:
- id: platform_dashboard
route: "/"
aliases: ["/ui"]
description: "Primary governance dashboard"
regions:
- id: "dashboard.health"
kind: "panel"
description: "Health metrics grid"
- id: "dashboard.nav"
kind: "navigation"
description: "Main navigation bar"
region_kinds:
panel: "Grouped content section"
navigation: "Links to other screens"HTML templates must include data-uiid attributes matching contract regions:
// In Maud templates
div data-uiid="dashboard.health" { /* content */ }
div data-uiid="dashboard.nav" { /* content */ }The validation tests verify:
- Every region in the contract has a matching DOM element
- Routes are reachable (return 200 OK)
- Region IDs are unique per screen
The contract is also exposed via HTTP at /platform/ui/contract:
curl http://localhost:8080/platform/ui/contract | jqReturns the same structure as specs/ui_contract.yaml as JSON.
This check runs as part of step 9 (Governance graph & UI) in selftest:
[9/11] Checking governance graph & UI contract...
✓ Graph invariants satisfied
✓ UI contract validation PASSED
Missing data-uiid in HTML:
- Add
data-uiid="region.id"attribute to the appropriate element - Check that region ID matches exactly (case-sensitive)
Region kind not defined:
- Add the kind to
region_kindsmap inui_contract.yaml - Or use an existing kind like
panel,header,navigation
Duplicate region ID:
- Region IDs must be unique within each screen
- Use dot notation:
screen.regionfor clarity
Route not reachable:
- Ensure the route is defined in
app-httprouter - Check for typos in the
routefield
- Governance artifact: UI contract is a first-class governed spec
- Agent-friendly:
/platform/ui/contractendpoint enables programmatic access - Testing: DOM tests in
crates/app-http/tests/ui_contract_dom.rs - Part of selftest: Integrated into step 9 governance check
Search across friction entries, questions, and tasks with a unified interface.
cargo run -p xtask -- issues-search <query>
# Filter by type
cargo run -p xtask -- issues-search "auth" --type friction
cargo run -p xtask -- issues-search "bundle" --type question
cargo run -p xtask -- issues-search "release" --type task
# Filter by status
cargo run -p xtask -- issues-search "bug" --status open
# Filter by REQ/AC references
cargo run -p xtask -- issues-search "test" --refs REQ-TPL-001
# JSON output for programmatic access
cargo run -p xtask -- issues-search "error" --json
# Limit results
cargo run -p xtask -- issues-search "docs" --limit 10| Flag | Description |
|---|---|
<query> |
Search query (matches ID, summary, description) |
--type <TYPE> |
Filter by type: friction, question, or task (omit for all) |
--status <STATUS> |
Filter by status |
--refs <REF> |
Filter by REQ/AC reference (e.g., REQ-TPL-001) |
--json |
Output in JSON format |
--limit <N> |
Maximum results to return (default: 50) |
- Searches friction entries from
friction/*.yaml - Searches questions from
questions/*.yaml - Searches tasks from
specs/tasks.yaml - Calculates relevance scores based on:
- ID match (highest priority, exact match bonus)
- Summary/title match
- Description/context match
- Category/label match
- Sorts results by relevance score (highest first)
- Returns unified results with type, ID, status, summary, and refs
0: Search completed (even if no results)- Non-zero: Search failed (file read error, parse error)
- Finding related issues: Search across all governance artifacts
- Agent workflows: Quickly locate relevant friction/questions for a task
- Triaging work: Find all open issues related to a specific REQ or AC
- Auditing: Find all issues mentioning a specific component or flow
Found 3 results for 'auth':
TYPE ID STATUS SUMMARY
────────────────────────────────────────────────────────────────────────────────
friction FRICTION-TOOL-001 open Auth token refresh fails si...
question Q-TPL-002 open Should auth use JWT or sess...
task TASK-AUTH-001 InProgress Implement OAuth2 flow
{
"query": "auth",
"total_results": 3,
"results": [
{
"issue_type": "friction",
"id": "FRICTION-TOOL-001",
"summary": "Auth token refresh fails silently",
"status": "open",
"refs": ["REQ-TPL-AUTH"],
"date": "2025-01-15",
"relevance_score": 15.0
}
]
}- Unified interface: Search all governance artifacts in one command
- Relevance scoring: Results sorted by match quality, not just date
- Type-aware: Understands friction, question, and task schemas
- Fast: Parses YAML files directly, no network calls
Create a GitHub issue from a friction entry.
cargo run -p xtask -- friction-gh-create <FRICTION_ID>
# With additional labels
cargo run -p xtask -- friction-gh-create FRICTION-TOOL-001 --labels "bug,urgent"
# Preview without creating (dry run)
cargo run -p xtask -- friction-gh-create FRICTION-TOOL-001 --dry-run
# Open in browser after creation
cargo run -p xtask -- friction-gh-create FRICTION-TOOL-001 --open| Flag | Description |
|---|---|
<FRICTION_ID> |
Friction ID to create issue from (e.g., FRICTION-TOOL-001) |
--labels <LABELS> |
Additional labels (comma-separated) |
--dry-run |
Preview issue without creating |
--open |
Open issue in browser after creation |
- Loads friction entry from
friction/<FRICTION_ID>.yaml - Checks if already linked to a GitHub issue (warns if so)
- Generates issue title:
[Friction] <summary> - Generates issue body with:
- Friction ID, category, severity, date
- Description
- Context (flow, phase if available)
- Related REQ/AC references
- Applies labels:
friction,category:<category>,priority:<severity>(if high/critical) - Creates GitHub issue using
ghCLI - Updates friction entry with issue reference in
related_items.issues
- GitHub CLI (
gh) installed and authenticated (gh auth login) - Repository must have a GitHub remote configured
0: Issue created successfully- Non-zero: Failed to create issue or friction entry not found
- Escalating friction: Turn a friction entry into a trackable GitHub issue
- Team visibility: Make friction visible to team members via GitHub
- Integration: Connect local governance artifacts to GitHub workflow
Creating GitHub issue from friction entry FRICTION-TOOL-001...
Created GitHub issue: https://github.com/owner/repo/issues/42
Issue number: #42
Updated friction entry with issue reference
Dry run - would create GitHub issue:
Title: [Friction] Build times increased after Cargo.lock update
Labels: friction, category:tooling, priority:high
Body:
## Friction: Build times increased after Cargo.lock update
**ID**: `FRICTION-TOOL-001` | **Category**: tooling | **Severity**: high | **Date**: 2025-01-15
### Description
Clean builds now take 3+ minutes instead of ~90 seconds after updating dependencies.
...
GitHub CLI not installed:
GitHub CLI (gh) not found. Install it from: https://cli.github.com/
Then run: gh auth login
Not authenticated:
GitHub CLI not authenticated.
Run: gh auth login
Friction entry already linked:
- Warning is shown but issue is still created
- Consider using
friction-gh-linkif issue already exists
- Atomic update: Friction entry is updated with issue reference after creation
- Label mapping: Severity is mapped to priority labels (high/critical only)
- Bidirectional: Creates a reference trail between friction and GitHub
Link an existing GitHub issue to a friction entry.
cargo run -p xtask -- friction-gh-link <FRICTION_ID> <ISSUE_NUMBER>
# Examples
cargo run -p xtask -- friction-gh-link FRICTION-TOOL-001 42
cargo run -p xtask -- friction-gh-link FRICTION-TOOL-001 "#42"| Flag | Description |
|---|---|
<FRICTION_ID> |
Friction ID to link (e.g., FRICTION-TOOL-001) |
<ISSUE_NUMBER> |
GitHub issue number (e.g., 42 or #42) |
- Parses issue number (handles
#prefix) - Loads friction entry from
friction/<FRICTION_ID>.yaml - Checks if already linked to this issue (returns early if so)
- Adds issue reference to
related_items.issueslist - Saves updated friction entry
0: Link created successfully (or already linked)- Non-zero: Friction entry not found or invalid issue number
- Retroactive linking: Connect a friction entry to an existing issue
- Manual creation: When issue was created outside of
friction-gh-create - Cross-referencing: Link friction to issues created by other workflows
Linked friction entry FRICTION-TOOL-001 to GitHub issue #42
Friction entry 'FRICTION-TOOL-001' is already linked to #42
Invalid issue number:
- Must be numeric (with optional
#prefix) - Example:
42,#42
Friction entry not found:
- Check that
friction/<FRICTION_ID>.yamlexists - Verify ID spelling
- Idempotent: Safe to run multiple times
- No validation: Does not verify issue exists on GitHub
- Lightweight: Only modifies the friction YAML file
Resolve a friction entry by marking it as resolved or won't fix.
cargo run -p xtask -- friction-resolve --id <FRICTION_ID> --resolved-by <WHO>
# With fix description
cargo run -p xtask -- friction-resolve \
--id FRICTION-TOOL-001 \
--resolved-by "human" \
--fix-description "Upgraded sccache to v0.8.0"
# With PR links
cargo run -p xtask -- friction-resolve \
--id FRICTION-TOOL-001 \
--resolved-by "agent" \
--pr https://github.com/owner/repo/pull/123 \
--pr https://github.com/owner/repo/pull/124
# Mark as won't fix
cargo run -p xtask -- friction-resolve \
--id FRICTION-TOOL-001 \
--resolved-by "human" \
--status wont_fix \
--fix-description "Accepted as known limitation"
# With verification notes
cargo run -p xtask -- friction-resolve \
--id FRICTION-TOOL-001 \
--resolved-by "human" \
--verification "Tested on CI - build times now under 90s"| Flag | Description |
|---|---|
--id <ID> |
Friction ID to resolve (e.g., FRICTION-TOOL-001) |
--resolved-by <WHO> |
Who resolved it (e.g., agent, human, username) |
--fix-description <DESC> |
Description of how it was fixed (optional) |
--pr <URL> |
PR links (repeatable) |
--verification <NOTES> |
Verification notes (optional) |
--status <STATUS> |
New status: resolved (default) or wont_fix |
- Loads friction entry from
friction/<FRICTION_ID>.yaml - Validates status is
resolvedorwont_fix - Updates status field
- Adds resolution block with:
resolved_by: Who resolved itresolved_at: Current timestamp (RFC 3339)fix_description: Optional fix descriptionpr_links: Optional list of PR URLsverification: Optional verification notes
- Saves updated friction entry
0: Friction entry resolved successfully- Non-zero: Entry not found or invalid status
- Closing friction: Mark a friction point as fixed
- Documenting resolution: Capture how and why it was resolved
- Audit trail: Record PRs and verification for future reference
- Won't fix: Document accepted limitations
Resolved friction entry: FRICTION-TOOL-001
Status: resolved
Resolved by: human
Fix: Upgraded sccache to v0.8.0
PRs: https://github.com/owner/repo/pull/123
After resolution, the friction YAML includes:
status: resolved
resolution:
resolved_by: human
resolved_at: "2025-01-15T10:30:00Z"
fix_description: "Upgraded sccache to v0.8.0"
pr_links:
- https://github.com/owner/repo/pull/123
verification: "Tested on CI - build times now under 90s"Already resolved:
- Warning is shown but status can be updated again
- Useful for re-resolving with updated information
Invalid status:
- Must be
resolvedorwont_fix - Other statuses (open, investigating, in_progress) use
friction-new
- Timestamp: Uses UTC timestamp in RFC 3339 format
- Overwrites: Previous resolution is replaced, not appended
- Surfaced via API: Resolution appears in
/platform/frictionendpoint
Create a new question artifact to capture ambiguity encountered during flows.
cargo run -p xtask -- question-new \
--category TPL \
--summary "Should auth use JWT or session cookies?" \
--flow governed-feature-dev \
--phase implementation \
--description "Implementing AC-TPL-AUTH-001 requires choosing auth mechanism"
# With related task
cargo run -p xtask -- question-new \
--category TPL \
--summary "Which crate for OpenAPI generation?" \
--flow governed-feature-dev \
--phase planning \
--description "Need to choose between utoipa and paperclip" \
--task-id TASK-API-001
# With REQ/AC references
cargo run -p xtask -- question-new \
--category BUNDLE \
--summary "Should bundle include test files?" \
--flow bundle \
--phase selection \
--description "Unclear if test files help or add noise" \
--refs REQ-TPL-BUNDLE \
--refs AC-TPL-BUNDLE-001
# Agent-created question
cargo run -p xtask -- question-new \
--category SUGGEST \
--summary "Ambiguous dependency between tasks" \
--flow suggest-next \
--phase dependency_analysis \
--description "TASK-A and TASK-B have circular dependency" \
--created-by agent| Flag | Description |
|---|---|
--category <CAT> |
Question category/component (e.g., TPL, BUNDLE, SUGGEST) |
--summary <SUMMARY> |
Brief summary of the question |
--flow <FLOW> |
Flow that generated this question |
--phase <PHASE> |
Phase within the flow |
--description <DESC> |
Detailed description of the ambiguity |
--created-by <WHO> |
Who created this: agent, human, or flow (default: human) |
--task-id <ID> |
Related task ID (optional) |
--refs <REF> |
REQ/AC IDs this question is about (repeatable) |
- Validates category format (uppercase alphanumeric)
- Validates
created_byis one of:agent,human,flow - Generates sequential question ID:
Q-<CATEGORY>-<NNN> - Creates question artifact with:
- ID, summary, context (flow, phase, description)
- Optional task_id and refs
- Created timestamp (RFC 3339)
- Status:
open
- Saves to
questions/<ID>.yaml
0: Question created successfully- Non-zero: Invalid category or created_by value
questions/Q-<CATEGORY>-<NNN>.yaml- Question artifact file
- During feature development: Capture design ambiguity
- During agent workflows: Record blockers that need human input
- During planning: Document decisions that need to be made
- For audit trail: Track why certain choices were made
Created question: Q-TPL-003
File: questions/Q-TPL-003.yaml
Flow: governed-feature-dev / implementation
Created by: human
Status: open
id: Q-TPL-003
summary: "Should auth use JWT or session cookies?"
context:
flow: governed-feature-dev
phase: implementation
description: "Implementing AC-TPL-AUTH-001 requires choosing auth mechanism"
files_involved: []
task_id: TASK-AUTH-001
refs:
- REQ-TPL-AUTH
- AC-TPL-AUTH-001
created_by: human
created_at: "2025-01-15T10:30:00Z"
status: openInvalid category:
- Must be alphanumeric (e.g.,
TPL,BUNDLE, notmy-component)
Invalid created_by:
- Must be one of:
agent,human,flow
- Sequential IDs: IDs are auto-generated within each category
- Surfaced via API: Appears in
/platform/questionsendpoint - Listed via CLI: Use
questions-listto view
Resolve a question by marking it as answered, resolved, or obsolete.
cargo run -p xtask -- question-resolve --id <QUESTION_ID> --resolved-by <WHO>
# Mark as answered with chosen option
cargo run -p xtask -- question-resolve \
--id Q-TPL-003 \
--resolved-by human \
--chosen-option "JWT" \
--notes "JWT provides stateless auth, better for microservices"
# Mark as resolved (decision implemented)
cargo run -p xtask -- question-resolve \
--id Q-TPL-003 \
--resolved-by agent \
--status resolved \
--notes "Implemented JWT auth per ADR-0015"
# Mark as obsolete (no longer relevant)
cargo run -p xtask -- question-resolve \
--id Q-TPL-003 \
--resolved-by human \
--status obsolete \
--notes "Feature was descoped"| Flag | Description |
|---|---|
--id <ID> |
Question ID to resolve (e.g., Q-TPL-003) |
--resolved-by <WHO> |
Who resolved it: agent, human, or flow |
--chosen-option <LABEL> |
Which option was chosen (label from options list, optional) |
--notes <NOTES> |
Resolution notes (optional) |
--status <STATUS> |
New status: answered, resolved (default), or obsolete |
- Loads question from
questions/<ID>.yaml - Validates status is one of:
answered,resolved,obsolete - Validates
resolved_byis one of:agent,human,flow - If
chosen_optionprovided and question has options, validates it matches - Updates status and adds resolution block:
resolved_by: Who resolved itresolved_at: Current timestamp (RFC 3339)chosen_option: Optional chosen option labelnotes: Optional resolution notes
- Saves updated question
0: Question resolved successfully- Non-zero: Question not found or invalid status/resolved_by
| Status | Meaning |
|---|---|
answered |
Decision made, waiting for implementation |
resolved |
Decision implemented |
obsolete |
Question no longer relevant |
- Decision made: Mark as
answeredwhen choice is clear - Implementation complete: Mark as
resolvedwhen decision is implemented - No longer needed: Mark as
obsoletewhen question is moot - Agent workflow: Record how ambiguity was resolved
Resolved question: Q-TPL-003
Status: resolved
Resolved by: human
Chosen option: JWT
Notes: JWT provides stateless auth, better for microservices
After resolution, the question YAML includes:
status: resolved
resolution:
resolved_by: human
resolved_at: "2025-01-15T11:00:00Z"
chosen_option: JWT
notes: "JWT provides stateless auth, better for microservices"Already resolved:
- Warning is shown but status can be updated again
- Useful for correcting or updating resolution
Invalid chosen_option:
- Warning if option doesn't match defined options
- Still allowed (options may not always be defined)
Invalid status:
- Must be
answered,resolved, orobsolete - Use
openstatus only via direct YAML edit
- Timestamp: Uses UTC timestamp in RFC 3339 format
- Overwrites: Previous resolution is replaced, not appended
- Surfaced via API: Resolution appears in
/platform/questionsendpoint
Check contract crates for API breaking changes.
cargo run -p xtask -- check-api-diff
# With ADR approval (optional)
cargo run -p xtask -- check-api-diff --adr docs/adr/0030-microcrate-architecture.md| Flag | Description |
|---|---|
--adr <PATH> |
Path to ADR approving the change (optional) |
Checks contract crates for breaking API changes by comparing against baseline:
-
Contract Crates Checked:
platform-contract- HTTP API typesxtask-contract- CLI output typesreceipts-core- Receipt schemasspec-types- Spec file types
-
Layering Validation:
- Verifies contract crates don't depend on forbidden packages (axum, tokio, clap, sqlx, tonic, jsonschema)
- Ensures dependencies point inward to foundation crates only
-
API Diff Detection:
- Uses
cargo-public-apiif available - Falls back to basic
cargo checkif tool not available - Detects breaking changes (removed functions, type changes)
- Uses
0: No breaking changes detected1: Breaking changes detected (requires ADR)
- Before merging PR - Ensure no breaking changes to contract crates
- After modifying contract APIs - Verify stability before committing
- In CI - Part of contract stability gate
No breaking changes:
🔍 Checking platform-contract...
✓ No breaking changes
🔍 Checking xtask-contract...
✓ No breaking changes
🔍 Checking receipts-core...
✓ No breaking changes
🔍 Checking spec-types...
✓ No breaking changes
Summary:
Checked crates: 4
Contract crates: platform-contract, xtask-contract, receipts-core, spec-types
✓ All contract crates are stable
Breaking changes detected:
🔍 Checking platform-contract...
Breaking changes detected:
Removed: platform_contract::Status::version
Type change: platform_contract::Status::health (String -> Health)
To approve this change:
1. Create an ADR documenting the breaking change
2. Update specs/contracts_manifest.yaml with new contract version
3. Update dependent crates and consumers
4. Run: cargo xtask release-prepare
❌ Breaking changes detected
- Contract Stability: Contract crates define the stable API surface of the platform
- Layering Enforcement: Contract crates cannot depend on adapters or HTTP frameworks
- ADR Requirement: Breaking changes must be documented in an ADR
- Tool Dependency: Uses
cargo-public-apiwhen available for precise diff detection
Check OpenAPI contract for breaking changes.
cargo run -p xtask -- check-openapi-diffValidates the /platform/* HTTP contract by checking OpenAPI spec:
-
Extracts Platform Endpoints:
- Parses
specs/openapi/openapi.yamlfor/platform/*paths - Validates expected endpoints are present
- Parses
-
Checks for Removed Endpoints:
- Compares against baseline list of expected platform endpoints
- Reports any missing endpoints as potential breaking changes
-
Validates Contract Version:
- Checks
specs/contracts_manifest.yamlfor HTTP contract version - Warns if contract version not tracked
- Checks
0: No breaking changes detected1: Breaking changes detected (requires ADR)
- After modifying platform endpoints - Ensure OpenAPI spec is updated
- Before releasing - Verify contract stability
- In CI - Part of contract stability gate
All endpoints present:
🔍 Checking OpenAPI contract for breaking changes...
Current platform endpoints:
- /platform/status
- /platform/graph
- /platform/tasks
- /platform/openapi
- /platform/issues
Summary:
Total endpoints: 13
Missing endpoints: 0
✓ OpenAPI contract is stable
Missing endpoints detected:
🔍 Checking OpenAPI contract for breaking changes...
Current platform endpoints:
- /platform/status
- /platform/graph
- /platform/tasks
Missing expected endpoints:
- /platform/openapi
- /platform/issues
❌ OpenAPI contract issues detected
Please ensure all expected platform endpoints are defined in OpenAPI spec.
- Platform Contract: The
/platform/*endpoints are part of the stable platform contract - Expected Endpoints: 13 core platform endpoints must always be present
- Contract Tracking: HTTP contract versions should be tracked in
specs/contracts_manifest.yaml
Check CLI JSON output schemas for breaking changes.
# Check against golden snapshots
cargo run -p xtask -- check-json-schemas
# Generate golden snapshots (for initial setup or after approved changes)
cargo run -p xtask -- check-json-schemas --generate| Flag | Description |
|---|---|
--generate |
Generate golden snapshots instead of checking |
Validates JSON output schemas for xtask commands:
-
Commands Checked:
ac-status --json- AC coverage reportfriction-list --json- Friction log entriesquestions-list --json- Questions listfork-list --json- Fork registryissues-search --json- Unified issues searchversion --json- Version information
-
Golden Snapshot Comparison:
- Compares current output against
specs/schemas/*.golden.json - Detects breaking changes (removed fields, type changes)
- Reports additions (non-breaking but notable)
- Compares current output against
-
Schema Validation:
- Validates JSON structure is valid
- Ensures golden snapshots exist for all commands
0: No breaking changes detected1: Breaking changes detected (requires ADR)
- After modifying JSON output - Ensure schema remains stable
- Before releasing - Verify contract stability
- Initial setup - Use
--generateto create golden snapshots
No breaking changes:
🔍 Checking ac-status...
✓ No breaking changes
🔍 Checking friction-list...
✓ No breaking changes
🔍 Checking questions-list...
✓ No breaking changes
🔍 Checking fork-list...
✓ No breaking changes
🔍 Checking issues-search...
✓ No breaking changes
🔍 Checking version...
✓ No breaking changes
Summary:
Checked commands: 6
Commands: ac-status, friction-list, questions-list, fork-list, issues-search, version
✓ All JSON schemas are stable
Breaking changes detected:
🔍 Checking ac-status...
Breaking changes detected:
Command: ac-status
- Removed field: schema_version
- Type change for field: coverage_percent (number -> string)
To approve this change:
1. Create an ADR documenting the breaking change
2. Update golden snapshot: specs/schemas/ac-status.golden.json
3. Update consumer documentation
4. Run: cargo xtask release-prepare
❌ Breaking changes detected
Generating golden snapshots:
📝 Generating golden snapshot for ac-status...
✓ Golden snapshot written to specs/schemas/ac-status.golden.json
📝 Generating golden snapshot for friction-list...
✓ Golden snapshot written to specs/schemas/friction-list.golden.json
...
- Golden Snapshots: Stored in
specs/schemas/directory - Contract Stability: JSON schemas are part of the stable CLI contract
- Initial Setup: Run with
--generateto create initial golden snapshots - Schema Format: All schemas must be valid JSON
Enforce dependency layering rules across the workspace.
cargo run -p xtask -- check-layeringValidates dependency layering to maintain architectural boundaries:
-
Contract Crate Layering:
- Checks contract crates don't depend on forbidden packages
- Forbidden: axum, tokio, clap, sqlx, tonic, jsonschema
- Ensures dependencies point to foundation crates only
-
Foundation Crate Constraints:
- Checks foundation crates have minimal dependencies (max 10)
- Foundation crates: http-errors, http-platform, http-core, telemetry
-
Circular Dependency Detection:
- Builds dependency graph from
cargo metadata - Detects cycles using DFS algorithm
- Reports any circular dependencies found
- Builds dependency graph from
0: All layering rules satisfied1: Layering violation detected
- After adding new crates - Verify layering compliance
- Before merging PR - Ensure architectural boundaries are maintained
- In CI - Part of architectural integrity gate
All rules satisfied:
🔍 Checking crate layering...
Checking contract crates:
✓ platform-contract - OK (4 dependencies)
✓ xtask-contract - OK (3 dependencies)
✓ receipts-core - OK (2 dependencies)
✓ spec-types - OK (2 dependencies)
Checking foundation crates:
✓ http-errors - OK (2 dependencies)
✓ http-platform - OK (3 dependencies)
✓ http-core - OK (4 dependencies)
✓ telemetry - OK (6 dependencies)
Checking for circular dependencies...
✓ No circular dependencies
Summary:
Checked crates: 8
Contract crates: platform-contract, xtask-contract, receipts-core, spec-types
Foundation crates: http-errors, http-platform, http-core, telemetry
Circular dependencies: 0
✓ All layering rules satisfied
Layering violations detected:
🔍 Checking crate layering...
Checking contract crates:
✓ platform-contract - OK (4 dependencies)
❌ xtask-contract has forbidden dependencies:
- tokio
- clap
✓ receipts-core - OK (2 dependencies)
✓ spec-types - OK (2 dependencies)
❌ Layering violations detected
Contract crates must not depend on: axum, tokio, clap, sqlx, tonic, jsonschema
Please fix layering issues before proceeding.
Circular dependencies detected:
🔍 Checking crate layering...
Checking for circular dependencies...
Circular dependencies detected:
Cycle: xtask-contract -> http-platform -> http-core -> xtask-contract
❌ Layering violations detected
Circular dependencies prevent clean builds and should be avoided.
Please fix layering issues before proceeding.
- Layering Rules: Enforce dependency inversion (higher layers depend on lower layers)
- Contract Isolation: Contract crates must not depend on adapters or HTTP frameworks
- Foundation Lightness: Foundation crates should stay lightweight (max 10 dependencies)
- Circular Dependencies: Prevent clean builds and indicate architectural issues
| Command | Speed | Coverage | Use Case |
|---|---|---|---|
check |
Fast | Code quality | Every commit |
bdd |
Medium | Acceptance | After AC work |
ac-status |
Fast | AC coverage | After BDD tests |
ac-history |
Fast | Time-series analysis | Review coverage trends |
ac-slo |
Fast | SLO gate | Release pipelines |
policy-test |
Fast | Governance | Validate policies |
bundle |
Fast | Context gen | Before LLM use |
quickstart |
Medium | Basic validation | First run |
selftest |
Slow | Comprehensive | CI, releases |
idp-check |
Medium | IDP surface | After API changes |
contracts-check |
Fast | Doc governance | Before PR merge |
contracts-fmt |
Fast | Doc sync | After selftest changes |
ui-contract-check |
Medium | UI contract + DOM | After UI changes |
issues-search |
Fast | Cross-artifact search | Find related issues |
friction-gh-create |
Fast | GitHub integration | Escalate friction to GitHub |
friction-gh-link |
Fast | GitHub integration | Link existing issues |
friction-resolve |
Fast | Lifecycle mgmt | Close friction entries |
question-new |
Fast | Artifact creation | Capture ambiguity |
question-resolve |
Fast | Lifecycle mgmt | Close questions |
Controls tracing output for all commands:
# Default (INFO level)
cargo run -p xtask -- check
# Verbose (DEBUG level)
RUST_LOG=debug cargo run -p xtask -- check
# Specific crate
RUST_LOG=xtask=trace cargo run -p xtask -- checkControls color output:
# Force colors (in CI)
CARGO_TERM_COLOR=always cargo run -p xtask -- check
# Disable colors
CARGO_TERM_COLOR=never cargo run -p xtask -- checkEnables low-resource mode for selftest (reduces output, optimizes for CI):
# Standard mode (verbose output)
cargo run -p xtask -- selftest
# Low-resource mode (condensed output)
XTASK_LOW_RESOURCES=1 cargo run -p xtask -- selftestWhen to use:
- CI environments - Reduces log output, easier to parse results
- Constrained environments - Lower memory/CPU usage
- Automated workflows - Cleaner output for scripting
- Quick local checks - Faster feedback without verbose BDD output
What it does:
- Suppresses detailed BDD scenario output
- Condenses step-by-step progress messages
- Maintains same validation rigor (all 7 steps run)
- Same exit codes (0 = pass, non-zero = fail)
# Sequential (stops on first failure)
cargo run -p xtask -- check && cargo run -p xtask -- bdd
# Always run both (for CI)
cargo run -p xtask -- check; cargo run -p xtask -- bdd# Install cargo-watch
cargo install cargo-watch
# Re-run on file changes
cargo watch -x 'run -p xtask -- check'jobs:
check:
runs-on: ubuntu-latest
steps:
- run: cargo run -p xtask -- check
bdd:
runs-on: ubuntu-latest
steps:
- run: cargo run -p xtask -- bddAdd to ~/.bashrc or ~/.zshrc:
alias xt='cargo run -p xtask --'
# Then use:
xt check
xt bdd
xt bundle implement_acTEMPLATE_API.md- Full API specification with schemasdocs/how-to/- Task-oriented guidesdocs/explanation/architecture.md- Design rationale