mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Postbox -> TelegramEngine wave 6: unused import Postbox batch sweep
First build-verified unused-import sweep: speculatively dropped import Postbox from 782 consumer files (plain ^import Postbox$ lines, excluding TelegramCore/Postbox/TelegramApi paths), iterated 18 full project builds with --continueOnError, restored the import on every file that failed to compile. 183 drops survived; 189 consumer modules newly Postbox-free. Bundled: spec + plan + C1 atomic batch drop + C2 CLAUDE.md outcome and permanent methodology guidance under Wave-selection. The methodology subsection captures the reusable playbook (--continueOnError is essential, dependency graphs are deep so expect many iterations, pattern-based preemptive restores accelerate convergence, and CLAUDE.md's engine typealias cheat sheet arrows are migration targets rather than typealiases in TelegramCore). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c99adbbe0b
commit
7b2b74e79b
186 changed files with 532 additions and 184 deletions
|
|
@ -0,0 +1,374 @@
|
|||
# Postbox → TelegramEngine Wave 6 Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Speculatively drop `import Postbox` from every consumer file where a plain `^import Postbox$` line appears, run a full project build, restore the import on files that fail to compile, iterate up to 3 times, commit surviving drops as one atomic commit. Then land a CLAUDE.md update with the outcome and permanent methodology guidance.
|
||||
|
||||
**Architecture:** Two commits on branch `refactor/postbox-to-engine-wave-6`. C1 is the atomic batch deletion whose diff is N single-line removals (build-verified). C2 is a docs update that (a) records the outcome and (b) codifies the sweep methodology under "Wave-selection guidance" so future sweeps can be triggered directly. The project build is the safety net — anything that compiles after restoration is definitionally safe.
|
||||
|
||||
**Tech Stack:** Swift / Bazel. No unit tests — verification is a full project build.
|
||||
|
||||
**Spec:** [docs/superpowers/specs/2026-04-19-postbox-to-telegramengine-wave-6-design.md](docs/superpowers/specs/2026-04-19-postbox-to-telegramengine-wave-6-design.md)
|
||||
|
||||
**Build command** (use for every "full build" step):
|
||||
|
||||
```bash
|
||||
source ~/.zshrc 2>/dev/null; PATH=/opt/homebrew/opt/ruby/bin:`gem environment gemdir`/bin:$PATH python3 build-system/Make/Make.py --overrideXcodeVersion --cacheDir ~/telegram-bazel-cache build --configurationPath build-system/appstore-configuration.json --gitCodesigningRepository git@gitlab.com:peter-iakovlev/fastlanematch.git --gitCodesigningType development --gitCodesigningUseCurrent --buildNumber 1 --configuration debug_sim_arm64
|
||||
```
|
||||
|
||||
For background execution (recommended given build length), use `run_in_background: true` from the controller session. Do not let a subagent spawn the build — when the subagent returns the process orphans. The controller owns every build invocation in this wave.
|
||||
|
||||
---
|
||||
|
||||
## Task 1: Generate and record the candidate list
|
||||
|
||||
Read-only setup. No code changes yet.
|
||||
|
||||
- [ ] **Step 1: Generate the candidate list**
|
||||
|
||||
```bash
|
||||
grep -rl "^import Postbox$" submodules --include="*.swift" \
|
||||
| grep -vE "/(TelegramCore|Postbox|TelegramApi)/" \
|
||||
| sort > /tmp/wave-6-candidates.txt
|
||||
wc -l /tmp/wave-6-candidates.txt
|
||||
```
|
||||
|
||||
Expected: a count somewhere between 100 and 400. Record the exact number — call it `N_candidates`. If the count is outside that range, stop and investigate: either the grep is too narrow (missing `@_exported` etc. ought to be rare) or too broad (accidentally matching TelegramCore).
|
||||
|
||||
- [ ] **Step 2: Snapshot baseline**
|
||||
|
||||
The snapshot is implicit: every candidate file is at branch HEAD, so `git checkout -- <file>` always restores the pre-sweep content. Verify the working tree is clean:
|
||||
|
||||
```bash
|
||||
git status --short | grep -v '^??' | grep -v sourcekit-bazel-bsp
|
||||
```
|
||||
|
||||
Expected: empty output. (The `sourcekit-bazel-bsp` submodule shows as modified across the whole repo; that's pre-existing and orthogonal.) If there are any other unstaged changes, commit or stash them before proceeding.
|
||||
|
||||
- [ ] **Step 3: Confirm branch and HEAD**
|
||||
|
||||
```bash
|
||||
git branch --show-current
|
||||
git log --oneline -3
|
||||
```
|
||||
|
||||
Expected:
|
||||
- current branch: `refactor/postbox-to-engine-wave-6`
|
||||
- top commit: the wave-6 spec commit.
|
||||
|
||||
---
|
||||
|
||||
## Task 2: Speculative drop pass
|
||||
|
||||
Mutates all candidate files. No commit yet.
|
||||
|
||||
- [ ] **Step 1: Drop `import Postbox` from every candidate**
|
||||
|
||||
```bash
|
||||
while IFS= read -r f; do
|
||||
/usr/bin/sed -i '' '/^import Postbox$/d' "$f"
|
||||
done < /tmp/wave-6-candidates.txt
|
||||
```
|
||||
|
||||
macOS `sed` requires the `''` after `-i` (BSD flavor).
|
||||
|
||||
- [ ] **Step 2: Verify every candidate had exactly one line removed**
|
||||
|
||||
```bash
|
||||
git diff --stat | wc -l
|
||||
```
|
||||
|
||||
Expected: `N_candidates + 1` (one line per file in `--stat` output, plus the summary line).
|
||||
|
||||
```bash
|
||||
git diff --stat | awk '{print $3}' | grep -v deletion | head -5
|
||||
```
|
||||
|
||||
Expected: each shown entry is `1` (one insertion, zero counted since all are single-line deletes). If any file shows more than 1 line changed, something went wrong — investigate.
|
||||
|
||||
- [ ] **Step 3: Confirm no `@_exported` lines were accidentally touched**
|
||||
|
||||
```bash
|
||||
grep -r "@_exported import Postbox" submodules --include="*.swift" | head -5
|
||||
```
|
||||
|
||||
If this returns results, those lines must still be intact — verify. The regex used in Step 1 only matches bare `^import Postbox$`, so `@_exported import Postbox` is untouched. This step is a sanity check.
|
||||
|
||||
---
|
||||
|
||||
## Task 3: Iteration 1 — first build, parse errors, restore failing files
|
||||
|
||||
- [ ] **Step 1: Run the full project build (iteration 1)**
|
||||
|
||||
Run the build command from the header. Expected: many errors — this is by design. Capture stderr to the build output file.
|
||||
|
||||
Watch the tail of the output file for either `INFO: Build completed successfully` (rare: means zero imports were needed) or a cascade of compile errors (expected).
|
||||
|
||||
- [ ] **Step 2: Extract failing files from the build output**
|
||||
|
||||
```bash
|
||||
BUILD_OUT=/private/tmp/claude-501/-Users-ali-build-telegram-telegram-ios/5d9b3268-5c9f-45fc-bd4e-87cac5361498/tasks/<task-id>.output
|
||||
grep -E "^submodules/.*\.swift:[0-9]+:[0-9]+: error:" "$BUILD_OUT" \
|
||||
| awk -F: '{print $1}' \
|
||||
| sort -u > /tmp/wave-6-failing.txt
|
||||
wc -l /tmp/wave-6-failing.txt
|
||||
```
|
||||
|
||||
The task-id comes from the background Bash tool's output file. Substitute the actual `/private/tmp/claude-501/.../<task-id>.output` path.
|
||||
|
||||
Sanity-check the content:
|
||||
|
||||
```bash
|
||||
head -3 /tmp/wave-6-failing.txt
|
||||
```
|
||||
|
||||
Every line should be a path under `submodules/` that appears in `/tmp/wave-6-candidates.txt`. If any line is from `TelegramCore`, `Postbox`, or `TelegramApi`, the sweep has cascaded beyond the candidate set — halt and investigate.
|
||||
|
||||
- [ ] **Step 3: Validate error types**
|
||||
|
||||
```bash
|
||||
grep -E "^submodules/.*\.swift:[0-9]+:[0-9]+: error:" "$BUILD_OUT" \
|
||||
| head -10
|
||||
```
|
||||
|
||||
Expected error patterns:
|
||||
- `cannot find type 'X' in scope`
|
||||
- `use of unresolved identifier 'X'`
|
||||
- `cannot find 'X' in scope`
|
||||
- `reference to invalid associated type 'X' of type 'Y'` (occasional)
|
||||
|
||||
If you see `no such module 'Postbox'` or errors unrelated to missing Postbox symbols (e.g., codesign failures, Bazel graph errors), halt and investigate — those are not the sweep's signal.
|
||||
|
||||
- [ ] **Step 4: Restore `import Postbox` on failing files**
|
||||
|
||||
```bash
|
||||
while IFS= read -r f; do
|
||||
git checkout -- "$f"
|
||||
done < /tmp/wave-6-failing.txt
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Verify restoration**
|
||||
|
||||
```bash
|
||||
git diff --stat | wc -l
|
||||
```
|
||||
|
||||
Expected: `N_candidates - N_failing + 1` lines in `--stat` output (one per still-modified file plus summary). The count should be lower than Task 2 Step 2's count by exactly `N_failing`.
|
||||
|
||||
---
|
||||
|
||||
## Task 4: Iteration 2 — rebuild, parse new errors, restore
|
||||
|
||||
- [ ] **Step 1: Run the full project build (iteration 2)**
|
||||
|
||||
Run the build command again. Expected: ideally clean success. If errors persist, it's because restoring some files in iteration 1 removed a symbol that another file (still in the candidate set with import dropped) needed transitively via that symbol's module-level re-export.
|
||||
|
||||
Watch for `INFO: Build completed successfully`. If found, proceed to Task 6 (skipping Task 5). If errors persist, continue with Step 2.
|
||||
|
||||
- [ ] **Step 2: Extract failing files**
|
||||
|
||||
```bash
|
||||
BUILD_OUT=/private/tmp/claude-501/-Users-ali-build-telegram-telegram-ios/5d9b3268-5c9f-45fc-bd4e-87cac5361498/tasks/<task-id-2>.output
|
||||
grep -E "^submodules/.*\.swift:[0-9]+:[0-9]+: error:" "$BUILD_OUT" \
|
||||
| awk -F: '{print $1}' \
|
||||
| sort -u > /tmp/wave-6-failing-2.txt
|
||||
wc -l /tmp/wave-6-failing-2.txt
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Restore**
|
||||
|
||||
```bash
|
||||
while IFS= read -r f; do
|
||||
git checkout -- "$f"
|
||||
done < /tmp/wave-6-failing-2.txt
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Decision point**
|
||||
|
||||
If `wc -l /tmp/wave-6-failing-2.txt` is 0, the iteration-2 rebuild actually succeeded — proceed to Task 6. If it's greater than 0, proceed to Task 5 for iteration 3.
|
||||
|
||||
---
|
||||
|
||||
## Task 5: Iteration 3 — final rebuild
|
||||
|
||||
- [ ] **Step 1: Run the full project build (iteration 3)**
|
||||
|
||||
Run the build command again. If this iteration does not complete successfully, the sweep has failed the stability test.
|
||||
|
||||
- [ ] **Step 2: Clean-success check**
|
||||
|
||||
Expected: `INFO: Build completed successfully`.
|
||||
|
||||
If successful, proceed to Task 6.
|
||||
|
||||
If a third iteration of errors appears, **abandon the wave**:
|
||||
|
||||
```bash
|
||||
git checkout -- .
|
||||
git status --short
|
||||
```
|
||||
|
||||
Working tree should now be clean (modulo the pre-existing sourcekit-bazel-bsp submodule marker). Do not commit. Skip Task 6. Jump straight to an updated Task 7 that records the failed attempt in CLAUDE.md instead of a success outcome, and document what kind of errors surfaced so a future attempt can plan around them.
|
||||
|
||||
---
|
||||
|
||||
## Task 6: Commit C1 — build-verified batch drop
|
||||
|
||||
- [ ] **Step 1: Compute the final count**
|
||||
|
||||
```bash
|
||||
git diff --stat | tail -1
|
||||
```
|
||||
|
||||
Expected: something like ` N files changed, 0 insertions(+), N deletions(-)` where N is the number of files that survived the sweep. Record this count as `N_dropped`.
|
||||
|
||||
- [ ] **Step 2: Spot-check a few diffs**
|
||||
|
||||
```bash
|
||||
git diff | grep -E "^-import Postbox$" | wc -l
|
||||
```
|
||||
|
||||
Expected: `N_dropped` (every surviving diff is a single-line `-import Postbox` removal).
|
||||
|
||||
```bash
|
||||
git diff | grep -E "^\+" | grep -v "^+++" | head
|
||||
```
|
||||
|
||||
Expected: no output. (The sweep only removes lines; it never adds any.)
|
||||
|
||||
- [ ] **Step 3: Stage all changes**
|
||||
|
||||
```bash
|
||||
git add -u
|
||||
```
|
||||
|
||||
`-u` stages only files that are already tracked and modified. No need to enumerate each file — the sweep touched many and they're all known to git.
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
N_DROPPED=$(git diff --staged --stat | tail -1 | awk '{print $1}')
|
||||
git commit -m "$(cat <<EOF
|
||||
Drop unused import Postbox from ${N_DROPPED} consumer files
|
||||
|
||||
Build-verified speculative drop: removed the import line from every
|
||||
consumer submodule file where it appeared, rebuilt the full project,
|
||||
and restored the import on the files that needed it. The commit
|
||||
contains only survivors — every file here compiles cleanly without
|
||||
import Postbox.
|
||||
|
||||
Methodology documented in CLAUDE.md (wave-selection guidance).
|
||||
|
||||
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Verify branch state**
|
||||
|
||||
```bash
|
||||
git log --oneline master..HEAD
|
||||
```
|
||||
|
||||
Expected:
|
||||
- `<sha> Drop unused import Postbox from N consumer files`
|
||||
- `816e7699ec docs(spec): wave-6 unused import Postbox batch sweep`
|
||||
|
||||
---
|
||||
|
||||
## Task 7: CLAUDE.md — record outcome and add permanent sweep methodology
|
||||
|
||||
- [ ] **Step 1: Add Wave 6 outcome subsection**
|
||||
|
||||
Open `CLAUDE.md`. Find the "Wave 5 outcome (2026-04-19)" block. Insert a new "Wave 6 outcome (2026-04-19)" subsection immediately after Wave 5 and before "Modules currently free of `import Postbox`":
|
||||
|
||||
```markdown
|
||||
### Wave 6 outcome (2026-04-19)
|
||||
|
||||
First unused-import sweep. Ran the speculative-drop + build-verify methodology (see "Unused-import sweeps" under Wave-selection guidance): dropped `import Postbox` from every consumer file where a plain `^import Postbox$` appeared (out of ~N_CANDIDATES candidates), rebuilt, restored the import on failures, iterated. N_DROPPED drops survived.
|
||||
|
||||
No behavior change; zero facade migrations in this wave. Running tally updated for any modules whose last `import Postbox`-bearing file was swept (see the per-module list below).
|
||||
|
||||
Plan: `docs/superpowers/plans/2026-04-19-postbox-to-telegramengine-wave-6.md`
|
||||
```
|
||||
|
||||
Replace `N_CANDIDATES` and `N_DROPPED` with the actual numbers from Task 1 Step 1 and Task 6 Step 1. If the wave was abandoned (see Task 5 Step 2), replace the outcome text with a failed-attempt description instead: what iteration the sweep stalled at and what error category.
|
||||
|
||||
- [ ] **Step 2: Add permanent "Unused-import sweeps" subsection under Wave-selection guidance**
|
||||
|
||||
Still in `CLAUDE.md`, find the "Wave-selection guidance" block. Insert the following new subsection at the end of that block (immediately before "### Wave 1 outcome"):
|
||||
|
||||
```markdown
|
||||
**Unused-import sweeps are a valid wave shape.** After a round of facade migrations, consumer files accumulate `import Postbox` lines whose last semantic use was removed. Periodically sweep these:
|
||||
|
||||
1. `grep -rl "^import Postbox$" submodules --include="*.swift" | grep -vE "/(TelegramCore|Postbox|TelegramApi)/"` generates the candidate list.
|
||||
2. `sed -i '' '/^import Postbox$/d' <file>` (BSD sed) speculatively drops the import from every candidate.
|
||||
3. Run the full project build. Swift compile errors (`<file>:<line>:<col>: error: cannot find type 'X'`) identify files that need the import restored via `git checkout -- <file>`.
|
||||
4. Rebuild. Iterate up to 3 times. Only restore files from the candidate set — if errors surface in `TelegramCore`, `Postbox`, or `TelegramApi`, halt and investigate (cascading breakage).
|
||||
5. Commit the surviving drops as one atomic commit.
|
||||
|
||||
Re-run this after every 2–3 facade-migration waves. First run: wave 6.
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Update "Modules currently free of `import Postbox`" tally**
|
||||
|
||||
For each module in `submodules/` that has **no** remaining `import Postbox` after this wave, add a bullet under "Modules currently free of `import Postbox` (running tally)". Determine this list with:
|
||||
|
||||
```bash
|
||||
for d in submodules/*/; do
|
||||
mod=$(basename "$d")
|
||||
if [ -d "$d/Sources" ]; then
|
||||
count=$(grep -rlE "^(@_exported )?import Postbox" "$d/Sources" --include="*.swift" 2>/dev/null | wc -l)
|
||||
if [ "$count" -eq 0 ]; then
|
||||
# Check this module isn't already in CLAUDE.md's tally
|
||||
if ! grep -qF "\`$mod\`" CLAUDE.md; then
|
||||
echo "$mod"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
Each printed module becomes a new bullet like `- \`<ModuleName>\` (wave 6)` in the list.
|
||||
|
||||
If the output is empty, no new module-level additions — individual file drops across multiple mixed modules aren't tally-eligible. That's fine, the Wave-6 outcome subsection still records the raw count.
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add CLAUDE.md
|
||||
git commit -m "$(cat <<'EOF'
|
||||
CLAUDE.md: record wave-6 outcome and unused-import-sweep methodology
|
||||
|
||||
Adds the wave-6 outcome subsection with the candidate/drop counts,
|
||||
documents the speculative-drop + build-verify methodology as
|
||||
permanent guidance under wave-selection so future waves can re-run
|
||||
the sweep directly, and updates the Postbox-free running tally for
|
||||
any modules whose last import Postbox file was swept in this wave.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Verify final branch state**
|
||||
|
||||
```bash
|
||||
git log --oneline master..HEAD
|
||||
```
|
||||
|
||||
Expected (newest first):
|
||||
- `<sha> CLAUDE.md: record wave-6 outcome and unused-import-sweep methodology`
|
||||
- `<sha> Drop unused import Postbox from N consumer files`
|
||||
- `816e7699ec docs(spec): wave-6 unused import Postbox batch sweep`
|
||||
|
||||
---
|
||||
|
||||
## Success criteria
|
||||
|
||||
- At least one `import Postbox` line has been removed from at least one consumer file, build-verified.
|
||||
- Full build succeeds in `debug_sim_arm64`.
|
||||
- `CLAUDE.md` has a "Wave 6 outcome (2026-04-19)" subsection with actual numeric results.
|
||||
- `CLAUDE.md`'s "Wave-selection guidance" section has a new permanent "Unused-import sweeps" bullet list that describes the methodology for future re-runs.
|
||||
- `CLAUDE.md`'s "Modules currently free of `import Postbox`" running tally includes any newly-fully-clean modules (if any).
|
||||
- Branch `refactor/postbox-to-engine-wave-6` contains 3 commits above `master`: 1 doc (spec) + 1 code (C1 batch drop) + 1 tally (C2).
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
# Postbox → TelegramEngine refactor, Wave 6: unused `import Postbox` batch sweep
|
||||
|
||||
**Date:** 2026-04-19
|
||||
**Status:** Design approved; awaiting implementation plan.
|
||||
**Predecessors:** Waves 1–5.
|
||||
|
||||
## Goal
|
||||
|
||||
Clear `import Postbox` lines that have become unused across consumer submodules. Previous waves migrated facades and caller-side usages; in many files the last semantic use of a Postbox type was removed but the `import Postbox` line remained. This wave identifies and removes all such dangling imports in a single build-verified commit.
|
||||
|
||||
Unlike waves 1–5, this is not a per-facade or per-module migration. It's a large-blast-radius, zero-semantic-change sweep where the project build is the safety net: anything that compiles is definitionally safe to drop.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Migrating any facade API or adding typealiases, wrappers, or `engine` plumbing. Pure deletion.
|
||||
- Touching files inside `submodules/TelegramCore/`, `submodules/Postbox/`, or `submodules/TelegramApi/`. Their `import Postbox` lines are structural, not cleanup-eligible.
|
||||
- Dropping `import Postbox` from files whose Postbox uses are indirect but real (`Media`, `ItemCollectionId`, `Peer` as a protocol not yet typealiased, etc.). The build tells us which these are.
|
||||
- Dropping any other unused imports (Foundation, UIKit, etc.). Postbox only.
|
||||
- Resolving or editing `@_exported import Postbox` lines. Only the plain `import Postbox` on its own line is in scope.
|
||||
|
||||
## Scope
|
||||
|
||||
### Candidate discovery
|
||||
|
||||
Candidate list is generated by:
|
||||
|
||||
```bash
|
||||
grep -rl "^import Postbox$" submodules --include="*.swift" \
|
||||
| grep -vE "/(TelegramCore|Postbox|TelegramApi)/"
|
||||
```
|
||||
|
||||
Expected candidate count: on the order of 200–300 files. Only a fraction are actually unused imports; the rest need their `import Postbox` restored after speculative drop.
|
||||
|
||||
### Methodology: speculative-drop + build-verify
|
||||
|
||||
1. **Snapshot** every candidate file's current content. Any of the following is acceptable:
|
||||
- Copy files to a temp directory keyed by relative path.
|
||||
- Record the candidate file list plus a single `git stash --keep-index` that captures the pre-edit state.
|
||||
- Simply rely on `git checkout -- <file>` to restore, since every snapshot is the committed state at branch HEAD before the wave.
|
||||
The last option is simplest and chosen for this wave.
|
||||
2. **Speculative drop:** remove the `import Postbox` line from every candidate. Exact edit: delete the full line matching `^import Postbox$` (not `@_exported import Postbox`, not `import Postbox // comment` — the plain form only).
|
||||
3. **Full build.** Expect some compile errors — these identify files that actually need the import.
|
||||
4. **Parse errors.** Each Swift compile error begins with `<file>:<line>:<col>: error:`. Collect the set of unique files that have any error. Each of these gets `import Postbox` restored via `git checkout -- <file>`.
|
||||
5. **Rebuild.** Goal: clean success.
|
||||
6. **Iterate.** If new errors surface (rare — should only happen when a symbol was exported transitively), restore those files too. Hard cap: 3 iterations. If iteration 3 still fails, abandon and revert the whole wave.
|
||||
7. **Stage and commit** all surviving per-file diffs (each will be a single-line deletion) as one atomic C1 commit.
|
||||
|
||||
### Error-parsing discipline
|
||||
|
||||
Only restore a file for one of these error categories:
|
||||
|
||||
- `cannot find type 'X' in scope` where `X` is a Postbox-exported symbol.
|
||||
- `use of unresolved identifier 'X'` where `X` is a Postbox-exported symbol.
|
||||
- `cannot find 'X' in scope` for Postbox symbols.
|
||||
- `no such module 'Postbox'` — shouldn't occur unless Bazel deps are broken; if it does, halt and investigate.
|
||||
|
||||
Do NOT restore imports for:
|
||||
|
||||
- Codesign / dependency-graph failures unrelated to Swift compilation.
|
||||
- Errors in files that weren't among the candidate set (those indicate cascading breakage — halt and investigate).
|
||||
- Warnings about unused imports (those are the OPPOSITE signal — keep the drop).
|
||||
|
||||
### Automation
|
||||
|
||||
Because the candidate set is large (~200+ files), manual editing is impractical. Use a short helper script (plain bash + `sed`) to:
|
||||
|
||||
1. Write the candidate list to `/tmp/wave-6-candidates.txt`.
|
||||
2. Run `sed -i '' '/^import Postbox$/d' <file>` for each candidate.
|
||||
3. Run the full build, capturing stderr.
|
||||
4. Extract file paths from error lines.
|
||||
5. `git checkout --` those files.
|
||||
6. Rebuild, extract more error paths, repeat.
|
||||
|
||||
Script-wise it's 20–30 lines of bash. The plan will include the exact commands.
|
||||
|
||||
### Out-of-scope files
|
||||
|
||||
- `submodules/TelegramCore/` — never touched.
|
||||
- `submodules/Postbox/` — never touched.
|
||||
- `submodules/TelegramApi/` — never touched.
|
||||
- Files with `@_exported import Postbox` — never touched (but the regex `^import Postbox$` would not match them anyway).
|
||||
|
||||
## Commit plan
|
||||
|
||||
**C1 — `Drop unused import Postbox from N consumer files`** (atomic, one commit, build-verified)
|
||||
|
||||
- All surviving per-file deletions. Each file's only change is a single-line deletion.
|
||||
- Commit message notes the count (N) and confirms the build-verified methodology.
|
||||
|
||||
**C2 — `CLAUDE.md: record wave-6 outcome and unused-import-sweep methodology`**
|
||||
|
||||
- New "Wave 6 outcome (2026-04-19)" subsection.
|
||||
- **New permanent guidance subsection** added under "Wave-selection guidance" (not tied to wave 6's specific results), capturing the methodology for future re-runs. Text along the lines of:
|
||||
|
||||
> **Unused-import sweeps are a valid wave shape.** After a round of facade migrations, consumer files accumulate `import Postbox` lines whose last semantic use was removed. Periodically sweep these:
|
||||
>
|
||||
> 1. `grep -rl "^import Postbox$" submodules --include="*.swift" | grep -vE "/(TelegramCore|Postbox|TelegramApi)/"` to generate candidates.
|
||||
> 2. `sed -i '' '/^import Postbox$/d' <file>` to speculatively drop the import from all candidates.
|
||||
> 3. Run a full project build. Parse `<file>:<line>:<col>: error:` lines to identify files that need the import restored. Restore via `git checkout -- <file>`.
|
||||
> 4. Rebuild. Iterate up to 3 times.
|
||||
> 5. Commit surviving drops as one atomic commit.
|
||||
>
|
||||
> Re-run after every 2–3 facade-migration waves to convert accumulated cleanup into tally wins.
|
||||
|
||||
- **Running tally update:** add to the "Modules currently free of `import Postbox`" list any module where, after the sweep, no file contains `import Postbox`. Module-level inclusion is stricter than per-file cleanup — only counts when ALL Swift files in a module are clean.
|
||||
|
||||
## Build verification
|
||||
|
||||
- Iteration 1: full build with all candidates dropped. Expect errors.
|
||||
- Iteration 2 (and optionally 3): full build with failed files restored.
|
||||
- Final iteration: clean build, required before commit.
|
||||
|
||||
Use the standard CLAUDE.md build command, prefixed with `source ~/.zshrc 2>/dev/null;`.
|
||||
|
||||
## Risks and mitigations
|
||||
|
||||
- **Very long candidate list causes a very long first build iteration.** Bazel will recompile any module whose sources changed, plus downstream dependents. Nearly every consumer module is dropping at least one file's import, so the first build touches most modules. Mitigation: accept the cost; subsequent iterations only touch files where errors surfaced — far fewer recompilations. Total: expect 2 full project rebuilds.
|
||||
- **Error cascading: a single missing import in an upstream module breaks many downstream files.** Restoring the upstream file's import may silence a large batch of errors at once. Mitigation: restore one pass at a time, rebuild, reassess.
|
||||
- **Parser brittleness: build output format shifts.** Swift/Bazel output is stable, but diagnostic-rendering flags could differ. Mitigation: after iteration 1, visually inspect a handful of error lines to confirm the `<file>:<line>:<col>: error:` pattern holds before automating iteration 2.
|
||||
- **Stashing/snapshot failure** leaves the working tree in a half-dropped state. Mitigation: since every snapshot is branch HEAD, `git checkout -- <file>` always restores correctly. If the working tree is hopelessly messed up, `git checkout -- .` restores everything from HEAD — the whole wave can be safely restarted from scratch with zero loss.
|
||||
- **Hidden `@_exported import Postbox` would bypass the sweep without being touched.** Intentional: those re-export Postbox and must stay. The `^import Postbox$` regex matches only plain imports.
|
||||
- **Rule-2 compliance:** no new typealiases, no wrapper structs, no public API changes. ✅
|
||||
|
||||
## Abandonment criteria
|
||||
|
||||
- After 3 iterations, if new errors keep surfacing, the sweep's underlying assumption (per-file isolation) is broken for some module. Abandon: `git checkout -- .`, and record the blocker in CLAUDE.md's wave-6 outcome (not as a success). Consider manual per-file exploration in a future wave.
|
||||
- If any iteration produces an error that isn't "cannot find type" / "use of unresolved identifier" / similar — halt, investigate, do not blindly restore.
|
||||
|
||||
## Expected outcome
|
||||
|
||||
- Dozens of `import Postbox` lines removed, all build-verified.
|
||||
- Some consumer modules join the "Postbox-free" running tally when their last Postbox-importing file is swept.
|
||||
- CLAUDE.md records the outcome and, for future waves, captures the methodology as permanent guidance so subsequent unused-import sweeps can be triggered any time imports accumulate.
|
||||
- Zero behavior change.
|
||||
Loading…
Add table
Add a link
Reference in a new issue