Skip to main content
← Back to list
01Issue
FeatureShippedSwamp CLI
Assigneesstack72

Relationships

#1079 UAT Phase 1d: data family verb gap-fill

Opened by stack72 · 7/10/2026· Shipped 7/11/2026

Summary

Phase 1d fills coverage gaps in the data command family. The data family already has deep dedicated coverage for delete, gc, query, search, and rename. This phase adds the missing dedicated command-dir tests for: get, list, versions, and prune.

Some coverage for these verbs exists inside e2e workflow journeys (e2e/workflow_data_test.ts) — this phase creates proper command-dir files with full contract coverage, JSON schema validation, and error-path testing. Do NOT delete the e2e tests; trim only where fully redundant per the coverage plan.

All new files land in the existing data-repo-doctor CI shard.

Dependency

Phase 8a (issue #1059) is landed. No other dependencies.

Existing State (do NOT duplicate)

These data test files already exist — do not recreate or duplicate:

  • tests/cli/data/delete_test.ts
  • tests/cli/data/gc_test.ts
  • tests/cli/data/query_test.ts
  • tests/cli/data/search_test.ts
  • tests/cli/data/search_provenance_test.ts
  • tests/cli/data/rename_test.ts
  • tests/cli/data/namespace/query_test.ts

e2e tests with partial data get/list/versions coverage (do NOT duplicate):

  • tests/cli/e2e/workflow_data_test.ts — "data list and get data produced by a workflow", "model-scoped vs workflow-scoped data", "data versions accumulate across multiple workflow runs"

Available helpers: createModel, installFixtureModel, runModelMethod, createWorkflow, installFixtureWorkflow, runWorkflow, captureRepoSnapshot

Useful fixtures:

  • tests/cli/fixtures/models/shell-producer.yaml — data-producing model
  • tests/cli/fixtures/models/shell-echo.yaml — simple model with output

Verified Contracts

data get

  • Model-scoped: <model> <data_name> — gets latest version by default
  • Workflow-scoped: --workflow [--run] <data_name>
  • model + workflow + name together → "Too many arguments…"
  • Neither model nor --workflow → "Either a model name or --workflow is required."
  • --version selects a specific version (default: latest)
  • --no-content omits the content field
  • JSON is the rich DataGetData: {id, name, model*, version, contentType, lifetime, tags, ownerDefinition{…}, createdAt, size?, checksum?, contentPath, content?}

data list

  • [model|--model] [--type log|file|resource|data] [--workflow [--run]]
  • JSON groups by tag type: {namespace, groups:[{type, items}]}

data versions

  • BOTH model and name are required (exact UserError naming both positional and flag forms)
  • JSON: {versions:[{version, size?, checksum?, isLatest}]}
  • Prints JSON in BOTH modes (log and --json)

data prune

  • Orphaned = owning definition no longer exists, checked across BOTH models/ AND .swamp/auto-definitions/ — auto-definition-backed models are NOT orphans
  • Deletes all versions of every data name of the orphaned model, then WAL checkpoint (non-dry-run)
  • Log-mode confirm: "Reclaim this orphaned data?" (skipped by --json/--force/--dry-run)
  • Empty preview → "No orphaned data to reclaim." exit 0
  • JSON: {modelsReclaimed, dataEntriesReclaimed, versionsDeleted, bytesReclaimed, dryRun, reclaimedModels:[…], walPagesTotal, walPagesCheckpointed}

New Test Files

data/get_test.ts (NEW)

  • Model-scoped happy path: create model, run data-producing method, data get <model> <name> → data content returned, JSON schema validated
  • Workflow-scoped: data get --workflow <wf> <name> → retrieves workflow-produced data
  • Too-many-args error: model + --workflow + name → "Too many arguments…", exit 1
  • Neither-arg error: data get with no model and no --workflow"Either a model name or --workflow is required.", exit 1
  • --version selects an older version (run the method twice, get version 1)
  • --no-content → JSON has no content field
  • JSON schema: DataGetSchema with all fields from DataGetData
  • Nonexistent model/name → exit 1
  • Exit codes: 0/1

data/list_test.ts (NEW)

  • Grouped-by-type output: produce data, data list <model> → JSON {namespace, groups:[{type, items}]} with items in the expected group
  • --type filter: --type data shows only data-tagged items, --type log shows only logs
  • Workflow scope: data list --workflow <wf> → only workflow-produced data
  • Empty repo → empty groups, exit 0
  • JSON schema validated
  • Exit codes: 0

data/versions_test.ts (NEW)

  • Versions accumulate: run method twice → data versions <model> <name> shows 2 versions with isLatest flag on the newer one
  • Both args required: missing model → exact UserError; missing name → exact UserError
  • JSON {versions:[{version, size?, checksum?, isLatest}]} printed in BOTH modes (verify JSON structure even without --json)
  • Nonexistent model/name → exit 1
  • Exit codes: 0/1

data/prune_test.ts (NEW)

  • Happy path: create a model, run it to produce data, then delete the model's definition YAML file directly (bypass model delete — simulates an orphaned definition) → data prune reclaims all its data; data get fails after prune
  • Auto-definition-backed data NOT pruned: install an extension with auto-definitions, run it, verify data prune does NOT reclaim its data (it's not an orphan because the definition exists in .swamp/auto-definitions/)
  • --dry-run reports what would be pruned but keeps files intact: use captureRepoSnapshot before and after, assert identical; JSON {dryRun:true, ...} with zero WAL counts
  • Nothing to prune → "No orphaned data to reclaim.", exit 0
  • Prompt decline (piped stdin, EOF = "no") → data still intact
  • JSON schema: DataPruneSchema with {modelsReclaimed, dataEntriesReclaimed, versionsDeleted, bytesReclaimed, dryRun, reclaimedModels, walPagesTotal, walPagesCheckpointed}
  • Exit codes: 0

Schemas

Add these new Zod schemas to src/cli/helpers/schemas.ts:

  • DataGetSchema — the rich DataGetData shape
  • DataListSchema{namespace, groups:[{type, items}]}
  • DataVersionsSchema{versions:[{version, size?, checksum?, isLatest}]}
  • DataPruneSchema — full prune result shape

Use .passthrough() on schemas (matching existing codebase convention).

Ground Rules

  • Read CLAUDE.md in the repo root first — its rules apply everywhere
  • Tests are more accurate than the code under test. Assert the documented contract. If swamp disagrees, the test stays red and you file the discrepancy upstream with swamp issue bug and reference it in a test comment. Never weaken a test to match current behavior.
  • Use the github-pr skill for commits and PR creation
  • Task 0 — ground truth: Before writing any test, build tip-of-main swamp and run each in-scope command by hand in a scratch repo (happy path, --json, one failure). Read the command definitions in ~/code/swamp-club/swamp/src/cli/commands/. Note any drift from this issue in the PR description.
  • Check open swamp-uat PRs for in-flight work touching your files before starting
  • Use grep -rl "data get\|data list\|data versions\|data prune" tests/cli/ before writing to avoid duplicating existing coverage

Test Pattern

All tests must follow this pattern — real binary, real commands, real exit codes:

import { assertEquals } from "@std/assert";
import {
  createRunnerFromEnv,
  installFixtureModel,
  runCommand,
  runJsonCommand,
  runModelMethod,
  withInitializedRepoContext,
} from "@swamp-uat/helpers";

const runner = createRunnerFromEnv();

Deno.test("swamp data get retrieves model-scoped data", () =>
  withInitializedRepoContext(runner, async (repo) => {
    // 1. Arrange: install shell-producer fixture, run it to produce data
    // 2. Act: run `swamp data get <model> <name> --json`
    // 3. Assert: exit code 0, JSON schema validated, content matches
  }));

Every test MUST:

  • Spawn the real swamp binary (via runCommand, runJsonCommand, or runner.render)
  • Assert an explicit exit code
  • Validate --json output through a Zod schema
  • End with waitFor(() => assertEquals(instance.hasExit()?.exitCode, N)) when using runner.render

How to Run & Verify

# 1. Format, lint, type-check
deno task fmt
deno task lint
deno task check

# 2. Run framework unit tests (includes CI guard test)
deno task test

# 3. Run the data tests directly
SWAMP_NO_TELEMETRY=1 SWAMP_SOURCE_DIR=~/code/swamp-club/swamp deno test --allow-read --allow-write --allow-env --allow-run --allow-net tests/cli/data/

# 4. Run the full CLI suite to check for regressions
SWAMP_NO_TELEMETRY=1 SWAMP_SOURCE_DIR=~/code/swamp-club/swamp deno task uat:cli

CI Shard Wiring

All new files go under tests/cli/data/ which is already covered by the data-repo-doctor CI shard. No CI changes needed.

Definition of Done

  • All 4 test files created per the table above (get, list, versions, prune)
  • All Zod schemas added to src/cli/helpers/schemas.ts
  • Every test spawns the real swamp binary — no mocking, no importing swamp internals
  • Every test asserts an explicit exit code
  • Every --json test validates through a Zod schema
  • Auto-definition orphan check explicitly tested in prune (not just definition-file orphans)
  • Upstream discrepancies filed with swamp issue bug and referenced in test comments
  • deno task fmt && deno task lint && deno task check && deno task test all green
  • SWAMP_NO_TELEMETRY=1 SWAMP_SOURCE_DIR=~/code/swamp-club/swamp deno task uat:cli passes
  • PR opened via github-pr skill, branching from main
02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNED+ 3 MOREFINDINGS+ 3 MOREPR_MERGED+ 1 MORENOTIFICATION_SKIPPED

Shipped

7/11/2026, 12:58:56 AM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack727/10/2026, 11:47:23 PM

Sign in to post a ripple.