Public: anyone can read this; the crew can change it.

Change a launched listing's price and facts: every asset is written again and its approval cleared #28

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

A launched listing's price and facts can now be changed, and every asset is written again with its approval cleared. The affected test files pass, but I did not run the whole suite. `bun x tsc --noEmit` and `bun scripts/lint-design.ts` printed no errors, but this clone has no `tsconfig.json`, so tsc printed its help text and checked nothing.

shipped production is serving it deploy 957b843

opened this

A launched listing's price and facts can now be changed, and every asset is written again with its approval cleared. The affected test files pass, but I did not run the whole suite. bun x tsc --noEmit and bun scripts/lint-design.ts printed no errors, but this clone has no tsconfig.json, so tsc printed its help text and checked nothing.

What changed

  • Action: updateFacts(db, who, { id, fields }) in src/actions.ts is audited as listing.update. It asks permit through the same lookup as retoneListing, so anon, other users and the read-only sample get the same refusals as for a tone change.
  • Validation: it validates through validate from src/listing.ts. Fields left out keep their current value, so { facts: { price: 649000 } } is enough.
  • Writes: one transaction updates the row and rewrites all six assets in the listing's tone, which clears every approval and replaces hand edits. It then emits listing.changed. Invalid input is a 422 with the form's message, and the transaction never starts.
  • Photos and headshot: untouched.
  • Page: the listing page shows Edit facts to whoever canEditListing allows. It opens GET /listings/:id/facts, the launch form filled in with the listing's facts, with no photo or headshot inputs. The form says edits are replaced and approvals cleared. Saving posts to /listings/:id/facts, same-origin checked.
  • Reuse: form in src/pages/home.ts is now exported with an optional editing argument, and the new page is in src/pages/facts.ts.
  • API: PATCH /api/listings/:id accepts { facts: {...} }, and contract/openapi.json is regenerated.
  • MCP: a new update_facts tool.
  • README: the walkthrough gains step 6, "Drop the price" (print the flyer is now step 7), and the README lists the new tool and PATCH example.
  • Tests:

- src/listings.test.ts checks the MLS description, social post and email text, and the flyer and email pages, for the new price. It also checks approvals read 0 of 6, a bad price is refused with nothing changed, and another user, anon and the sample are refused. - The same file covers the audit rows, the page form including a cross-origin refusal, PATCH, and MCP. - src/walkthrough.test.ts walks step 6. - src/server.test.ts had a hard-coded MCP tool list, so I added update_facts to it.

Choices

  • Price in the MLS text: the flyer's asset text doesn't contain the price. The flyer page draws it from the row, so the test checks the flyer page rather than that asset.
  • Terminal: left out, as the issue allows.
  • contract.json: unchanged, and update stays author-only.
  • Gate and fast scripts: scripts/gate.ts and scripts/fast.ts don't exist here, so I ran the affected test files by hand.

To try it: sign in, open one of your listings, press Edit facts, lower the price and save.

🤖 Generated with Claude Code

Closes #26

commented

A launched listing's price and facts can now be changed, and every asset is written again with its approval cleared. The affected test files pass, but I did not run the whole suite. bun x tsc --noEmit and bun scripts/lint-design.ts printed no errors, but this clone has no tsconfig.json, so tsc printed its help text and checked nothing.

What changed

  • Action: updateFacts(db, who, { id, fields }) in src/actions.ts is audited as listing.update. It asks permit through the same lookup as retoneListing, so anon, other users and the read-only sample get the same refusals as for a tone change.
  • Validation: it validates through validate from src/listing.ts. Fields left out keep their current value, so { facts: { price: 649000 } } is enough.
  • Writes: one transaction updates the row and rewrites all six assets in the listing's tone, which clears every approval and replaces hand edits. It then emits listing.changed. Invalid input is a 422 with the form's message, and the transaction never starts.
  • Photos and headshot: untouched.
  • Page: the listing page shows Edit facts to whoever canEditListing allows. It opens GET /listings/:id/facts, the launch form filled in with the listing's facts, with no photo or headshot inputs. The form says edits are replaced and approvals cleared. Saving posts to /listings/:id/facts, same-origin checked.
  • Reuse: form in src/pages/home.ts is now exported with an optional editing argument, and the new page is in src/pages/facts.ts.
  • API: PATCH /api/listings/:id accepts { facts: {...} }, and contract/openapi.json is regenerated.
  • MCP: a new update_facts tool.
  • README: the walkthrough gains step 6, "Drop the price" (print the flyer is now step 7), and the README lists the new tool and PATCH example.
  • Tests:

- src/listings.test.ts checks the MLS description, social post and email text, and the flyer and email pages, for the new price. It also checks approvals read 0 of 6, a bad price is refused with nothing changed, and another user, anon and the sample are refused. - The same file covers the audit rows, the page form including a cross-origin refusal, PATCH, and MCP. - src/walkthrough.test.ts walks step 6. - src/server.test.ts had a hard-coded MCP tool list, so I added update_facts to it.

Choices

  • Price in the MLS text: the flyer's asset text doesn't contain the price. The flyer page draws it from the row, so the test checks the flyer page rather than that asset.
  • Terminal: left out, as the issue allows.
  • contract.json: unchanged, and update stays author-only.
  • Gate and fast scripts: scripts/gate.ts and scripts/fast.ts don't exist here, so I ran the affected test files by hand.

To try it: sign in, open one of your listings, press Edit facts, lower the price and save.

🤖 Generated with Claude Code

commented

Fixed and pushed: the deploy failure was the new test, not the feature. The full bun test run passes here (115 tests).

I didn't see the deploy's failure message. This is my best explanation. The "Edit facts" test makes many writes as the shared test users alice and bob. The server allows each person a burst of 20 writes, refilled at 2 a second, and the other tests had already spent most of it. When the deploy ran the files in a different order, my test hit the limit. The test now uses its own two users, so it no longer shares that allowance.

I couldn't reproduce the failure locally, so whether the preview now passes is unconfirmed until the deploy reruns.

The change to the app is the one in the original description: Edit facts, PATCH {facts}, and update_facts. Only the test changed.

Approved

Clean. updateFacts asks permit through the same lookup as retone, is audited as listing.update, validates at the boundary, and runs the row update and asset rewrite in one transaction. The page POST is same-origin checked, the cells in contract.json are unchanged, the terminal is optional in the issue and the pull says it was left out, and the tests cover the page, API, MCP and refusals. The preview answers 200 on / and 401 for a guest on /facts.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs