Files
jparkerweb 32d1487dcf Delegate workflow installation to the skills CLI
Replace per-tool distribution generation with a canonical committed skills build so installation and updates share one format.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-20 13:42:31 -07:00

34 KiB

Handoff Playbook — Clearing the Map into a PLAN-DRAFT

Loaded at The Clearing Gate. Turns a cleared map into specs/<idea>/PLAN-DRAFT-<YYYYMMDD>.md that /plan2code-1-plan resumes from at Phase 4, then freezes pathfinder/ as the rationale record.

Backend note. The scoring rubric, the hard caps, the honesty rules, the template, and the mapping table are the same either way — and the draft is written to local disk either way, because /plan2code-1-plan reads a file, not a tracker. On **Backend:** github, github-issues.md replaces only the preflight table, the question links (issue URLs, already absolute), and the freeze steps.

Nothing here is creative. The gate is scored, the mapping is fixed, the template is literal. Follow it exactly or the resuming plan session silently loses work.

Preflight — before scoring anything

# Check If it fails
1 Re-run the reconcile pass: read every file in questions/, rebuild every map marker from the files Fix the map first. Markers are derived, never authored.
2 Zero [ ], zero [/], zero [!] rows in ## Question Checklist Not cleared. Return to the frontier.
3 ## Not yet specified is empty Not cleared. Graduate the fog into questions, or admit it is out of scope.
4 Every [x] row's file has a real ## Answer with a **Gist:** The file wins over the marker. Repair, then re-check.
5 ls specs/<idea>/ shows no existing PLAN-DRAFT-*.md One already exists — read it. Update it in place; never add a second dated draft.
6 The destination is reachable with nothing left to decide — no ## Answer defers a choice to "whoever implements this" Not cleared. Name the open decision and graduate it into a question.

Only after all six pass do you score the four dimensions.

The clearing-gate scoring rubric

Four dimensions, 0-25 each, scored against written evidence in questions/ — never against your recollection of the conversation. The gate needs every dimension at 18/25 or better. There is no averaging: 25/25/25/14 fails.

Band scale (applies to all four)

Band Meaning
23-25 Decided, written down, and consequences recorded. A developer could act on it without asking a question.
18-22 Decided and written down. Residual detail remains, but it is specification detail that Phase 5/6 settles — not a decision anyone still has to make.
12-17 A real decision is still open, or an answer exists with no evidence behind it. Gate fails.
0-11 The area was never charted. Gate fails, and the map was cleared prematurely.

The 18-boundary is the honest line between "needs designing" and "needs deciding". Pathfinder owns deciding. If someone still has to decide, you are not done.

What each dimension scores

Dimension Scores Raises it Lowers it
Requirements Clarity Are the requirements unambiguous? Every resolved grill answer states the decision AND what was rejected; the testing-posture answer names types, cadence, and coverage Answers phrased as preferences ("probably NDJSON") instead of decisions; a requirement that only exists in the map gist and not in a question file
Technical Feasibility Do we know HOW to build each component? Resolved sketch questions with a real artifact under sketch-NN/; research answers citing primary sources under ## Evidence; 00-codebase-context.md naming the actual files that change A mechanism nobody has exercised in this codebase; a research answer whose ## Evidence is empty or cites only a blog post
Integration Points Are all external dependencies identified? Every system named in ## Destination has a resolved question touching it; auth, quota, and failure behavior named per integration An integration mentioned in an answer but never questioned; a config store that was read but never written to during a sketch
Risk Assessment Are blockers documented with mitigations? Answers that record consequences; Locked: yes answers that say what breaks if reversed; ceilings with a stated behavior at the ceiling A recorded limit with no decided behavior past it; a Locked: yes answer with no consequences section

Hard caps

A cap overrides your judgment. While a cap condition holds, the dimension cannot exceed 17, so the gate cannot pass.

Cap Condition
Requirements ≤ 17 The testing-posture question is not resolved, or its answer omits any of types / cadence / coverage
Feasibility ≤ 17 Any research question is resolved with an empty ## Evidence
Integration ≤ 17 A system named in ## Destination has no resolved question touching it
Risk ≤ 17 Any Locked: yes answer records no consequences

Honesty rules

  • Score the written record, not the conversation. If the human agreed to something in a session and nobody wrote it into a ## Answer, it does not exist and it does not earn points.
  • A filled ## Answer is not automatically 25. An answer that decides but records no consequences tops out around 20.
  • Never round up to clear the gate. A 17 that "feels like an 18" is the exact case the gate exists to catch.
  • Never move a decision to ## Out of scope to raise a score. Out-of-scope is a scoping act with a reason; scope-cutting to pass a gate is score inflation with extra steps.
  • If two dimensions are borderline, write the one-line justification for each score into the Session End report. Justifications that cannot be written are scores that cannot be defended.

Worked example — idea audit-log-s3-export

Destination: "A spec a developer can implement: nightly export of tenant audit logs to customer-owned S3 buckets, with a signed manifest per run."

Resolved questions: Codebase context, Export format, Scheduling model, Destination auth, Retention and replay, Testing posture, Throughput ceiling. Ruled out: Failure notification.

First scoring pass:

Dimension Score Justification against evidence
Requirements Clarity 22/25 Four grill answers state decisions and rejections (NDJSON chosen, CSV rejected for nested actor payloads). Testing posture settled: integration + unit, run after each phase, moderate coverage. Minus 3: the manifest's exact field list is unspecified — a Phase 5 spec detail, not an open decision.
Technical Feasibility 21/25 sketch-02 uploaded a 400 MB multipart object to a real bucket end to end. 00-codebase-context.md names AuditExportJob and the existing Hangfire registration as the extension points. Minus 4: no component in this codebase has ever assumed a cross-account IAM role; the pattern is documented in AWS docs cited under ## Evidence but unexercised here.
Integration Points 23/25 Three integrations, each with a resolved question: S3 (Destination auth), Hangfire (Scheduling model), tenant config store (Codebase context). Auth and quota named per integration. Minus 2: the tenant config store's write path was read but never exercised by a sketch.
Risk Assessment 16/25 Consequences recorded on Export format and Destination auth. But Throughput ceiling establishes 200 MB per tenant per day at p95 and records no decided behavior above it — truncate, spill to the next run, or fail the run is still undecided.

Gate result: FAIL on Risk Assessment (16 < 18), and the orchestrator third clearing condition — the destination reachable with nothing left to decide — fails with it: a decision is genuinely still open. Do not write a PLAN-DRAFT. Name the failure, graduate questions/08-overflow-behavior.md (grill · HITL, Blocked by: none) from the gap, and end the session on the frontier.

Second scoring pass, one session later, with Overflow behavior resolved (spill to the next run, alarm at three consecutive spills):

Dimension Score
Requirements Clarity 22/25
Technical Feasibility 21/25
Integration Points 23/25
Risk Assessment 20/25

All four at 18 or better. Gate passes. Proceed to the mechanism.

The mechanism, stated plainly

Pathfinder writes specs/<idea>/PLAN-DRAFT-<YYYYMMDD>.md with the header line:

**Status:** Phase 3 Complete - Resume at Phase 4

/plan2code-1-plan already recognises that exact string. Its "Check for Existing Progress" block, which runs before Phase 1, reads:

- Status "Phase 3 Complete - Resume at Phase 4": Resume at Phase 4

That is the whole handoff. The string is the contract, and it needs zero changes to the planning skill — pathfinder is impersonating the Large-project Context Checkpoint that 1-plan's own Phase 3 performs, which writes the same status for the same reason.

Consequences of that being a literal string match:

  • Copy it byte for byte. Plain ASCII hyphen-minus surrounded by single spaces. An en dash, a colon, or "Phase 3 complete" in lower case breaks the match and 1-plan starts over at Phase 1 — throwing away every decision the map holds.
  • It goes on its own **Status:** line in the header block, not buried in prose.
  • The file must be named PLAN-DRAFT-<YYYYMMDD>.md and live directly in specs/<idea>/. PLAN-DRAFT-*.md is a reserved name inside pathfinder/ — never write it there.
  • Get the date from the shell (date +%Y%m%d in Bash, Get-Date -Format yyyyMMdd in PowerShell). Do not guess it.

Discovery is shell-only. specs/ is gitignored, so Glob silently returns nothing and every downstream skill would report "no PLAN-DRAFT found". Use ls specs/ and ls specs/<idea>/ (Bash) or Get-ChildItem specs/ (PowerShell) — the same rule 1-plan and /plan2code-2-document follow when they look for the file you are about to write.

Do not append ## Planning Metrics or any metrics comment. Pathfinder is not a metered step. 1-plan's Phase 7 owns that block and will add it when it finishes the plan. Do not emit any of the loop's completion tokens listed in the skill's Rules anywhere under specs/.

Map to PLAN-DRAFT mapping

Everything in the draft traces to something on the map. Nothing is invented at handoff time — if a section has no source, that is a gate failure you missed, not a paragraph to write from imagination.

Source on the cleared map Becomes
## Destination Section 1 Executive Summary (2-3 sentences, present tense) and Section 7 Success Criteria (the destination restated as checkable outcomes)
Resolved grill answers describing behavior Section 2.1 Functional Requirements, one FR-N per decided behavior
Resolved grill answers describing performance, security, scale, operability Section 2.2 Non-Functional Requirements, one NFR-N each
## Out of scope Section 2.3 Out of Scope — copied line for line, wording and order intact. The ONLY permitted change is the link prefix: ./questions/ becomes ./pathfinder/questions/, because the draft sits one level above the map. Do not re-word, re-order, or summarise; a re-worded scope boundary is a re-litigated one.
The testing-posture question's answer Section 2.4 Testing Strategy table (Types / Phase Testing / Coverage)
Resolved research answers and their ## Evidence Section 3 Tech Stack — the cited source becomes the Justification cell
questions/00-codebase-context.md The ## System Context section, and the components table in 4.3
Answers with Locked: yes Section 4 Architecture (4.1 Pattern rationale, 4.4 Data Model, 4.5 API Design) and Section 9 Assumptions — a locked decision is an assumption downstream work is allowed to rely on
Consequences recorded across all ## Answer sections Section 6 Risks and Mitigations — the consequence is the Risk, the decision that bounds it is the Mitigation
## Ground rules The AGENTS.md line in ## System Context; conventions the plan must not violate
The shape of the map (question count, integrations touched, components named) The ## Scope Assessment section
Resolved sketch questions and their artifacts Section 3 Justification cells and Section 6 Mitigation cells ("proven by pathfinder/sketch-02/")
Every resolved question, by name ## Pathfinder Provenance
Section 5 Implementation Phases stays empty. 1-plan Phase 6 breaks the work into phases. Pathfinder decides; it does not slice. Leave the placeholder note in place and do not put implementation checkboxes there.

Questions ruled out-of-scope never appear in Provenance and never become requirements. Their one line in ## Out of scope is their only trace — that is the point of the marker.

The PLAN-DRAFT template

Write this literally, substituting real content. Keep the section numbering exactly as shown — 1-plan and /plan2code-2-document both address sections by number.

> Pathfinder planning note - decisions, not implementation work. Archive with the spec; do not delete.

# Audit Log Export - Implementation Plan

**Created:** 2026-08-03
**Status:** Phase 3 Complete - Resume at Phase 4
**Charted by:** `/plan2code-0-pathfinder` over 9 sessions
**Planning record:** `specs/audit-log-s3-export/pathfinder/map.md` (no PLAN-CONVERSATION - this plan was charted, not conversed)
**Confidence (pathfinder):** Requirements-clarity 22/25 · Feasibility-technical 21/25 · Integration-points 23/25 · Risk-assessment 20/25

---

## 1. Executive Summary

Tenants can have their audit logs exported nightly to an S3 bucket they own, with a
signed manifest per run so they can prove completeness. Export runs on the existing
Hangfire schedule, writes NDJSON, and assumes a customer-provided cross-account IAM
role with an external ID. Runs that exceed the per-tenant daily ceiling spill into the
next run rather than truncating.

## 2. Requirements

### 2.1 Functional Requirements

- [ ] **FR-1:** Export each tenant's prior-day audit events as newline-delimited JSON, one object per event, UTF-8, no BOM
- [ ] **FR-2:** Write a per-run manifest listing object keys, event counts, byte counts, and a SHA-256 per object
- [ ] **FR-3:** Sign the manifest with the platform export key; publish the public key at a stable URL
- [ ] **FR-4:** Assume the tenant-configured IAM role with the tenant's external ID; never use platform-owned credentials against a customer bucket
- [ ] **FR-5:** Allow an operator to replay any run within a 7-day window without duplicating manifest sequence numbers
- [ ] **FR-6:** Spill events above the per-tenant daily ceiling into the next scheduled run, oldest first
- [ ] **FR-7:** Raise an alarm after three consecutive spilling runs for the same tenant

### 2.2 Non-Functional Requirements

- [ ] **NFR-1:** Sustain 200 MB per tenant per day at p95 without extending the nightly window past 04:00 UTC
- [ ] **NFR-2:** Never log tenant event bodies, bucket names, or assumed-role ARNs above debug level
- [ ] **NFR-3:** A failed run must leave no partial objects visible in the customer bucket
- [ ] **NFR-4:** Export must add no schema changes to the audit event write path

### 2.3 Out of Scope

<!-- copied line for line from pathfinder/map.md ## Out of scope; only the link prefix changes -->

- [Failure notification](./pathfinder/questions/07-failure-notification.md) — email/webhook delivery of run failures belongs to the platform alerting effort, not this export. The alarm in FR-7 is raised, not delivered.
- **On-demand export from the tenant UI** — the destination is the scheduled export. A user-triggered export is a separate effort with its own map.
- **Log formats other than NDJSON** — Parquet was raised and ruled past the destination.

### 2.4 Testing Strategy

| Aspect | Decision |
|---|---|
| Types | Unit + Integration |
| Phase Testing | Run after each phase |
| Coverage | Moderate (~60-80%) |

## System Context

**Project type:** Existing codebase — .NET 8 service, `src/Platform.Audit/`

| Aspect | Finding | Source |
|---|---|---|
| Entry points to change | `AuditExportJob`, registered in `HangfireStartup.ConfigureRecurringJobs()` | [Codebase context](./pathfinder/questions/00-codebase-context.md) |
| Existing patterns to follow | Jobs resolve tenant scope via `ITenantScopeFactory`; no job reads config directly | [Codebase context](./pathfinder/questions/00-codebase-context.md) |
| Integration surfaces | S3 (customer-owned), Hangfire scheduler, `TenantConfigStore` | [Destination auth](./pathfinder/questions/03-destination-auth.md), [Scheduling model](./pathfinder/questions/02-scheduling-model.md) |
| Technical debt in the path | `AuditQuery` materialises full result sets; streaming reader needed before FR-1 | [Codebase context](./pathfinder/questions/00-codebase-context.md) |
| System boundaries | Read-only against the audit store; writes only to customer buckets and the run-log table | [Retention and replay](./pathfinder/questions/04-retention-and-replay.md) |
| Conventions in force | `AGENTS.md` present and read; its logging and DI conventions govern | `pathfinder/map.md` ## Ground rules |

## Scope Assessment

**Assessment: Medium** — 11 requirements across 3 integrations, 5 components touched. No Large threshold is met.

| Indicator | Value |
|---|---|
| Requirements decided | 11 (7 FR + 4 NFR) |
| Components | 5 (`AuditExportJob`, `NdjsonWriter`, `ManifestSigner`, `S3RoleAssumer`, `ExportRunLog`) |
| Integrations | 3 (S3, Hangfire, `TenantConfigStore`) |
| Decisions charted | 8 resolved, 1 ruled out of scope |

## 3. Tech Stack

<!-- Phase 4 completes this table. Rows below are decided; do not re-open them. -->

| Category | Technology | Version | Justification |
|---|---|---|---|
| Serialization | `System.Text.Json` NDJSON writer | .NET 8 | [Export format](./pathfinder/questions/01-export-format.md) — no new dependency; CSV rejected for nested actor payloads |
| Object storage | `AWSSDK.S3` multipart upload | 3.7.x | [Throughput ceiling](./pathfinder/questions/06-throughput-ceiling.md) — proven in `pathfinder/sketch-02/` against a real bucket at 400 MB |
| Cross-account auth | STS `AssumeRole` + external ID | — | [Destination auth](./pathfinder/questions/03-destination-auth.md) — AWS confused-deputy guidance cited in that file's `## Evidence` |
| Scheduling | Existing Hangfire recurring job | in-repo | [Scheduling model](./pathfinder/questions/02-scheduling-model.md) — a new scheduler was rejected |

## 4. Architecture

### 4.1 Pattern

Pipeline inside the existing job host: query → stream → chunk → upload → manifest → sign.
Chosen because the audit store is the only source and the export is strictly one-way.
[Locked] A separate export microservice was rejected — see [Scheduling model](./pathfinder/questions/02-scheduling-model.md).

### 4.2 System Context Diagram

<!-- Phase 5 refines. Boundaries above are settled. -->

### 4.3 Components

| Component | Responsibility | Inputs | Outputs | Depends on |
|---|---|---|---|---|
| `AuditExportJob` | Orchestrates one tenant-run | Tenant id, run date | Run result | `TenantConfigStore` |
| `NdjsonWriter` | Streams events to chunked NDJSON | Event stream | Byte stream, counts | — |
| `S3RoleAssumer` | Assumes the tenant role, returns a scoped client | Role ARN, external ID | `IAmazonS3` | STS |
| `ManifestSigner` | Builds and signs the run manifest | Object metadata | Signed manifest | Platform export key |
| `ExportRunLog` | Records runs for replay and spill detection | Run result | Run rows | Platform DB |

### 4.4 Data Model

Manifest sequence numbers are per tenant, monotonic, and reused on replay.
[Locked] See [Retention and replay](./pathfinder/questions/04-retention-and-replay.md).

### 4.5 API Design

<!-- Phase 5 fills. No public API surface was decided during pathfinding. -->

## 5. Implementation Phases

<!-- Intentionally empty. Phase 6 of /plan2code-1-plan breaks the requirements
     above into implementation phases. Pathfinder decides; it does not slice. -->

## 6. Risks and Mitigations

| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Cross-account role assumption is unexercised in this codebase | Medium | High | Spike `S3RoleAssumer` against a second AWS account before any other component |
| A tenant exceeds the daily ceiling indefinitely | Medium | Medium | Spill oldest-first plus a three-run alarm — [Overflow behavior](./pathfinder/questions/08-overflow-behavior.md) |
| Partial objects visible after a failed run | Low | High | Upload to a run-scoped prefix, publish the manifest last — the manifest is the commit point |
| `AuditQuery` materialises full result sets | High | High | Streaming reader is a prerequisite, not an optimisation |
| Customer revokes the role mid-run | Low | Medium | Fail the run whole; replay window covers recovery |

## 7. Success Criteria

- [ ] A tenant with a configured role receives NDJSON and a signed manifest for the prior day, nightly
- [ ] The published public key verifies the manifest signature
- [ ] A 250 MB tenant-day completes without extending the window past 04:00 UTC
- [ ] A replay inside 7 days reproduces the run without a new sequence number
- [ ] A failed run leaves nothing visible in the customer bucket

## 8. Open Questions

<!-- 1-plan's template removes this section when empty; pathfinder keeps it with "None" so a
     resuming session can see the map cleared clean, rather than that the section was forgotten. -->

None. The map cleared with zero open questions.

## 9. Assumptions

- Tenants can create an IAM role in their own account — [Destination auth](./pathfinder/questions/03-destination-auth.md) [Locked]
- The nightly Hangfire window remains available and is not contended by other jobs — [Scheduling model](./pathfinder/questions/02-scheduling-model.md) [Locked]
- Manifest sequence reuse on replay is acceptable to tenant compliance teams — [Retention and replay](./pathfinder/questions/04-retention-and-replay.md) [Locked]
- Audit events are immutable once written, so a replay reproduces byte-identical output

## Pathfinder Provenance

Charted over 9 sessions. Each requirement above traces to a decision below; open the
question for what was rejected, why, and what it costs.

| Question | Gist |
|---|---|
| [Codebase context](./pathfinder/questions/00-codebase-context.md) | `AuditExportJob` and `HangfireStartup` are the extension points; `AuditQuery` needs a streaming reader first |
| [Export format](./pathfinder/questions/01-export-format.md) | NDJSON with a per-run signed manifest; CSV rejected for nested actor payloads |
| [Scheduling model](./pathfinder/questions/02-scheduling-model.md) | Reuse the existing Hangfire recurring job; a dedicated export service was rejected |
| [Destination auth](./pathfinder/questions/03-destination-auth.md) | Customer-owned bucket via assumed role plus external ID; no platform-held customer credentials |
| [Retention and replay](./pathfinder/questions/04-retention-and-replay.md) | 7-day replay window, sequence numbers reused on replay |
| [Testing posture](./pathfinder/questions/05-testing-posture.md) | Unit + integration, run after each phase, moderate coverage |
| [Throughput ceiling](./pathfinder/questions/06-throughput-ceiling.md) | 200 MB per tenant per day at p95; multipart upload proven in `pathfinder/sketch-02/` |
| [Overflow behavior](./pathfinder/questions/08-overflow-behavior.md) | Spill oldest-first into the next run; alarm after three consecutive spills |

Ruled out of scope: [Failure notification](./pathfinder/questions/07-failure-notification.md) — recorded in 2.3.

---

**Next:** Resume with `/plan2code-1-plan` at Phase 4 (Tech Stack).

- **Phase 7 verification:** sections 1, 2, System Context and Scope Assessment are already settled — their source of truth is `specs/audit-log-s3-export/pathfinder/map.md`, not this conversation. Verify sections 3-7 only.
- **Phase 7:** replace THIS file in place. Do not create a second PLAN-DRAFT in this folder.

Two things in that template that are not optional

No scrapable confidence numbers anywhere in the file. Write the confidence as Requirements-clarity 22/25 · Feasibility-technical 21/25 · Integration-points 23/25 · Risk-assessment 20/25 — hyphenated dimension labels, sub-scores over 25, no total, no percent sign.

The reason is exact. When a PLAN-DRAFT carries no METRICS_JSON comment, the metrics collector falls back to scraping it by regex: an overall-confidence pattern that requires a literal %, and four breakdown patterns that match a bare Requirements / Feasibility / Integration / Risk followed directly by whitespace, a colon, or a pipe and then digits. The breakdown patterns do not require a percent sign. A pathfinder-written draft always lacks that comment until /plan2code-1-plan Phase 7 appends one, so both the percent sign and the bare dimension words have to be kept off the page — otherwise the pipeline records a planning-step confidence that no planning step ever produced. The hyphen in Requirements-clarity breaks the match; a table row reading | Requirements | 11 | does not, which is why the Scope Assessment row is labelled Requirements decided.

The **Next:** footer must ship with both bullets. Pathfinder cannot edit the planning skill, so those two instructions travel inside the artifact:

  • Without the verification bullet, 1-plan's Phase 7 does exactly what it is told to do — "re-read conversation as source of truth" — finds a fresh conversation that starts at Phase 4 and contains no requirements discussion at all, concludes sections 1 and 2 are unsupported, and silently drops the requirements that N pathfinder sessions produced. The bullet redirects the source of truth for the settled sections to map.md.
  • Without the replace-in-place bullet, 1-plan's Phase 7 creates PLAN-DRAFT-<its own date>.md alongside yours. /plan2code-2-document then finds two drafts in the folder, hits its "Multiple found: List all, ask which to document" branch, and asks the user to disambiguate between a pathfinder draft and a plan draft that partially supersedes it.

Never drop the footer to make the file tidier. It is load-bearing.

System Context and Scope Assessment — why they buy you Phase 4

These two named, unnumbered sections are what make "Resume at Phase 4" legitimate rather than a shortcut. They stand in for the phases pathfinder already did the work of:

Draft section Satisfies Because pathfinder already
Sections 1 and 2 (including 2.4 Testing Strategy) 1-plan Phase 1: Requirements Analysis Grilled every functional and non-functional decision, and always charted a testing-posture question — that question exists specifically so Phase 1's testing prompt is already answered
## System Context 1-plan Phase 2: System Context Examination Wrote questions/00-codebase-context.md at Chart Step 3: directory structure, key components verified against actual code, patterns and conventions, integration points, technical debt, boundaries — Phase 2's own checklist, item for item
## Scope Assessment 1-plan Phase 3: Scope Assessment Produced the counts Phase 3 measures — requirements, components, integrations — as a byproduct of charting. Map the totals onto Phase 3's Small / Medium / Large table and state the verdict

Populate ## System Context from 00-codebase-context.md and nothing else. It is the one question guaranteed to exist on every map, it was resolved on the spot with the codebase open, and it is a legwork · AFK answer — factual, not preferential. Cite it in the Source column so a skeptical reader can check the finding against the file.

Populate ## Scope Assessment from the shape of the map. Count resolved questions that produced requirements (not 00-codebase-context.md, not out-of-scope ones), count distinct components named across the answers, count distinct external systems. Apply Phase 3's thresholds honestly: Large if any threshold is met. Score the counts, never the session count — a map can take nine sessions to clear and still be Medium, and the Phase 3 Complete - Resume at Phase 4 status string works regardless of the verdict, so there is nothing to gain by inflating it. Pathfinder cannot count implementation phases (Section 5 is deliberately left empty), so assess on requirements, components, and integrations only.

If the charting session found AGENTS.md absent, say so in the Conventions in force row rather than leaving it blank. The plan session needs to know the conventions were never available, not guess that they were checked.

Freeze the map

Once the PLAN-DRAFT is written and saved:

  1. Set **Status:** Cleared in map.md.
  2. Bump **Updated:** to today.
  3. Add a plan pointer line under the status: **Plan:** ../PLAN-DRAFT-20260803.md.
  4. Leave everything under pathfinder/ exactly where it is — map.md, every file in questions/, every sketch-NN/ directory.

Never delete pathfinder/. It is the rationale record behind the plan: what was decided, what was rejected, why, and what it costs. It sits in the same class as PLAN-CONVERSATION-*.md — the transcript a plan is defensible against — and /plan2code-4-finalize archives it alongside PLAN-DRAFT.md and PLAN-CONVERSATION-*.md into specs--completed/<idea>/. Deleting it turns every locked decision in the plan into an unexplained constraint six months from now.

Do not tidy it either. Do not collapse resolved questions into the map, do not prune ## Evidence, do not remove sketch directories because the code is throwaway. The sketch is the proof behind a feasibility score.

A later session that finds Status: Cleared must not resume work on it. The map is finished; there is nothing left to decide inside it. Point at the PLAN-DRAFT and /plan2code-1-plan, and stop. If the destination has been redrawn — the scope grew, an out-of-scope item came back, the goal changed — that is a fresh effort with a fresh map, not a resumption: a new kebab-case idea name, a new specs/<new-idea>/pathfinder/, charting from Step 1. The frontier stops at the destination, so a new destination gets a new frontier. Reopening a cleared map silently invalidates the PLAN-DRAFT that was built from it, and nothing downstream would notice.

What to tell the user

Session End for the cleared case reports six things, in this order:

# Report
1 The destination, restated — what the map was finding its way to, now reached
2 How many decisions were made, and the headline ones by name
3 What was ruled out of scope, and why (one line each)
4 The four confidence scores, with a one-line justification for any below 21
5 The PLAN-DRAFT path
6 The next command — carried by the Trail Footer, which at Cleared routes to /plan2code-1-plan

Example:

Destination reached: a spec a developer can implement for nightly audit-log export to customer-owned S3 buckets with a signed manifest.

8 decisions made across 9 sessions. The load-bearing ones: Export format settled on NDJSON with a signed manifest; Destination auth settled on assumed roles with an external ID so we never hold customer credentials; Overflow behavior settled on spilling rather than truncating.

Ruled out of scope: failure-notification delivery (belongs to the platform alerting effort), on-demand export from the tenant UI (its own effort), Parquet output (past the destination).

Confidence: Requirements-clarity 22/25 · Feasibility-technical 21/25 · Integration-points 23/25 · Risk-assessment 20/25. Feasibility is held at 21 because cross-account role assumption is unexercised in this codebase — it is a documented pattern, not a proven one here, and it is the first thing to spike.

Written: specs/audit-log-s3-export/PLAN-DRAFT-20260803.md. It resumes planning at Phase 4 — sections 1, 2, System Context and Scope Assessment are already settled. The reasoning behind every one of them stays in specs/audit-log-s3-export/pathfinder/; do not delete it.

Then the closing block from the skill's Session End — the mascot with the message The way is clear! Time to plan! followed by the Trail Footer, whose trail shows every stop walked to the destination and whose command is /plan2code-1-plan.

One branch. If ## Ground rules records AGENTS.md as absent, recommend /plan2code-init FIRST, and offer questions/00-codebase-context.md as its input:

Before planning: this project has no AGENTS.md, and /plan2code-1-plan blocks on that. Run /plan2code-init first and attach specs/audit-log-s3-export/pathfinder/questions/00-codebase-context.md — the recon pass already established the structure, conventions, and integration points it asks for. Then /plan2code-1-plan.

Nothing to commit — specs/ is gitignored. Say so once, then stop.

Failure modes

Symptom Cause Fix
1-plan starts at Phase 1 and re-asks for requirements The status string does not match byte for byte Compare against the quoted line above; watch for en dashes and casing
1-plan cannot find the draft at all Glob was used to discover specs/ Shell only: ls specs/
/plan2code-2-document asks which of two drafts to use The replace-in-place bullet was dropped from the footer Merge the two drafts into the pathfinder-dated one, delete the other, restore the footer
The finished plan is missing requirements the map decided The verification bullet was dropped from the footer Re-derive 2.1 and 2.2 from the resolved answers, restore the footer
Metrics report a planning confidence nobody scored A percent sign, or a bare dimension word followed by a number, reached the file Hyphenate the dimension labels and drop the percent sign
A locked decision in the plan has no visible reason pathfinder/ was deleted or pruned Unrecoverable. This is why the freeze step exists
Gate passes but the first implementation session immediately hits an undecided question A dimension was rounded up The gate was the check. Score the written record, not the feeling