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

#364 dataRepository.getContent rejects string type in production but docs and testing helper demonstrate strings

Opened by jentz · 5/16/2026· Shipped 5/18/2026

Summary

In a workflow-scope report's execute(context), the documented way to read step-execution data is context.dataRepository.getContent(type, modelId, dataName, version?). The skill references describe type as the model type string (e.g. "aws/ec2"), and the testing helper accepts a string. But at runtime the production data repository expects a ModelType object with a .toDirectoryPath() method, and rejects strings with:

TypeError: type.toDirectoryPath is not a function

There is no documented helper for constructing a ModelType from a string in the report-context API surface, and definitionRepository.findById(modelId) does not resolve to a usable object in workflow scope (it returns silently, no warning, no error).

This makes getContent effectively unusable in workflow-scope reports that follow the documented patterns — they have to bypass the API and read raw files from disk.

Where (the contradiction)

The swamp-report skill's testing reference shows strings:

// Read raw bytes and parse — same pattern as live reports
const raw = await context.dataRepository.getContent(
  "aws/ec2",        // <- string
  "my-ec2",
  "state-current",
  1,
);

report-types.md also implies strings via the parameter-mapping table:

Parameter Value
type context.modelType

For workflow scope, report-types.md says:

For workflow-scope reports, use step.modelType, step.modelId, and step.dataHandles from context.stepExecutions.

…and step.modelType is typed as string in the same reference:

stepExecutions: Array<{
  jobName: string;
  stepName: string;
  modelName: string;
  modelType: string;    // <- string
  ...
}>

So both the parameter-mapping table and the typed shape of stepExecutions[].modelType say strings.

Production runtime says objects. Calling getContent with the string value of step.modelType throws type.toDirectoryPath is not a function.

Reproduction

  1. Create a workflow-scope report extension whose execute iterates context.stepExecutions and calls

    await context.dataRepository.getContent(
      step.modelType,           // string per report-types.md
      step.modelId,
      handle.name,
      handle.version,
    );
  2. Run a workflow that produces step outputs and triggers the report.

  3. Observe: TypeError: type.toDirectoryPath is not a function at the call site.

Encountered while building a workflow-scope audit report against swamp 20260516.045246.0-sha.e6eda98d.

Expected

Either:

  • dataRepository.getContent accepts a string for the type parameter (matches docs and testing helper), or
  • the docs and testing helper are updated to require a ModelType object, and a constructor/helper (e.g. ModelType.fromString(step.modelType) or context.parseModelType(step.modelType)) is exposed on the report context.

Actual

getContent(string, ...) throws synchronously inside the production data repository on the first attempt to read step data. The error is not caught or wrapped, so it bubbles up as an unhandled exception during report execution.

Confounder: the testing helper (@systeminit/swamp-testing's createReportTestContext) accepts strings — so unit tests pass against the documented contract, and the breakage only surfaces against the real runtime.

Impact

  • Workflow-scope reports that need to read step data must bypass the documented API and read raw files from disk (<repoDir>/.swamp/data/<type>/<id>/<name>/<v>/raw).
  • The path layout is stable per the swamp-extension skill's docs, so this works — but it duplicates the responsibility of the data repository and breaks if swamp ever changes the on-disk format.
  • Unit tests written against the testing helper give false confidence: they pass with strings, then the live workflow throws.

Workaround

Reading the file directly:

async function readDataFile(
  context: any,
  modelType: string,
  modelId: string,
  dataName: string,
  version: number,
): Promise<Uint8Array | null> {
  const path =
    `${context.repoDir}/.swamp/data/${modelType}/${modelId}/${dataName}/${version}/raw`;
  try {
    return await Deno.readFile(path);
  } catch (err) {
    if (err instanceof Deno.errors.NotFound) return null;
    throw err;
  }
}

This works because context.repoDir, the directory layout, and step.modelType as a string are all stable across the production runtime. It's a workaround, not a fix — third-party code shouldn't need to know the on-disk layout.

Suggested resolutions (any one is sufficient)

  1. Accept strings. Make the production getContent coerce strings into the internal ModelType representation. This matches docs and the testing helper. Smallest change.

  2. Expose a parser. Add parseModelType(string) (or ModelType.fromString(string)) on the report-context API and update the docs + testing helper to require an object. Larger change but explicit.

  3. Hand workflow-scope steps a typed object. Change stepExecutions[].modelType from string to the same ModelType object shape used in method/model scope. Cleanest mental model long-term — but a breaking change for existing reports that read step.modelType as a string for logging/filtering (defensive .toString?.() fallbacks would no longer be needed).

The first option is least disruptive; the third is cleanest long-term.

Environment

  • swamp 20260516.045246.0-sha.e6eda98d
  • Workflow-scope report (scope: "workflow")
  • macOS 25.4.0 / Deno bundled with swamp
02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNED+ 2 MOREREVIEW+ 3 MOREPR_MERGEDSHIPPED

Shipped

5/18/2026, 4:29:42 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack725/18/2026, 2:50:16 PM

Sign in to post a ripple.