69270f4cfb
Three of the four packages were already clean on the brief's priorities. The brief predicted missing timeouts and unbounded reads; websearch already had a status check, a deferred close, a 4 MiB limit, an 8s total and a 1.5s connect cap on a cloned transport. The one bug with reach was a string grep across a package boundary. crawl.isServerError decided whether a failed robots.txt blocks a crawl by scanning err.Error() for " 50", " 51", " 52" and " 53", in a message built two packages away. Rewording that message would silently turn a 503 robots.txt into permission to crawl, which the surrounding comment says must never happen. Both packages now carry a typed StatusError that unwraps to the existing sentinel, so errors.Is is unchanged, and isServerError reads a number. webfetch checked the status after reading the body, the same shape the weather sweep found. A 500 pulled its error page up to MaxBytes off the wire, and an error page over the cap returned ErrTooLarge, naming the size and hiding the status. rss.Parse copied a feed document that can reach a megabyte through strings.NewReader(string(...)). Two comments claimed callers that do not exist. The privacy invariant holds across all four. None of them can read the store. rss.Ranker is the one seam that could carry notes outward, it is nil in the daemon, and its doc states the constraint. Every regex here is over structured input. (V-581)