refactor(cli): derive contract-backed command options from the tool contract (#10571)

* refactor(cli): derive contract-backed command options from the tool contract

Each contract-backed CLI command restated its contract's input fields as
hand-written incur options and mapped them back to snake_case input with
conditional spreads. Nothing checked that the two schemas agreed.

Add registerContractCommand: a per-command projection names only what the
CLI spells differently (positionals, caller-relative path fields, option
renames, CLI help wording, omitted optional fields with a reason). Option
schemas, decimal argv tokens and the contract's cross-field rules are
derived from the contract input schema, and parsed options map back to the
contract input mechanically.

Migrate inspect-sqlite-database and the thirteen flat binary-diagnostics
inspectors. Their --schema output is unchanged apart from property order,
and help lists options in contract order. Delete the SQLite superRefine that
mirrored the contract and the per-command spreads.

Add a parity test: every projected command exposes each contract field or
declares its omission, and each field admits exactly what the contract
admits for empty, NUL, relative-path, bound and numeric-spelling probes.

* refactor(cli): refuse unprojected contract input forms at registration

Address review findings on the contract projection:

- Bind inspect-sqlite-database to its contract by name instead of catalog
  position.
- Accept only field forms argv can carry (string, number, boolean, enum,
  and arrays of strings or enums) instead of rejecting a short list, so
  arrays of objects, tuples and other forms fail at registration.
- Refuse root input keywords other than the projected object constraints
  and presentation annotations, so a contract rule such as `not` cannot
  disappear from --schema.

* refactor(cli): describe contract commands independently of the CLI framework

Split the contract projection into a framework-neutral description and a
thin Incur adapter, so a later REA-owned CLI layer (#10583) can render the
same description.

- contractCliDescription.ts derives each positional and option from the
  contract and projection: key and short flag, help, argv admission
  schema, boolean-flag/repeatable/decimal/caller-path facts, object
  constraints renamed to CLI keys, the optional argv-time cross-field
  check, and the mapping back to contract input.
- contractCommand.ts only renders that description as Incur args and
  options and runs the handler.

Cross-field rules now refuse at argv parsing only when a projection asks
(inspect-sqlite-database does, keeping its behavior); otherwise the
service's contract parse refuses them as before. Exact-optional fields are
projected as optional because argv cannot carry an explicit undefined and
Incur's help reads flag and choice types only through optional.

The parity guard reads the descriptions, and also checks that boolean
fields parse as bare flags and that no projected field stays
exact-optional.
This commit is contained in:
morluto authored and GitHub committed 2026-11-15 04:30:18 +08:00
1 parent 29fb608559
commit f3b697da5a
6 files changed
+1145 -731

No files matched your search

+12
View File
@@ -578,6 +578,18 @@ which some clients require even alongside `prefixItems`. Tuples with a rest
schema also need explicit minimum lengths. Check parser/schema parity for empty,
short, overlong, and malformed values in both input and output projections.
A CLI command for a tool contract is described by `describeContractCommand` in
[`contractCliDescription.ts`](https://github.com/morluto/rea/blob/main/src/cli/contractCliDescription.ts)
and rendered for the CLI framework by `registerContractCommand` in
[`contractCommand.ts`](https://github.com/morluto/rea/blob/main/src/cli/contractCommand.ts).
The projection names only what the CLI spells differently: positionals,
caller-relative path fields, option renames and short flags, CLI help wording,
omitted optional fields with a reason, and whether the contract's cross-field
rules refuse at argv parsing or at the service's contract parse. Field schemas
and decimal argv tokens are derived, and
`tests/boundary/cli/cliContractCommandParity.test.ts` checks that each projected
command admits what its contract admits.
CLI translations must reuse the canonical semantic fields, enum membership and
list bounds. Document transport differences such as relative path spelling and
JSON text decoding; reject empty selections before path normalization. Preserve