Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help


id: cli.core kind: intent statement: “WHEN the tool adopts genesis::guide or a user runs ah sync THE CLI SHALL build the scaffold via Guide::builder, return Output or use ErrorSink with errors surfaced via suggestion footers, create or refresh property-derived contracts for the current scope, exit non-zero when spk lint fails or spk is unavailable, and support a check mode that writes nothing and fails on drift.”


cli-core spec delta: adopt genesis::guide

Constraints

idkindexprtraces_to
C-guide-builderinvariantthe tool’s main.rs CLI setup uses genesis::guide::Guide::builder() when the tool adopts genesis::guide (adoption is the maintainer’s decision — this spec fixes the contract, not the timing), with cargo test passing[[cli.core]]
C-output-handlersadvisorycommand handlers SHOULD return Output<T> or use ErrorSink[[cli.core]]
C-errorsink-selfhealadvisoryon a command error, ErrorSink SHOULD print the error with a suggestion footer and write to the error scratch (for --from-last-error)[[cli.core]]
C-sync-refusalinvariantah sync exits non-zero without writing when spk lint fails on any target file or when the spk binary is missing, reporting spk-unavailable for the latter[[cli.core]]
C-sync-checkinvariantah sync –check writes nothing, exits zero when all derived contracts exist and are fresh, and exits non-zero on drift or missing contracts[[cli.core]]
C-sync-registrationinvariantah sync is registered in the Command enum with help text and completions like every other subcommand[[cli.core]]
C-sync-scopeadvisorywithout an explicit scope, ah sync operates on the same default scope as ah check[[cli.core]]

Model

States

  • ad-hoc-cli
  • guide-built
  • linting
  • parsing
  • written
  • checked

Transitions

idfromtoguard
t-buildad-hoc-cliguide-built[[cli.core.C-guide-builder]]
t-refuselintinglinting[[cli.core.C-sync-refusal]]
t-parselintingparsing[[cli.core.C-sync-refusal]]
t-writeparsingwritten[[cli.core.C-sync-registration]]
t-checkparsingchecked[[cli.core.C-sync-check]]

Properties

idkindderives_fromgeneratorpredicate
P-guide-builderunit[[cli.core.C-guide-builder]]the adopted main.rsCLI setup is constructed via Guide::builder() and tests pass
P-handlersunit[[cli.core.C-output-handlers]]each command handlerhandlers return Output<T> or use ErrorSink where the advisory is honored
P-selfhealunit[[cli.core.C-errorsink-selfheal]]a failing command runthe error prints with a suggestion footer and lands in the error scratch readable by --from-last-error
P-refuseunit[[cli.core.C-sync-refusal]]a scope containing a lint-dirty dual-format file, and a scope with no spk binary on PATHsync exits non-zero with a reason in both cases and writes nothing
P-checkunit[[cli.core.C-sync-check]]a scope with fresh contracts, drifted contracts, and missing contractscheck mode exits zero, non-zero, and non-zero respectively; no file is modified in any case
P-registerunit[[cli.core.C-sync-registration]]ah –help and shell completion generationsync appears with help text and completes like other subcommands
P-scopeunit[[cli.core.C-sync-scope]]sync invoked with and without an explicit scopethe default scope matches ah check’s default scope

Purpose

Adopt genesis::guide for the CLI scaffold: Guide::builder() replaces ad-hoc setup, handlers standardize on Output<T>/ErrorSink, and errors become self-healing via suggestion footers and the error scratch.

Give adopters a single command that turns lint-clean Properties rows into gate-readable contracts, safely refreshable in CI via --check.

Non-Goals

  • Changing ah check scope resolution, findings, or exit-code semantics — owned by the gate spec
  • Defining contract file format or derived_from semantics — owned by the gate spec’s Contract Schema and Property-Derived Contracts requirements
  • Authoring or repairing spec text: ah sync derives contracts from existing lint-clean rows, it never edits the specs themselves
  • Vendoring or wrapping spk behavior: lint rules and their semantics live upstream in specodelic

Requirements

Requirement: CLI scaffold uses Guide

The tool’s main.rs CLI setup SHALL use genesis::guide::Guide::builder() when the tool adopts genesis::guide. Adoption is determined by the tool’s maintainer — this spec defines the contract for how to do it.

Scenario: Guide builder replaces ad-hoc setup

  • GIVEN the tool adopts genesis::guide
  • WHEN main.rs is updated to use Guide::builder(...)
  • THEN command handlers SHOULD return Output<T> or use ErrorSink
  • AND cargo test SHALL pass
  • VERIFIES [[cli.core.P-guide-builder]]

Scenario: ErrorSink for self-healing errors

  • GIVEN the tool adopts genesis::guide
  • WHEN a command returns an error
  • THEN ErrorSink SHOULD print the error with a suggestion footer
  • AND it SHOULD write to the error scratch (for --from-last-error)
  • VERIFIES [[cli.core.P-handlers]]
  • VERIFIES [[cli.core.P-selfheal]]

Requirement: Sync Command

ah sync SHALL create or refresh property-derived contracts for the current scope, SHALL exit non-zero without writing when spk lint fails on any target file or when spk is unavailable, and SHALL support --check, which writes nothing and exits non-zero on drift or missing contracts.

Scenario: Sync creates derived contracts

  • GIVEN the default scope contains a lint-clean dual-format spec with Properties rows
  • WHEN ah sync runs
  • THEN a derived contract exists per property row with derived_from recorded
  • VERIFIES [[cli.core.P-scope]]

Scenario: Sync is registered like every subcommand

  • GIVEN the tool’s CLI is built
  • WHEN a user runs ah --help or generates shell completions
  • THEN sync appears with help text and completes like the other subcommands
  • VERIFIES [[cli.core.P-register]]

Scenario: Sync refuses on lint failure

  • GIVEN the scope contains a dual-format spec that fails spk lint
  • WHEN ah sync runs
  • THEN it exits non-zero, names the offending file, and writes nothing
  • VERIFIES [[cli.core.P-refuse]]

Scenario: Missing spk reports spk-unavailable

  • GIVEN spk is not on PATH
  • WHEN ah sync runs
  • THEN it exits non-zero with an spk-unavailable reason
  • VERIFIES [[cli.core.P-refuse]]

Scenario: Check mode is CI-safe

  • GIVEN a scope with one drifted and one missing derived contract
  • WHEN ah sync --check runs
  • THEN it exits non-zero, reports both, and modifies no files
  • VERIFIES [[cli.core.P-check]]