Version. 0.5 Date. 2026-08-05 Supersedes. v0.4, v0.3, v0.2 and v0.1, none of them filed — each halted at pre-flight or superseded before filing. The record holds none of them. Changes from v0.4. One sentence. §4.3 announced that no count was given and then gave three numbers in the same sentence — the removal half-landed, taking the figure out of where it was asserted and restating it while explaining the removal. The count now lives only in the changes-line below, as history.
Changes from v0.3, carried. Two mechanical corrections found at a filing gate. §4's subsections were still numbered from when it was §3 — a renumbering pass that moved the headings and not their contents. And the count of how many invented figures v0.1 carried is removed rather than corrected again: it was written as two, corrected to three, and is actually four. (The correction to three came from the executing session; the fourth instance was one the drafting session had removed in its own recheck and then failed to count.)
Changes from v0.2, carried. Two corrections and a fourth option, all from the Operator's questions. Why the limit exists was never stated — everything retrieved goes into the model's prompt, and the limit is where the prompt runs out. The "raise fifty to five hundred" argument does not hold: the path using five hundred never calls the model, so its number is not comparable. The volume question is reframed — it is not how much there is today but what kind of engagement Loomworks intends to admit, and a diligence data room or a legacy codebase is not the same problem as a person's notes. And a fourth option is added: reading the record in batches and carrying forward, which needs no infrastructure, has no window to fall outside of, and would break B-11's source guarantee unless built with care.
Changes from v0.1, carried. Invented figures removed. v0.1 illustrated the answer's scope sentence with a concrete volume — "the fifty most recent of three hundred notes on record" — and used the same invented total again in §2. Fifty is real; the total was not, and it was written in the voice of observed behaviour in a note whose §1 argues that the volume is the one fact nobody has checked. Both are replaced by the mechanism rather than by better placeholders, since any figure at all would make the same claim.
Author. Claude.ai (drafting session). Operator: Marvin Percival.
Charter. standing-notes/dunin7-standing-authorization-charter-v0_1.
Build-list item. B-12.
Grounding. inspection-briefs/loomworks-b12-step-0-findings-v0_1 — every fact below comes from it, read in full before this note was drafted.
Status. Scoping. Puts options to the Operator. Decides nothing that the read does not already decide.
Everything retrieved goes into the model's prompt. There is a hard ceiling on how much text fits in one, and a cost proportional to how much you put there. The limit is where the prompt runs out — not a policy anyone chose.
Why fifty specifically is unread. The read established the constant and its location and nothing about its derivation. No comment explains it.
> A correction to v0.1 and v0.2 of this note. Both argued that the cheapest answer is raising fifty to five hundred, on the evidence that another path already uses five hundred through the same function. That path never calls the model — it is one of the server-composed intents that compose their reply directly from the rows. Five hundred works there because it goes into a list, not into a prompt. The two numbers are not comparable and the "one constant" argument does not carry the weight those versions put on it.
What survives the correction. Raising the limit is still the cheapest thing available and may still be enough. But it has a ceiling nobody has established, and that ceiling — not the other path's five hundred — is what bounds it.
v0.1 and v0.2 asked how many notes an engagement holds, as though there were one answer.
There is not, and the difference between kinds of engagement is larger than any growth within one. A person's own working notes and a diligence engagement over a data room, or an engagement over a legacy codebase, differ by orders of magnitude — and the second kind is not hypothetical. The record already carries a venture-diligence vertical.
So the design question is not what today's engagements hold. It is what kind of engagement Loomworks intends to admit — because a retrieval that serves the small case and fails the large one forecloses the large one.
Two facts are needed, and only one of them is a query:
How much is there, per kind of engagement — the distribution, not an average, and separated by what kind of work the engagement is doing. One read-only aggregate against production, and an Operator decision because it touches production.
How long a person will wait for an answer. Not a measurement — a judgement, and yours. It decides between the options below more sharply than volume does, because the option that never hits a ceiling is the one that pays per question.
One is already off the table.
Semantic search is unavailable, and not for a reason a change request can fix. The vector extension is absent from the Postgres server itself — not uninstalled in the database, not blocked by privileges, not present as a package. Using it would need a system-level install on the database host, which is an infrastructure decision rather than a build. (Set aside, not rejected. If the hosting changes, this reopens.)
Two are available with no elevation at all, installable by the application's own role in its own database — which matters because that role cannot even create a database.
| | What it does well | What it does badly |
|---|---|---|
| Word search (native, no extension) | Matches words and their variants; ranks results; the standard tool for this | Cannot find what you meant if you used different words |
| Fuzzy matching (pg_trgm) | Tolerates typos and partial words; finds substrings | Poor at ranking across a large corpus |
They compose. Word search as the primary, fuzzy as a fallback when it returns nothing, is a common and unremarkable arrangement.
Read the record in batches, carrying forward what matters. Retrieve a batch, let the model read it and keep what bears on the question, retrieve the next, repeat, then answer from what accumulated. No index, no extension, no schema change, and it runs against the code that exists.
Two things recommend it over both of the above. Coverage is total whatever the volume — there is no window to fall outside of. And relevance is judged by a model reading each note, which finds what a word search misses: the note that answers the question without containing any of its words.
One thing disqualifies it as the retrieval itself. It reads the whole record to answer one question, and reads it again for the next one. An index does that reading once and keeps the result. A loop is an index computed at question time, repeated per question — the same work, worse timing, paid every time.
> And it would break what B-11 just fixed, unless built carefully. B-11 made the answer's sources facts: the system attaches the records it handed over. In a loop the system hands over everything, so sources become either all of it — useless — or what the model says it kept, which is exactly the model-composed citation B-11 removed. > > The fix is the same move the provenance walk made. The model names its selections by identifier, per batch, and the system verifies each named identifier was in the batch it was shown. The model chooses; the system checks it could only have chosen from what it saw. Sources stay facts. This is not free, and it is the difference between a loop that preserves the guarantee and one that quietly gives it up.
Where the loop earns its place is not as the retrieval. Two positions:
As a re-rank. A cheap search narrows to candidates; the loop reads only those and judges them properly. The model's relevance judgement without paying it against the whole record.
As a pass run ahead of time. Run it once over the record, store what it found, query the store. That is building the index by model rather than by keyword — legitimate, larger, and a different item.
> One thing that recommends word search beyond its availability, and it is this project's own argument. A searched answer has to say what it looked at. Word search can say something checkable — the number of notes containing the terms searched for, the terms themselves, and the true total on record. The terms are stated and the matching is mechanical, so a reader can see what was asked of the record and what came back. Semantic search cannot. Its honest sentence would be the notes the system judged relevant — and relevance is a judgement the system would be asserting rather than a fact it could show. That is the same distinction B-11 turned on, where a citation the model composed became a source the system attached.
4.1 The seam is shared, and changing it changes more than the answer.
One function serves ten call sites. One of them feeds a block into the system prompt on every single conversational turn, whatever the person asked — not the intent this item is about. A search that changes what that function returns would silently change what the Companion sees on every turn, which is a far wider surface than B-12's subject.
So a search is a new path or a parameter, never a change to that function's default behaviour.
4.2 Membership is enforced at exactly one point, and a new path must not assume it.
The query function carries no membership predicate at all. The fence is at the endpoint, once, and everything below it trusts that whoever assembled the engagement identifier already passed through. Ten call sites inherit nothing.
A search either sits behind the same endpoint gate or carries its own predicate. There is nothing to inherit, and a search reaching across an engagement boundary would be the most serious defect this project could ship — it is exactly the fence the non-member contribution work was built on.
4.3 The honest sentence has to survive the change, and it is already right.
The answer currently says it drew on the most recent N of M notes on record, and that this was not a search of all of them — and that sentence is computed from real values, not hardcoded: the count actually retrieved, the true total, and the limit applied. It appears only when the window is partial.
> No example figures are given here on purpose. This note argues that the volume is unread; inventing one to illustrate a sentence would assert the very thing §2 says nobody has checked. (v0.1 did exactly that, and was halted at filing for it.)
> No count of how many is given, and that is deliberate: the number itself has been wrong every time this note tried to state it — in a note whose whole subject is figures asserted without being counted. It earns nothing and it comes out. (The changes-line at the top of this note records what the successive values were; that is history, not a live claim.)
Whatever B-12 does, that machinery adapts — but its wording must change with it, and the new wording is the part most likely to overclaim. The notes matching your question is honest. The most relevant notes is not, unless something can show what relevance meant.
5.1 Volume, per kind of engagement. §2. The decision above all others, and one of the two needing the Operator.
5.2 What a person will wait for an answer. §2. A judgement rather than a measurement, and it decides between search and the loop more sharply than volume does.
5.3 Whether production's database can do what this one can. Every capability fact in the read came from a local development instance. Whether the hosted database has the fuzzy-matching extension available, and whether the application's role can install it there, is unverified. A design resting on it would be built on an assumption.
5.4 Nothing in this codebase has ever been indexed. Not one column, anywhere — the search for index declarations returned zero across the whole engine. Whatever B-12 does would be the first index this project has ever created, over prose living inside a JSONB payload rather than its own column. That is ordinary work and it is not work anyone here has done before.
Establish the two facts at §2 before choosing. One is a query and one is your judgement, and together they decide more than any preference about mechanism.
If the largest engagement Loomworks intends to admit fits under the prompt ceiling: raise the limit toward that ceiling, keep the honest sentence, and close B-12. No search, no index, no extension. The item was written when nobody knew how much there was.
If it does not — and a data room or a legacy codebase will not: build word search as a new retrieval path, not a change to the shared function, behind the existing endpoint gate, with the answer stating the terms it matched on and the count it drew from.
Then the loop as a re-rank over what search returns, if search alone proves too blunt in use — rather than in anticipation. That ordering matters: search first is cheap and its failure mode is visible (it returns the wrong things and you can see them). Loop first is expensive and its failure mode is a wait.
And the loop as an ahead-of-time pass is its own item, not part of B-12. It is a different thing — building an index by model — and sizing it inside a retrieval decision would bury it.
The semantic option stays where the read put it: unavailable for infrastructure reasons, reopening only if the hosting changes.
DUNIN7 — Done In Seven LLC — Miami, Florida Loomworks — B-12 scoping note — v0.5 — 2026-08-05 The cheapest answer is a constant, and nobody has checked whether it would do.