Skip to content

refactor: extract shared helpers for task ID validation, file resolution, and frontmatter writing#94

Merged
lukstafi merged 2 commits intomainfrom
ludics/task-010fa0f1-s1/root
Mar 28, 2026
Merged

refactor: extract shared helpers for task ID validation, file resolution, and frontmatter writing#94
lukstafi merged 2 commits intomainfrom
ludics/task-010fa0f1-s1/root

Conversation

@lukstafi
Copy link
Copy Markdown
Owner

Summary

Follow-up to PR #79 — extracts duplicated logic from dashboard-server.ts into shared helpers to prevent a class of copy-paste bugs caught in the retrospective.

  • TASK_ID_RE — exported from src/tasks/markdown.ts, replaces four inline regexes across dashboard-server.ts
  • resolveTaskFile(taskId) — local helper inside startDashboardServer that centralises the resolve + safety-check + existence-check pattern used by task-promote, task-confirm, task-dismiss
  • updateFrontmatterField / addFrontmatterField — existing helpers from tasks/markdown.ts now used in both /api/slot-postpone and /api/task-promote, replacing two hand-rolled 15-line frontmatter loops
  • priorityValue() — exported from src/tasks/markdown.ts, imported into dashboard.ts; dead copy in flow.ts removed
  • Unit testssrc/tasks/priority-value.test.ts tests S < A < B < C ordering and unknown → 9

Test plan

  • bun run typecheck — clean
  • bun test — 257 pass, 0 fail (includes 4 new priorityValue tests)

🤖 Generated with Claude Code

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bde642194f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

output.push(line);
}
writeFileSync(taskFile, output.join("\n"));
addFrontmatterField(taskFile, "priority", newPriority);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Scope priority-field check to frontmatter before promote write

Calling addFrontmatterField(taskFile, "priority", newPriority) here can silently fail to persist a promotion when the task has no priority in frontmatter but the markdown body contains a top-level priority: line. addFrontmatterField checks existence with content.includes("\npriority:") (in src/tasks/markdown.ts) and may choose updateFrontmatterField, which only edits inside frontmatter and therefore performs no insertion; the API still returns the new priority, so UI/ordering can diverge from the file state.

Useful? React with 👍 / 👎.

lukstafi and others added 2 commits March 28, 2026 17:22
…ion, and frontmatter writing

- Add `TASK_ID_RE` constant and `priorityValue()` export to `src/tasks/markdown.ts`
- Remove dead local `priorityValue()` in `src/flow.ts` (was defined but never called)
- Replace local `priorityValue()` in `src/dashboard.ts` with import from `tasks/markdown.ts`
- Extract `resolveTaskFile()` helper in `dashboard-server.ts` to centralize path resolution + safety checks
- Replace all four inline task ID regexes in `dashboard-server.ts` with `TASK_ID_RE`
- Replace hand-rolled frontmatter loops in `/api/slot-postpone` and `/api/task-promote` with `updateFrontmatterField` / `addFrontmatterField`
- Add unit tests for `priorityValue()` sorting (S < A < B < C, unknown → 9)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The previous `content.includes("\nfield:")` check scanned the entire file.
A matching line in the markdown body would cause addFrontmatterField to call
updateFrontmatterField, which is frontmatter-scoped and would silently no-op,
leaving the field unwritten while the API returns the new value.

Fix: extract frontmatter block and check only that content for the field,
preventing false-positive matches from the document body.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@lukstafi lukstafi force-pushed the ludics/task-010fa0f1-s1/root branch from 84a18b4 to e018874 Compare March 28, 2026 16:22
@lukstafi lukstafi merged commit efa53f3 into main Mar 28, 2026
1 check passed
@lukstafi
Copy link
Copy Markdown
Owner Author

Retrospective: What I'd Do Differently Next Time

task-010fa0f1 — Dashboard API cleanup: extract shared helpers

1. Verify call sites before deleting a "duplicate" function

Before removing priorityValue() from flow.ts, I should have confirmed it was genuinely dead
code (never called), not just checking for the definition. In this case it was dead, but the right
habit is: grep -n 'priorityValue(' src/flow.ts first, then decide. Removing a function that
turns out to be called somewhere would cause a typecheck failure that I'd need to recover from.

2. Audit utility functions for whole-file scans before delegating to them

addFrontmatterField had a latent bug: content.includes("\nfield:") scanned the whole file,
not just the frontmatter. Before replacing a hand-rolled loop with a utility call, I should read
the utility's implementation and check for assumptions like "the content is frontmatter-only".
Had I done this during the initial refactor, the reviewer catch (PR comment round) would not have
been needed — the fix would have been in the first commit.

Checklist for future utility delegation:

  • Does the utility scope its search correctly (frontmatter-only vs whole file)?
  • Does it handle the "key absent" case in the same way as the code being replaced?
  • Are there edge cases (body contains the same key name) that differ from the original behaviour?

3. Add a regression test for the body-scope bug when fixing it

The addFrontmatterField body-scope fix was committed without a dedicated test that would have
caught the original bug and proves the fix. Next time, when addressing a reviewer comment about a
subtle edge case, add a test alongside the fix:

test("addFrontmatterField ignores body lines when checking existence", () => {
  // file has no frontmatter priority: field, but body contains "priority: foo"
  // addFrontmatterField should INSERT into frontmatter, not silently no-op
});

4. The proposal's flow.ts section was slightly misleading

The proposal said "Update flow.ts — remove local priorityValue(), import shared version". The
function was never called, so the right action was only the deletion, not adding an import. When
following a proposal, verify each step against actual call sites rather than treating the proposal
as ground truth.

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.

1 participant