feat: persist runtime tags on workflow run records (#387)#410
Conversation
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
There was a problem hiding this comment.
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
WorkflowRunInputtype alias usingz.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>>, andtoData()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 compatyaml_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)
- Consider adding a combined filter test (e.g.,
--tag+--statustogether) 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
Summary
Closes #387
When running a workflow with
--tagflags, tags flow through to data artifacts but are not stored on theWorkflowRunrecord itself. This means workflow history search cannot filter by tags. This PR stores merged workflow-level + runtime tags on the run record and adds--tagfiltering to history search.Changes
src/domain/workflows/workflow_run.ts— Addedtagsfield toWorkflowRunSchema(withz.default({})for backward compat),_tagsconstructor param, optionaltagsoncreate(),fromData()/toData()support,tagsgetter. AddedWorkflowRunInputtype alias for backward-compatiblefromData()input.src/domain/workflows/execution_service.ts— Mergeworkflow.tagsandoptions.runtimeTagsat run creation time (runtime tags take precedence).src/presentation/output/workflow_history_search_output.tsx— Addedtags?toWorkflowHistorySearchItem, 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 inapplyFilters(), tags intoSearchItem().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({}):fromData()param typeWorkflowRunDataWorkflowRunInputtype (z.input<>).default({})makestagsrequired in the output type, butfromData()must accept old YAML files withouttagstoData()empty tagstagswhen emptytags(even{})WorkflowRunDataoutput type requirestags; casting to conditionally omit adds complexity for marginal benefitEverything else matches the plan exactly: schema change, constructor,
create(),fromData(), getter, execution service merge, search item type, fzf selector, UI display,--tagCLI option,parseTagsimport, 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:
Tags are persisted in workflow run YAML files
After running with
--tag env=prod --tag region=us-east-1, the run YAML will include:Runs without tags will include
tags: {}. This is always present rather than conditionally omitted (see deviation above).Tag precedence
Runtime
--tagflags override workflow-definition-level tags:Interactive search
In the interactive fuzzy search UI (
swamp workflow run search), tags are:prodwill match runs taggedenv=prod[env=prod, region=us-east-1]in cyanBackward compatibility
tagsfield will parse correctly (Zod default{})WorkflowRun.create()second param is optional — existing callers are unaffectedtagsis optional onWorkflowHistorySearchItem— existing consumers are unaffectedTest plan
deno check— type checking passesdeno lint— linting passesdeno fmt— formatting passesdeno run test— all 1807 tests pass (0 failures)--tag env=prod, verify tags appear in the run YAML fileswamp workflow run search --tag env=prodreturns only matching runs🤖 Generated with Claude Code