Skip to main content
← Back to list
01Issue
FeatureShippedSwamp CLIPublic
Assigneeszack

Relationships

#3195 extension source add imports src/cli/mod.ts, so every change lists extension as an affected command

Opened by zack · 10/8/2026· Shipped 10/8/2026

Problem

src/cli/commands/extension_source_add.ts imports six directory resolvers from src/cli/mod.ts:

import {
  resolveDatastoresDir,
  resolveModelsDir,
  resolveReportsDir,
  resolveVaultsDir,
  resolveWebhooksDir,
  resolveWorkflowsDir,
} from "../mod.ts";

src/cli/mod.ts imports every command, so this one import puts the whole CLI in the extension command's module closure. Measured on main at 3a59b162 with the functions in scripts/affected_commands.ts:

  • The closure of src/cli/commands/extension.ts is 1,217 of 1,220 modules.
  • extension_source_add.ts is the only non-test importer of src/cli/mod.ts other than main.ts.

The effect is that affectedCommands in the verification attestation names extension for almost any source change. agent-constraints/verification-conventions.md records this as a known property ("extension is listed for almost every source change, because its closure reaches the whole CLI through src/cli/mod.ts"). Of the last 100 merged PRs, 95 list extension.

This matters to swamp-uat, which is starting to use affectedCommands to work out which UAT tests a change needs. With extension in nearly every list, the roughly 40 UAT test files that run extension commands are kept for changes that cannot reach them.

Proposed solution

Import the six names from the files that define them. They already live in their own modules, and mod.ts only re-exports them (its comment: "the canonical definitions live in separate files to avoid circular imports through mod.ts"):

import { resolveDatastoresDir } from "../resolve_datastores_dir.ts";
import { resolveModelsDir } from "../resolve_models_dir.ts";
import { resolveReportsDir } from "../resolve_reports_dir.ts";
import { resolveVaultsDir } from "../resolve_vaults_dir.ts";
import { resolveWebhooksDir } from "../resolve_webhooks_dir.ts";
import { resolveWorkflowsDir } from "../resolve_workflows_dir.ts";

This is the same kind of change as #2902 (swamp-club#3143, "import libswamp names from their defining files, not the barrel"), and scripts/unbarrel.ts can do the rewrite.

Also:

  • Update the extension bullet in the "Affected Commands" section of agent-constraints/verification-conventions.md, which will no longer be true.
  • Consider a guard so the edge does not come back, for example a rule in integration/ddd_layer_rules_test.ts that no file under src/cli/commands/ imports src/cli/mod.ts.

What was checked

In a scratch copy of the tree with only the import rewritten:

  • deno check main.ts, deno fmt --check and deno lint on the file pass.
  • The extension closure drops from 1,217 to 434 modules.
  • scripts/affected_commands_test.ts, integration/affected_commands_rules_test.ts, integration/ddd_layer_rules_test.ts and src/cli/mod_test.ts gave 111 passed and 1 failed. The failure was "git ls-files failed" because the copy was not a git repository. The wider suite was not run.

Estimated effect on UAT test selection, modelled over the last 100 merged PRs against one recorded UAT run: the share of test-file runtime that could be skipped rises from 14% to 21%, and the number of PRs that would skip more than half of it rises from 4 to 17. No PR's command list grows.

Alternatives

  • Leave the import and special-case extension in scripts/affected_commands.ts. That hides the edge from the report without removing a command file's dependency on the whole CLI.
02Bog Flow
✓OPEN✓TRIAGED✓IN PROGRESS✓SHIPPED+ 1 MOREASSIGNED+ 2 MOREREVIEW+ 7 MOREPR_MERGED+ 2 MORESESSION_SUMMARIZED

Shipped

10/8/2026, 9:28:38 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
zack assigned zack10/8/2026, 8:53:40 PM

Sign in to post a ripple.