initial: pi-setup workspace with skill + extension plan

This commit is contained in:
张宗平
2026-06-10 17:30:43 +08:00
commit 49e581247b
158 changed files with 28777 additions and 0 deletions
@@ -0,0 +1,64 @@
# Pre-Flight Schema Check — Stop Migration Cycles That Can't Succeed
Three phase-2 port migrations attempted in cycles 156-157 of this repo all failed for the same structural reason: the port surface projected ~5 fields, the consumer read ~13 fields. The migration would have silently dropped 8+ fields the consumer relied on. The lesson is captured in `docs/learnings/2026-05-13-bc-ports-narrowness-postmortem.md`. This document encodes that lesson as a pre-cycle check.
## When this gate runs
Before invoking `/rpi` on a cycle whose selected work matches any of:
- title contains `migrate`, `rewire`, `route through`, `port-ify`, `adapt to <Port>`
- title contains `<Module> → <Port>Port` or similar arrow syntax
- bd issue has label `migration` or `bc-port-adoption`
- selected_source is `harvested` and the queue entry has `kind: "migration"`
## Procedure
1. **Identify the port surface.** From the work title, locate the port type definition (typically `cli/internal/ports/<port>.go`). Extract the projected struct fields.
2. **Sample two consumer call sites.** From the work description, find the function or file being migrated. Grep for *its* current consumers — the call sites that depend on the data the migration will route through the port. Pick two representative ones (different files, different formatting/decision shapes).
3. **Field-fit comparison.**
```bash
PORT_FIELDS=$(grep -E '^\s+[A-Z][a-zA-Z0-9_]+\s+' cli/internal/ports/<port>.go | awk '{print $1}' | sort -u)
CONSUMER_FIELDS=$(grep -oE '\.[A-Z][a-zA-Z0-9_]+\b' <consumer-files> | sed 's/^\.//' | sort -u)
comm -23 <(echo "$CONSUMER_FIELDS") <(echo "$PORT_FIELDS")
```
The output is the set of fields the consumer reads that the port does NOT project.
4. **Decision.**
| Missing fields | Action |
|---|---|
| 0 | Migration is safe. Proceed with `/rpi`. |
| 12 | Migration with widening. Add the missing fields to the port + writer + tests in the same cycle. Mark mode `port-widen-and-migrate`. |
| 3+ | **Abort the migration cycle.** File a port-widening bd issue with the field list, log this cycle as `unchanged` with `selected_source: "pre-flight-schema-fail"`, return to Step 3 selection. |
5. **Special case — zero-data target.** If the consumer reads a field (e.g. `Target`) that exists in the type definition but *no actual entries in the production data store have that field set*, the consumer is dead-code-in-disguise. Don't widen — investigate whether the consumer was ever wired. Log as `selected_source: "pre-flight-dead-target"`.
## Why this check is cheap
A migration cycle costs ~15-30 minutes of /rpi (discovery + crank + validation). The pre-flight check is two `grep` calls and one `comm` — under 30 seconds. Catching even one bad migration pays for ~50 pre-flight runs. In this repo, three cycles spent on bad migrations (156, 157, plus the soc-0pku bead) would have been caught by 90 seconds of pre-flight.
## What this does NOT replace
This is a *cycle-selection* gate, not a code-quality gate. Validating the actual migration code still belongs to `/rpi` → `/validate`. The pre-flight only answers "is this migration even shaped right for the current port?"
## Worked example — cycle 157 (soc-0pku)
Selected work: `context_assemble.go → LoopReaderPort`
```
PORT_FIELDS=Number,Mode,Result,Commit,Milestone # 5
CONSUMER_FIELDS=Timestamp,Cycle,Target,GoalIDs,Result,Status,Sha,CanonicalSha,LogSha,GoalsPassing,GoalsTotal,Summary,Error # 13
Missing: Timestamp,Target,GoalIDs,Status,Sha,CanonicalSha,LogSha,GoalsPassing,GoalsTotal,Summary,Error # 11
```
Missing fields = 11. Threshold 3+. **Abort.** File port-widening issue: "Widen CycleEntry: +Timestamp,+Summary at minimum; full set deferred." Cycle is logged as `unchanged`, ladder advances.
This is exactly what cycle 161 ended up doing reactively — adding `StartedAt` and `Title` after the migrations bounced. With pre-flight, the widening would have happened *before* burning three cycles on doomed migrations.
## See also
- `docs/learnings/2026-05-13-bc-ports-narrowness-postmortem.md` — the source observation
- `references/scout-mode.md` — first-class result for cycles that intentionally don't execute
- `references/metronome-gate.md` — sibling cross-cycle gate