⚠ Deprecated: `gz gates` will be removed in a future release. Use `gz closeout` instead.
  ✓ Gate 1 (ADR): PASS
(docs/design/adr/foundation/ADR-0.0.27-exemplar-corpus-doctrine/ADR-0.0.27-exemp
lar-corpus-doctrine.md)
Gate 2 (TDD): uv run gz test
Running unit tests...
Validated: evaluation-justify-binding

✓ No evaluation-justify-binding violations.
Validated: evaluation-justify-binding

❌ 1 violation(s):

   → ADR-0.0.fixture: missing gz-justify artifact for low score
Error: Attestation receipt-binding gate failed (heavy/foundation policy).
  - missing: no receipt file at
arb-step-unittest-dddddddddddddddddddddddddddddddd.json
Recovery: re-run the cited ARB commands and re-cite the resolved receipt IDs.
Error: ADR closeout blocked — unwaived REQ coverage gaps in ADR-9.9.9-fixture:
  OBPI-9.9.9-99-fixture: REQ-9.9.9-99-01
Waive each gap with `gz obpi complete --accept-uncovered <REQ-ID>
--accept-uncovered-reason <REASON>` before closing the ADR.
ADR closeout receipt emitted.
  ADR: ADR-9.9.9-fixture
  Event: closed
ADR closeout receipt emitted.
  ADR: ADR-9.9.9-fixture
  Event: closed
ADR Eval: ADR-0.0.26 -- GO
  Weighted total: 0.75/4.0
  OBPIs scored: 0
ADR Eval: ADR-0.0.26 -- GO
  Weighted total: 0.75/4.0
  OBPIs scored: 0
ADR Eval: ADR-0.0.26 -- GO
  Weighted total: 0.75/4.0
  OBPIs scored: 0
ADR Eval: ADR-0.0.26 -- NO GO
  Weighted total: 0.75/4.0
  OBPIs scored: 0
ADR Eval: ADR-0.0.26 -- GO
  Weighted total: 0.75/4.0
  OBPIs scored: 0

Advisory proposal: dim:clarity:low
  Recurrence: 3
  Summary: Dimension 'clarity' scored in the 'low' band across 3 distinct
artifacts
  Rule target: docs/governance/clarity-low-improvement.md
Advisory: would file GHI for dim:clarity:low
No proofs directory for eval-feedback-cluster
No unfiled proposals for eval-feedback-cluster.

Proposal: dim:clarity:low
  Recurrence: 3
  Summary: Dimension 'clarity' scored in the 'low' band across 3 distinct
artifacts
  Rule target: docs/governance/clarity-low-improvement.md
Filed: https://github.com/owner/repo/issues/101

Proposal: dim:clarity:low
  Recurrence: 5
  Summary: Dimension 'clarity' scored in the 'low' band across 3 artifacts
  Rule target: docs/governance/clarity-low-improvement.md
Filed: https://github.com/owner/repo/issues/100

Proposal: dim:clarity:low
  Recurrence: 3
  Summary: Dimension 'clarity' scored in the 'low' band across 3 distinct
artifacts
  Rule target: docs/governance/clarity-low-improvement.md
Filed: https://github.com/owner/repo/issues/99
Chores registry diff:
  + agents-md-architectural-boundaries
  + arb-pattern-extraction
  + cli-contract-governance
  + complexity-reduction-xenon
  + config-paths-remediation
  + control-surface-rule-conflicts
  + control-surface-rule-vs-check-drift
  + control-surface-skill-rule-reachability
  + coverage-40pct
  + cross-platform-test-cleanup
  + dependency-currency
  + doc-coverage
  + eval-feedback-cluster
  + evidence-integrity-audit
  + exceptions-and-logging-rationalization
  + frontmatter-ledger-coherence
  + hardcoded-root-eradication
  + instructions-files-diet
  + memory-hygiene
  + module-sloc-cap-radon
  + pep257-docstring-compliance
  + pool-triage
  + pythonic-design-pattern-application
  + pythonic-design-pattern-detection
  + pythonic-refactoring
  + quality-check
  + repository-structure-normalization
  + schema-and-config-drift-audit
  + skill-authoring-quality
  + skill-command-doc-parity
  + skill-manifest-sync
  + skill-trigger-testing
  + sync-manpage-docstrings
  + test-isolation-compliance
  + test-manpage-examples
  + validate-manpages
  = only-local (local-only, preserved)
Chores registry diff:
  + agents-md-architectural-boundaries
  + arb-pattern-extraction
  + cli-contract-governance
  + complexity-reduction-xenon
  + config-paths-remediation
  + control-surface-rule-conflicts
  + control-surface-rule-vs-check-drift
  + control-surface-skill-rule-reachability
  + coverage-40pct
  + cross-platform-test-cleanup
  + dependency-currency
  + doc-coverage
  + eval-feedback-cluster
  + evidence-integrity-audit
  + exceptions-and-logging-rationalization
  + frontmatter-ledger-coherence
  + hardcoded-root-eradication
  + instructions-files-diet
  + memory-hygiene
  + module-sloc-cap-radon
  + pep257-docstring-compliance
  + pool-triage
  + pythonic-design-pattern-application
  + pythonic-design-pattern-detection
  + pythonic-refactoring
  + quality-check
  + repository-structure-normalization
  + schema-and-config-drift-audit
  + skill-authoring-quality
  + skill-command-doc-parity
  + skill-manifest-sync
  + skill-trigger-testing
  + sync-manpage-docstrings
  + test-isolation-compliance
  + test-manpage-examples
  + validate-manpages
  = only-local-slug (local-only, preserved)
Chores registry diff:
  + agents-md-architectural-boundaries
  + arb-pattern-extraction
  + cli-contract-governance
  + complexity-reduction-xenon
  + config-paths-remediation
  + control-surface-rule-conflicts
  + control-surface-rule-vs-check-drift
  + control-surface-skill-rule-reachability
  + coverage-40pct
  + cross-platform-test-cleanup
  + dependency-currency
  + doc-coverage
  + eval-feedback-cluster
  + evidence-integrity-audit
  + exceptions-and-logging-rationalization
  + frontmatter-ledger-coherence
  + hardcoded-root-eradication
  + instructions-files-diet
  + memory-hygiene
  + module-sloc-cap-radon
  + pep257-docstring-compliance
  + pool-triage
  + pythonic-design-pattern-application
  + pythonic-design-pattern-detection
  + pythonic-refactoring
  + quality-check
  + repository-structure-normalization
  + schema-and-config-drift-audit
  + skill-authoring-quality
  + skill-command-doc-parity
  + skill-manifest-sync
  + skill-trigger-testing
  + sync-manpage-docstrings
  + test-isolation-compliance
  + test-manpage-examples
  + validate-manpages
  = only-local (local-only, preserved)
ADR audit-check: ADR-0.0.23
PASS All linked OBPIs are completed with evidence.

Coverage: No REQs found for this ADR.
ADR audit-check: ADR-0.1.0
PASS All linked OBPIs are completed with evidence.

Coverage: No REQs found for this ADR.
ADR audit-check: ADR-0.1.0
PASS All linked OBPIs are completed with evidence.

Coverage: No REQs found for this ADR.
ADR audit-check: ADR-0.1.0
PASS All linked OBPIs are completed with evidence.

Coverage: No REQs found for this ADR.
ADR audit-check: ADR-0.1.0
PASS All linked OBPIs are completed with evidence.

Coverage: No REQs found for this ADR.
Backfill 1 covers-backfill warning(s):
  tests/x.py:1 REQ REQ-0.1.0-01-01 introduced @ aaaaaaa (0c / 0d before receipt
r1); see .claude/rules/tests.md § Invariant 6f for remediation
ADR audit-check: ADR-0.1.0
PASS All linked OBPIs are completed with evidence.

Coverage: No REQs found for this ADR.
Unresolvable 1 covers-backfill location(s) not resolvable in git:
  tests/x.py:1 unresolvable
ADR audit-check: ADR-0.1.0
PASS All linked OBPIs are completed with evidence.

Coverage: No REQs found for this ADR.
FAIL 1 covers-backfill finding(s):
  tests/x.py:1 REQ REQ-0.1.0-01-01 introduced @ aaaaaaa (0c / 0d before receipt
r1); see .claude/rules/tests.md § Invariant 6f for remediation

................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
..............................................................s.................
...................Skipping unparseable file:
/var/folders/7y/cvcpqqnj2_52yy4wl780kmqc0000gn/T/tmpzxew0_6f/test_broken.py
...........Malformed REQ line (skipped): - [ ] REQ-X-Y-Z: Malformed
(non-numeric).
Malformed REQ line (skipped): - [ ] REQ-: Empty body.
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
............................................
----------------------------------------------------------------------
Ran 4234 tests in 33.638s

OK (skipped=1)

Unit tests passed.

  ✓ Gate 2 (TDD): PASS
  ↳ Eval delta: skipped (no baselines) — 5 surfaces scored, overall 2.7/4.0
  → Gate 3 (Docs): uv run mkdocs build --strict

[31m │  ⚠  Warning from the Material for MkDocs team[0m
[31m │[0m
[31m │[0m  MkDocs 2.0, the underlying framework of Material for MkDocs,
[31m │[0m  will introduce backward-incompatible changes, including:
[31m │[0m
[31m │  × [0mAll plugins will stop working – the plugin system has been removed
[31m │  × [0mAll theme overrides will break – the theming system has been
rewritten
[31m │  × [0mNo migration path exists – existing projects cannot be upgraded
[31m │  × [0mClosed contribution model – community members can't report bugs
[31m │  × [0mCurrently unlicensed – unsuitable for production use
[31m │[0m
[31m │[0m  Our full analysis:
[31m │[0m
[31m │[0m
[4mhttps://squidfunk.github.io/mkdocs-material/blog/2026/02/18/mkdocs-2.0/[0m
[0m
INFO    -  Cleaning site directory
INFO    -  Building documentation to directory:
/Users/jeff/Documents/Code/gzkit/site
INFO    -  The following pages exist in the docs directory, but are not included
in the "nav" configuration:
  - AGENTS.md
  - drafts/claude-code-inventory.md
  - drafts/claude-code-vs-codex-control-surface-parity.md
  - drafts/sprint-and-drift-harness-governance.md
  - examples/presentations/index.md
  - examples/presentations/complete-series-script.md
  - examples/presentations/part1-script.md
  - examples/presentations/part2-script.md
  - examples/presentations/part3-script.md
  - examples/presentations/part4-script.md
  - examples/presentations/part5-script.md
  - examples/presentations/part6-script.md
  - examples/templates/req-template.md
  - governance/AGENTS.md
  - governance/advisory-rules-audit.md
  - governance/agent-contract-rationale.md
  - governance/agent-control-surface-fidelity-doctrine.md
  - governance/agent-control-surface-rendering-substrate.md
  - governance/ai-governance-brief.md
  - governance/ai-governance-research-gaps.md
  - governance/ai-governance-research-literature.md
  - governance/ai-governance-research-practice.md
  - governance/ai-governance-research-regulation.md
  - governance/ai-governance-verification.md
  - governance/ai-governance.md
  - governance/ai-governance.provenance.md
  - governance/arb-middleware.md
  - governance/defect-fix-routing.md
  - governance/harness-engineering-appraisal.md
  - governance/layer-three-derived-views.md
  - governance/model-regression-taxonomy.md
  - governance/operator-economy.md
  - governance/tests-rationale.md
  - governance/trust-doctrine.md
  - governance/GovZero/obpi-pipeline-runbook.md
  - governance/complexity/AGENTS.md
  - governance/complexity/distilled-characteristics-2026-05-04.md
  - governance/complexity/baselines/2026-05-04/baseline.summary.md
  - governance/research_sources/0900001680afb122.md
  -
governance/research_sources/1-introduction-the-imperative-of-public-values-in-ai
.md
  - governance/research_sources/1680afaeba.md
  -
governance/research_sources/a-closer-look-at-the-existing-risks-of-generative-ai
-mapping-the-who-what-and-how-of-real-world-inci.md
  - governance/research_sources/advancing-accountability-in-ai-en.md
  -
governance/research_sources/ai-risk-management-framework-japanese-translation.md
  -
governance/research_sources/anthropics-responsible-scaling-policy-version-30.md
  -
governance/research_sources/artificial-intelligence-risk-management-framework-ai
-rmf-10.md
  -
governance/research_sources/artificial-intelligence-risk-management-framework-ge
nerative-artificial-intelligence-profile.md
  - governance/research_sources/arxiv-240614713.md
  - governance/research_sources/arxiv-240714981.md
  -
governance/research_sources/auditing-work-exploring-the-new-york-city-algorithmi
c-bias-audit-regime.md
  - governance/research_sources/claude-4-system-card.md
  - governance/research_sources/hai-ai-index-report-2025-chapter3-final.md
  - governance/research_sources/hls20white20paper20final-v3.md
  -
governance/research_sources/introducing-the-oecd-ai-capability-indicators-en.md
  -
governance/research_sources/m-24-10-advancing-governance-innovation-and-risk-man
agement-for-agency-use-of-artificial-intelligenc.md
  -
governance/research_sources/m-25-21-accelerating-federal-use-of-ai-through-innov
ation-governance-and-public-trust.md
  -
governance/research_sources/m-25-22-driving-efficient-acquisition-of-artificial-
intelligence-in-government.md
  -
governance/research_sources/microsoft-word-ai-governance-tiimalasipaperi-arxivdo
cx.md
  - governance/research_sources/nistai600-1genai-profileipd.md
  - governance/research_sources/operator-system-card.md
  - governance/research_sources/preparedness-framework-v2.md
  - governance/research_sources/quantifying-detection-rates.md
  -
governance/research_sources/responsible-ai-governance-a-systematic-literature-re
view.md
  -
governance/research_sources/responsible-ai-governance-in-the-public-sector-expla
ining-contextual-dynamics-through-a-realist-synt.md
  - governance/research_sources/responsible-use-guide.md
  - governance/research_sources/steering-ais-future-en.md
  -
governance/research_sources/the-bureaucratic-challenge-to-ai-governance-an-empir
ical-assessment-of-implementation-at-us-federal.md
  -
governance/research_sources/the-governance-of-ai-companies-reconciling-purpose-w
ith-profits.md
  - harness-docs/GZK-GOV-007-ultrareview-and-gate-5.md
  - harness-docs/expanding-the-bitter-lesson-for-agentic-software-development.md
  - harness-docs/xhigh-measurement-protocol.md
  - releases/PATCH-v0.24.3.md
  - releases/PATCH-v0.25.10.md
  - releases/PATCH-v0.25.11.md
  - releases/PATCH-v0.25.12.md
  - releases/PATCH-v0.25.13.md
  - releases/PATCH-v0.25.14.md
  - releases/PATCH-v0.25.15.md
  - releases/PATCH-v0.25.16.md
  - releases/PATCH-v0.25.17.md
  - releases/PATCH-v0.25.18.md
  - releases/PATCH-v0.25.19.md
  - releases/PATCH-v0.25.7.md
  - releases/PATCH-v0.25.8.md
  - releases/PATCH-v0.25.9.md
  - releases/PATCH-v0.26.0.md
  - superpowers/plans/2026-03-26-pipeline-reliability-improvements.md
  - superpowers/specs/2026-03-26-pipeline-reliability-improvements-design.md
  - user/commands/adr-evaluate.md
  - user/commands/adr-report.md
  - user/commands/arb-advise.md
  - user/commands/arb-coverage.md
  - user/commands/arb-patterns.md
  - user/commands/arb-ruff.md
  - user/commands/arb-step.md
  - user/commands/arb-ty.md
  - user/commands/arb-typecheck.md
  - user/commands/arb-validate.md
  - user/commands/arb.md
  - user/commands/check.md
  - user/commands/chores-advise.md
  - user/commands/chores-doctor.md
  - user/commands/chores-propose-ghi.md
  - user/commands/chores-show.md
  - user/commands/drift.md
  - user/commands/format.md
  - user/commands/frontmatter-reconcile.md
  - user/commands/interview.md
  - user/commands/issue-file.md
  - user/commands/justify.md
  - user/commands/lint.md
  - user/commands/obpi-audit.md
  - user/commands/obpi-complete.md
  - user/commands/obpi-lock-check.md
  - user/commands/obpi-lock-claim.md
  - user/commands/obpi-lock-list.md
  - user/commands/obpi-lock-release.md
  - user/commands/obpi-lock-status.md
  - user/commands/obpi-withdraw.md
  - user/commands/personas-drift.md
  - user/commands/plan.md
  - user/commands/preflight.md
  - user/commands/readiness-evaluate.md
  - user/commands/roles.md
  - user/commands/skill-list.md
  - user/commands/skill-new.md
  - user/commands/test.md
  - user/commands/tidy.md
  - user/commands/typecheck.md
  - user/commands/validate.md
  - user/concepts/reporter-architecture.md
  - user/concepts/subagent-pipeline.md
  - user/concepts/task-overview.md
  - user/manpages/arb.md
  - user/manpages/closeout.md
  - user/manpages/gz-adr-audit-check.md
  - user/manpages/gz-chores.md
  - user/manpages/gz-issue.md
  - user/manpages/gz-justify.md
  - user/manpages/gz-personas.md
  - user/manpages/patch-release.md
  - user/skills/_TEMPLATE.md
  - user/skills/airlineops-parity-scan.md
  - user/skills/ghi-author.md
  - user/skills/ghi-close.md
  - user/skills/ghi-triage.md
  - user/skills/gz-adr-autolink.md
  - user/skills/gz-adr-promote.md
  - user/skills/gz-adr-recon.md
  - user/skills/gz-adr-sync.md
  - user/skills/gz-agent-sync.md
  - user/skills/gz-check-config-paths.md
  - user/skills/gz-complexity-distill.md
  - user/skills/gz-context-diet.md
  - user/skills/gz-deps-upgrade.md
  - user/skills/gz-issue-file.md
  - user/skills/gz-justify.md
  - user/skills/gz-migrate-semver.md
  - user/skills/gz-pythonic-pattern-apply.md
  - user/skills/gz-pythonic-pattern-detect.md
  - user/skills/gz-skill-router.md
  - user/skills/gz-tech-debt-review.md
  - user/skills/gz-tidy.md
INFO    -  Doc file 'user/runbook.md' contains a link
'commands/validate.md#--complexity-doctrine-links', but the doc
'user/commands/validate.md' does not contain an anchor
'#--complexity-doctrine-links'.
INFO    -  Documentation built in 2.38 seconds

  ✓ Docs build: PASS
  ✓ Skill Audit: PASS (skills=67 blocking=0 warnings=0)
  ✓ Gate 3 (Docs): PASS
  → Gate 4 (BDD): uv run -m behave features/
USING RUNNER: behave.runner:Runner
Feature: gz adr audit-check same-commit-window @covers backfill heuristic
(ADR-0.0.23 / OBPI-0.0.23-05) # features/adr_audit_covers_backfill.feature:1
  As an auditor of a gzkit-governed project,
  I want gz adr audit-check to flag @covers(REQ-...) decorators introduced
  in the same commit as the REQ's closing receipt,
  so that the cosmetic-backfill anti-pattern from GHI #309 cannot silence
  the audit even when an agent drives the entire codebase end-to-end.
  Feature: gz adr audit-check same-commit-window @covers backfill heuristic
(ADR-0.0.23 / OBPI-0.0.23-05)  # features/adr_audit_covers_backfill.feature:1

  @REQ-0.0.23-05-09
  Scenario: Heavy-lane same-commit backfill exits 3 with the remediation hint
# features/adr_audit_covers_backfill.feature:13
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And the audit-thresholds file is present at "data/audit_thresholds.json"
# features/steps/adr_audit_covers_backfill_steps.py:36
    Given a heavy ADR with a same-commit @covers backfill exists for
OBPI-0.1.0-01-demo # features/steps/adr_audit_covers_backfill_steps.py:50
    When I run the gz command "adr audit-check ADR-0.1.0-f"
# features/steps/gz_steps.py:209
    Then the command exits with code 3
# features/steps/gz_steps.py:220
    And the output contains "covers-backfill finding"
# features/steps/gz_steps.py:225
    And the output contains "Invariant 6f"
# features/steps/gz_steps.py:225

Feature: gz adr promote --kind taxonomy enforcement (ADR-0.0.17 /
OBPI-0.0.17-03) # features/adr_promote.feature:1
  As an operator promoting a pool ADR,
  I want --kind to declare and enforce taxonomic intent at promotion time,
  so that pool->canonical promotion is explicit, atomic, and audit-recorded.
  Feature: gz adr promote --kind taxonomy enforcement (ADR-0.0.17 /
OBPI-0.0.17-03)  # features/adr_promote.feature:1

  @REQ-0.0.17-03-01
  Scenario: --kind appears in --help with three choices            #
features/adr_promote.feature:11
    Given the workspace is initialized                             #
features/steps/gz_steps.py:67
    And a pool ADR "ADR-pool.sample-work" with target scope exists #
features/steps/gz_steps.py:271
    When I run the gz command "adr promote --help"                 #
features/steps/gz_steps.py:209
    Then the command exits with code 0                             #
features/steps/gz_steps.py:220
    And the output contains "--kind"                               #
features/steps/gz_steps.py:225
    And the output contains "foundation"                           #
features/steps/gz_steps.py:225
    And the output contains "feature"                              #
features/steps/gz_steps.py:225
    And the output contains "pool"                                 #
features/steps/gz_steps.py:225

  @REQ-0.0.17-03-01
  Scenario: --kind pool is rejected with exit 1
# features/adr_promote.feature:20
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And a pool ADR "ADR-pool.sample-work" with target scope exists
# features/steps/gz_steps.py:271
    When I run the gz command "adr promote ADR-pool.sample-work --semver 0.6.0
--kind pool" # features/steps/gz_steps.py:209
    Then the command exits with code 1
# features/steps/gz_steps.py:220
    And the output contains "source"
# features/steps/gz_steps.py:225

  @REQ-0.0.17-03-02
  Scenario: --kind foundation rejects non-0.0.x semver
# features/adr_promote.feature:26
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And a pool ADR "ADR-pool.sample-work" with target scope exists
# features/steps/gz_steps.py:271
    When I run the gz command "adr promote ADR-pool.sample-work --semver 0.6.0
--kind foundation"      # features/steps/gz_steps.py:209
    Then the command exits with code 1
# features/steps/gz_steps.py:220
    And the output contains "0.0."
# features/steps/gz_steps.py:225
    And the file
"design/adr/foundation/ADR-0.6.0-sample-work/ADR-0.6.0-sample-work.md" does not
exist # features/steps/gz_steps.py:250

  @REQ-0.0.17-03-03
  Scenario: --kind feature rejects 0.0.x semver
# features/adr_promote.feature:33
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And a pool ADR "ADR-pool.sample-work" with target scope exists
# features/steps/gz_steps.py:271
    When I run the gz command "adr promote ADR-pool.sample-work --semver 0.0.18
--kind feature"           # features/steps/gz_steps.py:209
    Then the command exits with code 1
# features/steps/gz_steps.py:220
    And the file
"design/adr/pre-release/ADR-0.0.18-sample-work/ADR-0.0.18-sample-work.md" does
not exist # features/steps/gz_steps.py:250

  @REQ-0.0.17-03-04
  Scenario: validation failure leaves no governance artifact behind
# features/adr_promote.feature:39
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And a pool ADR "ADR-pool.sample-work" with target scope exists
# features/steps/gz_steps.py:271
    When I run the gz command "adr promote ADR-pool.sample-work --semver 0.6.0
--kind foundation"       # features/steps/gz_steps.py:209
    Then the command exits with code 1
# features/steps/gz_steps.py:220
    And the file
"design/adr/foundation/ADR-0.6.0-sample-work/ADR-0.6.0-sample-work.md" does not
exist  # features/steps/gz_steps.py:250
    And the file
"design/adr/pre-release/ADR-0.6.0-sample-work/ADR-0.6.0-sample-work.md" does not
exist # features/steps/gz_steps.py:250

  @REQ-0.0.17-03-05
  Scenario: promoted ADR carries kind: in frontmatter
# features/adr_promote.feature:46
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And a pool ADR "ADR-pool.sample-work" with target scope exists
# features/steps/gz_steps.py:271
    When I run the gz command "adr promote ADR-pool.sample-work --semver 0.0.18
--kind foundation --force"                      # features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220
    And the file
"design/adr/foundation/ADR-0.0.18-sample-work/ADR-0.0.18-sample-work.md"
contains "kind: foundation"           # features/steps/gz_steps.py:235
    And the file
"design/adr/foundation/ADR-0.0.18-sample-work/ADR-0.0.18-sample-work.md"
contains "id: ADR-0.0.18-sample-work" # features/steps/gz_steps.py:235

  @REQ-0.0.17-03-06
  Scenario: --kind feature lands the promoted ADR in pre-release/
# features/adr_promote.feature:53
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And a pool ADR "ADR-pool.sample-work" with target scope exists
# features/steps/gz_steps.py:271
    When I run the gz command "adr promote ADR-pool.sample-work --semver 0.6.0
--kind feature --force" # features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220
    And the file
"design/adr/pre-release/ADR-0.6.0-sample-work/ADR-0.6.0-sample-work.md" exists
# features/steps/gz_steps.py:230

  @REQ-0.0.17-03-07
  Scenario: ledger artifact_renamed event records kind and semver
# features/adr_promote.feature:59
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And a pool ADR "ADR-pool.sample-work" with target scope exists
# features/steps/gz_steps.py:271
    When I run the gz command "adr promote ADR-pool.sample-work --semver 0.6.0
--kind feature --force" # features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220
    And ledger event "artifact_renamed" has field "kind" equal to "feature"
# features/steps/gz_steps.py:255
    And ledger event "artifact_renamed" has field "semver" equal to "0.6.0"
# features/steps/gz_steps.py:255
    And ledger event "artifact_renamed" has field "reason" equal to
"pool_promotion"                   # features/steps/gz_steps.py:255
    And ledger event "artifact_renamed" has field "new_id" equal to
"ADR-0.6.0-sample-work"            # features/steps/gz_steps.py:255

Feature: ARB self-reporting middleware # features/arb.feature:2
  As an agent producing verification evidence for Heavy-lane attestations
  I want a CLI surface that wraps QA commands and emits validated receipts
  So that attestation-enrichment claims can cite deterministic artifacts.
  @REQ-0.25.0-33-05
  Scenario: arb surface exposes every rule-declared verb  #
features/arb.feature:8
    When I run the gz command "arb --help"                #
features/steps/gz_steps.py:209
    Then the command exits with code 0                    #
features/steps/gz_steps.py:220
    And the output contains "ruff"                        #
features/steps/gz_steps.py:225
    And the output contains "step"                        #
features/steps/gz_steps.py:225
    And the output contains "ty"                          #
features/steps/gz_steps.py:225
    And the output contains "coverage"                    #
features/steps/gz_steps.py:225
    And the output contains "validate"                    #
features/steps/gz_steps.py:225
    And the output contains "advise"                      #
features/steps/gz_steps.py:225
    And the output contains "patterns"                    #
features/steps/gz_steps.py:225

  Scenario: arb validate returns zero-state cleanly on empty receipts dir  #
features/arb.feature:19
    When I run the gz command "arb validate --limit 5"                     #
features/steps/gz_steps.py:209
    Then the command exits with code 0                                     #
features/steps/gz_steps.py:220
    And the output contains "ARB Receipt Validation"                       #
features/steps/gz_steps.py:225
    And the output contains "Receipts scanned"                             #
features/steps/gz_steps.py:225

  Scenario: arb advise returns zero-state cleanly on empty receipts dir  #
features/arb.feature:25
    When I run the gz command "arb advise --limit 5"                     #
features/steps/gz_steps.py:209
    Then the command exits with code 0                                   #
features/steps/gz_steps.py:220
    And the output contains "ARB Advice"                                 #
features/steps/gz_steps.py:225
    And the output contains "Recommendations"                            #
features/steps/gz_steps.py:225
    And the output contains "No findings in recent receipts"             #
features/steps/gz_steps.py:225

  Scenario: arb patterns returns zero-state cleanly on empty receipts dir  #
features/arb.feature:32
    When I run the gz command "arb patterns --limit 5"                     #
features/steps/gz_steps.py:209
    Then the command exits with code 0                                     #
features/steps/gz_steps.py:220
    And the output contains "ARB Pattern Extraction Report"                #
features/steps/gz_steps.py:225

  Scenario: arb patterns compact mode emits single-line summary  #
features/arb.feature:37
    When I run the gz command "arb patterns --compact --limit 5" #
features/steps/gz_steps.py:209
    Then the command exits with code 0                           #
features/steps/gz_steps.py:220
    And the output contains "arb patterns:"                      #
features/steps/gz_steps.py:225

  Scenario: arb validate JSON output is machine-readable      #
features/arb.feature:42
    When I run the gz command "arb validate --json --limit 5" #
features/steps/gz_steps.py:209
    Then the command exits with code 0                        #
features/steps/gz_steps.py:220
    And the output contains "scanned"                         #
features/steps/gz_steps.py:225
    And the output contains "valid"                           #
features/steps/gz_steps.py:225
    And the output contains "unknown_schema"                  #
features/steps/gz_steps.py:225

Feature: Attestation receipt-binding gate (ADR-0.0.24) #
features/attestation_receipt_binding.feature:15
  As a governance maintainer relying on ARB receipts as proof of attestation
  I want gz validate --attestation-receipts and the gz obpi complete /
  gz adr emit-receipt gates to mechanically verify cited ARB receipts
  So that fabricated receipt IDs cannot pass for real evidence on heavy or
  foundation work, and lite-non-foundation work warns transparently.
  @REQ-0.0.24-01-01
  Scenario: Valid receipt resolves on heavy lane
# features/attestation_receipt_binding.feature:27
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And an arb step receipt
"arb-step-typecheck-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" with exit_status 0 exists
# features/steps/attestation_receipt_binding_steps.py:269
    When I run "gz validate --attestation-receipts 'typecheck clean (typecheck:
receipt arb-step-typecheck-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)' --lane heavy
--kind feature" # features/steps/obpi_lock_steps.py:61
    Then it exits with code 0
# features/steps/obpi_lock_steps.py:71
    And the output contains "resolved"
# features/steps/gz_steps.py:225

  @REQ-0.0.24-01-02
  Scenario: Missing receipt fails closed on heavy lane
# features/attestation_receipt_binding.feature:35
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And no arb receipts exist in the receipts root
# features/steps/attestation_receipt_binding_steps.py:281
    When I run "gz validate --attestation-receipts 'lint clean (lint: receipt
arb-ruff-deadbeef00000000000000000000beef)' --lane heavy --kind feature" #
features/steps/obpi_lock_steps.py:61
    Then it exits with code 3
# features/steps/obpi_lock_steps.py:71
    And the output contains "no receipt file at"
# features/steps/gz_steps.py:225

  @REQ-0.0.24-01-03
  Scenario: Status mismatch fails closed
# features/attestation_receipt_binding.feature:43
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And an arb step receipt "arb-step-unittest-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
with exit_status 1 exists
# features/steps/attestation_receipt_binding_steps.py:269
    When I run "gz validate --attestation-receipts 'unittest fixtures (unittest:
receipt arb-step-unittest-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb)' --lane heavy --kind
feature" # features/steps/obpi_lock_steps.py:61
    Then it exits with code 3
# features/steps/obpi_lock_steps.py:71
    And the output contains "exit_status=1"
# features/steps/gz_steps.py:225

  @REQ-0.0.24-01-04
  Scenario: Claim category mismatch fails closed
# features/attestation_receipt_binding.feature:51
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And an arb step receipt
"arb-step-typecheck-cccccccccccccccccccccccccccccccc" with exit_status 0 exists
# features/steps/attestation_receipt_binding_steps.py:269
    When I run "gz validate --attestation-receipts 'lint clean (lint: receipt
arb-step-typecheck-cccccccccccccccccccccccccccccccc)' --lane heavy --kind
feature" # features/steps/obpi_lock_steps.py:61
    Then it exits with code 3
# features/steps/obpi_lock_steps.py:71
    And the output contains "cited 'lint' but receipt is 'typecheck'"
# features/steps/gz_steps.py:225

  @REQ-0.0.24-01-05
  Scenario: Malformed receipt id is reported
# features/attestation_receipt_binding.feature:59
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And no arb receipts exist in the receipts root
# features/steps/attestation_receipt_binding_steps.py:281
    When I run "gz validate --attestation-receipts 'lint clean (lint: receipt
arb-ruff-ZZZZ-not-canonical)' --lane heavy --kind feature" #
features/steps/obpi_lock_steps.py:61
    Then the command exits non-zero
# features/steps/gz_steps.py:215
    And the output contains "malformed"
# features/steps/gz_steps.py:225

  @REQ-0.0.24-01-06
  Scenario: Zero receipts on heavy lane fails closed
# features/attestation_receipt_binding.feature:67
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And no arb receipts exist in the receipts root
# features/steps/attestation_receipt_binding_steps.py:281
    When I run "gz validate --attestation-receipts 'narrative-only attestation'
--lane heavy --kind feature" # features/steps/obpi_lock_steps.py:61
    Then it exits with code 3
# features/steps/obpi_lock_steps.py:71

  @REQ-0.0.24-01-06
  Scenario: Zero receipts on lite-non-foundation passes warn-only
# features/attestation_receipt_binding.feature:74
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And no arb receipts exist in the receipts root
# features/steps/attestation_receipt_binding_steps.py:281
    When I run "gz validate --attestation-receipts 'narrative-only attestation'
--lane lite --kind feature" # features/steps/obpi_lock_steps.py:61
    Then it exits with code 0
# features/steps/obpi_lock_steps.py:71

  @REQ-0.0.24-02-01
  Scenario: Heavy lane completion with valid receipt records meta-receipt-bind
# features/attestation_receipt_binding.feature:85
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And a heavy-lane brief "OBPI-0.99.0-01-fixture" under feature ADR
"ADR-0.99.0-fixture" exists on disk
# features/steps/attestation_receipt_binding_steps.py:289
    And an arb step receipt "arb-step-unittest-dddddddddddddddddddddddddddddddd"
with exit_status 0 exists                                            #
features/steps/attestation_receipt_binding_steps.py:269
    And a pipeline marker for "OBPI-0.99.0-01-fixture" is active
# features/steps/attestation_receipt_binding_steps.py:309
    When I complete OBPI "OBPI-0.99.0-01-fixture" with attestation citing
"arb-step-unittest-dddddddddddddddddddddddddddddddd" using attestor-present #
features/steps/attestation_receipt_binding_steps.py:337
    Then it exits with code 0
# features/steps/obpi_lock_steps.py:71
    And the ledger contains an event with field "event" equal to
"audit_receipt_emitted" whose extra.receipt_event is "meta-receipt-bind"
# features/steps/attestation_receipt_binding_steps.py:397
    And the ledger contains an event with field "event" equal to
"obpi_receipt_emitted"
# features/steps/attestation_receipt_binding_steps.py:420

  @REQ-0.0.24-02-02 @REQ-0.0.24-04-03
  Scenario: Heavy lane completion with missing receipt fails closed and writes
no completion event                                           #
features/attestation_receipt_binding.feature:97
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And a heavy-lane brief "OBPI-0.99.0-02-fixture" under feature ADR
"ADR-0.99.0-fixture-b" exists on disk                                  #
features/steps/attestation_receipt_binding_steps.py:289
    And no arb receipts exist in the receipts root
# features/steps/attestation_receipt_binding_steps.py:281
    When I complete OBPI "OBPI-0.99.0-02-fixture" with attestation citing
"arb-ruff-deadbeef00000000000000000000beef" using attestor-present #
features/steps/attestation_receipt_binding_steps.py:337
    Then it exits with code 3
# features/steps/obpi_lock_steps.py:71
    And the ledger does not contain an event for "OBPI-0.99.0-02-fixture" with
receipt_event "completed"                                     #
features/steps/attestation_receipt_binding_steps.py:455

  @REQ-0.0.24-02-03
  Scenario: Lite non-foundation completion with missing receipt warns and
proceeds                                                             #
features/attestation_receipt_binding.feature:106
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And a lite-feature brief "OBPI-0.99.0-03-fixture" under feature ADR
"ADR-0.99.0-fixture-c" exists on disk                                  #
features/steps/attestation_receipt_binding_steps.py:294
    And no arb receipts exist in the receipts root
# features/steps/attestation_receipt_binding_steps.py:281
    When I complete OBPI "OBPI-0.99.0-03-fixture" with attestation citing
"arb-ruff-deadbeef11111111111111111111beef" without attestor-present #
features/steps/attestation_receipt_binding_steps.py:356
    Then it exits with code 0
# features/steps/obpi_lock_steps.py:71
    And the ledger contains an event for "OBPI-0.99.0-03-fixture" with
receipt_event "completed"                                               #
features/steps/attestation_receipt_binding_steps.py:432

  @REQ-0.0.24-02-04
  Scenario: Foundation kind lite lane completion with missing receipt fails
closed                                                           #
features/attestation_receipt_binding.feature:115
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And a lite-foundation brief "OBPI-0.0.99-04-fixture" under foundation ADR
"ADR-0.0.99-fixture-d" exists on disk                          #
features/steps/attestation_receipt_binding_steps.py:299
    And no arb receipts exist in the receipts root
# features/steps/attestation_receipt_binding_steps.py:281
    When I complete OBPI "OBPI-0.0.99-04-fixture" with attestation citing
"arb-ruff-deadbeef22222222222222222222beef" using attestor-present #
features/steps/attestation_receipt_binding_steps.py:337
    Then it exits with code 3
# features/steps/obpi_lock_steps.py:71
    And the ledger does not contain an event for "OBPI-0.0.99-04-fixture" with
receipt_event "completed"                                     #
features/steps/attestation_receipt_binding_steps.py:455

  @REQ-0.0.24-02-05
  Scenario: Heavy ADR emit-receipt validated with missing receipt fails closed
# features/attestation_receipt_binding.feature:124
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And a heavy feature ADR "ADR-0.99.0-fixture-e" exists on disk
# features/steps/attestation_receipt_binding_steps.py:304
    And no arb receipts exist in the receipts root
# features/steps/attestation_receipt_binding_steps.py:281
    When I emit ADR receipt for "ADR-0.99.0-fixture-e" event "validated"
attestor "BDD User" attestation citing
"arb-ruff-deadbeef33333333333333333333beef" #
features/steps/attestation_receipt_binding_steps.py:374
    Then the command exits non-zero
# features/steps/gz_steps.py:215

  @REQ-0.0.24-04-01 @REQ-0.0.24-04-02
  Scenario: behave-req-tags validator passes when scenarios cover all REQs  #
features/attestation_receipt_binding.feature:137
    Given the workspace is the live repository                              #
features/steps/attestation_receipt_binding_steps.py:314
    When I run the gz command "validate --behave-req-tags"                  #
features/steps/gz_steps.py:209
    Then the command exits with code 0                                      #
features/steps/gz_steps.py:220

Feature: Advisory drift detection in gz check #
features/check_drift_advisory.feature:1
  The gz check command includes drift detection as an advisory (non-blocking)
  check that runs after all blocking quality checks complete.
  Scenario: Check help shows json flag       #
features/check_drift_advisory.feature:5
    When I run the gz command "check --help" # features/steps/gz_steps.py:209
    Then the command exits with code 0       # features/steps/gz_steps.py:220
    And the output contains "--json"         # features/steps/gz_steps.py:225
    And the output contains "advisory drift" # features/steps/gz_steps.py:225

Feature: Chores distribution end-to-end # features/chores_distribution.feature:1
  Heavy-lane Gate 4 proof for ADR-0.0.21 (chores as gzkit surface).
  Exercises the install -> scaffold -> list -> repair lifecycle against the
  real installed gzkit package (editable install in .venv resolves
  importlib.resources('gzkit.chores') to the canonical source tree).
  @REQ-0.0.21-07-01 @REQ-0.0.21-07-02 @REQ-0.0.21-07-06 @REQ-0.0.21-07-07
  Scenario: Package fallback works without gz init           #
features/chores_distribution.feature:11
    Given a fresh empty project directory                    #
features/steps/chores_distribution_steps.py:62
    When I run "gz chores list" as a subprocess              #
features/steps/chores_distribution_steps.py:98
    Then the subprocess exits with code 0                    #
features/steps/chores_distribution_steps.py:105
    And the subprocess output contains "quality-check"       #
features/steps/chores_distribution_steps.py:113
    And the subprocess output contains "skill-manifest-sync" #
features/steps/chores_distribution_steps.py:113

  @REQ-0.0.21-07-03
  Scenario: gz init populates project chores and --explain reports project
source  # features/chores_distribution.feature:19
    Given a fresh empty project directory
# features/steps/chores_distribution_steps.py:62
    When I run "gz init --no-skeleton" as a subprocess
# features/steps/chores_distribution_steps.py:98
    And I run "gz chores list --explain" as a subprocess
# features/steps/chores_distribution_steps.py:98
    Then the subprocess exits with code 0
# features/steps/chores_distribution_steps.py:105
    And the file ".gzkit/chores/quality-check/CHORE.md" exists
# features/steps/gz_steps.py:230
    And every chore row in the subprocess output reports "project" source
# features/steps/chores_distribution_steps.py:120

  @REQ-0.0.21-07-04
  Scenario: Re-running gz init preserves operator edits to a chore
# features/chores_distribution.feature:28
    Given a fresh empty project directory
# features/steps/chores_distribution_steps.py:62
    And the workspace has been initialized via gz init
# features/steps/chores_distribution_steps.py:71
    And the operator edits ".gzkit/chores/quality-check/CHORE.md" with marker
"OPERATOR-EDIT-MARKER-XYZ" # features/steps/chores_distribution_steps.py:77
    When I run "gz init --no-skeleton" as a subprocess
# features/steps/chores_distribution_steps.py:98
    Then the subprocess exits with code 0
# features/steps/chores_distribution_steps.py:105
    And the file ".gzkit/chores/quality-check/CHORE.md" contains
"OPERATOR-EDIT-MARKER-XYZ"              # features/steps/gz_steps.py:235

  @REQ-0.0.21-07-05
  Scenario: Merge diff fires for canonical-only slug and --yes writes the merge
# features/chores_distribution.feature:37
    Given a fresh empty project directory
# features/steps/chores_distribution_steps.py:62
    And the workspace has been initialized via gz init
# features/steps/chores_distribution_steps.py:71
    And the slug "quality-check" has been removed from
".gzkit/chores/registry.json" # features/steps/chores_distribution_steps.py:85
    When I run "gz init --no-skeleton --yes" as a subprocess
# features/steps/chores_distribution_steps.py:98
    Then the subprocess exits with code 0
# features/steps/chores_distribution_steps.py:105
    And the subprocess output contains "+ quality-check"
# features/steps/chores_distribution_steps.py:113
    And the registry ".gzkit/chores/registry.json" contains slug "quality-check"
# features/steps/chores_distribution_steps.py:135

Feature: Closeout ceremony enforcement # features/closeout_ceremony.feature:1
  The closeout ceremony presents a Defense Brief with closing arguments,
  product proof, and reviewer assessment. It blocks when evidence is missing.
  Scenario: Closeout dry-run shows Defense Brief section     #
features/closeout_ceremony.feature:5
    Given the workspace is initialized in heavy mode         #
features/steps/gz_steps.py:60
    And a heavy ADR exists with an OBPI brief                #
features/steps/closeout_product_proof_steps.py:51
    And the OBPI source file has public docstrings           #
features/steps/closeout_product_proof_steps.py:139
    And the OBPI brief has a closing argument                #
features/steps/closeout_ceremony_steps.py:12
    When I run the gz command "closeout ADR-0.1.0 --dry-run" #
features/steps/gz_steps.py:209
    Then the command exits with code 0                       #
features/steps/gz_steps.py:220
    And the output contains "Defense Brief"                  #
features/steps/gz_steps.py:225
    And the output contains "Closing Arguments"              #
features/steps/gz_steps.py:225

  Scenario: Closeout form includes Defense Brief when rendered  #
features/closeout_ceremony.feature:15
    Given the workspace is initialized in heavy mode            #
features/steps/gz_steps.py:60
    And a heavy ADR exists with an OBPI brief                   #
features/steps/closeout_product_proof_steps.py:51
    And the OBPI source file has public docstrings              #
features/steps/closeout_product_proof_steps.py:139
    And the OBPI brief has a closing argument                   #
features/steps/closeout_ceremony_steps.py:12
    When I run the gz command "closeout ADR-0.1.0 --dry-run"    #
features/steps/gz_steps.py:209
    Then the command exits with code 0                          #
features/steps/gz_steps.py:220
    And the output contains "Product Proof"                     #
features/steps/gz_steps.py:225

  Scenario: Defense Brief shows reviewer assessment when present  #
features/closeout_ceremony.feature:24
    Given the workspace is initialized in heavy mode              #
features/steps/gz_steps.py:60
    And a heavy ADR exists with an OBPI brief                     #
features/steps/closeout_product_proof_steps.py:51
    And the OBPI source file has public docstrings                #
features/steps/closeout_product_proof_steps.py:139
    And the OBPI brief has a closing argument                     #
features/steps/closeout_ceremony_steps.py:12
    And a reviewer assessment exists for the OBPI                 #
features/steps/closeout_ceremony_steps.py:35
    When I run the gz command "closeout ADR-0.1.0 --dry-run"      #
features/steps/gz_steps.py:209
    Then the command exits with code 0                            #
features/steps/gz_steps.py:220
    And the output contains "Reviewer Assessment"                 #
features/steps/gz_steps.py:225
    And the output contains "PASS"                                #
features/steps/gz_steps.py:225

Feature: Closeout product proof gate # features/closeout_product_proof.feature:1
  The closeout command validates that each OBPI has operator-facing
  documentation proof before allowing ADR closeout to proceed.
  Scenario: Closeout blocked when OBPI has no product proof  #
features/closeout_product_proof.feature:5
    Given the workspace is initialized in heavy mode         #
features/steps/gz_steps.py:60
    And a heavy ADR exists with an OBPI brief                #
features/steps/closeout_product_proof_steps.py:51
    When I run the gz command "closeout ADR-0.1.0 --dry-run" #
features/steps/gz_steps.py:209
    Then the command exits non-zero                          #
features/steps/gz_steps.py:215
    And the output contains "MISSING"                        #
features/steps/gz_steps.py:225
    And the output contains "missing product proof"          #
features/steps/gz_steps.py:225

  Scenario: Closeout allowed when OBPI has docstring proof   #
features/closeout_product_proof.feature:13
    Given the workspace is initialized in heavy mode         #
features/steps/gz_steps.py:60
    And a heavy ADR exists with an OBPI brief                #
features/steps/closeout_product_proof_steps.py:51
    And the OBPI source file has public docstrings           #
features/steps/closeout_product_proof_steps.py:139
    When I run the gz command "closeout ADR-0.1.0 --dry-run" #
features/steps/gz_steps.py:209
    Then the command exits with code 0                       #
features/steps/gz_steps.py:220
    And the output contains "docstring"                      #
features/steps/gz_steps.py:225

  Scenario: Closeout product proof shown in JSON mode               #
features/closeout_product_proof.feature:21
    Given the workspace is initialized in heavy mode                #
features/steps/gz_steps.py:60
    And a heavy ADR exists with an OBPI brief                       #
features/steps/closeout_product_proof_steps.py:51
    And the OBPI source file has public docstrings                  #
features/steps/closeout_product_proof_steps.py:139
    When I run the gz command "closeout ADR-0.1.0 --dry-run --json" #
features/steps/gz_steps.py:209
    Then the command exits with code 0                              #
features/steps/gz_steps.py:220
    And the output contains "product_proof"                         #
features/steps/gz_steps.py:225

Feature: gz validate --complexity-doctrine-links link integrity (OBPI-0.0.27-07)
# features/complexity_doctrine_links.feature:1
  As a governance maintainer
  I want gz validate --complexity-doctrine-links to fail-close on broken
citations
  So that operators following an advisor diagnosis at 2am never land on a
  missing or stale distilled-characteristics document.
  Feature: gz validate --complexity-doctrine-links link integrity
(OBPI-0.0.27-07)  # features/complexity_doctrine_links.feature:1

  @REQ-0.0.27-07-01
  Scenario: Well-formed citation resolves clean                      #
features/complexity_doctrine_links.feature:11
    Given the workspace is initialized                               #
features/steps/gz_steps.py:67
    Given a complexity-doctrine fixture with a well-formed citation  #
features/steps/complexity_doctrine_links_steps.py:62
    When I run the gz command "validate --complexity-doctrine-links" #
features/steps/gz_steps.py:209
    Then the command exits with code 0                               #
features/steps/gz_steps.py:220

  @REQ-0.0.27-07-02
  Scenario: Missing distilled-characteristics file fails closed       #
features/complexity_doctrine_links.feature:17
    Given the workspace is initialized                                #
features/steps/gz_steps.py:67
    Given a complexity-doctrine fixture with a missing distilled file #
features/steps/complexity_doctrine_links_steps.py:73
    When I run the gz command "validate --complexity-doctrine-links"  #
features/steps/gz_steps.py:209
    Then the command exits with code 3                                #
features/steps/gz_steps.py:220
    And the output contains "distilled-characteristics-1999-01-01.md" #
features/steps/gz_steps.py:225

  @REQ-0.0.27-07-03
  Scenario: Unresolved section anchor fails closed                   #
features/complexity_doctrine_links.feature:24
    Given the workspace is initialized                               #
features/steps/gz_steps.py:67
    Given a complexity-doctrine fixture with an unresolved anchor    #
features/steps/complexity_doctrine_links_steps.py:84
    When I run the gz command "validate --complexity-doctrine-links" #
features/steps/gz_steps.py:209
    Then the command exits with code 3                               #
features/steps/gz_steps.py:220
    And the output contains "nonexistent-metric"                     #
features/steps/gz_steps.py:225

  @REQ-0.0.27-07-04
  Scenario: Non-portable corpus revision fails closed                       #
features/complexity_doctrine_links.feature:31
    Given the workspace is initialized                                      #
features/steps/gz_steps.py:67
    Given a complexity-doctrine fixture with a non-portable corpus revision #
features/steps/complexity_doctrine_links_steps.py:95
    When I run the gz command "validate --complexity-doctrine-links"        #
features/steps/gz_steps.py:209
    Then the command exits with code 3                                      #
features/steps/gz_steps.py:220
    And the output contains "doctrine-amendment-protocol"                   #
features/steps/gz_steps.py:225

  @REQ-0.0.27-07-05
  Scenario: Speculative-skip marker bypasses a forward-reference citation  #
features/complexity_doctrine_links.feature:38
    Given the workspace is initialized                                     #
features/steps/gz_steps.py:67
    Given a complexity-doctrine fixture with a speculative-skip marker     #
features/steps/complexity_doctrine_links_steps.py:108
    When I run the gz command "validate --complexity-doctrine-links"       #
features/steps/gz_steps.py:209
    Then the command exits with code 0                                     #
features/steps/gz_steps.py:220

  @REQ-0.0.27-07-06
  Scenario: Validator integrates into gz validate --complexity-doctrine-links
direct invocation  # features/complexity_doctrine_links.feature:44
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    When I run the gz command "validate --complexity-doctrine-links"
# features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220
    And the output contains "complexity_doctrine_links"
# features/steps/gz_steps.py:225

  @REQ-0.0.27-07-07
  Scenario: Validate command doc documents the flag with example
# features/complexity_doctrine_links.feature:50
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    When I check that the file "docs/user/commands/validate.md" contains
"--complexity-doctrine-links" #
features/steps/complexity_doctrine_links_steps.py:128
    Then the file is documented
# features/steps/complexity_doctrine_links_steps.py:142

@adr-0.0.26 @heavy @foundation
Feature: Evaluation feedback loop end-to-end (ADR-0.0.26 / OBPI-0.0.26-05) #
features/evaluation_feedback_loop.feature:2
  As an operator running gz governance,
  I want the evaluation-feedback loop to traverse from low-score evaluation
  through justify scaffolding, clustering, GHI proposal, and trailer-validated
  rule edit,
  so that the agent's own structured reasoning artifacts feed back into the
  rule corpus through human-attested governance.
  @adr-0.0.26 @heavy @foundation
  Feature: Evaluation feedback loop end-to-end (ADR-0.0.26 / OBPI-0.0.26-05)  #
features/evaluation_feedback_loop.feature:2

  @REQ-0.0.26-01-01 @REQ-0.0.26-01-04
  Scenario: Successful evaluations append distinct adr-evaluation events
# features/evaluation_feedback_loop.feature:17
    Given the workspace is initialized for the evaluation-feedback loop
# features/steps/evaluation_feedback_loop_steps.py:231
    Given an adr-evaluation event for "ADR-0.99.0-emit-a" with weighted total
4.5 and timestamp "2026-05-03T22:00:00+00:00" #
features/steps/evaluation_feedback_loop_steps.py:253
    And an adr-evaluation event for "ADR-0.99.0-emit-a" with weighted total 4.6
and timestamp "2026-05-03T22:01:00+00:00"   #
features/steps/evaluation_feedback_loop_steps.py:253
    Then the ledger contains 2 "adr-evaluation" events for "ADR-0.99.0-emit-a"
# features/steps/evaluation_feedback_loop_steps.py:336

  @REQ-0.0.26-01-02
  Scenario: A malformed evaluation does not emit an adr-evaluation event     #
features/evaluation_feedback_loop.feature:23
    Given the workspace is initialized for the evaluation-feedback loop      #
features/steps/evaluation_feedback_loop_steps.py:231
    When I attempt to record a malformed adr-evaluation for "ADR-0.99.0-bad" #
features/steps/evaluation_feedback_loop_steps.py:306
    Then the ledger contains 0 "adr-evaluation" events for "ADR-0.99.0-bad"  #
features/steps/evaluation_feedback_loop_steps.py:336

  @REQ-0.0.26-01-03
  Scenario: gz validate --documents accepts the adr-evaluation event shape
# features/evaluation_feedback_loop.feature:28
    Given the workspace is initialized for the evaluation-feedback loop
# features/steps/evaluation_feedback_loop_steps.py:231
    Given an adr-evaluation event for "ADR-0.99.0-shape" with weighted total 4.0
and timestamp "2026-05-03T22:02:00+00:00" #
features/steps/evaluation_feedback_loop_steps.py:253
    When I run the gz command "validate --documents"
# features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220

  @REQ-0.0.26-02-01
  Scenario: Binding gate fails closed on a low dimension score with no justify
artifact              # features/evaluation_feedback_loop.feature:41
    Given the workspace is initialized for the evaluation-feedback loop
# features/steps/evaluation_feedback_loop_steps.py:231
    Given a low-score adr-evaluation event for "ADR-0.99.0-low" with dimension
"clarity" scoring 1.5 # features/steps/evaluation_feedback_loop_steps.py:266
    When I run the gz command "validate --evaluation-justify-binding
ADR-0.99.0-low"                 # features/steps/gz_steps.py:209
    Then the command exits non-zero
# features/steps/gz_steps.py:215
    And the output contains "ADR-0.99.0-low"
# features/steps/gz_steps.py:225

  @REQ-0.0.26-02-02
  Scenario: Binding gate fails closed on three or more red-team challenges
# features/evaluation_feedback_loop.feature:48
    Given the workspace is initialized for the evaluation-feedback loop
# features/steps/evaluation_feedback_loop_steps.py:231
    Given an adr-evaluation event for "ADR-0.99.0-rt" firing red-team challenges
"C1,C2,C3,C4" # features/steps/evaluation_feedback_loop_steps.py:292
    When I run the gz command "validate --evaluation-justify-binding
ADR-0.99.0-rt"            # features/steps/gz_steps.py:209
    Then the command exits non-zero
# features/steps/gz_steps.py:215

  @REQ-0.0.26-02-03
  Scenario: Binding gate exits 0 when a qualifying justify artifact is present
# features/evaluation_feedback_loop.feature:54
    Given the workspace is initialized for the evaluation-feedback loop
# features/steps/evaluation_feedback_loop_steps.py:231
    Given a low-score adr-evaluation event for "ADR-0.99.0-justified" with
dimension "clarity" scoring 1.5 #
features/steps/evaluation_feedback_loop_steps.py:266
    And a complete justify scaffold exists for "ADR-0.99.0-justified"
# features/steps/evaluation_feedback_loop_steps.py:361
    When I run the gz command "validate --evaluation-justify-binding
ADR-0.99.0-justified"                 # features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220

  @REQ-0.0.26-02-04
  Scenario: Binding gate exits 0 when scores are healthy and no challenges fired
# features/evaluation_feedback_loop.feature:61
    Given the workspace is initialized for the evaluation-feedback loop
# features/steps/evaluation_feedback_loop_steps.py:231
    Given an adr-evaluation event for "ADR-0.99.0-healthy" with dimension
"clarity" scoring 4.5 # features/steps/evaluation_feedback_loop_steps.py:279
    When I run the gz command "validate --evaluation-justify-binding
ADR-0.99.0-healthy"        # features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220

  @REQ-0.0.26-02-05
  Scenario: Threshold config drives binding gate behavior
# features/evaluation_feedback_loop.feature:67
    Given the workspace is initialized for the evaluation-feedback loop
# features/steps/evaluation_feedback_loop_steps.py:231
    Given the eval-feedback threshold "low_score_threshold" is set to 1.0
# features/steps/evaluation_feedback_loop_steps.py:372
    And an adr-evaluation event for "ADR-0.99.0-thresh" with dimension "clarity"
scoring 2.0 # features/steps/evaluation_feedback_loop_steps.py:279
    When I run the gz command "validate --evaluation-justify-binding
ADR-0.99.0-thresh"      # features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220

  @REQ-0.0.26-03-01
  Scenario: eval-feedback-cluster appears in gz chores list             #
features/evaluation_feedback_loop.feature:76
    Given the workspace is initialized for the evaluation-feedback loop #
features/steps/evaluation_feedback_loop_steps.py:231
    When I run the gz command "chores list"                             #
features/steps/gz_steps.py:209
    Then the command exits with code 0                                  #
features/steps/gz_steps.py:220
    And the output contains "eval-feedback"                             #
features/steps/gz_steps.py:225

  @REQ-0.0.26-03-02
  Scenario: Clustering chore emits no proposal below the recurrence threshold
# features/evaluation_feedback_loop.feature:82
    Given the workspace is initialized for the evaluation-feedback loop
# features/steps/evaluation_feedback_loop_steps.py:231
    Given a low-score adr-evaluation event for "ADR-0.99.0-cluster-1" with
dimension "clarity" scoring 1.5 #
features/steps/evaluation_feedback_loop_steps.py:266
    And a low-score adr-evaluation event for "ADR-0.99.0-cluster-2" with
dimension "clarity" scoring 1.5   #
features/steps/evaluation_feedback_loop_steps.py:266
    When the eval-feedback-cluster chore runs
# features/steps/evaluation_feedback_loop_steps.py:385
    Then 0 proposal records exist under
".gzkit/chores/eval-feedback-cluster/proofs/"                      #
features/steps/evaluation_feedback_loop_steps.py:391

  @REQ-0.0.26-03-03
  Scenario: Clustering chore emits one proposal at the recurrence threshold
# features/evaluation_feedback_loop.feature:89
    Given the workspace is initialized for the evaluation-feedback loop
# features/steps/evaluation_feedback_loop_steps.py:231
    Given a low-score adr-evaluation event for "ADR-0.99.0-cluster-1" with
dimension "clarity" scoring 1.5 #
features/steps/evaluation_feedback_loop_steps.py:266
    And a low-score adr-evaluation event for "ADR-0.99.0-cluster-2" with
dimension "clarity" scoring 1.5   #
features/steps/evaluation_feedback_loop_steps.py:266
    And a low-score adr-evaluation event for "ADR-0.99.0-cluster-3" with
dimension "clarity" scoring 1.5   #
features/steps/evaluation_feedback_loop_steps.py:266
    When the eval-feedback-cluster chore runs
# features/steps/evaluation_feedback_loop_steps.py:385
    Then 1 proposal record exists under
".gzkit/chores/eval-feedback-cluster/proofs/"                      #
features/steps/evaluation_feedback_loop_steps.py:391

  @REQ-0.0.26-03-04
  Scenario: Clustering chore re-run is idempotent (content-hash dedup)
# features/evaluation_feedback_loop.feature:97
    Given the workspace is initialized for the evaluation-feedback loop
# features/steps/evaluation_feedback_loop_steps.py:231
    Given a low-score adr-evaluation event for "ADR-0.99.0-idem-1" with
dimension "clarity" scoring 1.5 #
features/steps/evaluation_feedback_loop_steps.py:266
    And a low-score adr-evaluation event for "ADR-0.99.0-idem-2" with dimension
"clarity" scoring 1.5   # features/steps/evaluation_feedback_loop_steps.py:266
    And a low-score adr-evaluation event for "ADR-0.99.0-idem-3" with dimension
"clarity" scoring 1.5   # features/steps/evaluation_feedback_loop_steps.py:266
    When the eval-feedback-cluster chore runs
# features/steps/evaluation_feedback_loop_steps.py:385
    And the eval-feedback-cluster chore runs again
# features/steps/evaluation_feedback_loop_steps.py:385
    Then 1 proposal record exists under
".gzkit/chores/eval-feedback-cluster/proofs/"                   #
features/steps/evaluation_feedback_loop_steps.py:391

  @REQ-0.0.26-03-05
  Scenario: gz validate --chores-layout passes for the eval-feedback-cluster
chore  # features/evaluation_feedback_loop.feature:106
    Given the workspace is initialized for the evaluation-feedback loop
# features/steps/evaluation_feedback_loop_steps.py:231
    When I run the gz command "validate --chores-layout"
# features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220

  @REQ-0.0.26-04-01 @REQ-0.0.26-04-12
  Scenario: TTY plus PROPOSE confirmation files a GHI via mocked gh
# features/evaluation_feedback_loop.feature:114
    Given the workspace is initialized for the evaluation-feedback loop
# features/steps/evaluation_feedback_loop_steps.py:231
    Given a proposal record for cluster "dim:clarity:low" exists in the
eval-feedback-cluster proofs      #
features/steps/evaluation_feedback_loop_steps.py:406
    And the environment is interactive
# features/steps/evaluation_feedback_loop_steps.py:430
    And the operator confirms with "PROPOSE"
# features/steps/evaluation_feedback_loop_steps.py:446
    And gh issue create returns "https://github.com/owner/repo/issues/777"
# features/steps/evaluation_feedback_loop_steps.py:452
    When I invoke chores_propose_ghi for "eval-feedback-cluster"
# features/steps/evaluation_feedback_loop_steps.py:461
    Then the most recent proposal record has "filed" equal to true
# features/steps/evaluation_feedback_loop_steps.py:471
    And the most recent proposal record has "ghi_url" equal to
"https://github.com/owner/repo/issues/777" #
features/steps/evaluation_feedback_loop_steps.py:483

  @REQ-0.0.26-04-02
  Scenario: A headless run marks the proposal advisory-only
# features/evaluation_feedback_loop.feature:124
    Given the workspace is initialized for the evaluation-feedback loop
# features/steps/evaluation_feedback_loop_steps.py:231
    Given a proposal record for cluster "dim:clarity:low" exists in the
eval-feedback-cluster proofs #
features/steps/evaluation_feedback_loop_steps.py:406
    And the environment is headless
# features/steps/evaluation_feedback_loop_steps.py:438
    When I invoke chores_propose_ghi for "eval-feedback-cluster"
# features/steps/evaluation_feedback_loop_steps.py:461
    Then the most recent proposal record has "advisory" equal to true
# features/steps/evaluation_feedback_loop_steps.py:471
    And the most recent proposal record has "filed" equal to false
# features/steps/evaluation_feedback_loop_steps.py:477

  @REQ-0.0.26-04-03
  Scenario: A propose-ghi re-run does not refile an already-filed proposal
# features/evaluation_feedback_loop.feature:132
    Given the workspace is initialized for the evaluation-feedback loop
# features/steps/evaluation_feedback_loop_steps.py:231
    Given a filed proposal record for cluster "dim:clarity:low" exists with url
"https://github.com/owner/repo/issues/700" #
features/steps/evaluation_feedback_loop_steps.py:417
    And the environment is interactive
# features/steps/evaluation_feedback_loop_steps.py:430
    And the operator confirms with "PROPOSE"
# features/steps/evaluation_feedback_loop_steps.py:446
    And gh issue create returns "https://github.com/owner/repo/issues/999"
# features/steps/evaluation_feedback_loop_steps.py:452
    When I invoke chores_propose_ghi for "eval-feedback-cluster"
# features/steps/evaluation_feedback_loop_steps.py:461
    Then the most recent proposal record has "ghi_url" equal to
"https://github.com/owner/repo/issues/700"                 #
features/steps/evaluation_feedback_loop_steps.py:483

  @REQ-0.0.26-04-10
  Scenario: ProposalRecord deserializes with default optional fields           #
features/evaluation_feedback_loop.feature:141
    Given the workspace is initialized for the evaluation-feedback loop        #
features/steps/evaluation_feedback_loop_steps.py:231
    Given a minimal proposal record without filed, ghi_url, or advisory fields #
features/steps/evaluation_feedback_loop_steps.py:494
    Then the proposal record deserializes with "filed" equal to false          #
features/steps/evaluation_feedback_loop_steps.py:512
    And the proposal record deserializes with "advisory" equal to false        #
features/steps/evaluation_feedback_loop_steps.py:512
    And the proposal record deserializes with "ghi_url" equal to None          #
features/steps/evaluation_feedback_loop_steps.py:518

  @REQ-0.0.26-04-04 @REQ-0.0.26-05-03
  Scenario: Trailer validator fails closed on a rule-edit commit closing an
eval-feedback GHI without trailer  #
features/evaluation_feedback_loop.feature:156
    Given the workspace is initialized for the evaluation-feedback loop
# features/steps/evaluation_feedback_loop_steps.py:231
    Given a git repo with a rule-edit commit closing GHI 4242 without an
Eval-feedback-source trailer          #
features/steps/evaluation_feedback_loop_steps.py:553
    And gh issue view labels for 4242 include "eval-feedback"
# features/steps/evaluation_feedback_loop_steps.py:587
    When I run the gz command "validate --commit-trailers"
# features/steps/gz_steps.py:209
    Then the command exits non-zero
# features/steps/gz_steps.py:215

  @REQ-0.0.26-04-05
  Scenario: Trailer validator passes when the rule-edit commit carries an
Eval-feedback-source trailer  # features/evaluation_feedback_loop.feature:163
    Given the workspace is initialized for the evaluation-feedback loop
# features/steps/evaluation_feedback_loop_steps.py:231
    Given a git repo with a rule-edit commit closing GHI 4243 with an
Eval-feedback-source trailer      #
features/steps/evaluation_feedback_loop_steps.py:569
    And gh issue view labels for 4243 include "eval-feedback"
# features/steps/evaluation_feedback_loop_steps.py:587
    When I run the gz command "validate --commit-trailers"
# features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220

  @REQ-0.0.26-05-01 @REQ-0.0.26-05-02
  Scenario: Full evaluation-feedback loop traverses every transition end-to-end
# features/evaluation_feedback_loop.feature:173
    Given the workspace is initialized for the evaluation-feedback loop
# features/steps/evaluation_feedback_loop_steps.py:231
    Given a low-score adr-evaluation event for "ADR-0.99.0-loop-a" with
dimension "clarity" scoring 1.5   #
features/steps/evaluation_feedback_loop_steps.py:266
    And a low-score adr-evaluation event for "ADR-0.99.0-loop-b" with dimension
"clarity" scoring 1.5     # features/steps/evaluation_feedback_loop_steps.py:266
    And a low-score adr-evaluation event for "ADR-0.99.0-loop-c" with dimension
"clarity" scoring 1.5     # features/steps/evaluation_feedback_loop_steps.py:266
    When I run the gz command "validate --evaluation-justify-binding
ADR-0.99.0-loop-a"                   # features/steps/gz_steps.py:209
    Then the command exits non-zero
# features/steps/gz_steps.py:215
    Given a complete justify scaffold exists for "ADR-0.99.0-loop-a"
# features/steps/evaluation_feedback_loop_steps.py:361
    And a complete justify scaffold exists for "ADR-0.99.0-loop-b"
# features/steps/evaluation_feedback_loop_steps.py:361
    And a complete justify scaffold exists for "ADR-0.99.0-loop-c"
# features/steps/evaluation_feedback_loop_steps.py:361
    When I run the gz command "validate --evaluation-justify-binding
ADR-0.99.0-loop-a"                   # features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220
    When the eval-feedback-cluster chore runs
# features/steps/evaluation_feedback_loop_steps.py:385
    Then 1 proposal record exists under
".gzkit/chores/eval-feedback-cluster/proofs/"                     #
features/steps/evaluation_feedback_loop_steps.py:391
    Given the environment is interactive
# features/steps/evaluation_feedback_loop_steps.py:430
    And the operator confirms with "PROPOSE"
# features/steps/evaluation_feedback_loop_steps.py:446
    And gh issue create returns "https://github.com/owner/repo/issues/555"
# features/steps/evaluation_feedback_loop_steps.py:452
    When I invoke chores_propose_ghi for "eval-feedback-cluster"
# features/steps/evaluation_feedback_loop_steps.py:461
    Then the most recent proposal record has "filed" equal to true
# features/steps/evaluation_feedback_loop_steps.py:471
    And the most recent proposal record has "ghi_url" equal to
"https://github.com/owner/repo/issues/555" #
features/steps/evaluation_feedback_loop_steps.py:483

Feature: gz frontmatter reconcile ledger-wins reconciliation (ADR-0.0.16 /
OBPI-0.0.16-03) # features/frontmatter_reconcile.feature:1
  As an operator remediating frontmatter drift,
  I want gz frontmatter reconcile to rewrite drifted fields to match the ledger
  so that frontmatter stays consistent with its source of truth without
hand-editing.
  Feature: gz frontmatter reconcile ledger-wins reconciliation (ADR-0.0.16 /
OBPI-0.0.16-03)  # features/frontmatter_reconcile.feature:1

  @REQ-0.0.16-03-02
  Scenario: Reconcile rewrites drifted lane and emits a receipt  #
features/frontmatter_reconcile.feature:11
    Given the workspace is initialized                           #
features/steps/gz_steps.py:67
    And ADR-0.1.0 exists                                         #
features/steps/gz_steps.py:90
    Given ADR-0.1.0 has drifted lane frontmatter "heavy"         #
features/steps/frontmatter_reconcile_steps.py:52
    When I run the gz command "frontmatter reconcile"            #
features/steps/gz_steps.py:209
    Then the command exits with code 0                           #
features/steps/gz_steps.py:220
    And ADR-0.1.0 frontmatter "lane" equals "lite"               #
features/steps/frontmatter_reconcile_steps.py:58
    And a frontmatter-coherence receipt exists                   #
features/steps/frontmatter_reconcile_steps.py:67

  @REQ-0.0.16-03-03
  Scenario: Dry-run leaves ADR files untouched but emits the receipt  #
features/frontmatter_reconcile.feature:19
    Given the workspace is initialized                                #
features/steps/gz_steps.py:67
    And ADR-0.1.0 exists                                              #
features/steps/gz_steps.py:90
    Given ADR-0.1.0 has drifted lane frontmatter "heavy"              #
features/steps/frontmatter_reconcile_steps.py:52
    When I run the gz command "frontmatter reconcile --dry-run"       #
features/steps/gz_steps.py:209
    Then the command exits with code 0                                #
features/steps/gz_steps.py:220
    And ADR-0.1.0 frontmatter "lane" equals "heavy"                   #
features/steps/frontmatter_reconcile_steps.py:58
    And a frontmatter-coherence receipt exists                        #
features/steps/frontmatter_reconcile_steps.py:67

  @REQ-0.0.16-03-07
  Scenario: Unmapped status term exits with policy-breach code  #
features/frontmatter_reconcile.feature:27
    Given the workspace is initialized                          #
features/steps/gz_steps.py:67
    And ADR-0.1.0 exists                                        #
features/steps/gz_steps.py:90
    Given ADR-0.1.0 has drifted status frontmatter "Nonsense"   #
features/steps/gates_frontmatter_steps.py:17
    When I run the gz command "frontmatter reconcile"           #
features/steps/gz_steps.py:209
    Then the command exits with code 3                          #
features/steps/gz_steps.py:220
    And the output contains "Nonsense"                          #
features/steps/gz_steps.py:225

Feature: gz gates frontmatter integration (ADR-0.0.16 / OBPI-0.0.16-02) #
features/gates.feature:1
  As an operator running governance gates,
  I want Gate 1 to mechanically block on frontmatter-ledger drift,
  so that stale frontmatter never masquerades as truth during attestation.
  Feature: gz gates frontmatter integration (ADR-0.0.16 / OBPI-0.0.16-02)  #
features/gates.feature:1

  @REQ-0.0.16-02-02 @REQ-0.0.16-02-03
  Scenario: Gate 1 blocks on status frontmatter drift with exit 3        #
features/gates.feature:12
    Given the workspace is initialized                                   #
features/steps/gz_steps.py:67
    And ADR-0.1.0 exists                                                 #
features/steps/gz_steps.py:90
    Given ADR-0.1.0 has drifted status frontmatter "Completed"           #
features/steps/gates_frontmatter_steps.py:17
    When I run the gz command "gates --gate 1 --adr ADR-0.1.0"           #
features/steps/gz_steps.py:209
    Then the command exits with code 3                                   #
features/steps/gz_steps.py:220
    And the output contains "status"                                     #
features/steps/gz_steps.py:225
    And the output contains "gz chores run frontmatter-ledger-coherence" #
features/steps/gz_steps.py:225

  @REQ-0.0.16-02-04
  Scenario: gz gates rejects the --skip-frontmatter bypass flag          #
features/gates.feature:20
    Given the workspace is initialized                                   #
features/steps/gz_steps.py:67
    And ADR-0.1.0 exists                                                 #
features/steps/gz_steps.py:90
    When I run the gz command "gates --skip-frontmatter --adr ADR-0.1.0" #
features/steps/gz_steps.py:209
    Then the command exits non-zero                                      #
features/steps/gz_steps.py:215
    And the output contains "unrecognized arguments"                     #
features/steps/gz_steps.py:225

Feature: Heavy lane Gate 4 governance # features/heavy_lane_gate4.feature:1
  Heavy-lane ADR workflows must enforce Gate 4 BDD checks.
  Scenario: Attestation is blocked until Gate 4 passes              #
features/heavy_lane_gate4.feature:4
    Given the workspace is initialized in heavy mode                #
features/steps/gz_steps.py:60
    And a heavy ADR exists                                          #
features/steps/gz_steps.py:84
    And gate 2 and gate 3 are marked pass for ADR-0.1.0             #
features/steps/gz_steps.py:96
    When I run the gz command "attest ADR-0.1.0 --status completed" #
features/steps/gz_steps.py:209
    Then the command exits non-zero                                 #
features/steps/gz_steps.py:215
    And the output contains "Gate 4 must pass"                      #
features/steps/gz_steps.py:225

  Scenario: Closeout guidance includes Gate 4 BDD command              #
features/heavy_lane_gate4.feature:12
    Given the workspace is initialized in heavy mode                   #
features/steps/gz_steps.py:60
    And a heavy ADR exists                                             #
features/steps/gz_steps.py:84
    When I run the gz command "closeout ADR-0.1.0 --dry-run"           #
features/steps/gz_steps.py:209
    Then the command exits with code 0                                 #
features/steps/gz_steps.py:220
    And the output contains "Gate 4 (BDD): uv run -m behave features/" #
features/steps/gz_steps.py:225

  Scenario: Heavy ADR status reports Gate 4 as pending when not checked  #
features/heavy_lane_gate4.feature:19
    Given the workspace is initialized in heavy mode                     #
features/steps/gz_steps.py:60
    And a heavy ADR exists                                               #
features/steps/gz_steps.py:84
    When I run the gz command "adr status ADR-0.1.0 --json"              #
features/steps/gz_steps.py:209
    Then the command exits with code 0                                   #
features/steps/gz_steps.py:220
    And JSON path "gates.4" equals "pending"                             #
features/steps/gz_steps.py:241

  Scenario: Pipeline guidance requires guarded git sync before completion
accounting  # features/heavy_lane_gate4.feature:26
    Given the workspace is initialized with agent surfaces in heavy mode
# features/steps/gz_steps.py:74
    Then the file "AGENTS.md" contains "guarded git sync -> completion"
# features/steps/gz_steps.py:235
    And the file "AGENTS.md" contains "uv run gz git-sync --apply --lint --test"
# features/steps/gz_steps.py:235

  Scenario: Canonical lane doctrine narrows Heavy to runtime-contract changes
# features/heavy_lane_gate4.feature:31
    Given the workspace is initialized with agent surfaces in heavy mode
# features/steps/gz_steps.py:74
    Then the file "AGENTS.md" contains "Documentation/process/template-only
changes stay" # features/steps/gz_steps.py:235
    And the file "AGENTS.md" contains "command/API/schema/runtime-contract
changes"       # features/steps/gz_steps.py:235
    And the file "AGENTS.md" contains "uv run gz check"
# features/steps/gz_steps.py:235

Feature: gz issue file cross-repo defect filing wrapper (ADR-0.0.23 /
OBPI-0.0.23-04) # features/issue_file.feature:1
  As an agent or operator inside a gzkit-consuming repository,
  I want a wrapper that auto-stamps a provenance trailer, validates
  that the issue body references a gzkit-owned surface, and routes the
  issue at tvproductions/gzkit regardless of my git remote,
  so that gzkit-surface defects cannot be misrouted to the consumer's
  tracker even by accident, closing the Safeguard circumvention shape.
  @REQ-0.0.23-04-04 @REQ-0.0.23-04-05
  Scenario: Provenance trailer auto-stamps consumer slug and gz version
# features/issue_file.feature:11
    Given a fixture git remote "git@github.com:acme/widget.git"
# features/steps/issue_file_steps.py:21
    When I run the gz command "issue file --title T --body 'gz validate fails on
stale ledger' --enhancement --dry-run" # features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220
    And the output contains "Filed from acme/widget running gz v"
# features/steps/gz_steps.py:225
    And the output contains "Target: tvproductions/gzkit"
# features/steps/gz_steps.py:225
    And the output contains "Label: enhancement"
# features/steps/gz_steps.py:225

  @REQ-0.0.23-04-05
  Scenario: Issue is routed to tvproductions/gzkit regardless of consumer remote
# features/issue_file.feature:20
    Given a fixture git remote "https://github.com/other/consumer.git"
# features/steps/issue_file_steps.py:21
    When I run the gz command "issue file --title T --body 'gz cli audit
miscounts manpages' --defect --dry-run" # features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220
    And the output contains "Target: tvproductions/gzkit"
# features/steps/gz_steps.py:225
    And the output contains "Filed from other/consumer running gz v"
# features/steps/gz_steps.py:225

  @REQ-0.0.23-04-06
  Scenario: Body without a gzkit-owned surface marker is hard-rejected
# features/issue_file.feature:28
    Given a fixture git remote "git@github.com:acme/widget.git"
# features/steps/issue_file_steps.py:21
    When I run the gz command "issue file --title T --body 'consumer auth flow
regression' --defect --dry-run" # features/steps/gz_steps.py:209
    Then the command exits with code 1
# features/steps/gz_steps.py:220
    And the output contains "gzkit-owned surface"
# features/steps/gz_steps.py:225

Feature: gz justify pre-execution reasoning walkthrough (ADR-0.0.19 /
OBPI-0.0.19-05) # features/justify.feature:1
  As an operator authoring or attesting governance work,
  I want a deterministic 8-section reasoning scaffold for GHIs, OBPIs, or
  drafts and a validate subverb that gates completion on every section
  being filled,
  so that pre-execution reasoning is preserved as evidence rather than
  reconstructed post-hoc.
  @REQ-0.0.19-05-05 @REQ-0.0.19-05-06
  Scenario: Render scaffold for a GHI anchor with mocked gh  #
features/justify.feature:11
    Given gh issue view returns fixture body for "GHI-232"   #
features/steps/justify_steps.py:26
    When I run the gz command "justify GHI-232"              #
features/steps/gz_steps.py:209
    Then the command exits with code 0                       #
features/steps/gz_steps.py:220
    And the output contains "# Walkthrough: GHI-232"         #
features/steps/gz_steps.py:225
    And the output contains "_[To be filled]_"               #
features/steps/gz_steps.py:225

  @REQ-0.0.19-05-05 @REQ-0.0.19-05-06
  Scenario: Render scaffold for an OBPI anchor against a fixture brief  #
features/justify.feature:20
    Given a fixture OBPI brief for "OBPI-0.99.0-01"                     #
features/steps/justify_steps.py:48
    When I run the gz command "justify OBPI-0.99.0-01"                  #
features/steps/gz_steps.py:209
    Then the command exits with code 0                                  #
features/steps/gz_steps.py:220
    And the output contains "# Walkthrough: OBPI-0.99.0-01"             #
features/steps/gz_steps.py:225

  @REQ-0.0.19-05-05 @REQ-0.0.19-05-06
  Scenario: Render scaffold from --draft with --save and --draft-slug
# features/justify.feature:28
    When I run the gz command "justify --draft 'pre-decision text' --save
--draft-slug my-idea" # features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220
    And a scaffold artifact is written under "artifacts/justify"
# features/steps/justify_steps.py:125

  @REQ-0.0.19-05-05 @REQ-0.0.19-05-06
  Scenario: Reject ADR anchor with exit 1                            #
features/justify.feature:35
    When I run the gz command "justify ADR-0.0.19"                   #
features/steps/gz_steps.py:209
    Then the command exits with code 1                               #
features/steps/gz_steps.py:220
    And the output contains "justify reasons about change instances" #
features/steps/gz_steps.py:225

  @REQ-0.0.19-05-05 @REQ-0.0.19-05-06
  Scenario: Reject --draft + --save without --draft-slug              #
features/justify.feature:42
    When I run the gz command "justify --draft 'orphan draft' --save" #
features/steps/gz_steps.py:209
    Then the command exits with code 1                                #
features/steps/gz_steps.py:220
    And the output contains "--draft-slug is required"                #
features/steps/gz_steps.py:225

  @REQ-0.0.19-05-05 @REQ-0.0.19-05-06
  Scenario: Validate exits 0 on a complete walkthrough          #
features/justify.feature:49
    Given a complete justify walkthrough fixture at "filled.md" #
features/steps/justify_steps.py:107
    When I run the gz command "justify validate filled.md"      #
features/steps/gz_steps.py:209
    Then the command exits with code 0                          #
features/steps/gz_steps.py:220

  @REQ-0.0.19-05-05 @REQ-0.0.19-05-06
  Scenario: Validate exits 1 on an incomplete walkthrough              #
features/justify.feature:56
    Given an incomplete justify walkthrough fixture at "incomplete.md" #
features/steps/justify_steps.py:112
    When I run the gz command "justify validate incomplete.md"         #
features/steps/gz_steps.py:209
    Then the command exits with code 1                                 #
features/steps/gz_steps.py:220
    And the output names an unfilled section ordinal                   #
features/steps/justify_steps.py:131

  @REQ-0.0.19-05-05 @REQ-0.0.19-05-06
  Scenario: Validate exits 2 on a malformed walkthrough             #
features/justify.feature:64
    Given a malformed justify walkthrough fixture at "malformed.md" #
features/steps/justify_steps.py:117
    When I run the gz command "justify validate malformed.md"       #
features/steps/gz_steps.py:209
    Then the command exits with code 2                              #
features/steps/gz_steps.py:220

Feature: OBPI anchor drift reconciliation # features/obpi_anchor_drift.feature:1
  Completed OBPIs should preserve lifecycle state while reporting superseded
anchors
  when later siblings or ADR closeout commit on top of the anchor.
  Scenario: Reconcile preserves completion state while reporting superseded
anchor  # features/obpi_anchor_drift.feature:5
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And ADR-0.1.0 exists
# features/steps/gz_steps.py:90
    And a completed OBPI with anchor-tracked receipt exists for
OBPI-0.1.0-01-demo  # features/steps/gz_steps.py:103
    And the tracked module changes after the completion anchor
# features/steps/gz_steps.py:195
    When I run the gz command "obpi reconcile OBPI-0.1.0-01-demo --json"
# features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220
    And JSON path "runtime_state" equals "completed"
# features/steps/gz_steps.py:241
    And JSON path "anchor_state" equals "superseded"
# features/steps/gz_steps.py:241

Feature: OBPI atomic completion # features/obpi_complete.feature:1
  gz obpi complete atomically validates, writes evidence, flips status,
  records attestation, and emits a completion receipt in a single
  all-or-nothing transaction.
  Scenario: Missing OBPI exits 1
# features/obpi_complete.feature:6
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    When I run "gz obpi complete NONEXISTENT-99 --attestor jeff
--attestation-text Verified" # features/steps/obpi_lock_steps.py:61
    Then it exits with code 1
# features/steps/obpi_lock_steps.py:71

  Scenario: Help text shows required flags       #
features/obpi_complete.feature:11
    Given the workspace is initialized           # features/steps/gz_steps.py:67
    When I run "gz obpi complete -h"             #
features/steps/obpi_lock_steps.py:61
    Then it exits with code 0                    #
features/steps/obpi_lock_steps.py:71
    And the output contains "--attestor"         #
features/steps/gz_steps.py:225
    And the output contains "--attestation-text" #
features/steps/gz_steps.py:225

Feature: OBPI completion REQ-coverage gate #
features/obpi_completion_coverage_gate.feature:1
  gz obpi complete refuses completion when any REQ in the closing brief's
  Heavy and foundation-kind briefs are fail-closed; lite-non-foundation briefs
  emit a warning and proceed. The override path (--accept-uncovered) records a
  ledger event and requires --attestor-present for agent-relayed acceptance.
  @REQ-0.0.25-01-01
  Scenario: Gate passes when all REQs have passing covering tests
# features/obpi_completion_coverage_gate.feature:9
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And a heavy-foundation OBPI "OBPI-FIXTURE-01-01" with REQ "REQ-0.0.98-01-01"
exists                                                                #
features/steps/obpi_completion_coverage_gate_steps.py:333
    And a covering test for "REQ-0.0.98-01-01" that passes exists
# features/steps/obpi_completion_coverage_gate_steps.py:358
    And a valid arb step receipt
"arb-step-unittest-00000000000000000000000000000001" exists
# features/steps/obpi_completion_coverage_gate_steps.py:381
    And a pipeline marker for "OBPI-FIXTURE-01-01" is active
# features/steps/attestation_receipt_binding_steps.py:309
    When I complete coverage-gate OBPI "OBPI-FIXTURE-01-01" citing receipt
"arb-step-unittest-00000000000000000000000000000001" using attestor-present #
features/steps/obpi_completion_coverage_gate_steps.py:412
    Then the exit code is 0
# features/steps/obpi_completion_coverage_gate_steps.py:512

  @REQ-0.0.25-01-02
  Scenario: Gate exits 3 when heavy-lane REQ has no covering test
# features/obpi_completion_coverage_gate.feature:19
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And a heavy-foundation OBPI "OBPI-FIXTURE-01-02" with REQ "REQ-0.0.98-01-02"
exists                                                                #
features/steps/obpi_completion_coverage_gate_steps.py:333
    And a valid arb step receipt
"arb-step-unittest-00000000000000000000000000000002" exists
# features/steps/obpi_completion_coverage_gate_steps.py:381
    And a pipeline marker for "OBPI-FIXTURE-01-02" is active
# features/steps/attestation_receipt_binding_steps.py:309
    When I complete coverage-gate OBPI "OBPI-FIXTURE-01-02" citing receipt
"arb-step-unittest-00000000000000000000000000000002" using attestor-present #
features/steps/obpi_completion_coverage_gate_steps.py:412
    Then the exit code is 3
# features/steps/obpi_completion_coverage_gate_steps.py:512
    And the output mentions "REQ-0.0.98-01-02"
# features/steps/obpi_completion_coverage_gate_steps.py:520

  @REQ-0.0.25-01-03
  Scenario: Foundation-kind lite-lane brief exits 3 for uncovered REQ
# features/obpi_completion_coverage_gate.feature:29
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And a foundation-lite OBPI "OBPI-FIXTURE-01-03" with REQ "REQ-0.0.98-01-03"
exists                                                                 #
features/steps/obpi_completion_coverage_gate_steps.py:346
    And a valid arb step receipt
"arb-step-unittest-00000000000000000000000000000003" exists
# features/steps/obpi_completion_coverage_gate_steps.py:381
    And a pipeline marker for "OBPI-FIXTURE-01-03" is active
# features/steps/attestation_receipt_binding_steps.py:309
    When I complete coverage-gate OBPI "OBPI-FIXTURE-01-03" citing receipt
"arb-step-unittest-00000000000000000000000000000003" using attestor-present #
features/steps/obpi_completion_coverage_gate_steps.py:412
    Then the exit code is 3
# features/steps/obpi_completion_coverage_gate_steps.py:512

  @REQ-0.0.25-01-04
  Scenario: Lite-non-foundation brief warns and proceeds for uncovered REQ
# features/obpi_completion_coverage_gate.feature:38
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And a lite-feature OBPI "OBPI-FIXTURE-01-04" with REQ "REQ-0.0.98-01-04"
exists                                                                    #
features/steps/obpi_completion_coverage_gate_steps.py:352
    And a valid arb step receipt
"arb-step-unittest-00000000000000000000000000000004" exists
# features/steps/obpi_completion_coverage_gate_steps.py:381
    And a pipeline marker for "OBPI-FIXTURE-01-04" is active
# features/steps/attestation_receipt_binding_steps.py:309
    When I complete coverage-gate OBPI "OBPI-FIXTURE-01-04" citing receipt
"arb-step-unittest-00000000000000000000000000000004" using attestor-present #
features/steps/obpi_completion_coverage_gate_steps.py:412
    Then the exit code is 0
# features/steps/obpi_completion_coverage_gate_steps.py:512
    And the output mentions "Warning"
# features/steps/obpi_completion_coverage_gate_steps.py:520

  @REQ-0.0.25-01-05
  Scenario: Gate exits 3 when covering test fails
# features/obpi_completion_coverage_gate.feature:48
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And a heavy-foundation OBPI "OBPI-FIXTURE-01-05" with REQ "REQ-0.0.98-01-05"
exists                                                                #
features/steps/obpi_completion_coverage_gate_steps.py:333
    And a covering test for "REQ-0.0.98-01-05" that fails exists
# features/steps/obpi_completion_coverage_gate_steps.py:365
    And a valid arb step receipt
"arb-step-unittest-00000000000000000000000000000005" exists
# features/steps/obpi_completion_coverage_gate_steps.py:381
    And a pipeline marker for "OBPI-FIXTURE-01-05" is active
# features/steps/attestation_receipt_binding_steps.py:309
    When I complete coverage-gate OBPI "OBPI-FIXTURE-01-05" citing receipt
"arb-step-unittest-00000000000000000000000000000005" using attestor-present #
features/steps/obpi_completion_coverage_gate_steps.py:412
    Then the exit code is 3
# features/steps/obpi_completion_coverage_gate_steps.py:512

  @REQ-0.0.25-01-06
  Scenario: Any one passing covering test satisfies the REQ
# features/obpi_completion_coverage_gate.feature:58
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And a heavy-foundation OBPI "OBPI-FIXTURE-01-06" with REQ "REQ-0.0.98-01-06"
exists                                                                #
features/steps/obpi_completion_coverage_gate_steps.py:333
    And a covering test for "REQ-0.0.98-01-06" that passes exists
# features/steps/obpi_completion_coverage_gate_steps.py:358
    And a second covering test for "REQ-0.0.98-01-06" that fails exists
# features/steps/obpi_completion_coverage_gate_steps.py:372
    And a valid arb step receipt
"arb-step-unittest-00000000000000000000000000000006" exists
# features/steps/obpi_completion_coverage_gate_steps.py:381
    And a pipeline marker for "OBPI-FIXTURE-01-06" is active
# features/steps/attestation_receipt_binding_steps.py:309
    When I complete coverage-gate OBPI "OBPI-FIXTURE-01-06" citing receipt
"arb-step-unittest-00000000000000000000000000000006" using attestor-present #
features/steps/obpi_completion_coverage_gate_steps.py:412
    Then the exit code is 0
# features/steps/obpi_completion_coverage_gate_steps.py:512

  @REQ-0.0.25-02-01
  Scenario: Override path proceeds and records ledger event via attestor-present
# features/obpi_completion_coverage_gate.feature:69
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And a heavy-foundation OBPI "OBPI-FIXTURE-02-01" with REQ "REQ-0.0.98-02-01"
exists
# features/steps/obpi_completion_coverage_gate_steps.py:333
    And a valid arb step receipt
"arb-step-unittest-00000000000000000000000000000007" exists
# features/steps/obpi_completion_coverage_gate_steps.py:381
    And a pipeline marker for "OBPI-FIXTURE-02-01" is active
# features/steps/attestation_receipt_binding_steps.py:309
    When I complete coverage-gate OBPI "OBPI-FIXTURE-02-01" accepting
"REQ-0.0.98-02-01" reason "agent-relayed TTY-path proxy" citing
"arb-step-unittest-00000000000000000000000000000007" using attestor-present #
features/steps/obpi_completion_coverage_gate_steps.py:418
    Then the exit code is 0
# features/steps/obpi_completion_coverage_gate_steps.py:512
    And the ledger contains an "obpi_completion_uncovered_accept" event
# features/steps/obpi_completion_coverage_gate_steps.py:526

  @REQ-0.0.25-02-02
  Scenario: Headless override without pipeline marker is refused
# features/obpi_completion_coverage_gate.feature:79
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And a heavy-foundation OBPI "OBPI-FIXTURE-02-02" with REQ "REQ-0.0.98-02-02"
exists
# features/steps/obpi_completion_coverage_gate_steps.py:333
    And a valid arb step receipt
"arb-step-unittest-00000000000000000000000000000008" exists
# features/steps/obpi_completion_coverage_gate_steps.py:381
    When I complete coverage-gate OBPI "OBPI-FIXTURE-02-02" accepting
"REQ-0.0.98-02-02" reason "no-marker" citing
"arb-step-unittest-00000000000000000000000000000008" without attestor-present #
features/steps/obpi_completion_coverage_gate_steps.py:434
    Then the exit code is 3
# features/steps/obpi_completion_coverage_gate_steps.py:512

  @REQ-0.0.25-02-03
  Scenario: Partial accept-uncovered still fails for unwaived REQ
# features/obpi_completion_coverage_gate.feature:87
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And a heavy-foundation OBPI "OBPI-FIXTURE-02-03" with REQs
"REQ-0.0.98-03-01" and "REQ-0.0.98-03-02" exists
# features/steps/obpi_completion_coverage_gate_steps.py:340
    And a valid arb step receipt
"arb-step-unittest-00000000000000000000000000000009" exists
# features/steps/obpi_completion_coverage_gate_steps.py:381
    And a pipeline marker for "OBPI-FIXTURE-02-03" is active
# features/steps/attestation_receipt_binding_steps.py:309
    When I complete coverage-gate OBPI "OBPI-FIXTURE-02-03" accepting only
"REQ-0.0.98-03-01" reason "partial" citing
"arb-step-unittest-00000000000000000000000000000009" using attestor-present #
features/steps/obpi_completion_coverage_gate_steps.py:450
    Then the exit code is 3
# features/steps/obpi_completion_coverage_gate_steps.py:512

  @REQ-0.0.25-02-04
  Scenario: gz adr emit-receipt --event closed blocked when OBPI has unwaived
REQ gap                                              #
features/obpi_completion_coverage_gate.feature:96
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And a heavy ADR "ADR-FIXTURE-02-04" with a completed OBPI
"OBPI-FIXTURE-02-04" carrying unwaived REQ "REQ-0.0.98-02-04" exists #
features/steps/obpi_completion_coverage_gate_steps.py:387
    When I emit ADR receipt for "ADR-FIXTURE-02-04" event "closed" attestor "BDD
User" text "closing"                              #
features/steps/obpi_completion_coverage_gate_steps.py:491
    Then the exit code is 3
# features/steps/obpi_completion_coverage_gate_steps.py:512

  @REQ-0.0.25-02-05
  Scenario: accept-uncovered without accept-uncovered-reason exits 1
# features/obpi_completion_coverage_gate.feature:103
    Given the workspace is initialized in heavy mode
# features/steps/gz_steps.py:60
    And a heavy-foundation OBPI "OBPI-FIXTURE-02-05" with REQ "REQ-0.0.98-02-05"
exists
# features/steps/obpi_completion_coverage_gate_steps.py:333
    And a valid arb step receipt
"arb-step-unittest-0000000000000000000000000000000a" exists
# features/steps/obpi_completion_coverage_gate_steps.py:381
    And a pipeline marker for "OBPI-FIXTURE-02-05" is active
# features/steps/attestation_receipt_binding_steps.py:309
    When I complete coverage-gate OBPI "OBPI-FIXTURE-02-05" accepting
"REQ-0.0.98-02-05" without reason citing
"arb-step-unittest-0000000000000000000000000000000a" using attestor-present #
features/steps/obpi_completion_coverage_gate_steps.py:466
    Then the exit code is 1
# features/steps/obpi_completion_coverage_gate_steps.py:512

  @REQ-0.0.25-03-01
  Scenario: This feature file exists with scenario tags for all covered REQs  #
features/obpi_completion_coverage_gate.feature:112
    Given the workspace is the live repository                                #
features/steps/attestation_receipt_binding_steps.py:314
    Then the file "features/obpi_completion_coverage_gate.feature" exists     #
features/steps/gz_steps.py:230

  @REQ-0.0.25-03-02
  Scenario: AGENTS.md OBPI Acceptance Protocol names the REQ-coverage gate
# features/obpi_completion_coverage_gate.feature:117
    Given the workspace is the live repository
# features/steps/attestation_receipt_binding_steps.py:314
    Then AGENTS.md "OBPI Acceptance Protocol" section mentions "REQ-coverage
gate" # features/steps/obpi_completion_coverage_gate_steps.py:539

  @REQ-0.0.25-03-03
  Scenario: obpi-complete manpage documents the accept-uncovered flag
# features/obpi_completion_coverage_gate.feature:122
    Given the workspace is the live repository
# features/steps/attestation_receipt_binding_steps.py:314
    Then the file "docs/user/commands/obpi-complete.md" contains
"--accept-uncovered" # features/steps/gz_steps.py:235

  @REQ-0.0.25-03-04
  Scenario: CLI audit passes in the live repository post-edit  #
features/obpi_completion_coverage_gate.feature:127
    Given the workspace is the live repository                 #
features/steps/attestation_receipt_binding_steps.py:314
    When I run the gz command "cli audit"                      #
features/steps/gz_steps.py:209
    Then the exit code is 0                                    #
features/steps/obpi_completion_coverage_gate_steps.py:512

Feature: OBPI lock management # features/obpi_lock.feature:1
  Multi-agent work locks for OBPI coordination via gz obpi lock commands.
  Scenario: Claim creates a lock file                    #
features/obpi_lock.feature:4
    Given the workspace is initialized                   #
features/steps/gz_steps.py:67
    When I run "gz obpi lock claim OBPI-0.1.0-01 --json" #
features/steps/obpi_lock_steps.py:61
    Then it exits with code 0                            #
features/steps/obpi_lock_steps.py:71
    And the JSON output field "status" is "claimed"      #
features/steps/obpi_lock_steps.py:79

  Scenario: Claim fails when held by another agent                    #
features/obpi_lock.feature:10
    Given the workspace is initialized                                #
features/steps/gz_steps.py:67
    And an OBPI lock exists for "OBPI-0.1.0-01" held by agent "codex" #
features/steps/obpi_lock_steps.py:30
    When I run "gz obpi lock claim OBPI-0.1.0-01 --json"              #
features/steps/obpi_lock_steps.py:61
    Then it exits with code 1                                         #
features/steps/obpi_lock_steps.py:71
    And the JSON output field "status" is "conflict"                  #
features/steps/obpi_lock_steps.py:79

  Scenario: Release removes lock                          #
features/obpi_lock.feature:17
    Given the workspace is initialized                    #
features/steps/gz_steps.py:67
    When I run "gz obpi lock claim OBPI-0.1.0-01"         #
features/steps/obpi_lock_steps.py:61
    And I run "gz obpi lock release OBPI-0.1.0-01 --json" #
features/steps/obpi_lock_steps.py:61
    Then it exits with code 0                             #
features/steps/obpi_lock_steps.py:71
    And the JSON output field "status" is "released"      #
features/steps/obpi_lock_steps.py:79

  Scenario: Release validates ownership                               #
features/obpi_lock.feature:24
    Given the workspace is initialized                                #
features/steps/gz_steps.py:67
    And an OBPI lock exists for "OBPI-0.1.0-01" held by agent "codex" #
features/steps/obpi_lock_steps.py:30
    When I run "gz obpi lock release OBPI-0.1.0-01 --json"            #
features/steps/obpi_lock_steps.py:61
    Then it exits with code 1                                         #
features/steps/obpi_lock_steps.py:71
    And the JSON output field "status" is "ownership_error"           #
features/steps/obpi_lock_steps.py:79

  Scenario: Release with force overrides ownership                    #
features/obpi_lock.feature:31
    Given the workspace is initialized                                #
features/steps/gz_steps.py:67
    And an OBPI lock exists for "OBPI-0.1.0-01" held by agent "codex" #
features/steps/obpi_lock_steps.py:30
    When I run "gz obpi lock release OBPI-0.1.0-01 --force --json"    #
features/steps/obpi_lock_steps.py:61
    Then it exits with code 0                                         #
features/steps/obpi_lock_steps.py:71
    And the JSON output field "status" is "released"                  #
features/steps/obpi_lock_steps.py:79

  Scenario: Check exits 0 when held                     #
features/obpi_lock.feature:38
    Given the workspace is initialized                  #
features/steps/gz_steps.py:67
    When I run "gz obpi lock claim OBPI-0.1.0-01"       #
features/steps/obpi_lock_steps.py:61
    And I run "gz obpi lock check OBPI-0.1.0-01 --json" #
features/steps/obpi_lock_steps.py:61
    Then it exits with code 0                           #
features/steps/obpi_lock_steps.py:71
    And the JSON output field "status" is "held"        #
features/steps/obpi_lock_steps.py:79

  Scenario: Check exits 1 when free                      #
features/obpi_lock.feature:45
    Given the workspace is initialized                   #
features/steps/gz_steps.py:67
    When I run "gz obpi lock check OBPI-0.1.0-01 --json" #
features/steps/obpi_lock_steps.py:61
    Then it exits with code 1                            #
features/steps/obpi_lock_steps.py:71
    And the JSON output field "status" is "free"         #
features/steps/obpi_lock_steps.py:79

  Scenario: List shows active locks               #
features/obpi_lock.feature:51
    Given the workspace is initialized            #
features/steps/gz_steps.py:67
    When I run "gz obpi lock claim OBPI-0.1.0-01" #
features/steps/obpi_lock_steps.py:61
    And I run "gz obpi lock list --json"          #
features/steps/obpi_lock_steps.py:61
    Then it exits with code 0                     #
features/steps/obpi_lock_steps.py:71
    And the JSON output field "count" is "1"      #
features/steps/obpi_lock_steps.py:79

  Scenario: List auto-reaps expired locks               #
features/obpi_lock.feature:58
    Given the workspace is initialized                  #
features/steps/gz_steps.py:67
    And an expired OBPI lock exists for "OBPI-0.1.0-01" #
features/steps/obpi_lock_steps.py:45
    When I run "gz obpi lock list --json"               #
features/steps/obpi_lock_steps.py:61
    Then it exits with code 0                           #
features/steps/obpi_lock_steps.py:71
    And the JSON output field "count" is "0"            #
features/steps/obpi_lock_steps.py:79

  Scenario: Deprecated lock-claim alias works            #
features/obpi_lock.feature:65
    Given the workspace is initialized                   #
features/steps/gz_steps.py:67
    When I run "gz obpi lock-claim OBPI-0.1.0-01 --json" #
features/steps/obpi_lock_steps.py:61
    Then it exits with code 0                            #
features/steps/obpi_lock_steps.py:71
    And the JSON output field "status" is "claimed"      #
features/steps/obpi_lock_steps.py:79

Feature: Patch release discovery CLI # features/patch_release.feature:1
  The gz patch release command discovers qualifying GHIs since the last tag,
  computes the next patch version, and (unless --dry-run) writes a manifest
  and ledger event.
  Scenario: Help text exits zero and lists flags     #
features/patch_release.feature:6
    Given the workspace is initialized in heavy mode #
features/steps/gz_steps.py:60
    When I run the gz command "patch release --help" #
features/steps/gz_steps.py:209
    Then the command exits with code 0               #
features/steps/gz_steps.py:220
    And the output contains "--dry-run"              #
features/steps/gz_steps.py:225
    And the output contains "--json"                 #
features/steps/gz_steps.py:225

  Scenario: Dry run reports discovery without executing  #
features/patch_release.feature:13
    Given the workspace is initialized in heavy mode     #
features/steps/gz_steps.py:60
    When I run the gz command "patch release --dry-run"  #
features/steps/gz_steps.py:209
    Then the command exits with code 0                   #
features/steps/gz_steps.py:220
    And the output contains "Patch Release Discovery"    #
features/steps/gz_steps.py:225
    And the output contains "GHIs discovered"            #
features/steps/gz_steps.py:225

  Scenario: Dry run JSON output is well-formed                 #
features/patch_release.feature:20
    Given the workspace is initialized in heavy mode           #
features/steps/gz_steps.py:60
    When I run the gz command "patch release --dry-run --json" #
features/steps/gz_steps.py:209
    Then the command exits with code 0                         #
features/steps/gz_steps.py:220
    And JSON path "ghi_count" equals "0"                       #
features/steps/gz_steps.py:241
    And JSON path "tag" equals "None"                          #
features/steps/gz_steps.py:241

Feature: Persona control surface # features/persona.feature:1
  Agent personas define behavioral identity frames stored in
  .gzkit/personas/ and loaded at dispatch boundaries (ADR-0.0.11).
  Scenario: List personas in initialized workspace with no files  #
features/persona.feature:5
    Given the workspace is initialized                            #
features/steps/gz_steps.py:67
    When I run the gz command "personas list"                     #
features/steps/gz_steps.py:209
    Then the command exits with code 0                            #
features/steps/gz_steps.py:220

  Scenario: List personas shows implementer when file exists  #
features/persona.feature:10
    Given the workspace is initialized                        #
features/steps/gz_steps.py:67
    And a persona file "implementer" exists                   #
features/steps/persona_steps.py:11
    When I run the gz command "personas list --json"          #
features/steps/gz_steps.py:209
    Then the command exits with code 0                        #
features/steps/gz_steps.py:220
    And the output contains "implementer"                     #
features/steps/gz_steps.py:225
    And the output contains "methodical"                      #
features/steps/gz_steps.py:225

  Scenario: List personas shows main-session when file exists  #
features/persona.feature:18
    Given the workspace is initialized                         #
features/steps/gz_steps.py:67
    And a persona file "main-session" exists                   #
features/steps/persona_steps.py:11
    When I run the gz command "personas list --json"           #
features/steps/gz_steps.py:209
    Then the command exits with code 0                         #
features/steps/gz_steps.py:220
    And the output contains "main-session"                     #
features/steps/gz_steps.py:225
    And the output contains "methodical"                       #
features/steps/gz_steps.py:225

  Scenario: AGENTS.md persona section references main-session grounding  #
features/persona.feature:26
    Given the workspace is initialized with agent surfaces               #
features/steps/gz_steps.py:79
    Then the file "AGENTS.md" contains "main-session"                    #
features/steps/gz_steps.py:235
    And the file "AGENTS.md" contains "craftsperson"                     #
features/steps/gz_steps.py:235
    And the file "AGENTS.md" contains "governance not as overhead"       #
features/steps/gz_steps.py:235

  Scenario: AGENTS.md persona section lists available personas with roles  #
features/persona.feature:32
    Given the workspace is initialized with agent surfaces                 #
features/steps/gz_steps.py:79
    Then the file "AGENTS.md" contains "implementer"                       #
features/steps/gz_steps.py:235
    And the file "AGENTS.md" contains "narrator"                           #
features/steps/gz_steps.py:235
    And the file "AGENTS.md" contains "pipeline-orchestrator"              #
features/steps/gz_steps.py:235
    And the file "AGENTS.md" contains "quality-reviewer"                   #
features/steps/gz_steps.py:235
    And the file "AGENTS.md" contains "spec-reviewer"                      #
features/steps/gz_steps.py:235

  Scenario: Personas list is read-only        # features/persona.feature:40
    Given the workspace is initialized        # features/steps/gz_steps.py:67
    And a persona file "implementer" exists   #
features/steps/persona_steps.py:11
    When I run the gz command "personas list" # features/steps/gz_steps.py:209
    Then the command exits with code 0        # features/steps/gz_steps.py:220
    And the output contains "implementer"     # features/steps/gz_steps.py:225

  Scenario: Persona drift reports with governance evidence                    #
features/persona.feature:47
    Given the workspace is initialized                                        #
features/steps/gz_steps.py:67
    And the ledger contains governance events                                 #
features/steps/persona_steps.py:31
    When I run the gz command "personas drift --persona default-agent --json" #
features/steps/gz_steps.py:209
    Then the command exits with code 0                                        #
features/steps/gz_steps.py:220
    And the output is valid JSON                                              #
features/steps/task_governance_steps.py:45

  Scenario: Persona drift filters to single persona                           #
features/persona.feature:54
    Given the workspace is initialized                                        #
features/steps/gz_steps.py:67
    And the ledger contains governance events                                 #
features/steps/persona_steps.py:31
    When I run the gz command "personas drift --persona default-agent --json" #
features/steps/gz_steps.py:209
    Then the command exits with code 0                                        #
features/steps/gz_steps.py:220
    And the output contains "default-agent"                                   #
features/steps/gz_steps.py:225

  Scenario: Persona drift help includes description   #
features/persona.feature:61
    Given the workspace is initialized                #
features/steps/gz_steps.py:67
    When I run the gz command "personas drift --help" #
features/steps/gz_steps.py:209
    Then the command exits with code 0                #
features/steps/gz_steps.py:220
    And the output contains "behavioral proxies"      #
features/steps/gz_steps.py:225

Feature: Persona sync to vendor mirrors # features/persona_sync.feature:1
  Persona files in .gzkit/personas/ are mirrored to vendor surfaces
  by gz agent sync control-surfaces (ADR-0.0.13 item 3).
  Scenario: Sync mirrors personas to Claude surface         #
features/persona_sync.feature:5
    Given the workspace is initialized with agent surfaces  #
features/steps/gz_steps.py:79
    And a persona file "implementer" exists                 #
features/steps/persona_steps.py:11
    When I run the gz command "agent sync control-surfaces" #
features/steps/gz_steps.py:209
    Then the command exits with code 0                      #
features/steps/gz_steps.py:220
    And the file ".claude/personas/implementer.md" exists   #
features/steps/gz_steps.py:230

  Scenario: Manifest includes personas control surface      #
features/persona_sync.feature:12
    Given the workspace is initialized with agent surfaces  #
features/steps/gz_steps.py:79
    When I run the gz command "agent sync control-surfaces" #
features/steps/gz_steps.py:209
    Then the command exits with code 0                      #
features/steps/gz_steps.py:220
    And the file ".gzkit/manifest.json" contains "personas" #
features/steps/gz_steps.py:235

  Scenario: Init scaffolds default personas in clean workspace  #
features/persona_sync.feature:20
    Given the workspace is initialized                          #
features/steps/gz_steps.py:67
    Then the file ".gzkit/personas/default-agent.md" exists     #
features/steps/gz_steps.py:230
    And the file ".gzkit/personas/default-reviewer.md" exists   #
features/steps/gz_steps.py:230

  Scenario: Scaffolded personas pass surface validation    #
features/persona_sync.feature:25
    Given the workspace is initialized with agent surfaces #
features/steps/gz_steps.py:79
    When I run the gz command "validate --surfaces"        #
features/steps/gz_steps.py:209
    Then the command exits with code 0                     #
features/steps/gz_steps.py:220

Feature: Reporter rendering presets # features/reporter_rendering.feature:1
  The reporter module provides consistent Rich rendering for CLI tables and
panels.
  Scenario: status_table renders governance table
# features/reporter_rendering.feature:4
    Given a status_table with title "ADR Status" and columns "ADR,Lane,Status"
and 2 rows # features/steps/reporter_steps.py:13
    When the table is rendered to text
# features/steps/reporter_steps.py:66
    Then the rendered output contains "ADR Status"
# features/steps/reporter_steps.py:75
    And the rendered output contains "ADR-0.1.0"
# features/steps/reporter_steps.py:75

  Scenario: status_table renders empty state                                  #
features/reporter_rendering.feature:10
    Given a status_table with title "ADR Status" and columns "ADR" and 0 rows #
features/steps/reporter_steps.py:13
    When the table is rendered to text                                        #
features/steps/reporter_steps.py:66
    Then the rendered output contains "No data."                              #
features/steps/reporter_steps.py:75

  Scenario: kv_table renders key-value pairs           #
features/reporter_rendering.feature:15
    Given a kv_table with title "Overview" and 3 pairs #
features/steps/reporter_steps.py:32
    When the table is rendered to text                 #
features/steps/reporter_steps.py:66
    Then the rendered output contains "Overview"       #
features/steps/reporter_steps.py:75
    And the rendered output contains "Lane"            #
features/steps/reporter_steps.py:75
    And the rendered output contains "heavy"           #
features/steps/reporter_steps.py:75

  Scenario: ceremony_panel renders with double border        #
features/reporter_rendering.feature:22
    Given a ceremony_panel with title "Closeout" and 2 items #
features/steps/reporter_steps.py:38
    When the panel is rendered to text                       #
features/steps/reporter_steps.py:66
    Then the rendered output contains "Closeout"             #
features/steps/reporter_steps.py:75
    And the rendered output contains "Step 1"                #
features/steps/reporter_steps.py:75

  Scenario: list_table renders simple catalog                                  #
features/reporter_rendering.feature:28
    Given a list_table with title "Chores" and columns "Slug,Title" and 2 rows #
features/steps/reporter_steps.py:47
    When the table is rendered to text                                         #
features/steps/reporter_steps.py:66
    Then the rendered output contains "Chores"                                 #
features/steps/reporter_steps.py:75
    And the rendered output contains "chore-a"                                 #
features/steps/reporter_steps.py:75

  Scenario: list_table renders empty state                               #
features/reporter_rendering.feature:34
    Given a list_table with title "Skills" and columns "Name" and 0 rows #
features/steps/reporter_steps.py:47
    When the table is rendered to text                                   #
features/steps/reporter_steps.py:66
    Then the rendered output contains "No items found."                  #
features/steps/reporter_steps.py:75

Feature: OBPI reviewer agent dispatch  # OBPI-0.23.0-03 #
features/reviewer_agent.feature:1
  An independent reviewer agent verifies delivered work against OBPI
  promises with fresh-eyes assessment of promises-met, docs-quality,
  and closing-argument-quality.
  @review @dispatch
  Scenario: Reviewer prompt contains brief and closing argument           #
features/reviewer_agent.feature:7
    Given an OBPI brief with 2 requirements                               #
features/steps/reviewer_agent_steps.py:28
    And a closing argument "This work earned its closure by delivering X" #
features/steps/reviewer_agent_steps.py:35
    And 2 changed files and 1 doc file                                    #
features/steps/reviewer_agent_steps.py:45
    When I compose the reviewer prompt                                    #
features/steps/reviewer_agent_steps.py:52
    Then the prompt contains the OBPI identifier                          #
features/steps/reviewer_agent_steps.py:63
    And the prompt contains the brief content                             #
features/steps/reviewer_agent_steps.py:68
    And the prompt contains the closing argument                          #
features/steps/reviewer_agent_steps.py:73
    And the prompt contains all changed files                             #
features/steps/reviewer_agent_steps.py:78
    And the prompt contains the doc file                                  #
features/steps/reviewer_agent_steps.py:84
    And the prompt contains the assessment JSON schema                    #
features/steps/reviewer_agent_steps.py:90

  @review @dispatch
  Scenario: Reviewer prompt handles missing closing argument         #
features/reviewer_agent.feature:20
    Given an OBPI brief with 1 requirements                          #
features/steps/reviewer_agent_steps.py:28
    And no closing argument                                          #
features/steps/reviewer_agent_steps.py:40
    And 1 changed files and 0 doc file                               #
features/steps/reviewer_agent_steps.py:45
    When I compose the reviewer prompt                               #
features/steps/reviewer_agent_steps.py:52
    Then the reviewer prompt contains "No closing argument provided" #
features/steps/reviewer_agent_steps.py:99

  @review @parse
  Scenario: Valid PASS assessment is parsed from agent output          #
features/reviewer_agent.feature:28
    Given agent output with a valid PASS assessment for 2 requirements #
features/steps/reviewer_agent_steps.py:113
    When I parse the reviewer assessment                               #
features/steps/reviewer_agent_steps.py:170
    Then the assessment verdict is "PASS"                              #
features/steps/reviewer_agent_steps.py:175
    And 2 promise assessments are returned                             #
features/steps/reviewer_agent_steps.py:183
    And docs quality is "substantive"                                  #
features/steps/reviewer_agent_steps.py:191
    And closing argument quality is "earned"                           #
features/steps/reviewer_agent_steps.py:199

  @review @parse
  Scenario: Valid FAIL assessment is parsed from agent output  #
features/reviewer_agent.feature:37
    Given agent output with a valid FAIL assessment            #
features/steps/reviewer_agent_steps.py:133
    When I parse the reviewer assessment                       #
features/steps/reviewer_agent_steps.py:170
    Then the assessment verdict is "FAIL"                      #
features/steps/reviewer_agent_steps.py:175
    And docs quality is "missing"                              #
features/steps/reviewer_agent_steps.py:191
    And closing argument quality is "missing"                  #
features/steps/reviewer_agent_steps.py:199

  @review @parse
  Scenario: CONCERNS assessment with mixed promises                  #
features/reviewer_agent.feature:45
    Given agent output with a CONCERNS assessment and mixed promises #
features/steps/reviewer_agent_steps.py:147
    When I parse the reviewer assessment                             #
features/steps/reviewer_agent_steps.py:170
    Then the assessment verdict is "CONCERNS"                        #
features/steps/reviewer_agent_steps.py:175
    And promise 1 is met                                             #
features/steps/reviewer_agent_steps.py:207
    And promise 2 is not met                                         #
features/steps/reviewer_agent_steps.py:214

  @review @parse
  Scenario: Invalid agent output returns no assessment  #
features/reviewer_agent.feature:53
    Given agent output with no JSON block               #
features/steps/reviewer_agent_steps.py:164
    When I parse the reviewer assessment                #
features/steps/reviewer_agent_steps.py:170
    Then no assessment is returned                      #
features/steps/reviewer_agent_steps.py:221

  @review @artifact
  Scenario: Assessment artifact is stored alongside the brief  #
features/reviewer_agent.feature:59
    Given a parsed PASS reviewer assessment                    #
features/steps/reviewer_agent_steps.py:231
    And a temporary ADR package directory                      #
features/steps/reviewer_agent_steps.py:247
    When I store the reviewer assessment                       #
features/steps/reviewer_agent_steps.py:253
    Then a REVIEW artifact file exists in the briefs directory #
features/steps/reviewer_agent_steps.py:258
    And the artifact contains the verdict                      #
features/steps/reviewer_agent_steps.py:265
    And the artifact contains promise assessments              #
features/steps/reviewer_agent_steps.py:271

  @review @ceremony
  Scenario: Assessment is formatted for ceremony display        #
features/reviewer_agent.feature:68
    Given a parsed CONCERNS reviewer assessment with 3 promises #
features/steps/reviewer_agent_steps.py:282
    When I format the assessment for ceremony                   #
features/steps/reviewer_agent_steps.py:298
    Then the output contains a promise table with 3 rows        #
features/steps/reviewer_agent_steps.py:303
    And the output contains the docs quality                    #
features/steps/reviewer_agent_steps.py:314
    And the output contains the closing argument quality        #
features/steps/reviewer_agent_steps.py:319
    And the output contains the verdict                         #
features/steps/reviewer_agent_steps.py:324

Feature: State repair force-reconciliation # features/state_repair.feature:1
  The gz state --repair command force-reconciles all OBPI frontmatter
  status from ledger-derived state (ADR-0.0.9, OBPI-03).
  Scenario: Repair updates drifted frontmatter to match ledger  #
features/state_repair.feature:5
    Given the workspace is initialized                          #
features/steps/gz_steps.py:67
    And ADR-0.1.0 exists                                        #
features/steps/gz_steps.py:90
    And an OBPI brief exists with frontmatter status "Draft"    #
features/steps/state_repair_steps.py:14
    And the ledger marks OBPI-0.1.0-01 as completed             #
features/steps/state_repair_steps.py:29
    When I run the gz command "state --repair"                  #
features/steps/gz_steps.py:209
    Then the command exits with code 0                          #
features/steps/gz_steps.py:220
    And the OBPI brief frontmatter status is "Completed"        #
features/steps/state_repair_steps.py:48

  Scenario: Repair is idempotent                                 #
features/state_repair.feature:14
    Given the workspace is initialized                           #
features/steps/gz_steps.py:67
    And ADR-0.1.0 exists                                         #
features/steps/gz_steps.py:90
    And an OBPI brief exists with frontmatter status "Completed" #
features/steps/state_repair_steps.py:14
    And the ledger marks OBPI-0.1.0-01 as completed              #
features/steps/state_repair_steps.py:29
    When I run the gz command "state --repair"                   #
features/steps/gz_steps.py:209
    And I run the gz command "state --repair --json"             #
features/steps/gz_steps.py:209
    Then the command exits with code 0                           #
features/steps/gz_steps.py:220
    And the JSON output field "total" equals 0                   #
features/steps/state_repair_steps.py:56

  Scenario: Repair reports changes in JSON mode              #
features/state_repair.feature:24
    Given the workspace is initialized                       #
features/steps/gz_steps.py:67
    And ADR-0.1.0 exists                                     #
features/steps/gz_steps.py:90
    And an OBPI brief exists with frontmatter status "Draft" #
features/steps/state_repair_steps.py:14
    And the ledger marks OBPI-0.1.0-01 as completed          #
features/steps/state_repair_steps.py:29
    When I run the gz command "state --repair --json"        #
features/steps/gz_steps.py:209
    Then the command exits with code 0                       #
features/steps/gz_steps.py:220
    And the JSON output field "total" equals 1               #
features/steps/state_repair_steps.py:56

Feature: Subagent pipeline dispatch lifecycle #
features/subagent_pipeline.feature:1
  Stage 2 controller dispatches implementer subagents per plan task
  with model-aware routing and structured result handling.
  @dispatch
  Scenario: Tasks are extracted from a heading-format plan  #
features/subagent_pipeline.feature:6
    Given a plan with heading-format tasks                  #
features/steps/subagent_pipeline_steps.py:36
    When I extract plan tasks                               #
features/steps/subagent_pipeline_steps.py:53
    Then 3 tasks are found                                  #
features/steps/subagent_pipeline_steps.py:58
    And task 1 description is "Add the model"               #
features/steps/subagent_pipeline_steps.py:65

  @dispatch
  Scenario: Tasks are extracted from a numbered-list plan  #
features/subagent_pipeline.feature:13
    Given a plan with numbered-list tasks                  #
features/steps/subagent_pipeline_steps.py:43
    When I extract plan tasks                              #
features/steps/subagent_pipeline_steps.py:53
    Then 2 tasks are found                                 #
features/steps/subagent_pipeline_steps.py:58

  @dispatch
  Scenario: Empty plan yields zero tasks  #
features/subagent_pipeline.feature:19
    Given an empty plan                   #
features/steps/subagent_pipeline_steps.py:48
    When I extract plan tasks             #
features/steps/subagent_pipeline_steps.py:53
    Then 0 tasks are found                #
features/steps/subagent_pipeline_steps.py:58

  @dispatch
  Scenario: Simple task routes to haiku model              #
features/subagent_pipeline.feature:25
    Given a dispatch state with 1 task and 2 allowed paths #
features/steps/subagent_pipeline_steps.py:76
    Then task 1 model is "haiku"                           #
features/steps/subagent_pipeline_steps.py:99
    And task 1 complexity is "simple"                      #
features/steps/subagent_pipeline_steps.py:105

  @dispatch
  Scenario: Standard task routes to sonnet model           #
features/subagent_pipeline.feature:31
    Given a dispatch state with 1 task and 4 allowed paths #
features/steps/subagent_pipeline_steps.py:76
    Then task 1 model is "sonnet"                          #
features/steps/subagent_pipeline_steps.py:99
    And task 1 complexity is "standard"                    #
features/steps/subagent_pipeline_steps.py:105

  @dispatch
  Scenario: Complex task routes to opus model              #
features/subagent_pipeline.feature:37
    Given a dispatch state with 1 task and 7 allowed paths #
features/steps/subagent_pipeline_steps.py:76
    Then task 1 model is "opus"                            #
features/steps/subagent_pipeline_steps.py:99
    And task 1 complexity is "complex"                     #
features/steps/subagent_pipeline_steps.py:105

  @dispatch
  Scenario: DONE result advances to next task               #
features/subagent_pipeline.feature:43
    Given a dispatch state with 2 tasks and 1 allowed paths #
features/steps/subagent_pipeline_steps.py:76
    And task 1 is dispatched                                #
features/steps/subagent_pipeline_steps.py:84
    When task 1 returns DONE                                #
features/steps/subagent_pipeline_steps.py:118
    Then the dispatch action is "advance"                   #
features/steps/subagent_pipeline_steps.py:142
    And task 1 status is "done"                             #
features/steps/subagent_pipeline_steps.py:149

  @dispatch
  Scenario: DONE on last task completes dispatch           #
features/subagent_pipeline.feature:51
    Given a dispatch state with 1 task and 1 allowed paths #
features/steps/subagent_pipeline_steps.py:76
    And task 1 is dispatched                               #
features/steps/subagent_pipeline_steps.py:84
    When task 1 returns DONE                               #
features/steps/subagent_pipeline_steps.py:118
    Then the dispatch action is "complete"                 #
features/steps/subagent_pipeline_steps.py:142

  @dispatch
  Scenario: DONE_WITH_CONCERNS logs concerns and advances               #
features/subagent_pipeline.feature:58
    Given a dispatch state with 2 tasks and 1 allowed paths             #
features/steps/subagent_pipeline_steps.py:76
    And task 1 is dispatched                                            #
features/steps/subagent_pipeline_steps.py:84
    When task 1 returns DONE_WITH_CONCERNS with concern "might break X" #
features/steps/subagent_pipeline_steps.py:136
    Then the dispatch action is "advance"                               #
features/steps/subagent_pipeline_steps.py:142
    And all concerns include "might break X"                            #
features/steps/subagent_pipeline_steps.py:155

  @dispatch
  Scenario: NEEDS_CONTEXT triggers redispatch              #
features/subagent_pipeline.feature:66
    Given a dispatch state with 1 task and 1 allowed paths #
features/steps/subagent_pipeline_steps.py:76
    And task 1 is dispatched                               #
features/steps/subagent_pipeline_steps.py:84
    When task 1 returns NEEDS_CONTEXT                      #
features/steps/subagent_pipeline_steps.py:124
    Then the dispatch action is "redispatch"               #
features/steps/subagent_pipeline_steps.py:142

  @dispatch
  Scenario: NEEDS_CONTEXT circuit breaker after max retries  #
features/subagent_pipeline.feature:73
    Given a dispatch state with 1 task and 1 allowed paths   #
features/steps/subagent_pipeline_steps.py:76
    And task 1 has been dispatched 2 times                   #
features/steps/subagent_pipeline_steps.py:90
    When task 1 returns NEEDS_CONTEXT                        #
features/steps/subagent_pipeline_steps.py:124
    Then the dispatch action is "handoff"                    #
features/steps/subagent_pipeline_steps.py:142
    And task 1 status is "blocked"                           #
features/steps/subagent_pipeline_steps.py:149

  @dispatch
  Scenario: BLOCKED triggers fix attempt                   #
features/subagent_pipeline.feature:81
    Given a dispatch state with 1 task and 1 allowed paths #
features/steps/subagent_pipeline_steps.py:76
    And task 1 is dispatched                               #
features/steps/subagent_pipeline_steps.py:84
    When task 1 returns BLOCKED                            #
features/steps/subagent_pipeline_steps.py:130
    Then the dispatch action is "fix"                      #
features/steps/subagent_pipeline_steps.py:142

  @dispatch
  Scenario: BLOCKED after max fix attempts triggers handoff  #
features/subagent_pipeline.feature:88
    Given a dispatch state with 1 task and 1 allowed paths   #
features/steps/subagent_pipeline_steps.py:76
    And task 1 has been dispatched 2 times                   #
features/steps/subagent_pipeline_steps.py:90
    When task 1 returns BLOCKED                              #
features/steps/subagent_pipeline_steps.py:130
    Then the dispatch action is "handoff"                    #
features/steps/subagent_pipeline_steps.py:142
    And task 1 status is "blocked"                           #
features/steps/subagent_pipeline_steps.py:149

  @dispatch
  Scenario: Prompt includes allowed files and rules                           #
features/subagent_pipeline.feature:96
    Given a dispatch task for "Add validation" with paths "src/a.py,src/b.py" #
features/steps/subagent_pipeline_steps.py:167
    When I compose the implementer prompt                                     #
features/steps/subagent_pipeline_steps.py:179
    Then the prompt contains "src/a.py"                                       #
features/steps/subagent_pipeline_steps.py:184
    And the prompt contains "### Rules"                                       #
features/steps/subagent_pipeline_steps.py:184

  @dispatch
  Scenario: Result JSON is parsed from agent output  #
features/subagent_pipeline.feature:103
    Given agent output with a DONE result JSON block #
features/steps/subagent_pipeline_steps.py:194
    When I parse the handoff result                  #
features/steps/subagent_pipeline_steps.py:205
    Then the parsed status is "DONE"                 #
features/steps/subagent_pipeline_steps.py:210
    And the parsed files changed include "src/x.py"  #
features/steps/subagent_pipeline_steps.py:218

  @dispatch
  Scenario: Dispatch record tracks subagent lifecycle
# features/subagent_pipeline.feature:110
    Given a subagent dispatch record for task 1 as "Implementer" with model
"sonnet" # features/steps/subagent_pipeline_steps.py:230
    When the dispatch record is completed with status "done"
# features/steps/subagent_pipeline_steps.py:235
    Then the completed record has a completion timestamp
# features/steps/subagent_pipeline_steps.py:240
    And the completed record status is "done"
# features/steps/subagent_pipeline_steps.py:245

  @dispatch
  Scenario: Dispatch aggregation computes correct totals
# features/subagent_pipeline.feature:117
    Given 3 completed dispatch records with statuses
"done,blocked,done_with_concerns" #
features/steps/subagent_pipeline_steps.py:250
    When I aggregate dispatch results
# features/steps/subagent_pipeline_steps.py:260
    Then aggregation shows 2 completed and 1 blocked
# features/steps/subagent_pipeline_steps.py:265

  @dispatch
  Scenario: Model routing loads defaults     #
features/subagent_pipeline.feature:123
    Given no pipeline config file            #
features/steps/subagent_pipeline_steps.py:275
    When I load model routing config         #
features/steps/subagent_pipeline_steps.py:281
    Then implementer simple model is "haiku" #
features/steps/subagent_pipeline_steps.py:286
    And reviewer complex model is "opus"     #
features/steps/subagent_pipeline_steps.py:291

  @dispatch
  Scenario: Agent file validation detects missing files  #
features/subagent_pipeline.feature:130
    Given a project directory with no agent files        #
features/steps/subagent_pipeline_steps.py:296
    When I validate agent files                          #
features/steps/subagent_pipeline_steps.py:302
    Then validation finds 4 errors                       #
features/steps/subagent_pipeline_steps.py:307

  @dispatch @stage2
  Scenario: Stage 2 dispatch loop executes tasks sequentially
# features/subagent_pipeline.feature:136
    Given a plan with 3 tasks
# features/steps/subagent_pipeline_steps.py:319
    And allowed paths ["src/a.py", "src/b.py"]
# features/steps/subagent_pipeline_steps.py:324
    And brief requirements ["Config MUST parse TOML", "Validation MUST reject
nulls"]  # features/steps/subagent_pipeline_steps.py:329
    When the controller creates dispatch state for "OBPI-0.18.0-06" under
"ADR-0.18.0" # features/steps/subagent_pipeline_steps.py:334
    And dispatches each task sequentially with DONE results
# features/steps/subagent_pipeline_steps.py:341
    Then all 3 tasks are completed
# features/steps/subagent_pipeline_steps.py:356
    And dispatch state is finished
# features/steps/subagent_pipeline_steps.py:363
    And each task prompt includes brief requirements
# features/steps/subagent_pipeline_steps.py:368

  @dispatch @stage2
  Scenario: Stage 2 halts on BLOCKED task after fix attempts              #
features/subagent_pipeline.feature:147
    Given a plan with 2 tasks                                             #
features/steps/subagent_pipeline_steps.py:319
    And allowed paths ["src/a.py"]                                        #
features/steps/subagent_pipeline_steps.py:324
    When the controller creates dispatch state for "OBPI-X" under "ADR-X" #
features/steps/subagent_pipeline_steps.py:334
    And task 1 is dispatched                                              #
features/steps/subagent_pipeline_steps.py:84
    And task 1 returns BLOCKED                                            #
features/steps/subagent_pipeline_steps.py:130
    Then the dispatch action is "fix"                                     #
features/steps/subagent_pipeline_steps.py:142
    When task 1 is dispatched                                             #
features/steps/subagent_pipeline_steps.py:84
    And task 1 returns BLOCKED                                            #
features/steps/subagent_pipeline_steps.py:130
    Then the dispatch action is "handoff"                                 #
features/steps/subagent_pipeline_steps.py:142
    And task 2 remains pending                                            #
features/steps/subagent_pipeline_steps.py:376
    And dispatch state has 1 blocked task                                 #
features/steps/subagent_pipeline_steps.py:386

  @dispatch @review
  Scenario: Review dispatched after DONE task with both passing  #
features/subagent_pipeline.feature:161
    Given a dispatch state with 2 tasks and 2 allowed paths      #
features/steps/subagent_pipeline_steps.py:76
    And task 1 is dispatched                                     #
features/steps/subagent_pipeline_steps.py:84
    When task 1 returns DONE                                     #
features/steps/subagent_pipeline_steps.py:118
    Then review should be dispatched for task 1                  #
features/steps/subagent_pipeline_steps.py:398
    When both reviews pass for task 1                            #
features/steps/subagent_pipeline_steps.py:420
    Then the review action is "advance"                          #
features/steps/subagent_pipeline_steps.py:432

  @dispatch @review
  Scenario: Review not dispatched for BLOCKED task         #
features/subagent_pipeline.feature:170
    Given a dispatch state with 1 task and 1 allowed paths #
features/steps/subagent_pipeline_steps.py:76
    And task 1 is dispatched                               #
features/steps/subagent_pipeline_steps.py:84
    When task 1 returns BLOCKED                            #
features/steps/subagent_pipeline_steps.py:130
    Then review should not be dispatched for task 1        #
features/steps/subagent_pipeline_steps.py:409

  @dispatch @review
  Scenario: Critical spec finding triggers fix cycle       #
features/subagent_pipeline.feature:177
    Given a dispatch state with 1 task and 2 allowed paths #
features/steps/subagent_pipeline_steps.py:76
    And task 1 is dispatched                               #
features/steps/subagent_pipeline_steps.py:84
    When task 1 returns DONE                               #
features/steps/subagent_pipeline_steps.py:118
    And spec review finds critical issue for task 1        #
features/steps/subagent_pipeline_steps.py:439
    Then the review action is "fix"                        #
features/steps/subagent_pipeline_steps.py:432
    And task 1 review fix count is 1                       #
features/steps/subagent_pipeline_steps.py:458

  @dispatch @review
  Scenario: Review blocked after max fix cycles            #
features/subagent_pipeline.feature:186
    Given a dispatch state with 1 task and 2 allowed paths #
features/steps/subagent_pipeline_steps.py:76
    And task 1 is dispatched                               #
features/steps/subagent_pipeline_steps.py:84
    When task 1 returns DONE                               #
features/steps/subagent_pipeline_steps.py:118
    And spec review finds critical issue for task 1        #
features/steps/subagent_pipeline_steps.py:439
    Then the review action is "fix"                        #
features/steps/subagent_pipeline_steps.py:432
    When spec review finds critical issue for task 1       #
features/steps/subagent_pipeline_steps.py:439
    Then the review action is "fix"                        #
features/steps/subagent_pipeline_steps.py:432
    When spec review finds critical issue for task 1       #
features/steps/subagent_pipeline_steps.py:439
    Then the review action is "blocked"                    #
features/steps/subagent_pipeline_steps.py:432

  @dispatch @stage3
  Scenario: Stage 3 builds verification plan from brief requirements  #
features/subagent_pipeline.feature:198
    Given a brief with 2 requirements and distinct test paths         #
features/steps/subagent_pipeline_steps.py:471
    When I prepare Stage 3 verification                               #
features/steps/subagent_pipeline_steps.py:498
    Then the verification plan has 2 scopes                           #
features/steps/subagent_pipeline_steps.py:509
    And the verification strategy is "parallel"                       #
features/steps/subagent_pipeline_steps.py:516

  @dispatch @stage3
  Scenario: Stage 3 falls back to sequential with no test paths  #
features/subagent_pipeline.feature:205
    Given a brief with 2 requirements and no test paths          #
features/steps/subagent_pipeline_steps.py:488
    When I prepare Stage 3 verification                          #
features/steps/subagent_pipeline_steps.py:498
    Then the verification strategy is "sequential"               #
features/steps/subagent_pipeline_steps.py:516

  @dispatch @stage3
  Scenario: Stage 3 records timing metrics
# features/subagent_pipeline.feature:211
    Given a verification run of 5 seconds with strategy "parallel" and 3 groups
# features/steps/subagent_pipeline_steps.py:523
    When I compute verification timing
# features/steps/subagent_pipeline_steps.py:531
    Then elapsed seconds is 5.0
# features/steps/subagent_pipeline_steps.py:543
    And time saved is greater than 0
# features/steps/subagent_pipeline_steps.py:550

  @dispatch @stage3
  Scenario: Stage 3 creates dispatch records from verification results  #
features/subagent_pipeline.feature:218
    Given a verification plan with 2 scopes and PASS results            #
features/steps/subagent_pipeline_steps.py:557
    When I create verification dispatch records                         #
features/steps/subagent_pipeline_steps.py:589
    Then 2 dispatch records are created                                 #
features/steps/subagent_pipeline_steps.py:598
    And all dispatch records have role "Verifier"                       #
features/steps/subagent_pipeline_steps.py:605
    And all dispatch records have stage 3                               #
features/steps/subagent_pipeline_steps.py:611

Feature: Task lifecycle governance # features/task_governance.feature:1
  TASK entities have lifecycle commands via gz task CLI.
  Scenario: gz task --help shows subcommands  #
features/task_governance.feature:4
    Given the workspace is initialized        # features/steps/gz_steps.py:67
    When I run the gz command "task --help"   # features/steps/gz_steps.py:209
    Then the command exits with code 0        # features/steps/gz_steps.py:220
    And the output contains "list"            # features/steps/gz_steps.py:225
    And the output contains "start"           # features/steps/gz_steps.py:225
    And the output contains "complete"        # features/steps/gz_steps.py:225
    And the output contains "block"           # features/steps/gz_steps.py:225
    And the output contains "escalate"        # features/steps/gz_steps.py:225

  Scenario: gz task list shows no tasks when none exist  #
features/task_governance.feature:14
    Given the workspace is initialized                   #
features/steps/gz_steps.py:67
    And ADR-0.1.0 exists                                 #
features/steps/gz_steps.py:90
    And an OBPI exists for ADR-0.1.0                     #
features/steps/task_governance_steps.py:28
    When I run the gz command "task list OBPI-0.1.0-01"  #
features/steps/gz_steps.py:209
    Then the command exits with code 0                   #
features/steps/gz_steps.py:220
    And the output contains "No tasks found"             #
features/steps/gz_steps.py:225

  Scenario: gz task start transitions pending to in_progress   #
features/task_governance.feature:22
    Given the workspace is initialized                         #
features/steps/gz_steps.py:67
    And ADR-0.1.0 exists                                       #
features/steps/gz_steps.py:90
    And an OBPI exists for ADR-0.1.0                           #
features/steps/task_governance_steps.py:28
    And a pending task TASK-0.1.0-01-01-01 exists              #
features/steps/task_governance_steps.py:40
    When I run the gz command "task start TASK-0.1.0-01-01-01" #
features/steps/gz_steps.py:209
    Then the command exits with code 0                         #
features/steps/gz_steps.py:220
    And the output contains "Started"                          #
features/steps/gz_steps.py:225

  Scenario: gz task complete on pending task fails                #
features/task_governance.feature:31
    Given the workspace is initialized                            #
features/steps/gz_steps.py:67
    And ADR-0.1.0 exists                                          #
features/steps/gz_steps.py:90
    And an OBPI exists for ADR-0.1.0                              #
features/steps/task_governance_steps.py:28
    When I run the gz command "task complete TASK-0.1.0-01-01-01" #
features/steps/gz_steps.py:209
    Then the command exits non-zero                               #
features/steps/gz_steps.py:215
    And the output contains "Invalid TASK transition"             #
features/steps/gz_steps.py:225

  Scenario: gz task block records reason
# features/task_governance.feature:39
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And ADR-0.1.0 exists
# features/steps/gz_steps.py:90
    And an OBPI exists for ADR-0.1.0
# features/steps/task_governance_steps.py:28
    And a pending task TASK-0.1.0-01-01-01 exists
# features/steps/task_governance_steps.py:40
    And I run the gz command "task start TASK-0.1.0-01-01-01"
# features/steps/task_governance_steps.py:34
    When I run the gz command "task block TASK-0.1.0-01-01-01 --reason
Missing_API" # features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220
    And the output contains "Blocked"
# features/steps/gz_steps.py:225

  Scenario: gz task start resumes a blocked task                               #
features/task_governance.feature:49
    Given the workspace is initialized                                         #
features/steps/gz_steps.py:67
    And ADR-0.1.0 exists                                                       #
features/steps/gz_steps.py:90
    And an OBPI exists for ADR-0.1.0                                           #
features/steps/task_governance_steps.py:28
    And a pending task TASK-0.1.0-01-01-01 exists                              #
features/steps/task_governance_steps.py:40
    And I run the gz command "task start TASK-0.1.0-01-01-01"                  #
features/steps/task_governance_steps.py:34
    And I run the gz command "task block TASK-0.1.0-01-01-01 --reason blocked" #
features/steps/task_governance_steps.py:34
    When I run the gz command "task start TASK-0.1.0-01-01-01"                 #
features/steps/gz_steps.py:209
    Then the command exits with code 0                                         #
features/steps/gz_steps.py:220
    And the output contains "Resumed"                                          #
features/steps/gz_steps.py:225

  Scenario: gz task list --json returns valid JSON             #
features/task_governance.feature:60
    Given the workspace is initialized                         #
features/steps/gz_steps.py:67
    And ADR-0.1.0 exists                                       #
features/steps/gz_steps.py:90
    And an OBPI exists for ADR-0.1.0                           #
features/steps/task_governance_steps.py:28
    And a pending task TASK-0.1.0-01-01-01 exists              #
features/steps/task_governance_steps.py:40
    And I run the gz command "task start TASK-0.1.0-01-01-01"  #
features/steps/task_governance_steps.py:34
    When I run the gz command "task list OBPI-0.1.0-01 --json" #
features/steps/gz_steps.py:209
    Then the command exits with code 0                         #
features/steps/gz_steps.py:220
    And the output is valid JSON                               #
features/steps/task_governance_steps.py:45

  Scenario: gz task escalate records reason
# features/task_governance.feature:70
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And ADR-0.1.0 exists
# features/steps/gz_steps.py:90
    And an OBPI exists for ADR-0.1.0
# features/steps/task_governance_steps.py:28
    And a pending task TASK-0.1.0-01-01-01 exists
# features/steps/task_governance_steps.py:40
    And I run the gz command "task start TASK-0.1.0-01-01-01"
# features/steps/task_governance_steps.py:34
    When I run the gz command "task escalate TASK-0.1.0-01-01-01 --reason
Needs_human_decision" # features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220
    And the output contains "Escalated"
# features/steps/gz_steps.py:225

  Scenario: gz status shows task summary when tasks exist     #
features/task_governance.feature:81
    Given the workspace is initialized                        #
features/steps/gz_steps.py:67
    And ADR-0.1.0 exists                                      #
features/steps/gz_steps.py:90
    And an OBPI exists for ADR-0.1.0                          #
features/steps/task_governance_steps.py:28
    And a pending task TASK-0.1.0-01-01-01 exists             #
features/steps/task_governance_steps.py:40
    And I run the gz command "task start TASK-0.1.0-01-01-01" #
features/steps/task_governance_steps.py:34
    When I run the gz command "status"                        #
features/steps/gz_steps.py:209
    Then the command exits with code 0                        #
features/steps/gz_steps.py:220
    And the output contains "Tasks:"                          #
features/steps/gz_steps.py:225

  Scenario: gz status omits task section when no tasks exist  #
features/task_governance.feature:91
    Given the workspace is initialized                        #
features/steps/gz_steps.py:67
    And ADR-0.1.0 exists                                      #
features/steps/gz_steps.py:90
    And an OBPI exists for ADR-0.1.0                          #
features/steps/task_governance_steps.py:28
    When I run the gz command "status"                        #
features/steps/gz_steps.py:209
    Then the command exits with code 0                        #
features/steps/gz_steps.py:220

  Scenario: gz status shows escalated count
# features/task_governance.feature:98
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And ADR-0.1.0 exists
# features/steps/gz_steps.py:90
    And an OBPI exists for ADR-0.1.0
# features/steps/task_governance_steps.py:28
    And a pending task TASK-0.1.0-01-01-01 exists
# features/steps/task_governance_steps.py:40
    And I run the gz command "task start TASK-0.1.0-01-01-01"
# features/steps/task_governance_steps.py:34
    And I run the gz command "task escalate TASK-0.1.0-01-01-01 --reason
Needs_review" # features/steps/task_governance_steps.py:34
    When I run the gz command "status"
# features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220
    And the output contains "escalated"
# features/steps/gz_steps.py:225

  Scenario: gz state --json includes task data                #
features/task_governance.feature:109
    Given the workspace is initialized                        #
features/steps/gz_steps.py:67
    And ADR-0.1.0 exists                                      #
features/steps/gz_steps.py:90
    And an OBPI exists for ADR-0.1.0                          #
features/steps/task_governance_steps.py:28
    And a pending task TASK-0.1.0-01-01-01 exists             #
features/steps/task_governance_steps.py:40
    And I run the gz command "task start TASK-0.1.0-01-01-01" #
features/steps/task_governance_steps.py:34
    When I run the gz command "state --json"                  #
features/steps/gz_steps.py:209
    Then the command exits with code 0                        #
features/steps/gz_steps.py:220
    And the output is valid JSON                              #
features/steps/task_governance_steps.py:45

Feature: Requirement coverage reporting CLI #
features/test_traceability.feature:1
  The gz covers command reports requirement coverage from @covers
  annotations at ADR, OBPI, and REQ granularity.
  Scenario: All-REQ coverage summary exits with code 0
# features/test_traceability.feature:5
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And ADR-0.1.0 exists
# features/steps/gz_steps.py:90
    And an OBPI brief with one REQ and a decorator-covered test exists
# features/steps/test_traceability_steps.py:13
    When I run the gz command "covers --json --adr-dir design/adr --test-dir
tests" # features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220
    And JSON path "summary.total_reqs" equals "1"
# features/steps/gz_steps.py:241
    And JSON path "summary.covered_reqs" equals "1"
# features/steps/gz_steps.py:241

  Scenario: Filter by ADR shows only matching REQs
# features/test_traceability.feature:14
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And ADR-0.1.0 exists
# features/steps/gz_steps.py:90
    And an OBPI brief with one REQ and a decorator-covered test exists
# features/steps/test_traceability_steps.py:13
    When I run the gz command "covers ADR-0.1.0 --json --adr-dir design/adr
--test-dir tests" # features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220
    And JSON path "summary.total_reqs" equals "1"
# features/steps/gz_steps.py:241

  Scenario: Plain output is one-per-line
# features/test_traceability.feature:22
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And ADR-0.1.0 exists
# features/steps/gz_steps.py:90
    And an OBPI brief with one REQ and a decorator-covered test exists
# features/steps/test_traceability_steps.py:13
    When I run the gz command "covers --plain --adr-dir design/adr --test-dir
tests" # features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220
    And the output contains "covered"
# features/steps/gz_steps.py:225

  Scenario: Help text shows description and options  #
features/test_traceability.feature:30
    When I run the gz command "covers --help"        #
features/steps/gz_steps.py:209
    Then the command exits with code 0               #
features/steps/gz_steps.py:220
    And the output contains "--json"                 #
features/steps/gz_steps.py:225
    And the output contains "--plain"                #
features/steps/gz_steps.py:225

  Scenario: No REQs found returns empty summary
# features/test_traceability.feature:36
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And ADR-0.1.0 exists
# features/steps/gz_steps.py:90
    When I run the gz command "covers --json --adr-dir design/adr --test-dir
tests" # features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220
    And JSON path "summary.total_reqs" equals "0"
# features/steps/gz_steps.py:241

  Scenario: Audit-check includes coverage section in JSON output  #
features/test_traceability.feature:43
    Given the workspace is initialized                            #
features/steps/gz_steps.py:67
    And ADR-0.1.0 exists                                          #
features/steps/gz_steps.py:90
    And an OBPI brief with covered and uncovered REQs exists      #
features/steps/test_traceability_steps.py:50
    When I run the gz command "adr audit-check ADR-0.1.0 --json"  #
features/steps/gz_steps.py:209
    Then JSON path "coverage.total_reqs" equals "2"               #
features/steps/gz_steps.py:241
    And JSON path "coverage.covered_reqs" equals "1"              #
features/steps/gz_steps.py:241
    And JSON path "coverage.uncovered_reqs" equals "1"            #
features/steps/gz_steps.py:241

  Scenario: Audit-check flags uncovered REQs as blocking coverage findings  #
features/test_traceability.feature:52
    Given the workspace is initialized                                      #
features/steps/gz_steps.py:67
    And ADR-0.1.0 exists                                                    #
features/steps/gz_steps.py:90
    And an OBPI brief with covered and uncovered REQs exists                #
features/steps/test_traceability_steps.py:50
    When I run the gz command "adr audit-check ADR-0.1.0 --json"            #
features/steps/gz_steps.py:209
    Then the command exits with code 1                                      #
features/steps/gz_steps.py:220
    And JSON path "coverage_findings" is not empty                          #
features/steps/test_traceability_steps.py:88
    And JSON path "passed" equals "False"                                   #
features/steps/gz_steps.py:241

Feature: Spec-test-code drift detection CLI # features/triangle_drift.feature:1
  The gz drift command detects governance drift by scanning OBPI briefs,
  test @covers references, and the active code change set.
  Scenario: No drift detected exits with code 0
# features/triangle_drift.feature:5
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And ADR-0.1.0 exists
# features/steps/gz_steps.py:90
    And an OBPI brief with one REQ and a matching test exists
# features/steps/triangle_drift_steps.py:12
    When I run the gz command "drift --json --adr-dir design/adr --test-dir
tests" # features/steps/gz_steps.py:209
    Then the command exits with code 0
# features/steps/gz_steps.py:220
    And JSON path "summary.total_drift_count" equals "0"
# features/steps/gz_steps.py:241

  Scenario: Unlinked spec exits with code 1
# features/triangle_drift.feature:13
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And ADR-0.1.0 exists
# features/steps/gz_steps.py:90
    And an OBPI brief with one REQ and no matching test exists
# features/steps/triangle_drift_steps.py:47
    When I run the gz command "drift --json --adr-dir design/adr --test-dir
tests" # features/steps/gz_steps.py:209
    Then the command exits with code 1
# features/steps/gz_steps.py:220
    And JSON path "summary.unlinked_spec_count" equals "1"
# features/steps/gz_steps.py:241

  Scenario: Plain output is one-per-line
# features/triangle_drift.feature:21
    Given the workspace is initialized
# features/steps/gz_steps.py:67
    And ADR-0.1.0 exists
# features/steps/gz_steps.py:90
    And an OBPI brief with one REQ and no matching test exists
# features/steps/triangle_drift_steps.py:47
    When I run the gz command "drift --plain --adr-dir design/adr --test-dir
tests" # features/steps/gz_steps.py:209
    Then the command exits with code 1
# features/steps/gz_steps.py:220
    And the output contains "unlinked"
# features/steps/gz_steps.py:225

  Scenario: Help text shows description and options  #
features/triangle_drift.feature:29
    When I run the gz command "drift --help"         #
features/steps/gz_steps.py:209
    Then the command exits with code 0               #
features/steps/gz_steps.py:220
    And the output contains "--json"                 #
features/steps/gz_steps.py:225
    And the output contains "--plain"                #
features/steps/gz_steps.py:225

29 features passed, 0 failed, 0 skipped
200 scenarios passed, 0 failed, 0 skipped
1058 steps passed, 0 failed, 0 skipped
Took 0min 5.758s

LOG_WARNING:gzkit.triangle: Malformed REQ line (skipped): - [ ]
REQ-FIXTURE-01-01: gate fires.
LOG_WARNING:gzkit.triangle: Malformed REQ line (skipped): - [ ]
REQ-FIXTURE-01-01: gate fires.

  ✓ Gate 4 (BDD): PASS
  ⚠ Gate 5 (Human): PENDING (manual)
