# Harness Roadmap Pilot

> AI-assisted selection of the next highest-impact unblocked roadmap item. Scores candidates, recommends one, assigns it, and transitions to the appropriate next skill.

## When to Use

- When the team or individual needs to pick the next item to work on from the roadmap
- When there are multiple unblocked items and prioritization guidance is needed
- After completing a feature and looking for the next highest-impact work
- NOT when the roadmap does not exist (direct user to harness-roadmap --create)
- NOT when the user already knows what to work on (use harness-brainstorming or harness-autopilot directly)

## Process

### Iron Law

**Never assign or transition without the human confirming the recommendation first.**

Present the ranked candidates, the AI reasoning, and the recommended pick. Wait for explicit confirmation before making any changes.

---

### Phase 1: SCAN -- Score Candidates

1. Resolve the roadmap mode with `loadProjectRoadmapMode(projectRoot)` from `@harness-engineering/core`.
   - In `file-backed` mode (default): check that `docs/roadmap.md` exists. If missing, error. "No roadmap found at docs/roadmap.md. Run harness-roadmap --create first."
   - In `file-less` mode: `docs/roadmap.md` is intentionally absent. Synthesize the roadmap from the tracker:
     a. `loadTrackerClientConfigFromProject(projectRoot)` -> `createTrackerClient(config)` to obtain a `RoadmapTrackerClient`.
     b. `client.fetchAll()` -> map each `TrackedFeature` into a `RoadmapFeature` and group by milestone (or use a single synthetic milestone if the tracker has no milestone field).
     c. If the tracker call fails, surface the error verbatim; do not fall back to a file-backed branch.
2. Parse the roadmap (file-backed only) using `parseRoadmap` from `@harness-engineering/core`. (File-less mode produces the in-memory roadmap directly from step 1.)
3. Determine the current user:
   - Use the `--user` argument if provided
   - Otherwise, attempt to detect from git config: `git config user.name` or `git config user.email`
   - If neither available, proceed without affinity scoring
4. Call `scoreRoadmapCandidatesForMode(roadmap, { currentUser }, config)` from `@harness-engineering/core` (FR-S3). This is the mode-aware wrapper: in `file-backed` mode it delegates to `scoreRoadmapCandidates` unchanged; in `file-less` mode it routes through `scoreRoadmapCandidatesFileLess` for the D4 priority+createdAt ordering. Always passing through this wrapper keeps the skill mode-agnostic.
5. If no candidates: inform the human. "No unblocked planned or backlog items found. All items are either in-progress, done, blocked, or the roadmap is empty."

Present the top 5 candidates:

```
ROADMAP PILOT -- Candidate Scoring

Top candidates (scored by position 50%, dependents 30%, affinity 20%):

  #  Feature               Milestone    Priority  Score   Breakdown
  1. Feature A             MVP Release  P0        0.85    pos:0.9 dep:0.8 aff:1.0
  2. Feature B             MVP Release  P1        0.72    pos:0.8 dep:0.6 aff:0.5
  3. Feature C             Q2 Release   --        0.65    pos:0.7 dep:0.5 aff:0.0
  4. Feature D             Backlog      --        0.40    pos:0.3 dep:0.4 aff:0.0
  5. Feature E             Backlog      --        0.35    pos:0.2 dep:0.3 aff:0.0
```

### Phase 2: RECOMMEND -- AI-Assisted Analysis

1. For the top 3 candidates, read their spec files (if they exist):
   - Read the spec's Overview and Goals section
   - Read the spec's Success Criteria section
   - Assess effort and impact from the spec content

1b. Read the most recent pulse report (if any):

- List entries in `docs/pulse-reports/` and **filter to those matching the
  regex `/^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}\.md$/`** (the canonical
  `YYYY-MM-DD_HH-MM.md` pulse-report filename shape). Filtering before
  sorting prevents non-conforming files (e.g. `README.md`, `NOTES.md`,
  partial-timestamp drafts) from corrupting the signal.
- Lexical-sort the matched filenames (ISO timestamps sort
  chronologically) and take the LAST entry as the most recent.
- If zero entries match the regex (directory empty, absent, or only
  contains non-conforming files), soft-fail: skip this step and proceed
  without pulse signal. Do not block recommendation.
- For each top-3 candidate, scan the most recent pulse report's Headlines and
  Followups sections for keywords matching the candidate's name, milestone, or
  spec keywords. Note any signal that elevates priority (top followup item
  related to a candidate; an error spike in a candidate's area) or suppresses
  it (recent stable signal in candidate's area).
- When pulse signal is found, cite it verbatim in the recommendation rationale
  (e.g., "Pulse 2026-05-05_08-00 headline: 'auth errors up 30%' — elevates
  Auth Hardening").
- Use ONLY the most recent file. If older reports conflict with the most
  recent, ignore the older signal.

2. Provide a recommendation with reasoning:

```
RECOMMENDATION

I recommend Feature A (MVP Release, P0, score: 0.85).

Reasoning:
- Highest priority (P0) with strong positional signal (first in MVP milestone)
- Unblocks 2 downstream features (Feature X, Feature Y)
- You completed its blocker "Foundation" -- high context affinity
- Spec exists with clear success criteria (12 acceptance tests)
- Estimated effort: medium (8 tasks in the plan)

Alternative: Feature B (P1, score: 0.72) -- consider if Feature A's scope is too large for the current time window.

Proceed with Feature A? (y/n/pick another)
```

### Phase 3: CONFIRM -- Human Decision

1. Wait for human confirmation.
   - If **yes**: proceed to Phase 4.
   - If **pick another**: ask which candidate number, then proceed with that pick.
   - If **no**: stop. No changes made.

### Phase 4: ASSIGN -- Execute Assignment and Transition

1. Call `manage_roadmap` with action `update` to assign the feature:

   ```json
   manage_roadmap({
     path: "<project-root>",
     action: "update",
     feature: "<feature-name>",
     assignee: "<currentUser>"
   })
   ```

   - This updates the feature's `Assignee` field with assignment history tracking
   - Automatically triggers external sync (GitHub Issues) if tracker config exists in `harness.config.json`
   - External sync is fire-and-forget — errors are logged but do not block the assignment

2. Determine the transition target:
   - If the feature has a `spec` field (non-null): transition to `harness:autopilot`
   - If the feature has no `spec`: transition to `harness:brainstorming`

3. Present the transition to the human via `emit_interaction`:

   ```json
   emit_interaction({
     path: "<project-root>",
     type: "transition",
     transition: {
       completedPhase: "roadmap-pilot",
       suggestedNext: "<brainstorming|autopilot>",
       reason: "Feature '<name>' assigned and ready for <brainstorming|execution>",
       artifacts: ["docs/roadmap.md"],
       requiresConfirmation: true,
       summary: "Assigned '<name>' to <user>. <Spec exists -- ready for autopilot|No spec -- needs brainstorming first>.",
       qualityGate: {
         checks: [
           { "name": "roadmap-parsed", "passed": true },
           { "name": "candidate-scored", "passed": true },
           { "name": "human-confirmed", "passed": true },
           { "name": "assignment-written", "passed": true }
         ],
         allPassed: true
       }
     }
   })
   ```

4. Run `harness validate`.

---

## Harness Integration

- **`parseRoadmap` / `serializeRoadmap`** -- Parse and write `docs/roadmap.md` (file-backed mode only). Import from `@harness-engineering/core`.
- **`loadProjectRoadmapMode` / `loadTrackerClientConfigFromProject` / `createTrackerClient`** -- Resolve `roadmap.mode` and obtain a `RoadmapTrackerClient` for file-less mode. Import from `@harness-engineering/core`.
- **`scoreRoadmapCandidatesForMode`** -- Mode-aware scoring entry point. Import from `@harness-engineering/core`. In file-backed mode delegates to `scoreRoadmapCandidates`; in file-less mode routes through `scoreRoadmapCandidatesFileLess` (priority + createdAt sort, FR-S3).
- **`scoreRoadmapCandidates`** -- Underlying file-backed scoring algorithm. Prefer `scoreRoadmapCandidatesForMode` from the skill; direct callers in file-backed-only code paths can still use this.
- **`manage_roadmap update`** -- Used for assignment. Supports `assignee` field which delegates to `assignFeature` internally, handles history tracking, and automatically triggers external sync (GitHub Issues). In file-less mode, `manage_roadmap` dispatches through the tracker; the skill flow is unchanged.
- **`emit_interaction`** -- Used for the skill transition at the end. Transitions to `harness:brainstorming` (no spec) or `harness:autopilot` (spec exists).
- **`harness validate`** -- Run after assignment is written.

## Success Criteria

1. Roadmap is parsed and unblocked planned/backlog items are scored
2. Scoring uses two-tier sort: explicit priority first, then weighted score
3. AI reads top candidates' specs and provides recommendation with reasoning
4. Human confirms before any changes are made
5. Assignment updates feature field, appends history records, and syncs externally
6. Reassignment produces two history records (unassigned + assigned)
7. Transition routes to brainstorming (no spec) or autopilot (spec exists)
8. When a pulse report exists, the recommendation rationale cites pulse signal for any top-3 candidate whose area is referenced in the pulse Headlines or Followups.
9. `harness validate` passes after all changes

## Rationalizations to Reject

| Rationalization                                                                                                         | Reality                                                                                                                                 |
| ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| "The top-scored candidate is obviously correct, so I can assign it without asking the human"                            | The Iron Law: never assign or transition without the human confirming the recommendation first.                                         |
| "Affinity data is not available so the scoring is degraded -- I should just pick the first planned item"                | Proceed without affinity scoring by zeroing out the affinity weight. Position and dependents signals still produce meaningful rankings. |
| "The feature has no spec, but I can skip brainstorming and jump straight to planning since the summary is clear enough" | No spec routes to brainstorming, spec exists routes to autopilot. A one-line roadmap summary is not a spec.                             |

## Examples

### Example: Pick Next Item from a Multi-Milestone Roadmap

**Context:** A roadmap with 3 milestones, 8 features. 2 are in-progress, 1 is done, 2 are blocked, 3 are planned/backlog and unblocked. User is @cwarner who completed "Core Library Design".

**Phase 1: SCAN**

```
ROADMAP PILOT -- Candidate Scoring

Top candidates:
  #  Feature               Milestone    Priority  Score   Breakdown
  1. Graph Connector       MVP Release  P2        0.78    pos:0.8 dep:0.6 aff:1.0
  2. Performance Baselines Q3 Hardening --        0.45    pos:0.5 dep:0.3 aff:0.0
  3. Push Notifications    Backlog      --        0.30    pos:0.2 dep:0.2 aff:0.5
```

**Phase 2: RECOMMEND**

```
I recommend Graph Connector (MVP Release, P2, score: 0.78).

Reasoning:
- Only prioritized item among candidates (P2)
- You completed its blocker "Core Library Design" -- maximum affinity bonus
- Unblocks "API Integration" downstream
- Spec exists at docs/changes/graph-connector/proposal.md

Proceed? (y/n/pick another)
```

Human confirms **y**.

**Phase 4: ASSIGN**

```
manage_roadmap update: Graph Connector assignee -> @cwarner
History: +1 record (assigned, 2026-04-02)
Roadmap updated: docs/roadmap.md
External sync: github:harness-eng/harness#43 assigned (automatic)

Transitioning to harness:autopilot (spec exists)...
```

## Gates

- **No assignment without human confirmation.** The CONFIRM phase must complete with explicit approval. Never auto-assign.
- **No transition without assignment.** The skill must write the assignment before transitioning to the next skill.
- **No scoring without a parsed roadmap.** If `docs/roadmap.md` does not exist or fails to parse, stop with an error.

## Escalation

- **When no unblocked candidates exist:** Inform the human. Suggest reviewing blocked items to see if blockers can be resolved, or adding new features via `harness-roadmap --add`.
- **When affinity data is unavailable:** Proceed without affinity scoring (weight falls to 0 for all candidates). Note this in the output.
- **When external sync fails:** Log the error, complete the local assignment, and note that external sync can be retried with `harness-roadmap --sync`.
