Skip to content

feat(missions): per-mission taskPrefix override for triaged task ids#2334

Open
flexi767 wants to merge 12 commits into
Runfusion:mainfrom
flexi767:feat/per-mission-task-prefix
Open

feat(missions): per-mission taskPrefix override for triaged task ids#2334
flexi767 wants to merge 12 commits into
Runfusion:mainfrom
flexi767:feat/per-mission-task-prefix

Conversation

@flexi767

@flexi767 flexi767 commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Why

This supersedes #1930, which GitHub will not allow the author to reopen.

A Fusion project can represent one repository and deployment pipeline while durable missions represent distinct workstreams. In our project, general work uses FN-*, ImageEditor uses IMG-*, native/mobile uses MOB-*, and production incidents use ERR-*.

Those IDs leave the board and become durable references in commit trailers, branch names, implementation notes, migration filenames, logs, and alerts. Labels do not provide that context outside the board, and splitting one repository into multiple Fusion projects would duplicate repository, agent, merge, and deployment configuration.

Temporarily changing the project-wide prefix is unsafe because autopilot can triage other missions concurrently and allocate their tasks under the temporary namespace. An optional mission override makes allocation deterministic while preserving the project prefix as the default.

What changed

  • Persist an optional, nullable Mission.taskPrefix; unset missions inherit the project prefix.
  • Validate and expose the override in mission create/edit API and UI flows.
  • Pass the mission prefix as a transient task-creation hint during feature triage.
  • Reuse the allocator's existing per-prefix sequences; no allocator model changes.
  • Derive the commit-hook strip prefix from the actual task ID and safely quote fallback values.
  • Preserve explicit clear semantics (null means inherit; omission means no change).
  • Add a release changeset and migration 0026, the next free version on current main.

Review history

All actionable review threads on #1930 were resolved. Greptile's final review reported 5/5 confidence and no blocking issues. The branch has now been refreshed onto current main; the previous migration 0008 was moved to 0026 because upstream assigned 0008 to session-advisor state.

Validation

  • Dashboard task-prefix suites: 5 tests passed.
  • Engine commit-hook suite: 17 tests passed.
  • Core PostgreSQL mission-store and schema-applier suites: 86 tests passed against PostgreSQL 17.10.
  • Core, engine, and dashboard typechecks passed.
  • Scoped ESLint: no errors.
  • Frozen-lockfile offline install passed after declaring the dashboard's existing html2canvas runtime import.

Supersedes #1930.

Summary by CodeRabbit

  • New Features

    • Added per-mission task prefix overrides for triaged task IDs. The override is persisted in PostgreSQL and used for distributed task ID allocation and related commit hook generation.
    • Mission create/edit UI and APIs now support taskPrefix, including clear-to-inherit behavior and automatic uppercase normalization.
  • Bug Fixes

    • Backend distributed task ID prefix minting now correctly honors per-call/operator-provided prefixes.
    • Commit-message hook generation now derives and safely escapes quoting based on the task ID prefix.
  • Tests & Migration

    • Added migration/schema baseline support and PostgreSQL + UI/API regression tests for persistence, clearing, and validation.

fusion-merge-train and others added 9 commits July 6, 2026 11:42
Add an optional `taskPrefix` field on Mission so a single mission's tickets
can use a distinct id prefix (e.g. ERR-) while the rest of the board keeps the
project-wide prefix (default FN-). Previously taskPrefix was project-scoped
only; flipping it changed every new ticket board-wide including autopilot.

The distributed id allocator was already multi-prefix, so this only threads a
per-mission prefix through triage:
- Mission.taskPrefix (nullable) persisted via a new additive migration (v140).
- MissionStore.triageFeature passes it into TaskCreateInput.taskPrefix (a
  transient minting hint, not persisted on the task).
- createTaskWithDistributedReservation prefers input.taskPrefix over settings.
- buildCommitMsgTrailerHook derives the strip PREFIX from the task id itself
  rather than the project-wide option, so ERR-5 strips correctly while the
  project prefix is still FN (fixes all engine call sites at once).
- Mission create + edit UI (MissionManager) exposes a Task prefix input;
  mission-routes POST/PATCH validate it (letter-led alphanumeric, uppercased).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-prefix

# Conflicts:
#	packages/core/src/db.ts
…ck prefix

Address greptile feedback on PR Runfusion#1930:
- Mission edit save sends taskPrefix:null when the field is cleared so JSON
  retains the key and PATCH clears the stored mission override.
- Commit-msg hook quotes "$PREFIX" in case and escapes sed ERE metacharacters
  on the options.taskPrefix fallback path.
…on taskPrefix

Rebase the feat/per-mission-task-prefix work onto main after the SQLite→PostgreSQL
cutover. Take main's stubbed db.ts and modular store.ts, then re-port the feature:

- missions.task_prefix column (schema + migration 0008 + schema-applier)
- AsyncMissionStore CRUD/upsert/triage threads Mission.taskPrefix
- createTaskBackend + createTaskWithDistributedReservation honor input.taskPrefix
- Keep greptile fixes: null PATCH clear, commit-msg prefix escape/quote
- Port mission taskPrefix tests to PG harness; mock dashboard route tests

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
escapeSedEre left `/` raw, so a fallback prefix like TEAM/API produced invalid
sed `s/^TEAM/API-//i` and could abort the commit-msg hook. Escape `/` with the
other ERE metacharacters; cover with a unit test.

Greptile: databaseId 3583850800 on PR Runfusion#1930.
MissionManager state used mission-types.MissionWithSummary while fetchMissions
returned api/legacy.MissionWithSummary. taskPrefix was string vs string|null,
so the Array.isArray ternary widened to a dual-array union and failed setState
(TS2345). Align component Mission.taskPrefix with the API and annotate the
normalized list as MissionWithSummary[].
JSON.stringify produced PREFIX="$(id)" which /bin/sh expands via command
substitution when the commit-msg hook runs. Emit POSIX single-quoted
literals via shellSingleQuote (embedded ' → '\''). Apply the same quoting
to TRAILER_NAME and CO_AUTHOR_TRAILER. Cover $(id), ; rm -rf, and O'Brien.

Greptile P1 security: databaseIds 3583890011, 3583943640 on PR Runfusion#1930.
Copilot AI review requested due to automatic review settings July 19, 2026 11:15

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Mission task prefix overrides

Layer / File(s) Summary
Schema and mission persistence
packages/core/src/mission-types.ts, packages/core/src/mission-store.ts, packages/core/src/async-mission-store*, packages/core/src/postgres/*, packages/core/src/__tests__/postgres/*
Adds nullable mission task-prefix storage, migration 0026, synchronous and asynchronous persistence, replication, and PostgreSQL coverage.
Dashboard validation and mission editing
packages/dashboard/src/mission-routes.ts, packages/dashboard/src/__tests__/mission-task-prefix-routes.test.ts, packages/dashboard/app/api/legacy.ts, packages/dashboard/app/components/*, packages/dashboard/package.json
Validates, normalizes, displays, creates, updates, and clears mission task prefixes through dashboard APIs and forms; adds the dashboard runtime dependency.
Triage propagation and task-ID allocation
packages/core/src/types.ts, packages/core/src/async-mission-store.ts, packages/core/src/mission-store.ts, packages/core/src/task-store/*, packages/core/src/__tests__/postgres/mission-store.pg.test.ts, .changeset/mission-task-prefix.md
Passes mission prefixes into task creation and prefers them over project defaults during distributed ID allocation.
Commit-message hook prefix handling
packages/engine/src/worktree-hooks.ts, packages/engine/src/__tests__/worktree-hooks.test.ts
Derives task prefixes from task IDs and safely quotes shell and sed expressions in generated hooks.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Dashboard
  participant MissionRoutes
  participant MissionStore
  participant TaskStore
  participant TaskAllocator
  Dashboard->>MissionRoutes: submit mission taskPrefix
  MissionRoutes->>MissionStore: validate and persist taskPrefix
  MissionStore-->>Dashboard: return mission
  Dashboard->>TaskStore: triage mission feature
  TaskStore->>TaskAllocator: create task with taskPrefix
  TaskAllocator-->>TaskStore: return prefixed task ID
Loading

Possibly related PRs

  • Runfusion/Fusion#2331: Both update PostgreSQL schema-applier bookkeeping around migration version 0026.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: per-mission taskPrefix overrides for triaged task IDs.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds an optional per-mission taskPrefix override that lets a single Fusion project host workstreams with distinct ticket namespaces (e.g. ERR-*, IMG-*, MOB-*) without touching the project-wide prefix or risking autopilot conflicts. It also hardens the generated commit-msg hook by switching from JSON.stringify double-quoting to POSIX single-quoting and deriving the strip prefix from the actual task ID rather than the possibly-stale project setting.

  • Storage: a nullable task_prefix text column is added via idempotent migration 0026; the Drizzle schema, both store implementations (PG and SQLite), and all insert/update/upsert paths consistently map undefined → NULL so a cleared override immediately re-inherits the project prefix.
  • Triage: createTaskWithDistributedReservationImpl and createTaskBackendImpl now check input.taskPrefix before settings.taskPrefix, and triageFeature threads mission.taskPrefix as a transient TaskCreateInput hint; no allocator model changes are required.
  • Commit hook security: shellSingleQuote prevents $(), backtick, and $VAR expansion in generated hook scripts; escapeSedEre escapes / and other ERE metacharacters in the fallback sed expression; the case pattern now uses "$PREFIX"-* (variable expansion, not a hardcoded literal) so per-mission prefix hooks strip the correct prefix even when the project default diverges.

Confidence Score: 5/5

Safe to merge. All write paths consistently map cleared prefixes to NULL, the migration is additive and idempotent, and the commit-hook quoting changes eliminate the previously identified command-injection surface.

The change is well-scoped and well-tested: 86 PostgreSQL store/schema tests, 17 worktree-hook unit tests covering empty, special-char, injection, and single-quote edge cases, 5 dashboard task-prefix tests, and route-level regression tests all pass. The null=clear vs omit=no-change contract is enforced end-to-end. The POSIX single-quoting and ERE-escaping logic is verifiably correct for the full space of inputs the validator allows, and is defense-in-depth for the fallback path.

No files require special attention. The security-sensitive shell-quoting logic in packages/engine/src/worktree-hooks.ts has dedicated test coverage for injection, backtick, slash, and embedded-single-quote cases.

Important Files Changed

Filename Overview
packages/engine/src/worktree-hooks.ts Switches PREFIX/TRAILER_NAME/CO_AUTHOR_TRAILER from JSON.stringify double-quoting to POSIX single-quoting, adds shellSingleQuote and escapeSedEre helpers, and derives the strip prefix from the actual task ID rather than options.taskPrefix — fixing the ERR-5-vs-FN prefix mismatch and prior shell-injection risks. Logic and tests are sound.
packages/dashboard/src/mission-routes.ts Adds validateTaskPrefix helper and threads it into POST and PATCH handlers. Correctly implements null=clear vs omit=no-change semantics; route calls updateMission with taskPrefix:undefined when null is sent. Test suite covers all branches.
packages/core/src/task-store/remaining-ops-4.ts Adds input.taskPrefix as the primary prefix in createTaskWithDistributedReservationImpl, falling back to settings.taskPrefix then 'FN'. Clean one-liner change with correct precedence order.
packages/core/src/task-store/task-creation.ts Same per-mission prefix override applied to createTaskBackendImpl (backend path). Consistent with remaining-ops-4.ts; pre-existing 'KB' default unchanged.
packages/core/src/postgres/migrations/0026_mission_task_prefix.sql Additive-only, idempotent migration using ADD COLUMN IF NOT EXISTS guarded by a regclass check. Correctly assigned to version 0026, the next free slot on current main.
packages/core/src/async-mission-store-queries.ts Adds taskPrefix to MissionRow, missionColumns select, rowToMission mapping (null→undefined via
packages/core/src/async-mission-store.ts Threads taskPrefix from MissionCreateInput into the Mission record at construction time, and passes mission?.taskPrefix as a transient TaskCreateInput hint during triage. Optional chaining correctly produces undefined when no mission is loaded.
packages/dashboard/app/components/MissionManager.tsx Adds taskPrefix to MissionFormData, EMPTY_MISSION_FORM default, handleMissionTaskPrefixChange validator (client-side pattern guard), and three input elements. Edit-save correctly sends null so JSON.stringify preserves the key. Prior review thread about missing pattern validation is resolved in this revision.
packages/core/src/postgres/schema-applier.ts Exports MISSION_TASK_PREFIX_VERSION='0026', advances SCHEMA_BASELINE_VERSION to 0026, and appends the migration block at the correct position in applySchemaBaseline.
packages/dashboard/package.json Promotes the pre-existing html2canvas import to an explicit runtime dependency so frozen-lockfile offline installs succeed.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant UI as MissionManager (UI)
    participant RT as mission-routes (API)
    participant MS as AsyncMissionStore
    participant DB as PostgreSQL
    participant TA as Task Allocator
    participant WH as worktree-hooks

    Note over UI,DB: Mission create / edit
    UI->>RT: "POST /missions { taskPrefix: ERR }"
    RT->>RT: validateTaskPrefix → ERR
    RT->>MS: "createMission({ taskPrefix: ERR })"
    MS->>DB: "INSERT missions (task_prefix = ERR)"

    UI->>RT: "PATCH /missions/:id { taskPrefix: null }"
    RT->>RT: validateTaskPrefix(null) → undefined
    RT->>MS: "updateMission(id, { taskPrefix: undefined })"
    MS->>DB: "UPDATE missions SET task_prefix = NULL"

    Note over MS,WH: Feature triage
    MS->>MS: triageFeature(featureId)
    MS->>MS: lookup mission.taskPrefix → ERR
    MS->>TA: "createTask({ taskPrefix: ERR })"
    TA->>TA: "prefix = input.taskPrefix ?? settings.taskPrefix ?? FN"
    TA-->>MS: "Task { id: ERR-42 }"

    Note over WH: Commit-msg hook generation
    MS->>WH: "installCommitMsgHook(taskId=ERR-42, taskPrefix=FN)"
    WH->>WH: "derivedPrefix = ERR from ERR-42"
    WH->>WH: "taskPrefix = derivedPrefix || options.taskPrefix || FN"
    WH->>WH: "PREFIX=shellSingleQuote(ERR)"
    WH->>WH: "sed = shellSingleQuote(s/^ERR-//i)"
    WH-->>MS: "hook script with PREFIX='ERR'"
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant UI as MissionManager (UI)
    participant RT as mission-routes (API)
    participant MS as AsyncMissionStore
    participant DB as PostgreSQL
    participant TA as Task Allocator
    participant WH as worktree-hooks

    Note over UI,DB: Mission create / edit
    UI->>RT: "POST /missions { taskPrefix: ERR }"
    RT->>RT: validateTaskPrefix → ERR
    RT->>MS: "createMission({ taskPrefix: ERR })"
    MS->>DB: "INSERT missions (task_prefix = ERR)"

    UI->>RT: "PATCH /missions/:id { taskPrefix: null }"
    RT->>RT: validateTaskPrefix(null) → undefined
    RT->>MS: "updateMission(id, { taskPrefix: undefined })"
    MS->>DB: "UPDATE missions SET task_prefix = NULL"

    Note over MS,WH: Feature triage
    MS->>MS: triageFeature(featureId)
    MS->>MS: lookup mission.taskPrefix → ERR
    MS->>TA: "createTask({ taskPrefix: ERR })"
    TA->>TA: "prefix = input.taskPrefix ?? settings.taskPrefix ?? FN"
    TA-->>MS: "Task { id: ERR-42 }"

    Note over WH: Commit-msg hook generation
    MS->>WH: "installCommitMsgHook(taskId=ERR-42, taskPrefix=FN)"
    WH->>WH: "derivedPrefix = ERR from ERR-42"
    WH->>WH: "taskPrefix = derivedPrefix || options.taskPrefix || FN"
    WH->>WH: "PREFIX=shellSingleQuote(ERR)"
    WH->>WH: "sed = shellSingleQuote(s/^ERR-//i)"
    WH-->>MS: "hook script with PREFIX='ERR'"
Loading

Reviews (4): Last reviewed commit: "fix(dashboard): validate mission prefix ..." | Re-trigger Greptile

Comment thread packages/dashboard/app/components/MissionManager.tsx Outdated
@flexi767

Copy link
Copy Markdown
Contributor Author

This is ready for another review.

The concrete use case is one Fusion project for one repository/deployment pipeline, with durable mission namespaces for separate workstreams (FN-*, IMG-*, MOB-*, and ERR-*). Those task IDs are used outside the board in branches, commits, implementation notes, logs, and alerts. Labels lose that context, separate Fusion projects duplicate repository/agent/merge configuration, and temporarily changing the project-wide prefix races with concurrent autopilot triage. A nullable per-mission override keeps allocation deterministic while preserving the project prefix as the default.

I refreshed the branch onto current main, moved the migration to the next free number (0026), added the release changeset, addressed the prior review feedback, and declared the dashboard’s existing html2canvas runtime dependency that exposed a current-main typecheck failure. Local validation now includes PostgreSQL 17.10: the mission-store and schema-applier suites pass 86/86, the focused dashboard suites pass 5/5, the engine hook suite passes 17/17, and core/engine/dashboard typechecks pass.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
packages/engine/src/__tests__/worktree-hooks.test.ts (2)

96-96: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use JSDoc-style comments for FNXC annotations.

As per coding guidelines, it is preferred to use concise JSDoc-style comments (/** ... */) instead of single-line comments for FNXC product area annotations.

♻️ Proposed refactor

For example, update line 96 as follows:

-// FNXC:WorktreeHooks 2026-07-14-12:00: fallback options.taskPrefix is quoted in case and escaped for sed -E so metacharacters cannot break the hook or strip the wrong value (greptile P2 on PR `#1930`).
+/** FNXC:WorktreeHooks 2026-07-14-12:00: fallback options.taskPrefix is quoted in case and escaped for sed -E so metacharacters cannot break the hook or strip the wrong value (greptile P2 on PR `#1930`). */

Also applies to: 105-105, 113-113

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/engine/src/__tests__/worktree-hooks.test.ts` at line 96, Convert the
FNXC annotations near the worktree hook tests from single-line comments to
concise JSDoc-style comments using /** ... */. Apply this consistently to the
annotations at the referenced locations while preserving their existing text and
surrounding test logic.

Source: Coding guidelines


102-102: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer .toContain over .toMatch for exact string assertions.

For exact substring negations, using .toContain is more readable and consistent with other assertions in this test suite (such as line 110). It avoids the need to heavily escape regex metacharacters ("leaning toothpick syndrome").

♻️ Proposed refactor
-    expect(hook).not.toMatch(/s\/\^A\.B\+C-\/\/i/);
+    expect(hook).not.toContain("s/^A.B+C-//i");
-    expect(cmdSub).not.toMatch(/PREFIX="\$\(id\)"/);
+    expect(cmdSub).not.toContain('PREFIX="$(id)"');

Also applies to: 117-117

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/engine/src/__tests__/worktree-hooks.test.ts` at line 102, Update the
exact substring negations in the worktree hook tests to use the appropriate
`.not.toContain` assertions instead of `.not.toMatch`, including the assertion
near line 102 and the corresponding one near line 117; preserve the existing
expected string contents without regex escaping.
packages/core/src/mission-store.ts (1)

649-693: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing rationale comment for taskPrefix clearing semantics.

createMission/updateMission here implement the same "write NULL to re-inherit the project prefix" contract as async-mission-store-queries.ts, but only the async file documents it via an FNXC comment (citing PR #1930 / greptile P1). Without the same note here, a future edit to updated.taskPrefix ?? null (Line 1293) or mission.taskPrefix ?? null (Line 681) could silently break clearing.

As per coding guidelines: "Add FNXC:Area-of-product comments in yyyy-MM-dd-hh:mm format describing important user-facing requirements, implementation rationale, or requirement changes... ensure important user requirements are encoded in code comments."

📝 Suggested comment addition
       branchStrategy: mission.branchStrategy ? JSON.stringify(mission.branchStrategy) : null,
+      // FNXC:MissionTaskPrefix 2026-07-19-12:53: write NULL when cleared so the mission re-inherits the project prefix (mirrors async-mission-store-queries.ts, PR `#1930`).
       taskPrefix: mission.taskPrefix ?? null,

Also applies to: 1256-1306

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/mission-store.ts` around lines 649 - 693, Add an FNXC
rationale comment in the synchronous mission creation and update paths, adjacent
to the taskPrefix persistence expressions in createMission and the corresponding
update logic, documenting that writing NULL clears the mission override so it
re-inherits the project prefix and referencing the existing contract rationale.
Use the required yyyy-MM-dd-hh:mm format and preserve the current NULL behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/dashboard/src/mission-routes.ts`:
- Around line 191-202: Update validateTaskPrefix to throw badRequest(...) for
both invalid type and invalid format cases, ensuring taskPrefix validation
failures are recognized as client errors and return HTTP 400 through
catchHandler.

In `@packages/engine/src/worktree-hooks.ts`:
- Line 269: Update the generated sed expression in the fallback task-ID branch
to use the existing shellSingleQuote helper, producing a POSIX single-quoted
shell literal after applying escapeSedEre. Preserve the current prefix-removal
behavior while ensuring taskPrefix characters, including backticks, cannot
trigger shell command substitution when the hook runs.

---

Nitpick comments:
In `@packages/core/src/mission-store.ts`:
- Around line 649-693: Add an FNXC rationale comment in the synchronous mission
creation and update paths, adjacent to the taskPrefix persistence expressions in
createMission and the corresponding update logic, documenting that writing NULL
clears the mission override so it re-inherits the project prefix and referencing
the existing contract rationale. Use the required yyyy-MM-dd-hh:mm format and
preserve the current NULL behavior.

In `@packages/engine/src/__tests__/worktree-hooks.test.ts`:
- Line 96: Convert the FNXC annotations near the worktree hook tests from
single-line comments to concise JSDoc-style comments using /** ... */. Apply
this consistently to the annotations at the referenced locations while
preserving their existing text and surrounding test logic.
- Line 102: Update the exact substring negations in the worktree hook tests to
use the appropriate `.not.toContain` assertions instead of `.not.toMatch`,
including the assertion near line 102 and the corresponding one near line 117;
preserve the existing expected string contents without regex escaping.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 598ac597-3d4c-44c3-91f2-a5194934b078

📥 Commits

Reviewing files that changed from the base of the PR and between ecffdbb and f123270.

📒 Files selected for processing (22)
  • .changeset/mission-task-prefix.md
  • packages/core/src/__tests__/postgres/mission-store.pg.test.ts
  • packages/core/src/__tests__/postgres/schema-applier.test.ts
  • packages/core/src/async-mission-store-queries.ts
  • packages/core/src/async-mission-store.ts
  • packages/core/src/mission-store.ts
  • packages/core/src/mission-types.ts
  • packages/core/src/postgres/index.ts
  • packages/core/src/postgres/migrations/0026_mission_task_prefix.sql
  • packages/core/src/postgres/schema-applier.ts
  • packages/core/src/postgres/schema/project.ts
  • packages/core/src/task-store/remaining-ops-4.ts
  • packages/core/src/task-store/task-creation.ts
  • packages/core/src/types.ts
  • packages/dashboard/app/api/legacy.ts
  • packages/dashboard/app/components/MissionManager.tsx
  • packages/dashboard/app/components/__tests__/MissionManager.task-prefix.test.tsx
  • packages/dashboard/app/components/mission-types.ts
  • packages/dashboard/src/__tests__/mission-task-prefix-routes.test.ts
  • packages/dashboard/src/mission-routes.ts
  • packages/engine/src/__tests__/worktree-hooks.test.ts
  • packages/engine/src/worktree-hooks.ts

Comment thread packages/dashboard/src/mission-routes.ts
Comment thread packages/engine/src/worktree-hooks.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/dashboard/app/components/__tests__/MissionManager.task-prefix.test.tsx (1)

164-165: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prevent test flakiness by using asynchronous DOM queries after state updates.

waitFor resolves immediately once the mock is called, which happens before React finishes its re-render with the fetched data. The subsequent synchronous getAllByRole query is susceptible to race conditions and may throw if the button hasn't appeared in the DOM yet.

Use an asynchronous query like findAllByRole to safely wait for the UI to update.

🛠️ Proposed fix to ensure stable DOM querying
     await waitFor(() => expect(mockFetchMission).toHaveBeenCalledWith("M-001", projectId));
-    fireEvent.click(screen.getAllByRole("button", { name: "Edit mission" })[0]);
+    const editButtons = await screen.findAllByRole("button", { name: "Edit mission" });
+    fireEvent.click(editButtons[0]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/dashboard/app/components/__tests__/MissionManager.task-prefix.test.tsx`
around lines 164 - 165, Update the test after the mockFetchMission assertion to
await screen.findAllByRole("button", { name: "Edit mission" }) instead of using
the synchronous getAllByRole query, ensuring the button is present after React
finishes rendering before firing the click.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@packages/dashboard/app/components/__tests__/MissionManager.task-prefix.test.tsx`:
- Around line 164-165: Update the test after the mockFetchMission assertion to
await screen.findAllByRole("button", { name: "Edit mission" }) instead of using
the synchronous getAllByRole query, ensuring the button is present after React
finishes rendering before firing the click.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 76d35c95-7570-48f6-a67d-efd65ca1b47f

📥 Commits

Reviewing files that changed from the base of the PR and between 92195db and 7bfe7c6.

📒 Files selected for processing (2)
  • packages/dashboard/app/components/MissionManager.tsx
  • packages/dashboard/app/components/__tests__/MissionManager.task-prefix.test.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/dashboard/app/components/MissionManager.tsx

@gsxdsm

gsxdsm commented Jul 19, 2026

Copy link
Copy Markdown
Collaborator

Thanks for explanation this makes sense

@gsxdsm

gsxdsm commented Jul 19, 2026

Copy link
Copy Markdown
Collaborator

Merge conflicts resolved (maintainer follow-up)

This PR is CONFLICTING with current main (main claimed migration 0026 bigint counters and 0027 workflow IR pin).

Fork push to flexi767/Fusion-upstream failed (no push access from this environment despite maintainerCanModify), so the conflict resolution is opened as:

#2347 (feat/per-mission-task-prefix-2334)

Resolution notes:

  • Mission task_prefix migration renumbered 0026 → 0028
  • 0000_initial.sql baseline includes task_prefix on project.missions
  • Schema applier wires 0026 + 0027 + 0028; baseline marker → 0028
  • Code-org legacy.ts re-exports kept; missions.ts create/update carry taskPrefix

Prefer merging #2347 (or cherry-picking that tip onto this fork branch if you can push).

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.

3 participants