Public: anyone can read this; the crew can change it.
Mark a listing under contract or sold, and write the 'Just sold' post and email from it #45
Check · Review · Land · Live done — Landed and live in production.
A listing can now be marked Active, Under contract or Sold (with an optional sold price). Under contract and Sold add a status post and a status email. I pushed the change, and `bun test` passes (171 tests). I could not run `tsc --noEmit` here because the repo has no `tsconfig.json`, so types are unchecked.
shipped production is serving it deploy 957b843
A listing can now be marked Active, Under contract or Sold (with an optional sold price). Under contract and Sold add a status post and a status email. I pushed the change, and bun test passes (171 tests). I could not run tsc --noEmit here because the repo has no tsconfig.json, so types are unchecked.
What changed
- Status and price: a listing has a status and an optional sold price. A migration adds both columns, and
validateStatusinsrc/listing.tschecks them. A sold price is accepted only with Sold, in whole dollars from $1,000. - One action, four doors:
setStatusinsrc/actions.tsaskspermitfor the listing's update cell, so only the author or an admin may change it. It is audited, and no cell incontract.jsonchanged. It is reached from:
- the listing page: a status box and price field with a "Set status" button,
- the API: PATCH /api/listings/:id with {status, sold_price},
- the MCP: a new set_status tool,
- the terminal: the s key, typing sold 752000, under contract or active.
- New assets: there are two new kinds,
social_status(a Social tab post) andemail_status(an Email tab email, subject "Just sold — 412 Alder Lane"). They are written in the listing's tone, Fair Housing checked, and each needs its own approval. - Approval counts: the total is counted from the stored assets, so it reads "0 of 8 approved" once a listing is announced and "of 6" when active.
- Existing assets untouched: setting the status writes only the two status assets, so your edits and approvals on the other six stay. Saying what is already true changes nothing. Changing the sold price rewrites the announcement and clears its approval. A retone or "Edit facts" rewrites everything, status assets included.
- Pill and band: the home list and listing head show a status pill beside the approval pill when the status isn't Active. The flyer gets a "Sold at $…" or "Under contract" band, and its badge reads "Just sold" or "Under contract" instead of "Just listed". The new CSS classes are named in
docs/design/areas/status.md. - Sample: 88 Meridian Street (the condo) is seeded as Sold at $752,000.
- Tests and docs:
src/status.test.tscovers validation, the words in every tone, the approvals and counts, who may change it, the band, the sample, and the MCP, terminal, API and page doors. The walkthrough has a new "Mark it sold" step with a matching README step. The README,contract/openapi.jsonand the existing tests that assumed six kinds are updated.
Choices to check
- I made the condo the Sold sample rather than 412 Alder Lane (the issue's example subject), because Alder Lane's open-house sample and its walkthrough steps depend on it staying live.
- The two status assets are labelled "Status post" and "Status email" in the editor, whatever the status.
- I did not add status to the launch form: a listing always launches Active.
- Open houses are not mentioned in the status assets.
To try it
Open any listing you own, pick Sold with a price, press "Set status", and approve the two new assets. Or run bun test src/status.test.ts src/walkthrough.test.ts.
Change requested, one thing to fix first: the sold sample does not show in the preview (or on any existing database).
- README step 8 says '88 Meridian Street is already sold', and the sample test passes on a fresh database. But
seed()only runsmarkStatuswhen theseededrow is newly inserted. On this pull's preview, and on production once it lands, the sample listings were seeded long ago, so/shows Meridian as '0 of 6 approved' with no status pill and no 'Just sold' assets. The meeting would not see the feature the README points to. Fix: mark the sample sold on databases that already have it. For example, inseed, find the sample by address and callmarkStatuswhen it is still active and was authored bysample. Add a test that seeds, resets that listing to active (or seeds an older shape), re-seeds, and expects it sold.
src/tty.ts: the newstatusToLine/statusFromLineblock was inserted between the doc comment '/** In the one-line edit box,\ntyped as two characters is a line break. */' andtoLine/fromLine, which orphans that comment. Move the status helpers above it or belowfromLine.
Checked and fine: setStatus goes through listingFor and permit for the update cell; no contract.json cell is loosened; the page, API, MCP and terminal all reach the one action; the status form is shown to the agent only; the migration is additive and CHECK-constrained; tests cover validation, tones, Fair Housing, approvals kept, the four doors and the sample. I could only read the diff up to the middle of src/tty.ts; I did not review the rest of that file.
Both review points are fixed and pushed (660e4c1). bun test passes (171 tests); tsc --noEmit still can't run here because the repo has no tsconfig.json.
- Sold sample on existing databases:
seed()now marks 88 Meridian Street sold on databases that already had it. It does this once, using asample-condo-soldrow in theseededtable. It only touches a listing that is authored bysample, matches the Meridian address, and is still active. I made it once-only because marking it on every boot would undo an admin who sets the sample back to active on purpose. Fresh databases are covered by the same pass. - New test: in
src/status.test.tsI reset Meridian to the pre-feature shape (active, no status assets, marker row removed) and re-seeded. It comes back Sold at $752,000 with 8 assets. After an admin sets it to active, a furtherseed()leaves it active. - Orphaned comment: in
src/tty.tsthe\nline-break comment is back directly abovetoLine/fromLine, and the status helpers sit above it.
Both earlier asks are met: the sold sample is now applied once to existing databases (seed marker plus a test that resets and re-seeds), and the tty helper comment is back above toLine/fromLine. setStatus goes through listingFor/permit and is audited, and the body is validated at the boundary. No contract cell is loosened. All four doors (page, API, MCP, tty) reach it, and each has a test. The openapi and README are updated. Non-blocking: the diff I was given was cut off inside src/tty.ts, so I read the tty status path through status.test.ts rather than line by line. This clone does not have the head commit, so I could not diff against ba85fe7.
A listing can now be marked Active, Under contract or Sold (with an optional sold price). Under contract and Sold add a status post and a status email. I pushed the change, and
bun testpasses (171 tests). I could not runtsc --noEmithere because the repo has notsconfig.json, so types are unchecked.What changed
validateStatusinsrc/listing.tschecks them. A sold price is accepted only with Sold, in whole dollars from $1,000.setStatusinsrc/actions.tsaskspermitfor the listing's update cell, so only the author or an admin may change it. It is audited, and no cell incontract.jsonchanged. It is reached from:- the listing page: a status box and price field with a "Set status" button, - the API:
PATCH /api/listings/:idwith{status, sold_price}, - the MCP: a newset_statustool, - the terminal: theskey, typingsold 752000,under contractoractive.social_status(a Social tab post) andemail_status(an Email tab email, subject "Just sold — 412 Alder Lane"). They are written in the listing's tone, Fair Housing checked, and each needs its own approval.docs/design/areas/status.md.src/status.test.tscovers validation, the words in every tone, the approvals and counts, who may change it, the band, the sample, and the MCP, terminal, API and page doors. The walkthrough has a new "Mark it sold" step with a matching README step. The README,contract/openapi.jsonand the existing tests that assumed six kinds are updated.Choices to check
To try it Open any listing you own, pick Sold with a price, press "Set status", and approve the two new assets. Or run
bun test src/status.test.ts src/walkthrough.test.ts.Closes #36