# Session Gotchas — bugs and design failures from the FC-01/FC-02 build session

This skill was authored from a real session designing FC-01 ("Crossfire") and FC-02 ("Three Doors") with Jory. Below are the specific mistakes that came up and what to do instead.

## 1. Shooting box vs. shooting area

**Mistake**: Initial FC-01 used a `shootingBox` prop, which physically locks the shooter to a 3 ft × 3 ft square. This made most targets unshootable.

**Correct**: For freestyle field courses, use a `faultLineSegment` polygon + a `startPosition` mark. The shooter can move anywhere inside the polygon.

`shootingBox` is appropriate ONLY for classifier-style stages with a fixed shooting position.

## 2. Berm as boundary

**Mistake**: First fault-line attempt used the bay's berms as implicit side/back boundaries — only the inner edges had fault lines.

**Correct (per the user)**: *"All shooting areas should be a three-dimensional shape defined on the outside by a fault line, not the bay edge."* The polygon must close on EVERY outer edge with fault lines (or walls, which are valid boundaries).

## 3. Walls in front of paper targets

**Mistake**: Original FC-01 had walls placed where bullets through the paper would hit them. The user pointed out this tears up the club's props.

**Correct**: For every paper target, trace the bullet trajectory from a realistic shooter position THROUGH the target. The line must terminate in a berm, not a wall, prop, or other target. Move the wall or rotate the target until safe.

## 4. Pass-through into another target

**Mistake**: Two paper targets in roughly the same vertical column at different y-depths created a phantom-hit hazard — bullets through T13 hit T12 from rear-band shooter positions.

**Correct**:
- Stagger y-depth between adjacent paper in the same x-column.
- For a back row at y=1, alternate to y=3 every other target: y=1, 3, 1, 1, 3, 1.
- Verify with the bullet-line math from at least three reachable shooter positions: rear-center, rear-left-corner, rear-right-corner.

## 5. Hand-drawn fault lines don't snap

**Mistake (user-side)**: Editing fault lines in the editor produces sub-inch coordinates like (7.83, 19.83) — visually fine but messy in JSON.

**Correct**: When cleaning up hand-edited geometry, snap to integer coordinates. Group collinear adjacent segments into single segments. Make sure all endpoints meet cleanly so the polygon closes.

## 6. Hand-rotated target angles can cause wall hits

**Mistake (user-side)**: Rotating a target stand in the editor produced facing angles like -67.29° (WSW). For a target in a corner of the shooting area, the resulting bullet trajectory hit the nearest wall.

**Correct**: When cleaning up hand-edited facings, snap to standard angles (0, 90, 135, 180, 225, 270) — and verify the post-pass-through trajectory still terminates in a berm.

Pre-check before applying any non-cardinal facing:
1. Where does the bullet go after pass-through? (face direction extended past the target)
2. Does that vector cross any wall or paper?
3. Does it reach a berm?

## 7. Editor's `roundCount` field defaults to 12

**Mistake**: `toStageJson()` returns `roundCount: 12` even when the brief override is set higher. The exported JSON had wrong round count.

**Correct**: After `toStageJson()`, manually override:
```javascript
stage.roundCount = stage.brief.roundCountOverride || /* actual */;
```

## 8. Bash heredoc clobbering the JSON file

**Mistake**: Used a Bash heredoc with `$(cat << 'INNER' ... INNER)` placeholder pattern to overwrite the file. The shell evaluated the literal placeholder and wrote garbage.

**Correct**: Always use the `Write` tool for files that contain code/JSON. Bash heredocs are error-prone for structured content. (Also flagged by the user with a system notice.)

## 9. Editor autosave can overwrite a fresh load

**Mistake**: After the user loaded a new file via `Open...`, the editor showed an old state because autosave from a previous session in localStorage was still active.

**Correct workflow for the user**: Click `+ New` first to wipe local state, dismiss the restore prompt with `Start Fresh`, THEN `Open...` the file. Skill should mention this if the user reports a blank canvas or stale view after loading.

## 10. "Fit" button can leave the view off-screen

**Mistake**: After applying a new stage with very different bay dimensions, the canvas zoom can land somewhere that hides all props.

**Correct**: Always click `Fit` after `applyStageJson`. If the user reports a blank canvas in their browser, suggest clicking `Fit`.

## 11. Walls can serve as polygon perimeter

**Insight** (from the user's FC-02 v4 edit): A 6-ft-tall vertical wall is a physical barrier the shooter cannot cross. It can substitute for a fault line segment in the polygon perimeter, with short fault-line segments bridging from the wall ends to the next perimeter feature.

**Useful pattern**: Place a wall on the inside edge of a lane (e.g., x=8, y=22-30) and have fault lines for the rest of the perimeter (the top, the front, the outer side). The wall provides a tangible visual cue for the shooter PLUS counts as the legal boundary.

## 12. Target close to fault line = too close to engage

**Mistake (FC-02 v3)**: Front fault line at y=4 with center targets at y=1-3. Shooter at the fault line (y=4) is 1-3 ft from the targets. Below USPSA's 5-yard minimum.

**Correct**: Front fault line should be at least 5 yards (15 ft) uprange of the closest target. For targets at y=1, put the front fault at y=16+.

OR position the targets further downrange so the closest reachable point is 5+ yards away.

## 13. Tightly clustered center targets fit better with side lanes

**Insight**: When the shooting area is U-shaped with lanes down each side, the center cutout (downrange terrain) is narrow. Center-row targets must fit into this narrow x range — pack them at 2 ft on-center with alternating y-depth, total cluster width ≈ 11.5 ft for 6 targets.

## 14. The user prefers terse engineering interactions

**Style note**: When iterating on a stage, the user prefers short status updates between chunks (1-2 sentences each), with screenshots inline. Save the long-form prose for the final stage brief. Acknowledge corrections concisely and apply them — don't relitigate previous decisions.

## 15. Stage-brief "gotchas" are NOT tactical shooting tips

**Mistake**: First several stage briefs in this session had gotchas like *"engage from the lane"*, *"slow your transitions"*, *"pick the wrong array and you'll run back across the bay"*. The user called this out — that's coaching the shooter, which is inappropriate for a stage brief.

**Correct**: The gotchas field is for **RO and setup-crew reminders** only — things that, if forgotten, cause a procedural penalty, a DQ, or a build error. Examples:
- "Mandatory reload between Box A and Box B — failure = 1 procedural per shot fired"
- "No-shoot NS1 touches T6 on the south edge — set flush, not overlapping"
- "Start position requires both hands flat on barricade above the marked line"
- "Round count: 14 paper × 2 = 28 rounds"

The shooter develops their own plan from the diagram and procedure. The brief is a neutral document and should not coach engagement order, position selection, or pacing.

## 16. New-stage-designs save location

**Convention**: save user-authored stage JSON to a clearly-named folder. Default suggestion when the user has no preference: `~/Desktop/new stage designs/` (create it if needed).

## 17. Interpreting common iteration phrases

These are user-facing language patterns from the dev session that need consistent translation to coordinates/angles.

### "Mirror the right side to match the left side"

Apply the symmetry transform: for each LEFT-side target at `(x, y)` with `facingDegrees = f`, the mirrored RIGHT-side target is at:
```
x_new      = bayWidthFeet - x_old
y_new      = y_old                (unchanged)
facing_new = (360 - f) mod 360
```

For an NE-angled left target at facing=150°, the mirrored right target is at facing=210°.
For an E-facing left target at facing=90°, the mirrored right target is at facing=270°.
For an ENE-angled left target at facing=110°, the mirrored right target is at facing=250°.

When mirroring an ANGLED stand, also swap `baseEndpointA` and `baseEndpointB` so the stand stays geometrically correct after the x-flip.

### "Angle that target X% more toward the shooter"

The shooter is typically uprange (facing 180° direction in v2). "More angled toward shooter" means rotate the facing toward 180°.

Formula: `facing_new = facing_old + X% × (180 - facing_old)` for left-side targets (where facing < 180 means the target faces NE).
For right-side targets (where facing > 180 means NW), it's `facing_new = facing_old - X% × (facing_old - 180)`.

Examples from session:
- "T7 30% more angled toward shooter" — was facing=135 → `135 + 0.30 × (180-135) = 148.5 → 150°`
- Mirror right side gets the same `30%` rotation: T12 was 225 → `225 - 0.30 × 45 = 211.5 → 210°`

Round to clean numbers (multiples of 5° or 10°) when possible.

### "Angle that target a little more uprange"

Same as above with a smaller percent. "A little" ≈ 20-25%. "More" ≈ 30-40%. "Much more" ≈ 50%+.

Example: "T9 a little more uprange" — was facing=90 (pure east) → `90 + 0.22 × (180-90) = 109.8 → 110°`.

### "Make the shooting area X feet wide between wall and targets"

The user is specifying the lane width as measured from the wall's x to the target line's x.

To achieve `lane_width = W` with targets at `target_x`:
- `wall_x = target_x + W` (for left lane — wall east of targets)
- `wall_x = target_x - W` (for right lane — wall west of targets)

Often paired with "scoot the targets toward the berm." Resolve both: first move targets to the new x (closer to berm by ~1 ft), then place the wall at `target_x + W`.

### "Scoot the targets toward the berm by ~1 foot"

Translate each LEFT-side target's x by -1; each RIGHT-side target's x by +1. Don't change y. For angled stands, also translate both `baseEndpointA.x` and `baseEndpointB.x` by the same delta.

### "Remove the jut" / "Just make the lane straight"

If the polygon had an L-shaped lane with a jut, simplify to a single rectangle. Adjust fault-line segments accordingly. Wall typically moves to the new (simpler) inner edge of the lane.

## 18. The "rename to FC-NN" pattern

When the user says "rename to FC-NN" or "make it FC-NN," update three places:
1. The `code` field in the stage JSON.
2. The Stage Settings dialog `stage-code` input (so the title bar matches in the editor).
3. The output filename — `<save-folder>/FC-NN_<Name>.json` (default save-folder suggestion: `~/Desktop/new stage designs/`).

If the OLD file with the previous code still exists on disk, ASK whether to leave it or delete it. Don't silently leave orphaned files.

## 19. Don't put targets inside the shooter polygon

**Mistake (FC-02 v1)**: Built east-facing T5/T6 at (2, 20-21.5) and (1, 25-26.5), and west-facing T9/T10 at (33, 20-21.5) and (34, 25-26.5). All four were INSIDE the lanes (the polygon's left lane spans x=0–10, y=20–30; right lane mirror). User flagged it: targets belong in downrange terrain, NOT inside the fault line.

**Correct**: Move them OUTSIDE the polygon. For east-facing targets reachable from inside the left lane, push them SOUTH of the lane front fault. FC-02 v2 final positions: T5 at (1, 18–19.5), T6 at (1, 13–14.5), both south of the y=20 fault, still east-facing so the lane shooter can engage them from the NE.

Same principle for west-facing right targets — south of the lane front fault, just west of the right berm.

See [[safety_rules]] § 9 for the full rule.

## 20. Drop fault segments that overlap an outer-perimeter fault

**Mistake (FC-02 v1)**: Built outer rectangle with front fault at y=20 (x=0–35), AND inner cutout with south fault at y=20 (x=10–25). The cutout south fault is collinear with — and a subset of — the outer front fault. Two faults drawn in the same place clutter the diagram and read as "two shooting areas."

**Correct**: When laying out a frame-with-cutout polygon, check whether any cutout edge is collinear with an outer-perimeter fault. If so, drop the inner one. The cutout becomes 3-sided (here: open south, with cutout west / north / east only). The shooter's legal area is unchanged because the outer front fault already enforces the boundary.

See [[safety_rules]] § 10.

## 21. No-shoots can shoot-through just like paper

**Mistake (FC-02 v1)**: Placed NS1 (east-facing no-shoot) at (5, 15.5-17) to bracket the angled T3/T4 paper. Did NOT trace the bullet line from rear-band shooter positions through the no-shoot's plane. Math: bullet from shooter (10, 32) to T3 (4, 12) crosses x=5 (NS1's cardboard plane) at y=15.33 — 2 inches south of NS1's bottom edge. Shooter at (8, 32) crosses at y=17 (right at NS1's top edge). Both grazes. From shooter x ≈ 8–10, the NS gets shot through on every legitimate attempt at T3. User flagged it.

**Correct**: Removed NS1/NS2 from FC-02 v2. For future stages, either:
- Place no-shoots PASTED to the paired paper (touching, not floating in the bullet line).
- OR explicitly verify the bullet line from every "natural" shooter position misses every nearby NS by ≥ 1 ft.
- OR use hardcover ON the paper instead of a separate no-shoot to add difficulty.

See [[safety_rules]] § 11.

## 22. Stages don't have to be symmetric

**Insight from the user**: Several iterations in the dev session ended with mirrored left/right designs because the user explicitly asked for "mirror the right side." But not every stage should be symmetric. Asymmetric stages break shooter assumptions and reward thinking — they're often the more interesting designs.

**Behavior change for the skill**: Added Symmetry as a question in the interview (see SKILL.md Step 1). When the user picks "Asymmetric" or "Doesn't matter," don't reflexively call `mirrorTargetSet` or apply the (x, y, facing) → (W-x, y, 360-facing) transform. Build each side independently from the philosophy.

For "Symmetric" (or when Miculek-style § Symmetrical Layouts applies), use the mirror formula in § 17.

## 23. Fault segments must be 4-ft-divisible (club stock sticks)

**Mistake (latent across FC-01/FC-02)**: Used arbitrary fault-segment lengths like 6 ft, 10 ft, 13 ft, 15 ft, etc. throughout the dev session. None of these can be built cleanly from a club's 4-ft / 8-ft stock fault sticks.

**Correct**: Every fault segment must have a length that's a multiple of 4 ft. Plan polygon vertices so all segments work: 4, 8, 12, 16, 20, 24, 28, 32, ...

Bay dimensions should also be 4-ft-divisible — 32 × 40, 36 × 40, 40 × 40 are clean. 35 × 40 forces a 35-ft segment somewhere, which won't build. If the user wants a 35-wide bay, inset the polygon by 1.5 ft on each side to get a 32-ft polygon width that does build.

**Verification before saving**: compute every fault segment's length, assert each is divisible by 4. See [[safety_rules]] § 12 for the full rule.

## 24. Ported walls must be on a fault-line edge (the shooter touches the wall)

**Mistake (FC-02 v1)**: Placed the "Port Wall" at y=12 with the shooter polygon ending at y=20 (front fault). The wall was 8 ft downrange of the shooter, floating in the middle of downrange terrain. Two problems:
1. Shots that miss the 1-ft port hit the solid wall — repeated impact wears the prop.
2. The "port shot" became an extreme-angle thread-the-needle from across the bay, not the lean-into-the-port experience that ported walls are meant to give.

**Correct**: A wall WITH a port must sit on a fault-line edge of the shooter polygon. The shooter walks up to the wall, leans against it, and aims through the port at point-blank range.

For FC-02 specifically, the right placement is the Port Wall at y=20 spanning x=10–25 (along the outer front fault) — shooter at y=20.1 is touching the wall.

Walls WITHOUT ports (pure visual blockers) CAN sit a few feet downrange of the polygon. The rule only applies when the wall has a cutout the shooter aims through.

**Quick mnemonic**: *If the wall has a hole in it, the shooter touches it. If the wall is solid, the shooter looks past it.*

See [[safety_rules]] § 13.

## 25. Wall lengths must be 2/4/8 ft stock panel combos

**Mistake (FC-02 v1)**: Made the Port Wall 15 ft long (from x=10 to x=25). 15 ft is odd — it can't be built from any combination of 2 ft, 4 ft, and 8 ft stock panels. Setup crew would have to cut a panel.

**Correct**: Wall length must be an even integer ≥ 2. Build longer walls by butting panels end-to-end (prefer 8s for fewer joints, then 4s, reserve 2s for edge cases). A 15 ft wall should become 14 ft (8+4+2) or 16 ft (8+8) depending on geometry needs.

**Verification before saving**: compute every wall's length, assert it's an even integer. Odd lengths → snap to nearest even.

See [[safety_rules]] § 13 "Wall length must be buildable from 2, 4, and 8 ft stock panels."
