Skip to content

Comments

feat: persist runtime tags on workflow run records (#387)#410

Merged
stack72 merged 1 commit intomainfrom
feat/persist-runtime-tags-on-workflow-run-387
Feb 21, 2026
Merged

feat: persist runtime tags on workflow run records (#387)#410
stack72 merged 1 commit intomainfrom
feat/persist-runtime-tags-on-workflow-run-387

Conversation

@stack72
Copy link
Contributor

@stack72 stack72 commented Feb 21, 2026

Summary

Closes #387

When running a workflow with --tag flags, tags flow through to data artifacts but are not stored on the WorkflowRun record itself. This means workflow history search cannot filter by tags. This PR stores merged workflow-level + runtime tags on the run record and adds --tag filtering to history search.

Changes

  • src/domain/workflows/workflow_run.ts — Added tags field to WorkflowRunSchema (with z.default({}) for backward compat), _tags constructor param, optional tags on create(), fromData()/toData() support, tags getter. Added WorkflowRunInput type alias for backward-compatible fromData() input.
  • src/domain/workflows/execution_service.ts — Merge workflow.tags and options.runtimeTags at run creation time (runtime tags take precedence).
  • src/presentation/output/workflow_history_search_output.tsx — Added tags? to WorkflowHistorySearchItem, included tags in fzf selector for fuzzy search, display tags inline in interactive UI.
  • src/cli/commands/workflow_run_search.ts — Added --tag <KEY=VALUE> CLI option (repeatable), AND-logic tag filtering in applyFilters(), tags in toSearchItem().
  • src/cli/commands/workflow_run_search_test.ts (new) — Tests for tag filtering.
  • src/domain/workflows/workflow_run_test.ts — 6 new tests for tag storage, serialization, roundtrip, and backward compat.
  • src/infrastructure/persistence/yaml_workflow_run_repository_test.ts — 2 new repository roundtrip tests for tags.

Plan vs Implementation

The implementation follows the plan with two deviations, both caused by TypeScript type constraints with Zod's .default({}):

Area Plan Implementation Reason
fromData() param type WorkflowRunData New WorkflowRunInput type (z.input<>) Zod .default({}) makes tags required in the output type, but fromData() must accept old YAML files without tags
toData() empty tags Omit tags when empty Always include tags (even {}) WorkflowRunData output type requires tags; casting to conditionally omit adds complexity for marginal benefit

Everything else matches the plan exactly: schema change, constructor, create(), fromData(), getter, execution service merge, search item type, fzf selector, UI display, --tag CLI option, parseTags import, AND-logic filtering, and all tests.

User Impact

New capability: filter workflow run history by tags

Users can now tag workflow runs and search/filter by those tags:

# Run a workflow with tags
swamp workflow run deploy-service --tag env=prod --tag region=us-east-1

# Search runs filtered by tags (AND logic — all tags must match)
swamp workflow run search --tag env=prod
swamp workflow run search --tag env=prod --tag region=us-east-1

# Combine with existing filters
swamp workflow run search --tag env=prod --status succeeded --since 7d

Tags are persisted in workflow run YAML files

After running with --tag env=prod --tag region=us-east-1, the run YAML will include:

tags:
  env: prod
  region: us-east-1

Runs without tags will include tags: {}. This is always present rather than conditionally omitted (see deviation above).

Tag precedence

Runtime --tag flags override workflow-definition-level tags:

# workflow definition has: tags: { env: staging }
# run with: --tag env=prod
# result on run record: { env: prod }

Interactive search

In the interactive fuzzy search UI (swamp workflow run search), tags are:

  • Included in the fzf search index, so typing prod will match runs tagged env=prod
  • Displayed inline on matching results as [env=prod, region=us-east-1] in cyan

Backward compatibility

  • Existing workflow run YAML files without a tags field will parse correctly (Zod default {})
  • WorkflowRun.create() second param is optional — existing callers are unaffected
  • tags is optional on WorkflowHistorySearchItem — existing consumers are unaffected

Test plan

  • deno check — type checking passes
  • deno lint — linting passes
  • deno fmt — formatting passes
  • deno run test — all 1807 tests pass (0 failures)
  • Manual: run a workflow with --tag env=prod, verify tags appear in the run YAML file
  • Manual: swamp workflow run search --tag env=prod returns only matching runs
  • Manual: interactive search shows tags inline and they are fzf-searchable

🤖 Generated with Claude Code

Store merged workflow-level + runtime tags on WorkflowRun records and
add --tag filtering to workflow run history search.

- Add tags field to WorkflowRunSchema with Zod default({}) for backward
  compatibility with existing YAML files
- Add WorkflowRunInput type for backward-compatible fromData() input
- Merge workflow.tags and runtime --tag flags in execution service
  (runtime tags take precedence)
- Add tags to WorkflowHistorySearchItem for search and display
- Add --tag CLI option to workflow run search with AND-logic filtering
- Include tags in fzf fuzzy search selector and interactive UI display
- Add unit tests for tags on WorkflowRun entity
- Add repository roundtrip tests for tag persistence
- Add search filter tests for --tag AND logic
@stack72 stack72 requested a review from johnrwatson February 21, 2026 19:20
@stack72 stack72 marked this pull request as ready for review February 21, 2026 19:41
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

This PR cleanly implements tag persistence on workflow run records, enabling tag-based filtering in workflow history search. The implementation is well-designed and follows project guidelines.

Domain-Driven Design Analysis ✅

  • WorkflowRun correctly acts as an aggregate root tracking execution state
  • Tags are properly treated as a value object: stored as Readonly<Record<string, string>> and copied on serialization to prevent mutation
  • WorkflowExecutionService appropriately handles tag merging (domain service responsibility)
  • Repository layer correctly persists and loads tags with backward compatibility

Code Quality ✅

  • TypeScript strict mode: All new types are properly defined. The WorkflowRunInput type alias using z.input<> elegantly handles Zod's default behavior for backward compatibility
  • Named exports: All exports follow project conventions
  • License headers: Present on all new files
  • Immutability: Tags getter returns Readonly<Record<string, string>>, and toData() copies tags with spread operator

Test Coverage ✅

Comprehensive test coverage across all layers:

  • workflow_run_search_test.ts: 4 tests for tag filtering (AND logic, single tag, items without tags, no filter)
  • workflow_run_test.ts: 6 new tests for tag storage, serialization, roundtrip, and backward compat
  • yaml_workflow_run_repository_test.ts: 2 repository roundtrip tests

The backward compatibility test (fromData with missing tags defaults to empty) is particularly valuable for ensuring existing YAML files continue to work.

Security ✅

No security concerns. Tags are simple string key-value pairs validated through Zod schema.

Suggestions (non-blocking)

  1. Consider adding a combined filter test (e.g., --tag + --status together) in a future PR to strengthen integration coverage

Verdict

Clean implementation that follows DDD principles, has excellent test coverage, and maintains backward compatibility. The plan deviations documented in the PR description are well-reasoned and appropriate.

🤖 Reviewed with Claude Code

@stack72 stack72 merged commit 3746c30 into main Feb 21, 2026
7 checks passed
@stack72 stack72 deleted the feat/persist-runtime-tags-on-workflow-run-387 branch February 21, 2026 19:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Persist runtime tags on workflow run records

1 participant