From 6acaea630ea6cf0efb69aabdc271846006f5c6ef Mon Sep 17 00:00:00 2001 From: "@permadeath.com" Date: Mon, 24 Aug 2026 14:42:11 -0400 Subject: [PATCH] docs(todo): tick the issue captures and record what they measured MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four of the five prose claims held against real bytes; the fifth — that an issue number is in no record — was true only of records written since repos got DIDs, and the entry now says so. Three new entries carry what the captures turned up: Bobbin rewrites an issue record and rewrites a legacy comment further, a repo-scoped PDS listing drops the pre-DID rows, and a generated type does not check its own $type. Co-Authored-By: Claude Opus 5 (1M context) Change-Id: I8762cd4cd9aba3f17a4953bc94cdb7903fc49222 --- TODO.md | 90 +++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 75 insertions(+), 15 deletions(-) diff --git a/TODO.md b/TODO.md index 720f1a0..5f2daf2 100644 --- a/TODO.md +++ b/TODO.md @@ -1568,13 +1568,16 @@ and borrows `pr`'s conventions rather than inventing new ones beside them. overruling. `IssueState::from_label` reads the envelope's bare word where `from_token` reads a record's whole NSID, and an unrecognised word leaves the row unsettled and listable rather than crashing -- [ ] No issue *numbers*. The number is the appview's own id, in no record and - no XRPC response, exactly like a pull's; atgc resolves a pull's by - scraping the page, and the entry above about that scrape says it is a - bet on somebody else's HTML that has already been seen to fail. Making - a second bet of the same kind to ship a first cut was not worth it, so - `issue view 23` refuses and says why. Every command takes the record key - or the at:// URI instead +- [ ] No issue *numbers*. The number is the appview's own id, in no record + written since repos got DIDs and in no XRPC response — the pre-DID shape + did carry it, as an `issueId` beside an `owner`, which + `tests/fixtures/issue_old_record.json` is a captured example of; that + spelling is gone and nothing indexes it. Exactly like a pull's, then; + atgc resolves a pull's by scraping the page, and the entry above about + that scrape says it is a bet on somebody else's HTML that has already + been seen to fail. Making a second bet of the same kind to ship a first + cut was not worth it, so `issue view 23` refuses and says why. Every + command takes the record key or the at:// URI instead - [ ] Residual, after the index landed: a state still reads `?` when Bobbin has not indexed the issue and the author does not own the repo that is most of them: a maintainer's close is a record in the @@ -2906,9 +2909,10 @@ and borrows `pr`'s conventions rather than inventing new ones beside them. outright — while `pr list`, `pr view`, `pr diff` and `pr merge` all still work on one; - a legacy `sh.tangled.repo.issue.comment` names its subject as a bare - at-uri where `sh.tangled.feed.comment` takes a strongRef whose CID it - has nowhere to put, so a thread older than the unification would read - as empty (`clients::tangled::comments` reads both shapes); + `issue` at-uri and its body as a plain string, where + `sh.tangled.feed.comment` takes a `subject` strongRef and a markdown + object, so neither type reads the other's record + (`clients::tangled::comments` reads both shapes); - `sh.tangled.repo.issue` types `repo` as a DID and the appview still ingests records carrying an at-uri there, which `FetchedIssue:: repo_did` answers `None` for — where `Issue` would refuse the record. @@ -2923,11 +2927,67 @@ and borrows `pr`'s conventions rather than inventing new ones beside them. captured shapes each generated type accepts and which it refuses, so a regeneration against a tightened schema fails there instead of in somebody's listing -- [ ] No `sh.tangled.repo.issue` or `sh.tangled.repo.issue.state` record is - captured under `tests/fixtures/`, so the issue read path is the one - record family whose tolerance rests on doc comments with no bytes behind - them — including the at-uri-in-`repo` case above, which is asserted - nowhere. A capture off a live PDS would close it +- [x] The issue family is captured now: eight files under `tests/fixtures/`, + taken off live PDSes and off Bobbin by unauthenticated requests, run + through the generated types in `lexicon::tangled` and through the read + path's own helpers in `cmd/issue/fixtures.rs`. What they pin, in the + order the prose claimed it: + + - **`repo` holds an at-uri in the wild.** 268 of 339 records surveyed + across eight accounts do, and four of the ten on the captured page. + `Issue` refuses every one; `FetchedIssue::repo_did` answers `None`, + as its doc comment says, and now on bytes rather than on a + description of them. + - **`createdAt` is required and often absent or empty.** 99 of the 339 + carry no usable stamp — 12 without the property at all, 87 with the + empty string — and 82 of 130 `.issue.state` records have none either, + two of them naming no issue at all. `state_event` reads them and lets + them lose on the sort, which was the claim. + - **`body` is optional and always there.** Every one of the 339 has + one, which is the appview's `issue body is empty` refusal seen from + the record side, and the reason `issue create` refuses a title-only + issue before the write. + - **The number is in a record after all.** The pre-DID shape carries + `issueId` beside an `owner`, neither of them ever in the lexicon. + Nothing written since has it, so `issue view 23` refusing still + stands — but "in no record" was too strong, and the captured record + is `issue_old_record.json`. + - **A close/reopen/close chain is three records seven seconds wide.** + Captured live; `newest_state` settles it the same way whichever order + the records arrive in +- [ ] Bobbin does not hand back the issue record it indexed, and for one + collection it does not hand back a record at all. `listIssuesBy` rewrites + a pre-DID record's `repo` at-uri to the repo DID and drops the record's + own `repoDid`, under the record's real CID; `feed.listComments` rewrites + a legacy comment further — the body lifted into an object, the bare + `issue` at-uri turned into a `subject` strongRef whose `cid` is + `bafkqaaa`, the CID of no bytes — while leaving `$type` naming the + legacy collection. Both are pinned by paired captures of the same + records off both services. The pull half is not like this + (`the_indexed_copy_of_a_pull_is_the_same_record`), so `cmd::pr::read`'s + merge and `cmd::issue::read`'s merge do not rest on the same assumption + even though they are the same shape of code +- [ ] `names_repo` compares `repo` to the repo DID exactly, so a repo-scoped + `issue list` reading only the PDS drops every pre-DID issue the account + filed against that repo — six of ten rows survive on the captured page, + and the index shows nine of the same ten because it rewrote them first. + So `--source bobbin` lists issues that the PDS half of the same command + cannot, on records the account itself wrote. Matching the at-uri too + means resolving it, and it names the repo *record*, whose key is not the + repo name and whose authority is the owner, not the repo — one lookup + per distinct at-uri, cached, is the shape of the fix. Left recorded + rather than done: the rows are wrong by omission today and would be + wrong by a network round trip tomorrow, and which is worse is a + judgement worth making deliberately +- [ ] The generated record types do not check their own `$type` on the way + in. A legacy comment as the index rewrites it deserializes cleanly into + `FeedComment` although its `$type` still says + `sh.tangled.repo.issue.comment`, and reserializing it emits `$type` + twice — the container's tag and the one `extra_data` carried in. Both + are pinned in `a_legacy_issue_comment_is_not_the_record_the_index_hands + _back`. Nothing reads records that way today, so this is a note about + what a typed read path would not buy: the collection would still have to + be checked by hand - [x] Integration environments: whole *sequences* of commands driven through the built binary against mock services on loopback ports (`tests/support/`, `tests/stack_flows.rs`, `tests/pr_flows.rs`). What -- 2.51.2