# Handoff — 2026-05-18

State of the cupertino + cupertino-symbolgraphs work as of 2026-05-18T05:00Z, written for the next Claude session (and the human reading over its shoulder).

## Status update — 2026-05-18T06:38 (save in flight, do not re-trigger)

**The 11h re-index has been started.** Do NOT run `cupertino save` again — it is already running, detached, on the Studio.

| | |
|---|---|
| Process | PID **35243** on the Studio (`Mihaela's Mac Studio`) |
| Started | 2026-05-18T06:20:44+0200 |
| Expected finish | ~17:20 local (Zagreb +0200) |
| Caffeinate | PID 35288 watching 35243 (prevents idle sleep) |
| Pidfile | `/Users/mmj/.cupertino-dev/.reindex.pid` |
| Log file | `/Users/mmj/.cupertino-dev/reindex-20260518-062030.log` |
| Binary | `/Volumes/Code/DeveloperExt/public/cupertino/Packages/.build/release/cupertino` (post-PR-#767, has `.databaseTarget` + `.foundOptionalSource` events) |
| Phase | Scanning (no `Progress: N/M` lines yet — AST counter kicks in after scan) |
| Brew DB | UNTOUCHED, last verified 06:30 (`May 17 21:51:29 2026 2475872256`) |

**The save is local to the Studio.** It cannot be tracked, paused, or resumed from any other Mac. Other Macs can only watch the log over SSH if reachable, or wait for the bundle ship.

### What changed since the original handoff was written

- PR **#767** merged into cupertino main (`99a0823`). Adds two `Indexer.DocsService.Event` cases:
  - `.databaseTarget(URL)` — emitted before any disk activity, logs `💾 Output: <path>`
  - `.foundOptionalSource(label:url:)` — symmetric to existing `.missingOptionalSource`, logs `✅ <label> directory found at <path>`
  - Closes an asymmetric-emission gap in `optionalDir(_:label:events:)` that left long-running saves silent about which optional sources they detected
- All optional sources (Swift Evolution / Swift.org / Apple Archive / HIG) symlinked at `~/.cupertino-dev/{...}` → `~/.cupertino/{...}`. Log confirms all four detected at startup.
- `~/bin/reindex-cupertino-dev.sh` is the defensive launcher (brew-DB safety check, disk space, sleep status, in-flight PID guard, binary config pinning). Re-running it while PID 35243 is alive would refuse, but don't try.
- cupertino main `99a0823` = develop `99a0823` (0/0 divergence)
- cupertino-refactor sibling clone DELETED (2.8 GB reclaimed; was 5 behind, 0 ahead, stash was pure swiftformat output)

### What to do next, in order

1. **Don't restart the save.** Confirm it's still alive: `kill -0 35243 2>/dev/null && echo alive || echo done`
2. **Watch progress:** `tail -f /Users/mmj/.cupertino-dev/reindex-20260518-062030.log`
3. **Detect completion:** when the log contains `✅ Search index built successfully` (one grep: `grep -F 'Search index built successfully' /Users/mmj/.cupertino-dev/reindex-20260518-062030.log`), the job is done. Voice-alert: `say -v "Ava" "Ava: Reindex done"`.
4. **Verify the re-indexed DB** carries iter-1+2+3 coverage (spot-check `search_generics View`, confirm `doc_symbols.generic_constraints` populated to ~38% per PR #760 measurement).
5. **STOP at this point.** Bundle prep + version bump + tag + Homebrew + CHANGELOG promotion are all **gated on explicit user "go"** per the no-version-bumps memory rule. Do not pre-stage any of it.

### If the process is gone before completion

- `tail -100 /Users/mmj/.cupertino-dev/reindex-20260518-062030.log` to see why
- Brew DB safety check first: `stat -f '%Sm %z' ~/.cupertino/search.db` MUST still be `May 17 21:51:29 2026 2475872256`
- DO NOT re-run the save without user direction — the failure mode matters
- The dev DB at `~/.cupertino-dev/search.db` will be partial; can be `rm`'d before retry

### If the human switches Mac mid-save

- The save keeps running on the Studio regardless
- The new Mac can clone cupertino + read this handoff doc (it's committed)
- The new Mac CANNOT see the save progress unless reachable to the Studio via SSH (`ssh studio "tail -f ~/.cupertino-dev/reindex-20260518-062030.log"`)
- The compiled bundle (after step 4) is what gets shipped across Macs, not the in-flight save

## TL;DR

Pre-v1.2.0 ceremony in progress. Code on `main` is empirically clean across both repos. The one big remaining step before tagging v1.2.0 is the ~11h `cupertino save --docs` re-index against `~/.cupertino-dev/` using the new `apple-constraints.json` table (61,040 entries) derived from cupertino-symbolgraphs v0.1.1. Re-index is **gated on user "go"** per the standing no-version-bumps-without-explicit-go rule.

## Repo state

| repo | main HEAD | latest tag | notes |
|---|---|---|---|
| `mihaelamj/cupertino` (public) | `ec85708` | `v1.1.0` | main + develop in sync (0/0 divergence). All iter-1+2+3 hierarchy work landed (PRs #757, #758, #760, #762, #764, #765). |
| `mihaelamj/cupertino-symbolgraphs` (public, just flipped 2026-05-18) | `51213e0` | `v0.1.1` | 269 OK / 137 SKIP / 0 FAIL across 5 SDKs (macOS / iOS / watchOS / visionOS / tvOS). 100% brew-DB completeness routing. 99 tests / 14 suites. CI green every push. |
| `mihaelamj/cupertino-docs` (public) | `8ecd5a8f374` (commit) | n/a | Raw JSON corpus. Last data commit was `20c7ba9d80c data: merge Claw mini's 5.5-day crawl into the v1.1.0 corpus`. |
| `mihaelamj/cupertino-docs-private` | **deleted** | — | Was the private corpus mirror. Deleted 2026-05-18 per user direction ("I don't need it"). All in-tree references to it scrubbed via PR #765. |
| `mihaelamj/homebrew-tap` (public) | (not checked this session) | — | Will need a Formula version bump + new bundle URL/sha when v1.2.0 ships. |

## Local artifacts on the Studio (regeneratable everywhere)

| Path | What | How to regenerate |
|---|---|---|
| `~/.cupertino/docs/` | 414,810 files / 2.3 GB raw corpus | `cupertino setup` OR `git clone cupertino-docs && cp -r docs/* ~/.cupertino/docs/`. Already byte-identical to public `cupertino-docs/docs/` except `metadata.json` (which carries mid-crawl state on public, finished state local). |
| `~/.cupertino/search.db` | 2,475,872,256 bytes / `May 17 21:51:29` | **NEVER TOUCH** — production brew DB. Read-only sqlite SELECT/PRAGMA OK. No writes. |
| `~/.cupertino-dev/apple-constraints.json` | 61,040 entries / 10 MB | `cupertino-constraints-gen generate --from-directory <unpacked-corpus> -o ~/.cupertino-dev/apple-constraints.json` (~30s against the unpacked cupertino-symbolgraphs v0.1.1 corpus zip). |
| `~/.cupertino-dev/search.db` | 4 KB / leftover from develop's testing | Will be (re)built fresh by the pending `cupertino save --docs` re-index. |

## The v1.2.0 ceremony — completed + remaining steps

| Step | State | Notes |
|---|---|---|
| 1. iter-1 + iter-2 + iter-3 hierarchy code on cupertino main | ✅ done | `ec85708` |
| 2. cupertino-symbolgraphs v0.1.1 shipped | ✅ done | tag + GH release + public-fetchable corpus zip; sha256 `a35fc1b9…2307d`, manifest sha256 `4862b016…2049` |
| 3. `cupertino-constraints-gen` against v0.1.1 corpus → apple-constraints.json | ✅ done | 61,040 entries at `~/.cupertino-dev/` |
| 4. Re-index `~/.cupertino-dev` with new apple-constraints.json | ⏳ **GATED ON USER GO** | ~11h overnight; command in next section |
| 5. Verify re-indexed DB carries iter-1+2+3 coverage end-to-end | ⏳ post-reindex | spot-check `search_generics View` returns expected SwiftUI rows; confirm `generic_constraints` populated to ~38% per develop's PR #760 measurement |
| 6. Package the new DB as v1.2.0 bundle zip | ⏳ | same pattern as v1.0.0/1/2 ships |
| 7. Bump `Shared.Constants.App.version` 1.1.0 → 1.2.0 | ⏳ **gated** | hard rule: no version bump without explicit "go" |
| 8. Tag v1.2.0 on cupertino | ⏳ **gated** | |
| 9. Create GH release with bundle zip | ⏳ | |
| 10. Update Homebrew formula in `mihaelamj/homebrew-tap` | ⏳ | |
| 11. Update CHANGELOG + README | ⏳ | CHANGELOG `## Unreleased — staged for 1.2.0` block is already populated |
| 12. Update #183 roadmap | ⏳ | per the "Update roadmap on every step" memory rule |

## The re-index command (when user says go)

```bash
cd /Volumes/Code/DeveloperExt/public/cupertino/Packages
make build-release   # ensures the iter-1+2+3 binary runs, NOT brew's older one
./.build/release/cupertino save --docs \
    --docs-dir  ~/.cupertino/docs \
    --base-dir  ~/.cupertino-dev \
    --yes
```

What each flag means:
- `--docs` only build search.db (not packages.db / samples.db)
- `--docs-dir ~/.cupertino/docs` read input from the brew docs corpus (read-only access, allowed by memory rule)
- `--base-dir ~/.cupertino-dev` write all output here (search.db, reads apple-constraints.json already in place)
- `--yes` skip the preflight confirmation prompt

The save will:
1. Find `~/.cupertino-dev/apple-constraints.json` and load it
2. Run AST extraction over all 414,810 doc files (iter-1)
3. Apply the symbolgraph-constraints table via SQL UPDATE (iter-3, runs BEFORE iter-2)
4. Run the hierarchy walk to propagate parent constraints (iter-2)
5. Write `~/.cupertino-dev/search.db` with `doc_symbols.generic_constraints` populated

Expected output: 351k+ rows in `doc_symbols`; ~38% of generic-bearing rows have constraints populated per develop's PR #760 measurement.

## Pre-flight safety (mandatory before the 11h job)

- [ ] Brew DB untouched: `stat -f '%Sm %z' ~/.cupertino/search.db` should match `May 17 21:51:29 2026 2475872256`
- [ ] Disk space ≥ 10 GB: `df -h /Users/<you>`
- [ ] `make build-release` ran fresh in `cupertino/Packages/` — confirms cupertino.config.json points at `~/.cupertino-dev/`
- [ ] Machine won't sleep: `pmset -g` shows `disksleep=0` (or run on internal SSD)

## Hard rules to honor

1. **No version bumps without explicit "go".** `Shared.Constants.App.version` stays at 1.1.0, no tags, no Homebrew formula bump, no CHANGELOG promotion from `Unreleased` → `[X.Y.Z]`, until user explicitly says go. "Looks ready" is not authorization.
2. **Never touch brew DBs or binary.** `~/.cupertino/*` and `/opt/homebrew/bin/cupertino` are user-production. No `cupertino save/setup/fetch/migrate` against them. Read-only sqlite SELECT/PRAGMA OK. ALWAYS `make build-release` (not raw `swift build`) so the binary auto-isolates to `~/.cupertino-dev/`.
3. **Swift everywhere, no Python.** For diagnostic / analysis tasks, use `cupertino-symbolgraphs-audit` (3 subcommands shipped: `validate-corpus`, `framework-stats`, `count-by-status`) or write a one-off Swift script via `swift run`. Do NOT reach for Python in bash heredocs.
4. **No em-dashes in committed sources, commits, PRs, docs.** Use semicolon / period / colon instead.
5. **No AI attribution anywhere.** No "Co-Authored-By: Claude", no "Generated with", no emoji/markers that hint at AI authorship. All work must look human-authored.
6. **No GitLab pushes.** GitHub remotes only.
7. **Pre-commit hooks on cupertino:** SwiftLint, SwiftFormat, Package purity, and the `changelog-touched` guard. The last one requires either a CHANGELOG.md entry for source-touching commits OR the literal `[no-changelog]` token in the commit message body (only for genuinely comment/doc-only commits that compile to identical output).
8. **`[no-changelog]` token caveat:** the changelog-touched hook reads `.git/COMMIT_EDITMSG` which is populated AFTER pre-commit runs, so the token in the current commit's message doesn't reach the hook on the first attempt. Workaround: add a CHANGELOG entry instead (the hook author's intended path).

## Audit-honest confidence levels (per layer)

| Claim | Confidence | Verification |
|---|---|---|
| cupertino main builds + 2,289 tests pass | 99% | latest GHA + local |
| cupertino-symbolgraphs main builds + 99 tests pass | 99% | latest GHA `26009880627` ✓ |
| cupertino-symbolgraphs v0.1.1 corpus is well-formed | 99% | 532/532 .symbols.json valid; 137/137 knownNonExtractable verified non-extractable across 5 SDKs |
| 100% routing of cupertino's brew-DB framework slugs | 100% | fixture-backed `BrewDBCoverageTests` |
| Code-produces-same-output across recent commits | 100% | re-extracted on `8b3eefb`; byte-identical (modulo Apple-tool extraction-timestamp noise) to prior v2-tvos run |
| Apple's symbolgraph-extract is semantically right | 98% | trust + develop's consumer-side ForEach + RandomAccessCollection assertion via PR #764 |
| Re-indexed DB will carry iter-1+2+3 coverage | 95% | works on develop's SwiftUI mini-corpus per PR #760 measurement (38.4%); not yet verified on full 351k corpus |
| Apple SDK-content redistribution terms | 95% | precedent from cupertino-docs being public; not zero |

## Bootstrap on a new Mac

To pick this up on another machine:

```bash
# 1. Clone the three relevant repos to the per-machine standard paths
#    (Studio: /Volumes/Code/DeveloperExt/{public,private}/...; see mihaela-agents/MACHINES.md)
git clone git@github.com:mihaelamj/cupertino                  <public-base>/cupertino
git clone git@github.com:mihaelamj/cupertino-symbolgraphs     <public-base>/cupertino-symbolgraphs
git clone git@github.com:mihaelamj/cupertino-docs             <public-base>/cupertino-docs

# 2. Install + setup cupertino (gets brew binary + brew DB + brew docs)
brew install mihaelamj/tap/cupertino
cupertino setup    # downloads ~/.cupertino/docs/ + ~/.cupertino/search.db

# 3. Build the dev binary (auto-isolated to ~/.cupertino-dev/)
cd <public-base>/cupertino/Packages
make build-release

# 4. Build cupertino-symbolgraphs binaries
cd <public-base>/cupertino-symbolgraphs
swift build -c release

# 5. Generate apple-constraints.json from the v0.1.1 corpus
mkdir -p /tmp/sg-prep && cd /tmp/sg-prep
gh release download v0.1.1 -R mihaelamj/cupertino-symbolgraphs -p 'corpus-v0.1.1.zip'
mkdir unpacked && cd unpacked && unzip -q ../corpus-v0.1.1.zip && cd ..
<public-base>/cupertino/Packages/.build/release/cupertino-constraints-gen generate \
    --from-directory unpacked \
    -o ~/.cupertino-dev/apple-constraints.json

# 6. Ready for re-index when user says go (see the re-index command above)
```

## Open follow-ups (not blocking v1.2.0)

- `cupertino-symbolgraphs#10` deferred 2 subcommands: `cross-ref-brew` (needs sqlite3 design call) + `probe-skipped`. Audit binary currently has 3 of the 5 originally-scoped subcommands.
- The `changelog-touched` hook's stage-name deprecation warning (informational, breaks Sep 2026): `pre-commit migrate-config` to silence.
- Node 20 deprecation warning on GHA `actions/checkout@v4` (breaks Sep 2026): bump to `actions/checkout@v5` when available.

## What to NOT do without checking first

- Don't run `cupertino save` against `~/.cupertino/*` (the brew location) — only against `~/.cupertino-dev/`.
- Don't tag, bump versions, or push to Homebrew without explicit "go".
- Don't push to any GitLab remote (rule).
- Don't recreate `cupertino-docs-private` — it was deliberately deleted.

---

End of handoff. Pair workflow with "develop" is NOT continued on the next machine (single-Claude per user direction); the channel file at `~/Downloads/claude-chat.jsonl` on the Studio stays as a record but is not transferred.
