ctl-core 0.1.0

Shared clap chassis for the *ctl CLIs
Documentation
# yaml-language-server: $schema=https://github.com/victor-software-house/qctl/releases/download/v0.1.2/tasks.schema.json
schema_version: 3
prefix: CTC

style:
  timezone: "-03:00"
  section_order: [queue, horizon, archive]
active: CTC-006

queue:
  - id: CTC-006
    title: Test fixture tree and per-suite temp dirs
    scope: ctl-core
    outcome: >-
      Integration tests write files through a small fixture API, not
      repeated fs::write + indoc. Each suite or scenario gets its own
      temp root.
    blocked_by: []
    acceptance:
      - "A cfg(test) or ctl-core test feature exposes the helper (not a new public runtime crate unless we need one)."
      - "root.file(path, body) (or equivalent) is the write path. Nested paths create parents."
      - "Suite::new(name) / suite.scenario(name) each own a TempDir that drops at the end of the test."
      - "verctl (then qctl/forkctl) can drop the copy-pasted fs::write fixtures after pinning that ctl-core version."
    notes: >-
      Triggered by verctl tests (prepare_stage, changelog, publish).
      Do not invent a second tempfile wrapper in each *ctl.

  - id: CTC-008
    title: Own the declared-input layer every ctl CLI parses config with
    scope: ctl-core
    outcome: >-
      One implementation of "read it, parse the shape, validate it once,
      complain in the repo's own words" — instead of one per CLI, drifting.
    blocked_by: []
    acceptance:
      - "The shared validators live here: a path that must stay inside the repository, a single file name, a list that needs at least one entry, a value that cannot be empty."
      - "Each one is a garde `custom` rule generic over the context, so it works in a schema validated against nothing and in one validated against the whole document."
      - "A complaint says what a person changes (\"must declare at least one label\"), never a stock validator's wording (\"length is lower than 1\")."
      - "One entry point loads a file: read, serde for shape, garde once at the boundary, nothing downstream re-checking."
      - "verctl drops its own src/schema.rs after pinning that ctl-core version, and no copy is left behind."
      - "The declare-your-own-target template renderer is available to any ctl CLI, not only verctl."
    notes: >-
      2026-08-18: verctl built this while shipping served files (VER-018,
      and VER-022 is the matching row there). It is already shared between
      two unrelated schemas in that repo — a TOML config file and a Jinja
      template's own exports — which is the evidence it is not
      verctl-shaped. Do this row before VER-022 so that one is a move
      rather than a fork. Related: qctl's schemars work and VER-021 want
      JSON Schema generated from these same types, so keep the types
      derive-friendly.

horizon:
  - id: CTC-003
    title: Optional per-user daemon sharing one session and view
    scope: ctl-core
    kind: evaluation
    outcome: >-
      Multiple *ctl clients attach to one local session (skill-cli shape).
    open: >-
      Pretty/JSON views must be adopted by qctl and forkctl first (QCTL-008).
      Do not pull tokio into default features.
    notes: Same idea as QCTL-007. Keep one implementation, in this crate.

archive:
  - id: CTC-009
    title: Prove this repo's release lane by shipping one release through it
    scope: ctl-core
    outcome: >-
      The next ctl-core version comes out of a Version PR, so the lane is
      known to work here rather than assumed to because it works elsewhere.
    notes: >-
      2026-08-18, checked rather than assumed. The lane is wired and green —
      Version PR ran twice on main today — but it has never carried a
      release: there is no changeset, so every run no-ops. v0.0.1 through
      v0.0.3 were cut by hand, which the history shows plainly, because
      CHANGELOG.md was last touched by a feature commit (f8cfdf6) and no
      "version packages" commit exists at all. `[prepare]` arrived after that
      in cf11ac2 (#6) and has therefore never run. This matters because
      ctl-core is about to become the home of the declared-input layer
      (CTC-008), and verctl will pin it — a release path nobody has walked is
      a bad thing to discover while migrating two other repos onto it.
      The pin here is still verctl 0.0.3, so this repo has neither served
      files nor pins-on-the-Version-PR yet.
    completed: 2026-08-22T15:18:10
    evidence:
      - 'ctl-core#12 carried the changeset. #13 was the Version PR: 0.0.3 to 0.0.4, CHANGELOG written, Cargo.lock staged by cargo update --workspace.'
      - 'First Publish failed: origin/main missing on a shallow checkout. #14 added fetch-depth: 0. Dispatch then published.'
      - tag v0.0.4 is at 5b02305, the same SHA as GitHub Release target_commitish. Cargo.lock in that tree is 0.0.4. crates.io has 0.0.4.
    disposition: completed

  - id: CTC-007
    title: Version PR uses the released verctl tarball
    scope: ci
    completed: "2026-08-17T05:59:57"
    disposition: completed
    outcome: >-
      Version PR execs github:verctl from PATH. No cargo install --git.
      mise envs match verctl: rust in dev, tarball in release.
    evidence:
      - "github.com/victor-software-house/ctl-core/pull/3"
      - "MISE_ENV=release on Version PR; mise install --locked"
      - "MISE_ENV=dev,release on Publish"

  - id: CTC-005
    title: ColorMode tables for command pretty output
    scope: ctl-core
    completed: "2026-08-17T02:21:47"
    disposition: completed
    outcome: >-
      kv/grid take ColorMode. never emits no ANSI. View.show
      passes the view color. Consumers do not strip ANSI.
    evidence:
      - "crates.io ctl-core 0.0.3"
      - "src/table.rs; tests use ColorMode::Never"

  - id: CTC-002
    title: Publish ctl-core to crates.io
    scope: ctl-core
    completed: "2026-08-17T01:23:25"
    disposition: completed
    outcome: >-
      Consumers pin a crates.io version instead of a git rev.
    evidence:
      - "crates.io ctl-core 0.0.3"
      - "github.com/victor-software-house/ctl-core/releases/tag/v0.0.3"
      - "mise github:victor-software-house/verctl@0.0.1 for publish"

  - id: CTC-004
    title: Harden ctl-core tests before any consumer migration
    scope: ctl-core
    completed: "2026-08-17T00:17:36"
    disposition: completed
    outcome: >-
      Public API is covered harder than forkctl+qctl+verctl chassis
      tests. No extra clap/help copies land until this is green.
    evidence:
      - "github.com/victor-software-house/ctl-core main fdf6e67"
      - "tests/{color_argv,format_tokens,flags_cli,flag_warnings,help_render,view,parse}"
      - "peek --color --no-color; first-party concat! still fails clippy"
      - "chassis last-wins + {bin}: warning: on clashes"
    notes: >-
      Do not pad empty tests to out-count forkctl+qctl+verctl. Named
      public-path coverage is the bar.

  - id: CTC-001
    title: Shared clap chassis, views, and formatdoc
    scope: ctl-core
    completed: "2026-08-16T23:13:19"
    disposition: completed
    outcome: >-
      ctl-core owns flatten flags, styled help, Envelope/View, and
      formatdoc. Not a command.
    evidence:
      - "github.com/victor-software-house/ctl-core main 02c7e9f"
      - "prelude, Render, FormatArgs/ColorLong, cargo features"
      - "verctl already consumes it"