Public: anyone can read this; the crew can change it.
The MLS description shows its length against the MLS public remarks limit, and one over it cannot be approved without saying so #109
Check · Review · Land · Live done — Landed and live in production.
The MLS description on `/listings/:id` now shows `N / 1,000 characters` beside its box. It counts in code points and updates as the agent types. I ran the listing, post-length, OpenAPI and terminal tests and they pass. `tsc` and the gate and design-lint scripts were not run: there is no `tsconfig.json`, and the repo has no `scripts/gate.ts` or `scripts/design-lint.ts` (`scripts/lint-design.ts` is…
shipped production is serving it deploy 957b843
The MLS description on /listings/:id now shows N / 1,000 characters beside its box. It counts in code points and updates as the agent types. I ran the listing, post-length, OpenAPI and terminal tests and they pass. tsc and the gate and design-lint scripts were not run: there is no tsconfig.json, and the repo has no scripts/gate.ts or scripts/design-lint.ts (scripts/lint-design.ts is the lint script and printed no findings). I did not run the whole suite, and I never started the app.
What changed
- Limit and counting:
MLS_LIMIT = 1000sits besideLIMITSinsrc/postlength.ts, with the counting helpers. The page,/fair-housing, the edit response and the terminal all usecountLine(kind, text). - Approving over the limit:
approveAssetinsrc/actions.tsrefuses an MLS description over 1,000 with "Too long for the MLS remarks by N. Approve it knowing so: send tooLong: true." The page's Approve button reads "Approve — too long for the MLS" and sendstoo_long. - Terminal: it shows the count and the note, and asks for a second
a. - Audit: such an approval is recorded as
approved_too_long_for_mls; an over-length post still readsapproved_too_long_for_x. I did not find a seller-report path that reads these outcomes, so I changed nothing there. - API and MCP: both go through the same
approveAsset, so the rule holds there. They refuse approving outright (person_required), so only the page and terminal can use the acknowledgement. The PATCH summary in the OpenAPI description now names both limits, andcontract/openapi.jsonis regenerated. - Live counter:
static/listing.jsrecounts in code points on every keystroke for the MLS box. The 600 ms server check no longer overwrites that count. - No layout shift: the counter has
min-width: 24chinstatic/app.css. - README: the agent section says it in one sentence.
Tests
- A 1,000-character description approves plainly.
- A 1,001-character one is refused without the acknowledgement, refused with a non-
truevalue, and accepted withtooLong: true. - The audit rows read
approvedthenapproved_too_long_for_mls. - The page renders the counter, and
/fair-housinganswers1,001 / 1,000 characters. - The three sample listings' MLS descriptions stay under the limit in every tone.
Changed on purpose: the existing "each social post shows its length" test posted an over-length string as kind: "mls" and expected no length back. The MLS now has a length, so I changed that request to email_update, which still has none. Post-length behaviour is otherwise unchanged.
Not done: the X-style multi-limit line is not used for the MLS, since it has one limit. I did not loosen any contract.json cell.
To try it: open a listing's MLS description, paste more than 1,000 characters, and watch the counter. Save it, then Approve; the button names the overrun.
🤖 Generated with Claude Code
The change is sound and reuses the existing tooLong path, but one behaviour has no test. Fix this first: the terminal door for the MLS description is untested.
src/tty.ts now shows N / 1,000 characters, shows the over-limit note, asks for a second a, and prints Approved, too long for the MLS. The existing terminal tests (src/tty.test.ts around lines 213-224) only cover X. Add a terminal test: an MLS description over 1,000 shows the count and Too long for the MLS remarks by N, the first a asks, the second a approves, and the audit row reads approved_too_long_for_mls. Box 4 says the rule holds through the terminal, and that needs a test that fails without the change.
Smaller points:
- In src/actions.ts the approveAsset doc comment is now one very long line. Re-wrap it.
- There is no test that the API/MCP path refuses an over-limit MLS approval. They refuse all approvals via person_required, so a one-line assertion would pin it.
- The seller-report requirement in box 3: I found no report code that reads audit outcomes. Say so explicitly in the README or the pull, or point to the code that shows it.
No contract.json cell is loosened. Security and escaping look fine.
I've addressed all four of Sentinel's points on this branch and pushed. src/tty.test.ts and src/listings.test.ts pass (57 tests); I did not run the full suite.
- Terminal test: I added "the terminal shows the MLS description's count, and one over 1,000 needs a second a" in
src/tty.test.ts.
- It uses a 1,003-character MLS description.
- The screen shows 1,003 / 1,000 characters and ! Too long for the MLS remarks by 3.
- The first a asks and leaves "0 of 7 approved".
- The second a prints "Approved, too long for the MLS." and shows "1 of 7 approved".
- The audit row reads approved_too_long_for_mls.
- The terminal MLS paths are new in this pull, so the test fails without it.
- API and MCP refusal: the existing "only a person approves" test in
src/listings.test.tsnow also pins that a 1,001-character MLS description withtooLong: trueis refused withperson_requiredon both theapiandmcpdoors, and stays unapproved. - Doc comment: the
approveAssetcomment insrc/actions.tsis re-wrapped. - Seller report: I found no report code that reads audit outcomes, and the README now says so. The audit trail (
approved_too_long_for_mls) is where it's recorded. If a seller report is meant to show it, that is a separate change.
Earlier asks are met. The terminal test covers the MLS count and the second-a flow. The API/MCP refusal with tooLong is pinned in the person-approves test. The approveAsset doc comment is re-wrapped. The README states that no seller report reads audit outcomes. The shared overNote/countLine helpers keep one rule across the page, API, MCP and terminal, and no contract cell is loosened. I read the diff and did not exercise the preview.
The MLS description on
/listings/:idnow showsN / 1,000 charactersbeside its box. It counts in code points and updates as the agent types. I ran the listing, post-length, OpenAPI and terminal tests and they pass.tscand the gate and design-lint scripts were not run: there is notsconfig.json, and the repo has noscripts/gate.tsorscripts/design-lint.ts(scripts/lint-design.tsis the lint script and printed no findings). I did not run the whole suite, and I never started the app.What changed
MLS_LIMIT = 1000sits besideLIMITSinsrc/postlength.ts, with the counting helpers. The page,/fair-housing, the edit response and the terminal all usecountLine(kind, text).approveAssetinsrc/actions.tsrefuses an MLS description over 1,000 with "Too long for the MLS remarks by N. Approve it knowing so: send tooLong: true." The page's Approve button reads "Approve — too long for the MLS" and sendstoo_long.a.approved_too_long_for_mls; an over-length post still readsapproved_too_long_for_x. I did not find a seller-report path that reads these outcomes, so I changed nothing there.approveAsset, so the rule holds there. They refuse approving outright (person_required), so only the page and terminal can use the acknowledgement. The PATCH summary in the OpenAPI description now names both limits, andcontract/openapi.jsonis regenerated.static/listing.jsrecounts in code points on every keystroke for the MLS box. The 600 ms server check no longer overwrites that count.min-width: 24chinstatic/app.css.Tests
truevalue, and accepted withtooLong: true.approvedthenapproved_too_long_for_mls./fair-housinganswers1,001 / 1,000 characters.Changed on purpose: the existing "each social post shows its length" test posted an over-length string as
kind: "mls"and expected no length back. The MLS now has a length, so I changed that request toemail_update, which still has none. Post-length behaviour is otherwise unchanged.Not done: the X-style multi-limit line is not used for the MLS, since it has one limit. I did not loosen any
contract.jsoncell.To try it: open a listing's MLS description, paste more than 1,000 characters, and watch the counter. Save it, then Approve; the button names the overrun.
🤖 Generated with Claude Code
Closes #106