---
id: "ct_2026-04-17"
project: "agent-workspace-template"
sessionId: "45328ba3-bd9b-41bd-aca1-845c50dce134"
createdAt: "2026-04-17T01:50:00Z"
tags: ["m1-m6", "pillar-2-design", "dogfood", "interface-drift", "eval-gate", "publish-prep", "docs-consolidation"]
packsReferenced: ["rag-hybrid-bm25-vector", "golden-eval-harness", "pattern-decision-tree", "shadcn-data-table", "linear-command-palette"]
---

# Trace ct_2026-04-17

**Project:** agent-workspace-template  
**Session:** 45328ba3-bd9b-41bd-aca1-845c50dce134  
**Created:** 2026-04-17T01:50:00Z

## Packs Referenced

- rag-hybrid-bm25-vector
- golden-eval-harness
- pattern-decision-tree
- shadcn-data-table
- linear-command-palette

## Tags

- m1-m6
- pillar-2-design
- dogfood
- interface-drift
- eval-gate
- publish-prep
- docs-consolidation

## Cross-References

Packs consumed in this session: `rag-hybrid-bm25-vector`, `golden-eval-harness`, `pattern-decision-tree`, `shadcn-data-table`, `linear-command-palette`

## Scenario

1. Five parallel workers were about to build a catalog in pieces without a shared blueprint for what one entry (a pack) looks like.
2. First real CLI install failed: [INVALID] Failed to fetch pack metadata: Pack payload missing slug. The API returned { pack: {...} }; the CLI expected the pack object bare.
3. Retry after the envelope fix: metadata OK but [NOT_FOUND] /api/packs/<slug>/raw. Raw MD is a content route under /packs, not an API route.
4. 5 concurrent install tests hit random Windows EPERM on fs.rename against a shared AGENTS.md destination.

## Files Touched

- src/lib/pack-schema.ts
- cli/src/registry.ts
- cli/src/install.ts

## Changes

4 file-level changes across 4 rows.

## Why

1. **Pin the shape before the work.** — Pick one shape for the data before five workers start using it.
2. **Mocks lie. Dogfood the handshake.** — Two workers wrapped the data differently, so nothing flowed through.
3. **Group by content type, not caller.** — The CLI asked for the file at the wrong address. Right house, wrong street.
4. **If the OS says 'busy,' wait a beat.** — Five installs ran at once and Windows said 'busy' even though nothing was wrong.

## Failure Modes

- **[MID] Two parallel workers ship incompatible shapes; integration fails at the wire.**
  - Trigger: No shared type pinned before parallel work starts; each worker invents its own.
  - Prevention: Pin the canonical schema before parallel fan-out; add a type-compile gate on merge. (see: pattern-decision-tree)
- **[SR] Unit tests green, first real install fails: 'Pack payload missing slug'.**
  - Trigger: API and CLI each mocked the counterparty; contract envelope drifted undetected.
  - Prevention: End-to-end contract test that spans real API + real CLI + real filesystem. No mocks at the boundary. (see: golden-eval-harness)

---

# Row 1

## Scenario

Five parallel workers were about to build a catalog in pieces without a shared blueprint for what one entry (a pack) looks like.

## Files Touched

- src/lib/pack-schema.ts

## Changes

### `src/lib/pack-schema.ts`

+9 TypeScript types locking the Pack shape for five parallel workers. Blueprint only, no runtime code.

- Added: `Pack`, `PackContract`, `PackLayers`, `TransferMatrixEntry`, `Telemetry`, `SecurityReview`, `PackComparison`, `ChangelogEntry`, `PackSource`

## Why

- **Plain:** Pick one shape for the data before five workers start using it.
- **Analogy:** Like everyone agreeing on paper size before the printers start running.
- **Principle:** A shared schema is the contract that lets parallel work converge. Without it every worker drifts.
- **Hook:** Pin the shape before the work.

## Failure Modes

- **[MID] Two parallel workers ship incompatible shapes; integration fails at the wire.**
  - Trigger: No shared type pinned before parallel work starts; each worker invents its own.
  - Prevention: Pin the canonical schema before parallel fan-out; add a type-compile gate on merge. (see: pattern-decision-tree)

---

# Row 2

## Scenario

First real CLI install failed: [INVALID] Failed to fetch pack metadata: Pack payload missing slug. The API returned { pack: {...} }; the CLI expected the pack object bare.

## Files Touched

- cli/src/registry.ts

## Changes

### `cli/src/registry.ts`

RegistryClient.get(): parse → (parsed && 'pack' in parsed) ? parsed.pack : parsed. Envelope-aware unwrap.


## Why

- **Plain:** Two workers wrapped the data differently, so nothing flowed through.
- **Analogy:** Like mailing a letter — one uses an envelope, the other hands it bare. Receiver only opens envelopes.
- **Principle:** Shape is part of the contract. Mocks hide shape drift; only a real handshake reveals it.
- **Hook:** Mocks lie. Dogfood the handshake.

## Failure Modes

- **[SR] Unit tests green, first real install fails: 'Pack payload missing slug'.**
  - Trigger: API and CLI each mocked the counterparty; contract envelope drifted undetected.
  - Prevention: End-to-end contract test that spans real API + real CLI + real filesystem. No mocks at the boundary. (see: golden-eval-harness)

---

# Row 3

## Scenario

Retry after the envelope fix: metadata OK but [NOT_FOUND] /api/packs/<slug>/raw. Raw MD is a content route under /packs, not an API route.

## Files Touched

- cli/src/registry.ts

## Changes

### `cli/src/registry.ts`

getRawMarkdown(): path /api/packs/*/raw → /packs/*/raw. Content lives under /packs; /api is JSON only.


## Why

- **Plain:** The CLI asked for the file at the wrong address. Right house, wrong street.
- **Analogy:** Like mailing a letter to '42 Main' when the house is '42 Elm.' Post office returns it even though the building exists.
- **Principle:** URLs group by content type, not by caller. /api means data; /packs means content.
- **Hook:** Group by content type, not caller.

## Failure Modes

_None documented._

---

# Row 4

## Scenario

5 concurrent install tests hit random Windows EPERM on fs.rename against a shared AGENTS.md destination.

## Files Touched

- cli/src/install.ts

## Changes

### `cli/src/install.ts`

atomicWriteFile(): add EPERM/EACCES/EBUSY retry with backoff; preserve write-before-rename semantics.


## Why

- **Plain:** Five installs ran at once and Windows said 'busy' even though nothing was wrong.
- **Analogy:** Five people trying to swap the same bookmark in one book. The book allows one swap at a time; others wait a beat.
- **Principle:** Atomicity on rename is OS-dependent. When the OS serializes a shared resource, retry turns the race into a queue.
- **Hook:** If the OS says 'busy,' wait a beat.

## Failure Modes

_None documented._
