Skip to content

Add Flowlord task rerun - #269

Merged
jbsmith7741 merged 6 commits into
mainfrom
flowlord-rerun
Sep 23, 2026
Merged

jbsmith7741 merged 6 commits into
mainfrom
flowlord-rerun

Conversation

@jbsmith7741

@jbsmith7741 jbsmith7741 commented Sep 10, 2026 •

Copy link
Copy Markdown
Collaborator

Quality check

  • Documentation included
  • Test coverage

Summary

  • Add POST /rerun to replay a task by primary key (type, job, id, created), copying Info exactly, reusing the pipeline ID with a new created timestamp, and stripping retry-related meta while setting rerun=manual.
  • Replace the tasks page replay button with a confirmation modal showing task details, then redirect to today's tasks view filtered by ID after a successful rerun.
  • Wire task and workflow row actions to open backload with prefilled phase, workflow, meta, and date parameters, including workflow-scoped phase lookup when multiple workflows share a task name.
  • Fix: Keep selected cell active during window scroll
  • Convert CircleCI tests to github Actions

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add task reruns and workflow-aware backload actions

✨ Enhancement 🐞 Bug fix 🧪 Tests 🕐 40+ Minutes

Grey Divider

AI Description

• Adds confirmed task reruns that preserve identity and sanitize retry metadata.
• Deep-links task and workflow actions into workflow-scoped, prefilled backload previews.
• Adds persistence lookups, UI refinements, development fixtures, and coverage.
Diagram

sequenceDiagram
    actor Operator
    participant Pages as Task and Workflow UI
    participant Backload as Backload UI
    participant API as Flowlord API
    participant DB as SQLite Cache
    participant Bus as Task Bus

    Operator->>Pages: Choose rerun
    Pages->>API: POST rerun key
    API->>DB: Load source task
    DB-->>API: Original record
    API->>DB: Store sanitized rerun
    API->>Bus: Publish task
    API-->>Pages: Return queued task
    Pages-->>Operator: Show filtered result

    Operator->>Pages: Run workflow phase
    Pages->>Backload: Open prefilled preview
    Backload->>API: Request scoped backload
    API->>DB: Resolve workflow phase
    DB-->>API: Template and rules
    API-->>Backload: Return task preview
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Reuse the backload endpoint
  • ➕ Avoids introducing a separate rerun API.
  • ➕ Reuses the existing preview and execution path.
  • ➖ Backload regenerates tasks from workflow templates rather than copying the selected record.
  • ➖ Preserving the original ID and Info would require special-case backload semantics.
  • ➖ Source metadata could be reconstructed incorrectly.
2. Use a transactional outbox
  • ➕ Provides stronger consistency between SQLite persistence and task-bus publication.
  • ➕ Supports reliable retries when the producer send fails.
  • ➖ Requires an outbox schema, dispatcher, and delivery-state management.
  • ➖ Adds substantial operational complexity beyond the current application pattern.

Recommendation: Keep the dedicated rerun endpoint because rerunning an exact historical record has different semantics from template-based backloading. The current persistence-then-publish flow also matches existing backload behavior; a transactional outbox should be considered separately if guaranteed delivery becomes a requirement.

Files changed (18) +1482 / -202

Enhancement (11) +1021 / -199
handler.goRegister reruns and scope backloads by workflow +7/-1

Register reruns and scope backloads by workflow

• Registers the POST /rerun route. Backload phase resolution now uses the requested workflow when supplied, avoiding ambiguous task and job matches.

apps/flowlord/handler.go

backload.tmplExpose workflow and generated task IDs +5/-0

Expose workflow and generated task IDs

• Adds the selected workflow to template details and an optional ID column for executed backload results.

apps/flowlord/handler/backload.tmpl

backload.jsSupport prefilled workflow-aware backload previews +278/-156

Support prefilled workflow-aware backload previews

• Applies task, job, workflow, date, and metadata query parameters to the form and supports automatic previews. It disambiguates matching phases by workflow and links executed tasks back to filtered task views.

apps/flowlord/handler/static/backload.js

style.cssStyle row actions, rerun modal, and responsive tables +212/-9

Style row actions, rerun modal, and responsive tables

• Adds task and workflow action-button styling plus the rerun confirmation modal. It also constrains table layouts and wraps long content to prevent horizontal overflow.

apps/flowlord/handler/static/style.css

task.jsAdd confirmed task rerun interactions +234/-24

Add confirmed task rerun interactions

• Collects the selected task's primary key and details, displays an accessible confirmation modal, and posts rerun requests. Successful requests redirect to the new task record while errors surface inline and scroll position is preserved.

apps/flowlord/handler/static/task.js

utils.jsAdd shared backload deep-link utilities +81/-1

Add shared backload deep-link utilities

• Adds metadata parsing, task and workflow row extraction, and backload URL construction. Shared row-action handling navigates to prefilled, automatically previewed backloads.

apps/flowlord/handler/static/utils.js

task.tmplAdd rerun controls to task rows +25/-2

Add rerun controls to task rows

• Adds rerun identity attributes and a replay action to each task row. It also defines the confirmation modal and passes the rerun endpoint into task-page initialization.

apps/flowlord/handler/task.tmpl

workflow.tmplAdd workflow phase run actions +26/-6

Add workflow phase run actions

• Adds a run action and fixed column layout to workflow rows. Filtering now selects cells by semantic class so the new leading action column does not shift indexes.

apps/flowlord/handler/workflow.tmpl

rerun.goImplement the task rerun endpoint +95/-0

Implement the task rerun endpoint

• Loads a task by its complete primary key, preserves its type, job, ID, and Info, and creates a fresh task timestamp. Retry-related metadata is removed, manual rerun provenance is added, and the task is stored and published.

apps/flowlord/rerun.go

tasks.goAdd primary-key task record lookup +24/-0

Add primary-key task record lookup

• Introduces GetTaskRecord to retrieve a single historical task by type, job, ID, and creation timestamp for exact reruns.

apps/flowlord/sqlite/tasks.go

workflow.goAdd workflow-scoped phase lookup +34/-0

Add workflow-scoped phase lookup

• Introduces GetPhase to resolve a task and optional job within a specific workflow file, preventing collisions across workflows.

apps/flowlord/sqlite/workflow.go

Bug fix (1) +5 / -3
table-sort.jsResolve sortable columns by actual cell index +5/-3

Resolve sortable columns by actual cell index

• Uses the matched header's cell index instead of its position within the sortable-header list, preserving correct sorting after action columns are added.

apps/flowlord/handler/static/table-sort.js

Tests (5) +346 / -0
handler_test.goCover rerun handling and scoped backloads +108/-0

Cover rerun handling and scoped backloads

• Adds a workflow-specific backload case and integration-style rerun tests covering success, missing records, invalid requests, metadata cleanup, timestamps, and bus publication.

apps/flowlord/handler_test.go

rerun_test.goTest rerun task construction and metadata sanitation +83/-0

Test rerun task construction and metadata sanitation

• Exercises retry metadata removal, preservation of workflow and template metadata, invalid metadata handling, identity reuse, and reset execution fields.

apps/flowlord/rerun_test.go

tasks_test.goTest exact task record retrieval +34/-0

Test exact task record retrieval

• Verifies primary-key task lookup returns the expected payload and rejects a mismatched creation timestamp.

apps/flowlord/sqlite/tasks_test.go

workflow_test.goTest workflow phase disambiguation +44/-0

Test workflow phase disambiguation

• Confirms identical task and job names resolve to the correct workflow-specific template and reports missing workflows.

apps/flowlord/sqlite/workflow_test.go

seed_dev.sqlAdd local task and alert UI fixtures +77/-0

Add local task and alert UI fixtures

• Adds repeatable same-day seed data for pipelines, repeated task identities, long IDs, alerts, and unmatched alerts. The fixture supports local validation of filtering, linking, layouts, and reruns.

apps/flowlord/test/seed_dev.sql

Other (1) +110 / -0
go.work.sumRefresh workspace dependency checksums +110/-0

Refresh workspace dependency checksums

• Records checksums for newer transitive Google Cloud and supporting Go modules resolved in the workspace.

go.work.sum

@qodo-code-review

qodo-code-review Bot commented Sep 10, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Failed sends create phantom reruns ✓ Resolved 🐞 Bug ☼ Reliability
Description
rerunHandler inserts the new task as running before calling producer.Send, but it does not
remove or fail that record when publication returns an error. A broker failure therefore leaves work
that was never queued in the task database, where the incomplete-task scanner can later turn it into
a false alert.
Code

apps/flowlord/rerun.go[R83-86]

+	tm.taskCache.Add(*t)
+	if err := tm.producer.Send(t.Type, t.JSONBytes()); err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
Evidence
SQLite.Add converts an empty result to running and commits the row before Send is attempted.
The incomplete-task query selects old running records and converts them into alerts, so the failed
publication remains operationally visible as unfinished work.

apps/flowlord/rerun.go[83-86]
apps/flowlord/sqlite/tasks.go[43-68]
apps/flowlord/sqlite/tasks.go[227-260]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A producer failure occurs after the rerun has been persisted as running, leaving a task record for work that was never delivered.

## Fix Focus Areas
- apps/flowlord/rerun.go[83-86]
- apps/flowlord/sqlite/tasks.go[43-72]
- apps/flowlord/sqlite/tasks.go[227-260]

## Recommended Fix
Make rerun persistence and publication consistent using an outbox transaction, or explicitly delete or mark the inserted rerun as a send failure when `producer.Send` fails. Add a producer-failure test that verifies no running record remains.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Queued reruns disappear from history 🐞 Bug ☼ Reliability
Description
rerunHandler cannot observe whether taskCache.Add succeeded because SQLite.Add logs database
errors and returns no result. If persistence fails while producer publication succeeds, the endpoint
returns “Rerun queued” even though the new run has no initial task-history or audit record.
Code

apps/flowlord/rerun.go[R83-84]

+	tm.taskCache.Add(*t)
+	if err := tm.producer.Send(t.Type, t.JSONBytes()); err != nil {
Evidence
The handler unconditionally proceeds from Add to publication and a successful response.
SQLite.Add catches an Exec error, writes only a log message, and returns without exposing the
failure to its caller.

apps/flowlord/rerun.go[83-94]
apps/flowlord/sqlite/tasks.go[43-72]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The rerun endpoint publishes and reports success even when its initial task-record insertion fails because `SQLite.Add` does not return an error.

## Fix Focus Areas
- apps/flowlord/rerun.go[83-94]
- apps/flowlord/sqlite/tasks.go[43-72]

## Recommended Fix
Change the persistence API used by reruns to return insertion errors and stop before publication when the insert fails. Return an appropriate server error and add a test using a failing or closed database.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. The test suite no longer compiles ✓ Resolved 🐞 Bug ≡ Correctness
Description
TestSanitizeRerunMeta appends the undefined token Qu to the return expression. Any build or test
command compiling the Flowlord package fails before the new rerun tests can run.
Code

apps/flowlord/rerun_test.go[14]

+		return sanitizeRerunMeta(in)Qu
Evidence
The cited return statement contains sanitizeRerunMeta(in)Qu, which is not valid Go syntax and is
entirely introduced by this PR.

apps/flowlord/rerun_test.go[12-15]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`TestSanitizeRerunMeta` contains a stray `Qu` token after `sanitizeRerunMeta(in)`, making the Go package fail to compile.

## Fix Focus Areas
- apps/flowlord/rerun_test.go[12-15]

## Recommended Fix
Remove the trailing `Qu` so the closure directly returns `sanitizeRerunMeta(in)`, then run the Flowlord test suite.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View high (1)
4. Rerun tasks receive altered metadata ✓ Resolved 🐞 Bug ≡ Correctness
Description
sanitizeRerunMeta calls url.QueryUnescape on the complete result of vals.Encode(), converting
encoded ampersands, plus signs, and percent signs within metadata values into query syntax or
invalid encodings. When workflow or template consumers later call url.ParseQuery, a value such as
key=a%26b has become key=a&b, so it is split into separate metadata fields and changes the rerun
task's effective input.
Code

apps/flowlord/rerun.go[25]

+	s, err := url.QueryUnescape(vals.Encode())
Evidence
The sanitizer parses the original query, correctly re-encodes it with url.Values.Encode(), and
then decodes the entire serialized query; for example, note=a%26b is first preserved as one value
but the final unescape changes it to note=a&b. That string is assigned directly to the new rerun
task, and multiple downstream task-processing paths parse metadata with url.ParseQuery, which
treats the resulting literal & as a field separator.

apps/flowlord/rerun.go[16-29]
apps/flowlord/rerun.go[32-40]
apps/flowlord/rerun.go[83-84]
apps/flowlord/taskmaster.go[397-410]
apps/flowlord/sqlite/workflow.go[187-192]
workflow/workflow.go[117-122]
tmpl/tmpl.go[202-205]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description

`sanitizeRerunMeta` globally unescapes the query produced by `url.Values.Encode()`, corrupting legal encoded metadata values by turning escaped delimiters, plus signs, and percent signs into syntax or invalid encodings that downstream `url.ParseQuery` calls interpret differently.

## Fix Focus Areas

- apps/flowlord/rerun.go[16-29]
- apps/flowlord/rerun_test.go[12-35]

## Recommended Fix

After removing retry state and setting `rerun=manual`, return `vals.Encode()` directly rather than applying `url.QueryUnescape` to the complete encoded query. Add round-trip tests for retained metadata values containing encoded `&`, `+`, and `%` characters, asserting that each remains a single unchanged value after the sanitized result is parsed.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

5. Task rows cannot open backloads 🐞 Bug ≡ Correctness
Description
The new taskRowDataFromRow helper is exported but never connected to enableRowBackloadActions on
the task table. Users viewing a task row only receive the rerun control, while the backload deep
link is available exclusively from workflow rows.
Code

apps/flowlord/handler/static/utils.js[R235-241]

+    function taskRowDataFromRow(row) {
+        if (!row) return null;
+        return {
+            type: ((row.querySelector('.type-cell') || {}).textContent || '').trim(),
+            job: ((row.querySelector('.job-cell') || {}).textContent || '').trim(),
+            meta: ((row.querySelector('.meta-cell') || {}).textContent || '').trim()
+        };
Evidence
The task-row extractor has no call sites outside its own wrapper/export, and task initialization
only registers rerun handling. By contrast, the workflow template renders a play button and
explicitly calls enableRowBackloadActions, demonstrating the missing task-page wiring.

apps/flowlord/handler/static/utils.js[235-271]
apps/flowlord/handler/static/utils.js[402-418]
apps/flowlord/handler/static/task.js[506-518]
apps/flowlord/handler/task.tmpl[168-176]
apps/flowlord/handler/workflow.tmpl[83-92]
apps/flowlord/handler/workflow.tmpl[141-145]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The task-row backload data extractor is unused, so task rows cannot invoke the backload deep link described by this change.

## Fix Focus Areas
- apps/flowlord/handler/static/utils.js[235-271]
- apps/flowlord/handler/static/task.js[506-518]
- apps/flowlord/handler/task.tmpl[168-176]

## Recommended Fix
Render a distinct backload action on task rows and register it with `enableRowBackloadActions` using `taskRowDataFromRow`, without allowing that handler to intercept the rerun button. Include the task creation or cron date when building the backload URL.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
Review mode: 🧠 Deep: This PR adds a new rerun API plus substantial backend, database, UI, and workflow/backload logic across many independent edit sites, creating a high density of easy-to-miss behavioral defects.

Grey Divider

Tip of the day
💡 Did you know, you can add REVIEW.md to your repo root and Qodo follows it on every PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread apps/flowlord/rerun_test.go Outdated
Comment thread apps/flowlord/rerun.go Outdated
Comment thread apps/flowlord/rerun.go Outdated
Comment thread apps/flowlord/handler/static/utils.js Outdated
Comment thread apps/flowlord/rerun.go Outdated
  * Add POST /rerun to replay a task by primary key with sanitized meta and same pipeline ID.
  * Replace browser confirm with a details modal and redirect to today's tasks filtered by ID.
  * Update SendFunc and rerun to persist error when producer send fails instead of leaving running records
  * Return encoded rerun meta and remove unused task row helpers from the UI
@jbsmith7741
jbsmith7741 merged commit 8d75440 into main Sep 23, 2026
4 checks passed
@jbsmith7741
jbsmith7741 deleted the flowlord-rerun branch September 23, 2026 21:26
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.

2 participants