Public: anyone can read this; the crew can change it.
A lead who buys or sells with the agent is marked closed with a date, and a year later a home-anniversary check-in draft waits on the desk #110
Check · Review · Land · Live — It conflicts with its base.
first in the queue: no estimate: nothing landed in the last hour
A lead can now be marked closed — bought or sold — with a closing date, and a year later a "happy home anniversary" check-in draft waits on the desk. `bun test` is green (527) and `bun run lint:design` is clean. I could not run `bun x tsc --noEmit` because the repo has no `tsconfig.json`, and there is no `scripts/gate.ts`.
22 files · +772 −47
look it conflicts with main in src/db.ts, src/leads.ts — bring the branch up to date and it can land deploy 2cad6ad
Conflicts in 2 filesdeploy 2cad6ad
Website spec: 4 findings, 4 the edge owns (report only)
- / no <link rel="canonical"> — canonical
- / missing og:image — open-graph
- / the first focusable element is not a skip link (an in-page #target link) — skip-link
- / a 3929-byte body was sent without br or gzip though Accept-Encoding: br, gzip — https://specification.website/ (the edge owns this)
- / http://127.0.0.1:33511/tokens.css?v=d43314d1: a 2299-byte body was sent without br or gzip though Accept-Encoding: br, gzip — https://specification.website/ (the edge owns this)
- / http://127.0.0.1:33511/static/app.css?v=b40616cd: a 17333-byte body was sent without br or gzip though Accept-Encoding: br, gzip — https://specification.website/ (the edge owns this)
- / no Cross-Origin-Opener-Policy — coop (the edge owns this)
- / no ETag on the HTML — caching
Look
A lead can now be marked closed — bought or sold — with a closing date, and a year later a "happy home anniversary" check-in draft waits on the desk. bun test is green (527) and bun run lint:design is clean. I could not run bun x tsc --noEmit because the repo has no tsconfig.json, and there is no scripts/gate.ts.
What changed
- Marking closed. From a lead's page,
PATCH /leads/:idorPOST /leads/:id/statewith{"state":"closed","kind":"bought|sold","closed_on":"YYYY-MM-DD"}, the MCPmark_leadtool, andyin the terminal all go through one action. It is a lead update throughpermit, recorded in the audit log asclosedwith the kind and date. No contract cell changed. - Validation. The date must be a real day from 1990 on and no more than a year ahead, counted on the agent's calendar. A bad kind or date is a 422 naming
kindorclosed_on. - Undo and follow-ups. The lead stays
qualifiedand gainsclosedKindandclosedOn, so follow-ups stop exactly as with qualified.state: "open"(the #23 re-open) undoes it and clears both. - Counts and filter. The Activity page's lost-reason block now has a "Closed in the last 30 days" block beside it, and closed leads sit under Closed. The CSV export gains
closedandclosed oncolumns. - Anniversary draft. On each anniversary of
closed_onin the agent's time zone, the clock'sturncreates one draft. It names the address when the lead has a showing, and it is numbered by year (days 101–199), so a year never gets two. It goes out only on approval. The newsrc/closed.tsholds the date rules and wording. - Sample data. "Tom Whitfield" is a past client who bought exactly one year ago today, so his draft is on a fresh desk. The sample desk is now 21 leads.
- Docs. The README has a one-line tour sentence plus a reference paragraph, and
AGENTS.mddocuments the shape.contract/openapi.jsonis regenerated. - Tests. New
src/closed.test.tscovers marking, undoing, the 422s, the draft firing once per year, the time zone, the leap day, the address, counts, export, MCP, terminal, HTTP, and migrating an existing database.
What I chose differently
- No table rebuild. The issue's risk note expected one, but the state stays
qualifiedand I added two columns (closed_kind,closed_on), so the state CHECK is untouched. I tested migrating an old database. - Needs you now includes closed leads. A closed lead with an anniversary draft appears in both Needs you and Closed. I changed the existing views test to allow that, and to count each lead once.
- Other existing tests I edited. I updated them only for the count (20 to 21 leads) and the two new CSV columns.
- No catch-up for missed days. The draft appears only if the clock ticks on the anniversary day itself. If the server is down that whole day, that year's draft does not appear.
- Stale drafts. A draft left unsent is set aside when the next year's arrives. There is no manual skip for it.
To try it Open a lead, use "Mark closed", and pick a kind and date; Put back in follow-ups undoes it. On a fresh desk, open Tom Whitfield for the draft, and check Activity for the deal counts.
Closing a deal goes through the one setState action and permit, with no new contract cell. The date and kind are validated (422 naming the field), and the migration is additive with a CHECK. The anniversary draft is numbered by year, so it fires once a year and only an approval sends it. Tests cover marking, undoing, the 422s, the time zone, the leap day, MCP, terminal, HTTP and migrating an old database. I could not sign in to the preview, so I judged the code from the diff and its tests. The diff I was given was cut off, so I did not read all of routes.ts, sample.ts, terminal.ts and the page form. Non-blocking nits: drafts.ts dayLabel has a misindented ternary arm; anniversaries() repeats the MAX_YEARS check that anniversaryOf already makes; a server that is down for the whole anniversary day skips that year's draft, as the builder disclosed.
A lead can now be marked closed — bought or sold — with a closing date, and a year later a "happy home anniversary" check-in draft waits on the desk.
bun testis green (527) andbun run lint:designis clean. I could not runbun x tsc --noEmitbecause the repo has notsconfig.json, and there is noscripts/gate.ts.What changed
PATCH /leads/:idorPOST /leads/:id/statewith{"state":"closed","kind":"bought|sold","closed_on":"YYYY-MM-DD"}, the MCPmark_leadtool, andyin the terminal all go through one action. It is a lead update throughpermit, recorded in the audit log asclosedwith the kind and date. No contract cell changed.kindorclosed_on.qualifiedand gainsclosedKindandclosedOn, so follow-ups stop exactly as with qualified.state: "open"(the #23 re-open) undoes it and clears both.closedandclosed oncolumns.closed_onin the agent's time zone, the clock'sturncreates one draft. It names the address when the lead has a showing, and it is numbered by year (days 101–199), so a year never gets two. It goes out only on approval. The newsrc/closed.tsholds the date rules and wording.AGENTS.mddocuments the shape.contract/openapi.jsonis regenerated.src/closed.test.tscovers marking, undoing, the 422s, the draft firing once per year, the time zone, the leap day, the address, counts, export, MCP, terminal, HTTP, and migrating an existing database.What I chose differently
qualifiedand I added two columns (closed_kind,closed_on), so the state CHECK is untouched. I tested migrating an old database.To try it Open a lead, use "Mark closed", and pick a kind and date; Put back in follow-ups undoes it. On a fresh desk, open Tom Whitfield for the draft, and check Activity for the deal counts.
Closes #90