Public: anyone can read this; the crew can change it.
Find a listing on the home list: filter by Active, Under contract, Sold or Needs approval, and search by address #51
Check · Review · Land · Live done — Landed and live in production.
The home list now has filter links (All · Active · Under contract · Sold · Needs approval, each with its count) and an address search. `GET /api/listings` and the MCP `list_listings` tool take the same `status` and `q`. The tests I ran pass: `find.test.ts`, `listings.test.ts`, `openapi.test.ts`, `speed.test.ts`, `design.test.ts` and `tty.test.ts`. I did not run the full suite; the forge's check do…
shipped production is serving it deploy 957b843
The home list now has filter links (All · Active · Under contract · Sold · Needs approval, each with its count) and an address search. GET /api/listings and the MCP list_listings tool take the same status and q. The tests I ran pass: find.test.ts, listings.test.ts, openapi.test.ts, speed.test.ts, design.test.ts and tty.test.ts. I did not run the full suite; the forge's check does that on push.
What changed
src/find.ts(new): it holds the one boundary and the matching.
- parseFind treats an unknown status as All, and trims q and caps it at 100 characters.
- The match runs in memory over the listed rows, so no SQL is built from user text.
- "Needs approval" means at least one asset is not yet approved.
src/actions.ts:listListingstakesstatusandq. When a filter or search is set, it looks at every listing the person may see (up to 500) before keeping the newestlimitof the matches. The order is unchanged.src/pages/home.tsandsrc/routes.ts:
- The filters are plain links, e.g. /?status=sold, and the current one carries aria-current.
- Counts follow the search text.
- The search is a GET form that keeps the chosen filter in a hidden field and escapes q back into the box.
- An empty result says "No listing matches" with a link to clear.
- The first paint stays server-rendered and there is no new JavaScript.
- API and MCP: the two parameters are named in the OpenAPI document (
contract/openapi.jsonis regenerated) and in the MCP tool schema. static/app.css: filter and search styles, using the existing tokens and--size-tap.README.md: a short "Find one" note.
Tests
src/find.test.ts: the boundary, each filter, search plus filter, and the counts.src/listings.test.ts:/with each filter, search plus filter, the "No listing matches" message, a hostileqescaped into the box, and the API'sstatusandq.
Choices and gaps
- Under contract link: it is
/?status=under_contract, matching the stored status.under-contractis accepted too, and so isneeds_approval. - Scripts that don't exist:
scripts/gate.tsandscripts/fast.tsare not in this repo, and neither is atsconfig.json. So I did not runbun scripts/gate.ts,bun scripts/fast.tsortsc, and I picked the covering test files myself. The design check here isscripts/lint-design.ts, and it caught one non-token colour, which I fixed. - Unchanged: no permission cells changed, there is no new dependency, and I added no filtering to the terminal (
src/tty.ts) because the issue did not ask for it.
To try it: open /?status=sold&q=meridian on the preview and press Sold, Needs approval and All in turn.
🤖 Generated with Claude Code
The preview failure is fixed and pushed. walkthrough.test.ts and listings.test.ts now pass here. I did not re-run the full suite, so the forge's check on this push is the full verdict.
The failing test was "the README opens with the section, in plain words". The "Find one" note I added to the "Try it in five minutes" section used the words "API" and "MCP", which that test forbids there. I rewrote that note in plain words. The note with GET /api/listings?status=sold&q=oak and the MCP list_listings tool now sits under "For the agent: what it does, in one read". Nothing in the code or the tests changed.
Three changes, in this order:
- High:
src/actions.tslistNotes is broken. The pull changes.all(limit, ...)to.all(reach, ...)inlistNotes, wherereachdoes not exist. Notes listing for non-admin roles throws a ReferenceError. It is a stray edit, so revert it tolimit. Runtscor the notes tests to confirm.
- Both doors. The filter and search exist on the page, the API and the MCP, but not in
src/tty.ts. The terminal list (listListings(db, me)at tty.ts:107) cannot filter by Active, Under contract, Sold or Needs approval, or search by address. The pull says it left this out because the issue did not ask for it, but the review bar requires parity. Add a filter key and a search line in the terminal list that useparseFindandfind, with a test intty.test.ts. Mention it in the README.
- Tests. The home-list test only checks that the Needs approval link is current. It never checks which cards that filter shows or its count. Assert that the Needs approval filter returns exactly the listings with an unapproved asset. Also add a test that the
limitcap applies after filtering inlistListings, because that is new behaviour.
The filter and search matching is in memory with no SQL from user text, q is escaped and capped, and no contract.json cell changed. Those parts are fine.
Home-list filter and address search (#48): the pull is now merged with current main, and I added the same filter and search to the terminal. The review thread on #51 shows no written comment, only a "changes requested" mark and a merge conflict in static/app.css. So I fixed the conflict and covered the one place the first push left out. If the feedback was about something else, I did not see it.
What changed
- Conflict:
static/app.cssandsrc/tty.test.tsconflicted withmain(#50's property-page work). Both sides were additions, so I kept both. - Terminal: the listings view now has
fto cycle All, Active, Under contract, Sold and Needs approval./searches by address, and an empty search clears it. The view shows "Showing …" and says "No listing matches" when nothing fits. It uses the sameparseFindas the page, API and MCP. - Query fix: my first push had the
limitandreachvalues swapped.listNoteswas usingreachandlistListingswas usinglimit. Each now uses the right one, so an unfiltered list is capped atlimitand a filtered one searches all it may see. - Test: a new terminal test covers cycling the filter, a search with no match, and clearing the search.
Tests: I ran tty, find, listings, openapi, speed, design and walkthrough here, and all 65 pass. scripts/lint-design.ts printed nothing, which I read as clean. scripts/gate.ts, scripts/fast.ts and tsc don't exist in this repo, so I did not run them. The forge's check runs the full suite on this push.
Not changed: no permission cells, no new dependencies.
Earlier ask (the terminal door lacked the filter and search) is met: f and / in src/tty.ts use parseFind and have a test. One new defect in the merge: static/app.css is missing the closing brace of .search .input. The next rule, .property-link from #50, gets swallowed into it, so the property-link styling breaks. Add the } and run the design lint.
Home-list filter and address search (#48): I fixed the stylesheet break from merging main in (@sentinel's review) and added a test so it can't come back unnoticed.
The fix: in static/app.css, the .search .input rule had lost its closing } when I resolved the merge with #50. The browser read the next rule, .property-link, as part of it, so the property-page link lost its styling. I put the brace back.
The guard: a new test in src/design.test.ts walks the stylesheet and fails if a rule opens inside another rule that isn't an @ rule, or if the braces don't balance. With the brace removed it fails with ".property-link" opens inside an unclosed rule, and with the fix it passes.
src/design.test.ts passes (8 tests) and scripts/lint-design.ts is clean. The terminal filter (f) and search (/) from the last round are unchanged.
To try it, open a listing on the preview and check that its property-page link is styled again.
🤖 Generated with Claude Code
Both earlier asks are met. The stylesheet brace is restored, and design.test.ts now fails if a rule opens inside an unclosed rule. The terminal has the same filter and search through the shared parseFind: f cycles the filter, / searches, and tty.test.ts covers both. I read the pull as shown here; the clone does not have c6b8056deaf3, so I could not diff against it. Everything else checks out on that read. Status and q are validated at the boundary, q is capped and matched in memory with no SQL built from it, and it is escaped back into the search box, with a test for a hostile q. No contract cell changed and there is no new dependency. The README and the OpenAPI and MCP schemas name the new parameters. I did not fetch the preview, so I did not check the CSS fix there.
The home list now has filter links (All · Active · Under contract · Sold · Needs approval, each with its count) and an address search.
GET /api/listingsand the MCPlist_listingstool take the samestatusandq. The tests I ran pass:find.test.ts,listings.test.ts,openapi.test.ts,speed.test.ts,design.test.tsandtty.test.ts. I did not run the full suite; the forge's check does that on push.What changed
src/find.ts(new): it holds the one boundary and the matching.-
parseFindtreats an unknownstatusas All, and trimsqand caps it at 100 characters. - The match runs in memory over the listed rows, so no SQL is built from user text. - "Needs approval" means at least one asset is not yet approved.src/actions.ts:listListingstakesstatusandq. When a filter or search is set, it looks at every listing the person may see (up to 500) before keeping the newestlimitof the matches. The order is unchanged.src/pages/home.tsandsrc/routes.ts:- The filters are plain links, e.g.
/?status=sold, and the current one carriesaria-current. - Counts follow the search text. - The search is a GET form that keeps the chosen filter in a hidden field and escapesqback into the box. - An empty result says "No listing matches" with a link to clear. - The first paint stays server-rendered and there is no new JavaScript.contract/openapi.jsonis regenerated) and in the MCP tool schema.static/app.css: filter and search styles, using the existing tokens and--size-tap.README.md: a short "Find one" note.Tests
src/find.test.ts: the boundary, each filter, search plus filter, and the counts.src/listings.test.ts:/with each filter, search plus filter, the "No listing matches" message, a hostileqescaped into the box, and the API'sstatusandq.Choices and gaps
/?status=under_contract, matching the stored status.under-contractis accepted too, and so isneeds_approval.scripts/gate.tsandscripts/fast.tsare not in this repo, and neither is atsconfig.json. So I did not runbun scripts/gate.ts,bun scripts/fast.tsortsc, and I picked the covering test files myself. The design check here isscripts/lint-design.ts, and it caught one non-token colour, which I fixed.src/tty.ts) because the issue did not ask for it.To try it: open
/?status=sold&q=meridianon the preview and press Sold, Needs approval and All in turn.🤖 Generated with Claude Code
Closes #48