mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-05 19:28:46 +02:00
docs: plan for postbox wave 106 — speculative import Postbox drop sweep round 2
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
59e3e714fa
commit
5a3a4f5536
1 changed files with 493 additions and 0 deletions
|
|
@ -0,0 +1,493 @@
|
|||
# Wave 106: Speculative `import Postbox` Drop Sweep (round 2) 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:** Drop `import Postbox` from any consumer-module Swift file in `submodules/` whose remaining content no longer references a Postbox-only symbol. Wave 106 of the Postbox → TelegramEngine refactor — round 2 of the wave-93 speculative-drop sweep.
|
||||
|
||||
**Architecture:** Procedural sweep with build-feedback loop. (1) inventory candidates → (2) pre-flight regex pre-restore → (3) drop imports en masse → (4) build with `--continueOnError` → (5) restore failures → iterate → (6) final clean build → (7) optional BUILD-dep sweep → (8) single atomic commit. No code semantic changes — only `import` and BUILD `deps` lines.
|
||||
|
||||
**Tech Stack:** Swift, Bazel via `Make.py`, `grep`/`sed` for inventory, no unit tests. Verification is the full-project debug-sim-arm64 build.
|
||||
|
||||
**Iteration budget:** 2-5 build cycles (wave-93 precedent: 2 iter — drop, restore, clean).
|
||||
|
||||
**Note on TDD:** No unit tests in this project. Each task verifies via Bazel build + diff inspection. Build feedback IS the test.
|
||||
|
||||
**Spec:** `docs/superpowers/specs/2026-04-26-postbox-wave-106-import-drop-sweep-design.md`.
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
| Artifact | Role |
|
||||
|---|---|
|
||||
| `/tmp/wave106-candidates.txt` | All consumer files currently `import Postbox` |
|
||||
| `/tmp/wave106-skiplist.txt` | Files that match preemptive-restore regex (keep import) |
|
||||
| `/tmp/wave106-droplist.txt` | candidates − skiplist; files to edit |
|
||||
| `/tmp/wave106-build-iterN.log` | Per-iteration build log |
|
||||
| `/tmp/wave106-restore-iterN.txt` | Files needing restore after iter N |
|
||||
| `/tmp/wave106-final-droplist.txt` | Net dropped files after all iterations |
|
||||
| `submodules/**/*.swift` | Edited files (single-line Edit each) |
|
||||
| `submodules/**/BUILD` | (Optional Step 7) packages with no remaining Postbox imports |
|
||||
|
||||
---
|
||||
|
||||
## Task 1: Pre-flight WIP check
|
||||
|
||||
**File:** none (read-only).
|
||||
|
||||
- [ ] **Step 1: Verify clean working tree (modulo known-persistent state)**
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
git status --short
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```
|
||||
m build-system/bazel-rules/sourcekit-bazel-bsp
|
||||
?? build-system/tulsi/
|
||||
?? submodules/TgVoip/
|
||||
?? third-party/libx264/
|
||||
```
|
||||
|
||||
If output contains anything else (modified `M` files, other untracked dirs), HALT — there is unrelated WIP that would get tangled with the wave commit. Resolve before proceeding.
|
||||
|
||||
- [ ] **Step 2: Confirm we are on `master`**
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
git branch --show-current
|
||||
```
|
||||
|
||||
Expected: `master`. If not, stop and ask.
|
||||
|
||||
---
|
||||
|
||||
## Task 2: Inventory candidate files
|
||||
|
||||
**File:** none (read-only).
|
||||
|
||||
- [ ] **Step 1: Build the candidate list**
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
grep -rl "^import Postbox" submodules --include="*.swift" \
|
||||
| grep -v "^submodules/Postbox/" \
|
||||
| grep -v "^submodules/TelegramCore/" \
|
||||
| grep -v "^submodules/TelegramApi/" \
|
||||
| sort -u > /tmp/wave106-candidates.txt
|
||||
wc -l /tmp/wave106-candidates.txt
|
||||
```
|
||||
|
||||
Expected: between ~700 and ~1200 files (wave-93-era was ~1200; waves 94-105 may have peeled some).
|
||||
|
||||
- [ ] **Step 2: Sanity-check the exclusion filters worked**
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
grep -E "^submodules/(Postbox|TelegramCore|TelegramApi)/" /tmp/wave106-candidates.txt | head -5
|
||||
```
|
||||
|
||||
Expected: empty output (no excluded paths leaked through).
|
||||
|
||||
---
|
||||
|
||||
## Task 3: Build the skip-list via preemptive regex
|
||||
|
||||
**File:** none (read-only).
|
||||
|
||||
- [ ] **Step 1: Run the combined skip-regex against candidates**
|
||||
|
||||
The skip-regex is the union of three tiers from the spec. Run:
|
||||
|
||||
```sh
|
||||
grep -El "\bPostbox\b|\bMediaBox\b|\bMediaResource\b|\bMediaResourceData\b|\bMediaResourceId\b|\bPostboxCoding\b|\bPostboxDecoder\b|\bPostboxEncoder\b|\bMemoryBuffer\b|\bTempBoxFile\b|\bValueBoxKey\b|\bPostboxView\b|\bcombinedView\b|\bPeerId\b|\bMessageId\b|\bMediaId\b|\bMessageIndex\b|\bMessageAndThreadId\b|\bPeerNameIndex\b|\bStoryId\b|\bItemCollectionId\b|\bFetchResourceSourceType\b|\bFetchResourceError\b|\bPeer\b|\bMessage\b|\bMedia\b" \
|
||||
$(cat /tmp/wave106-candidates.txt) \
|
||||
| sort -u > /tmp/wave106-skiplist.txt
|
||||
wc -l /tmp/wave106-skiplist.txt
|
||||
```
|
||||
|
||||
Expected: most of the candidate list (likely 600-1100 files matched) — `\bPeer\b`, `\bMessage\b`, `\bMedia\b` are deliberately broad and catch many false positives. False positives are SAFE — they just mean fewer drops, not bad drops.
|
||||
|
||||
- [ ] **Step 2: Compute the drop-list**
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
comm -23 /tmp/wave106-candidates.txt /tmp/wave106-skiplist.txt > /tmp/wave106-droplist.txt
|
||||
wc -l /tmp/wave106-droplist.txt
|
||||
head -20 /tmp/wave106-droplist.txt
|
||||
```
|
||||
|
||||
Expected: 5-50 files in the drop-list (wave 93 had 12). If 0, the regex is over-matching — halt and revisit. If >100, the regex is under-matching — halt, expand patterns, re-run.
|
||||
|
||||
- [ ] **Step 3: Spot-verify 3 random drop candidates**
|
||||
|
||||
Run for each of 3 files from the head of the drop-list:
|
||||
|
||||
```sh
|
||||
head -3 /tmp/wave106-droplist.txt | while read f; do
|
||||
echo "=== $f ==="
|
||||
grep -nE "Postbox|MediaBox|MediaResource|PeerId|MessageId|MediaId|MessageIndex" "$f" | head -5
|
||||
done
|
||||
```
|
||||
|
||||
Expected: Only `import Postbox` line appears. If any other Postbox-token appears, the file should have been skipped — add the missing pattern to the regex in Step 1, redo Steps 1-2, and re-spot-check.
|
||||
|
||||
---
|
||||
|
||||
## Task 4: Drop `import Postbox` from drop-list files
|
||||
|
||||
**Files:** every path listed in `/tmp/wave106-droplist.txt`.
|
||||
|
||||
- [ ] **Step 1: Read each drop-list file's import block to locate the exact `import Postbox` line**
|
||||
|
||||
For each file in the drop-list, the line is `import Postbox` (exact match, no whitespace variations expected). Use a single-purpose `sed` to remove it from all drop-list files:
|
||||
|
||||
```sh
|
||||
while read f; do
|
||||
sed -i '' '/^import Postbox$/d' "$f"
|
||||
done < /tmp/wave106-droplist.txt
|
||||
```
|
||||
|
||||
The `sed -i ''` syntax is BSD/macOS specific — required on Darwin.
|
||||
|
||||
- [ ] **Step 2: Verify the imports were removed**
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
grep -lE "^import Postbox$" $(cat /tmp/wave106-droplist.txt) | wc -l
|
||||
```
|
||||
|
||||
Expected: 0 (no file in the drop-list still contains `import Postbox`).
|
||||
|
||||
- [ ] **Step 3: Verify no other lines were touched**
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
git diff --stat | tail -5
|
||||
git diff --shortstat
|
||||
```
|
||||
|
||||
Expected: same number of files modified as drop-list size. Each file should show `-1` insertion (or `-1` deletion). If any file shows multiple deletions, something went wrong — `git checkout -- $(cat /tmp/wave106-droplist.txt)` and investigate.
|
||||
|
||||
---
|
||||
|
||||
## Task 5: Build iteration 1 — capture failures
|
||||
|
||||
**File:** none (build only).
|
||||
|
||||
- [ ] **Step 1: Run the build with `--continueOnError`**
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
source ~/.zshrc 2>/dev/null && \
|
||||
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 \
|
||||
--continueOnError 2>&1 | tee /tmp/wave106-build-iter1.log
|
||||
```
|
||||
|
||||
Expected: Build completes (with errors). Wall-clock 30-260s depending on cache state.
|
||||
|
||||
- [ ] **Step 2: Extract failing files**
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
grep -E ":[0-9]+:[0-9]+: error:" /tmp/wave106-build-iter1.log \
|
||||
| awk -F: '{print $1}' \
|
||||
| sort -u > /tmp/wave106-restore-iter1.txt
|
||||
wc -l /tmp/wave106-restore-iter1.txt
|
||||
cat /tmp/wave106-restore-iter1.txt
|
||||
```
|
||||
|
||||
Expected: a subset of the drop-list. Wave 93 saw 5 of 12 needing restore. If the count > 50% of drop-list, the regex is missing a major pattern — HALT, analyze the failure cluster, add the missing pattern to Task 3 Step 1, restart from Task 4.
|
||||
|
||||
- [ ] **Step 3: Verify no errors in TelegramCore/Postbox/TelegramApi**
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
grep -E "^submodules/(TelegramCore|Postbox|TelegramApi)/" /tmp/wave106-restore-iter1.txt
|
||||
```
|
||||
|
||||
Expected: empty. If non-empty: HALT immediately, `git checkout -- submodules/`, and revert the wave — scope drift indicates the candidate filter or sed pattern is wrong.
|
||||
|
||||
---
|
||||
|
||||
## Task 6: Restore failing files (iter 1)
|
||||
|
||||
**Files:** every path in `/tmp/wave106-restore-iter1.txt`.
|
||||
|
||||
- [ ] **Step 1: Re-add `import Postbox` to each failing file**
|
||||
|
||||
Use awk uniformly (BSD `sed -i '' 'i\'` line-continuation is fragile inside shell loops). Insert `import Postbox` immediately before `import TelegramCore` if present, else immediately after the first existing `import ` line:
|
||||
|
||||
```sh
|
||||
while read f; do
|
||||
awk '
|
||||
BEGIN { added = 0 }
|
||||
!added && /^import TelegramCore$/ { print "import Postbox"; print; added = 1; next }
|
||||
{ print }
|
||||
END {
|
||||
if (!added) {
|
||||
# fallback path was not used — try post-first-import injection
|
||||
# (this END block is a no-op; awk cannot re-emit lines after END)
|
||||
}
|
||||
}
|
||||
' "$f" > "$f.tmp"
|
||||
if ! grep -q "^import Postbox$" "$f.tmp"; then
|
||||
# no TelegramCore anchor found — fall back to "after first import"
|
||||
awk '
|
||||
BEGIN { added = 0 }
|
||||
!added && /^import / { print; print "import Postbox"; added = 1; next }
|
||||
{ print }
|
||||
' "$f" > "$f.tmp"
|
||||
fi
|
||||
mv "$f.tmp" "$f"
|
||||
done < /tmp/wave106-restore-iter1.txt
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Verify restorations**
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
grep -L "^import Postbox$" $(cat /tmp/wave106-restore-iter1.txt)
|
||||
```
|
||||
|
||||
Expected: empty (every file in the restore list now contains `import Postbox` again).
|
||||
|
||||
- [ ] **Step 3: Update the working drop-list**
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
comm -23 /tmp/wave106-droplist.txt /tmp/wave106-restore-iter1.txt > /tmp/wave106-final-droplist.txt
|
||||
wc -l /tmp/wave106-final-droplist.txt
|
||||
```
|
||||
|
||||
This is the current "successfully dropped" set.
|
||||
|
||||
---
|
||||
|
||||
## Task 7: Build iteration 2 — verify clean (or iterate further)
|
||||
|
||||
**File:** none (build only).
|
||||
|
||||
- [ ] **Step 1: Re-run the build with `--continueOnError`**
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
source ~/.zshrc 2>/dev/null && \
|
||||
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 \
|
||||
--continueOnError 2>&1 | tee /tmp/wave106-build-iter2.log
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Extract any new failures**
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
grep -E ":[0-9]+:[0-9]+: error:" /tmp/wave106-build-iter2.log \
|
||||
| awk -F: '{print $1}' \
|
||||
| sort -u > /tmp/wave106-restore-iter2.txt
|
||||
wc -l /tmp/wave106-restore-iter2.txt
|
||||
```
|
||||
|
||||
- [ ] **Step 3: If non-empty, repeat Task 6 with `iter2.txt` and run Task 7 again as iter3.**
|
||||
|
||||
Stop when:
|
||||
- `restore-iterN.txt` is empty → proceed to Task 8.
|
||||
- `N == 5` → HALT (diminishing returns); commit what is green via Task 9.
|
||||
|
||||
Each repeat: substitute `iter1` → `iter2` → `iter3` etc. throughout. Update the final-droplist after each restore: `comm -23 /tmp/wave106-final-droplist.txt /tmp/wave106-restore-iterN.txt > /tmp/wave106-final-droplist.txt.new && mv /tmp/wave106-final-droplist.txt.new /tmp/wave106-final-droplist.txt`.
|
||||
|
||||
---
|
||||
|
||||
## Task 8: Final clean build (no `--continueOnError`)
|
||||
|
||||
**File:** none (build only).
|
||||
|
||||
- [ ] **Step 1: Run a clean build to confirm no inter-module ordering issue was masked**
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
source ~/.zshrc 2>/dev/null && \
|
||||
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 2>&1 | tail -30
|
||||
```
|
||||
|
||||
Expected: build success, no `error:` lines in the tail. If failure: an inter-module visibility issue exists that `--continueOnError` masked. Restore the final-droplist file(s) implicated by the error, repeat Task 7 / Task 8.
|
||||
|
||||
---
|
||||
|
||||
## Task 9 (optional): BUILD-dep sweep
|
||||
|
||||
**Files:** various `submodules/*/BUILD` files.
|
||||
|
||||
This step removes `//submodules/Postbox` from any Bazel package whose Swift sources no longer contain `import Postbox`. Skip this task if iteration time is constrained — the import drops alone are the core wave value; deps trim is housekeeping.
|
||||
|
||||
- [ ] **Step 1: Find packages whose `BUILD` still depends on `//submodules/Postbox` but whose `Sources/**/*.swift` no longer imports it**
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
for build in $(find submodules -name BUILD -not -path "submodules/Postbox/*"); do
|
||||
pkg_dir=$(dirname "$build")
|
||||
if grep -q "//submodules/Postbox" "$build" 2>/dev/null; then
|
||||
if ! grep -rq "^import Postbox$" "$pkg_dir" --include="*.swift" 2>/dev/null; then
|
||||
echo "$build"
|
||||
fi
|
||||
fi
|
||||
done > /tmp/wave106-build-deps-candidates.txt
|
||||
wc -l /tmp/wave106-build-deps-candidates.txt
|
||||
cat /tmp/wave106-build-deps-candidates.txt
|
||||
```
|
||||
|
||||
Expected: 0-5 candidates. If 0, skip to Task 10.
|
||||
|
||||
- [ ] **Step 2: For each candidate BUILD, locate the `//submodules/Postbox` line and remove it via Edit**
|
||||
|
||||
Note that BUILD files often list deps as either `"//submodules/Postbox"` (string) or via aliases. Use Read to inspect each, then Edit to drop just the dep line. The exact string pattern varies — typically `"//submodules/Postbox",` on its own line within a `deps = [ ... ]` block.
|
||||
|
||||
For each candidate file, Read the lines around the match, then Edit to remove the line preserving the surrounding bracket structure.
|
||||
|
||||
- [ ] **Step 3: Re-run the clean build (no `--continueOnError`) to confirm no dep was load-bearing**
|
||||
|
||||
Run the same command as Task 8 Step 1.
|
||||
|
||||
If failure: a transitive dep was being satisfied through Postbox. Restore the dep line(s) implicated by the error and re-run.
|
||||
|
||||
---
|
||||
|
||||
## Task 10: Commit the wave
|
||||
|
||||
**File:** `git`.
|
||||
|
||||
- [ ] **Step 1: Inspect final diff statistics**
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
git diff --stat
|
||||
git diff --shortstat
|
||||
```
|
||||
|
||||
Expected: N file modifications, all `-1` line changes (just `import Postbox` lines), possibly plus a small number of BUILD diffs from Task 9.
|
||||
|
||||
- [ ] **Step 2: Confirm only allowed paths are touched**
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
git diff --name-only | grep -vE "^submodules/" | head -5
|
||||
git diff --name-only | grep -E "^submodules/(Postbox|TelegramCore|TelegramApi)/" | head -5
|
||||
```
|
||||
|
||||
Both expected: empty. If either has output: HALT — rogue changes exist; investigate before committing.
|
||||
|
||||
- [ ] **Step 3: Stage only the modified Swift and BUILD files**
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
git add $(git diff --name-only)
|
||||
git status --short
|
||||
```
|
||||
|
||||
Expected: all changes staged with `M`. Untracked dirs (`build-system/tulsi/`, `submodules/TgVoip/`, `third-party/libx264/`) and the `m` submodule marker remain untouched.
|
||||
|
||||
- [ ] **Step 4: Commit with the wave message**
|
||||
|
||||
Substitute `<N>` with the count from `/tmp/wave106-final-droplist.txt`, `<M>` with the total restored across iterations, and `<K>` with the BUILD deps removed (0 if Task 9 skipped).
|
||||
|
||||
```sh
|
||||
N=$(wc -l < /tmp/wave106-final-droplist.txt | tr -d ' ')
|
||||
M=$(cat /tmp/wave106-restore-iter*.txt 2>/dev/null | sort -u | wc -l | tr -d ' ')
|
||||
K=$(git diff --cached --name-only | grep -c BUILD)
|
||||
|
||||
git commit -m "$(cat <<EOF
|
||||
Postbox -> TelegramEngine wave 106 (import drop sweep round 2)
|
||||
|
||||
Speculative drop of \`import Postbox\` in $N files where the last
|
||||
Postbox-typed symbol reference was peeled off by waves 94-105.
|
||||
Methodology: pattern-based pre-flight skip + drop + build-feedback
|
||||
restore loop (wave-93-validated recipe). $M files restored after build.
|
||||
$K BUILD deps removed.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||||
EOF
|
||||
)"
|
||||
git status --short
|
||||
```
|
||||
|
||||
Expected: clean commit, working tree returns to the known-persistent untracked-only state.
|
||||
|
||||
---
|
||||
|
||||
## Task 11: Update memory file with wave outcome
|
||||
|
||||
**File:** `/Users/isaac/.claude/projects/-Users-isaac-build-telegram-telegram-ios/memory/project_postbox_refactor_next_wave.md`.
|
||||
|
||||
- [ ] **Step 1: Read the current memory file to find the recent-commits section**
|
||||
|
||||
Read the top section listing wave commits.
|
||||
|
||||
- [ ] **Step 2: Insert a wave-106 line below the wave-105 entry**
|
||||
|
||||
Append (substituting the actual commit hash from `git log -1 --format=%H | head -c 10`):
|
||||
|
||||
```markdown
|
||||
- `<HASH>` — wave 106: speculative `import Postbox` drop sweep round 2. <N> files dropped, <M> restored after build feedback. Methodology re-run of wave 93 (`72de7c4fd5`) with expanded pre-flight regex (added bare-name escapes `\bPeer\b`/`\bMessage\b`/`\bMedia\b` per wave-93 lesson). <K> BUILD deps removed. <iter-count> build cycles.
|
||||
```
|
||||
|
||||
Update the memory file's `description:` frontmatter to reflect wave 106 as the latest.
|
||||
|
||||
---
|
||||
|
||||
## Halt-and-revert recipe (if anything goes seriously wrong)
|
||||
|
||||
If at any point the build fails in TelegramCore/Postbox/TelegramApi, or iteration count exceeds 5 with non-trivial residue, or scope drifts beyond the spec:
|
||||
|
||||
```sh
|
||||
git checkout -- submodules/
|
||||
git status --short # should match the pre-flight expected output
|
||||
```
|
||||
|
||||
The wave is fully reversible until Task 10 commits.
|
||||
|
||||
---
|
||||
|
||||
## Plan Self-Review Notes
|
||||
|
||||
- **Spec coverage:** Tasks 1-11 map 1:1 to the 8-step procedure in the spec plus pre-flight (Task 1) and post-commit memory update (Task 11). Halt conditions appear in Tasks 5/7/9 and the final halt-and-revert recipe.
|
||||
- **Placeholder scan:** No TBDs/TODOs. All `<N>`/`<M>`/`<K>`/`<HASH>` are explicitly substituted via shell expansion in Step 4 of Task 10.
|
||||
- **Type/method consistency:** Single-purpose tasks operating on filesystem and grep — no method-name drift risk.
|
||||
- **Iteration shape:** Tasks 5-7 form the iteration loop; Task 8 is the validation gate; Task 9 is optional housekeeping; Task 10 commits.
|
||||
Loading…
Add table
Add a link
Reference in a new issue