Merged
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Retro: single-app-pivot
Date: 2026-03-08
PR: #7
Cycles: 1/3 (with 1 inner fix cycle after verify)
Outcome: PASS
Summary
Consolidated the two-target iOS architecture (main app + share extension) into a single
app target. The builder delivered a complete implementation in one cycle: moved
ContentExtractor and PiperAPIClient into the Piper target, replaced AppGroupStorage with
StandardStorage (UserDefaults.standard), created PipelineController, PipeView, and a full
PipelineControllerTests suite covering all 5 spec cases. Verify failed on two issues that
both turned out to be harness gaps rather than code defects: backend npm dependencies were
not installed before running tsc/eslint/vitest, and the iOS layer linter incorrectly
flagged UserDefaults references in test files. A fix agent resolved both without touching
any application code. The reviewer gave PASS.
Cycle log
Cycle 1
StandardStorage), ContentExtractor.swift and PiperAPIClient.swift moved to
ios/Piper/Services/, readability.js moved to ios/Piper/Resources/, PipelineController.swift
created, PipeView.swift created, ContentView.swift updated with Pipe Article button,
PipelineControllerTests.swift (5 test cases), CookieManagerTests.swift updated with Test 9,
all PiperShareExtensionTests moved to PiperTests with updated imports,
PiperShareExtension/ and Piper.entitlements deleted, lint-ios-layers.sh updated to exclude
test files from Rule 2.
npm installhad not been run inbackend/beforerun-verify.shinvokednpm run type-check,npm run lint,npm test.lint-ios-layers.shRule 2 flaggedCookieManagerTests.swiftfor referencingUserDefaults— the test legitimately verifies thatStandardStoragewrites toUserDefaults.standard, but the linter's exclusion for test files was only added in thesame PR, so the original script was applied against the new test code.
Root cause analysis
run-verify.shrunsnpm run type-check / lint / testinbackend/without first ensuringnode_modulesis present. On a fresh worktree (nonpm install) all three commands fail with "cannot find module" errors, producing noisy false failures that are entirely unrelated to the feature under review.npm install --silent(ornpm ci --silent) torun-verify.shbefore running backend npm scriptslint-ios-layers.shRule 2 had no exemption for test files. The newCookieManagerTests.swifttest (Test 9) directly asserts thatUserDefaults.standardis written — a legitimate and necessary test. The linter flagged it as a violation. The fix (add*Tests.swiftexclusion) was applied in the same PR, so verify was run against the pre-fix script.lint-ios-layers.shnow excludes*Tests.swiftfrom Rule 2) — no further action neededWhat worked well
protocols (
CookieProviding,ContentExtracting,PiperAPIClientProtocol), views nevertouching network or storage, PipelineController fully decoupled from UI, and a single
Config.backendBaseURLconstant unchanged from the previous architecture.invalidURL) were delivered on the first pass with correct error message strings matching the
spec verbatim.
CookieManagerTests.swiftTest 9 needed to directlyreference
UserDefaults.standardto verify storage behavior, and proactively updated thelinter to accommodate this — a self-correcting move that required no reviewer input.
contained.
Harness issues
run-verify.shdoes not install backend dependencies: On every fresh worktree,npm run type-check,npm run lint, andnpm testwill fail ifnode_modulesis absent. Thishas no pre-check or auto-install step. The failure is misleading because it looks like a
code error rather than a missing dependency.
lint-ios-layers.shRule 2 did not exempt test files: A test that asserts storagebehavior must reference the storage mechanism by design. The original script had no carve-out
for this pattern. This is now fixed in the codebase, but it caused an unnecessary verify
failure and a fix cycle.
Actions
.claude/scripts/run-verify.sh: Addednpm install --silentbefore backend npm scripts so fresh worktrees do not produce spurious dependency failures. (root cause: finding Add Claude Code GitHub Workflow #1).github/scripts/lint-ios-layers.sh: Already fixed in PR feat: single-app-pivot #7 —*Tests.swiftexcluded from Rule 2. (root cause: finding feat: backend-worker #2)