Sending a capture: a page nothing reads, or an address over 500 characters, is refused whatever the person corrects #24

Closed
opened 2026-10-01 10:47:18 +00:00 by tiagoagueda · 0 comments
Owner

Found on 2026-09-29 in a read-only review of postulo-chromium at 7998de372, following a capture from the popup to the core's POST /api/v1/captures at postulo 95348908d and running the core's parser and request schema on the snapshot.

Related to #6.

Two kinds of capture are refused by Postulo for reasons no edit in the extension can change, so they are marked Refused and stay so on every resend. The popup invites the first ("Fill in what you know"), and the second comes from the tab's own address, which the form does not show.

1. Nothing read from the page

  • Where: src/popup.js:102 shows t("nothingRead") ("Nothing could be read from this page. Fill in what you know; nothing leaves this browser until you send it.", src/_locales/en/messages.json:250-253) and leaves Send enabled. In the core, api/api.py:583-620, _read(), raises 422 "Nothing resembling a job posting was found there." when remembered.read_page returns None, and _capture() (api/api.py:451-466) applies the corrections only after _read() has returned.
  • What happens: a posting published as plain text with no <title> and no heading, or the document a browser shows for a PDF advert, reads as nothing in the popup. The person types the title and company and presses Send. Postulo reads the same page, finds nothing (on the snapshot, registry.parse_page returns None for a page whose body is one <pre> or one <embed>), and answers 422 before looking at what they typed. The outbox marks the capture Refused (kindOfFailure, src/lib/api.js:212-224); Edit and Send gets the same answer until it is deleted.

2. An address over 500 characters

  • Where: src/popup.js:80-81 keeps tab.url as the record's address, fragment included, and src/lib/outbox.js:59 sends it as the capture's url. In the core, api/api.py:185, PageIn.url: PageAddress = Field(max_length=500). For a ticked posting from a results page, src/popup.js:300-301 uses posting.data.url instead, which tidy() (src/lib/parse.js:690-701) has already cut to 500 characters.
  • What happens: a posting opened from a long job-search address (a search engine's job panel or a board's tracking link, typically with a long fragment) is refused with "url: String should have at most 500 characters"; the snapshot's CaptureIn refuses a 561-character address the same way. The form has no address field, so nothing can fix it. A ticked posting whose own address is longer is instead accepted with an address cut at 500 characters, which leads nowhere. The core's url=url[:500] at api/api.py:482 shows truncation was meant to happen there, but the schema refuses first.
  • Related: known() (src/lib/api.js:193-198) sends titles and companies up to 500 characters and any number of postings, while KnownQueryIn and KnownIn (api/api.py:274-285) cap them at 250 and 100. One long title, or a results page of more than 100 postings, makes the whole question fail and the "captured before" marks silently do not appear.

Why it matters and the fix

  • Why it matters: the person corrects a capture as asked and still cannot send it; the refusal message does not say what to change, and a truncated address lands in their listings as a broken link.
  • Fix: in the extension, drop the fragment from the capture's url before sending (it never identifies a posting to the server); when the address is still over 500 characters, say so in a translated sentence at capture time rather than after a refusal. In tidy(), leave url out rather than cutting it. When nothing was read, either keep Send disabled with a sentence saying Postulo needs something to read, or, better, let the core accept a capture whose corrections carry a title when no source read the page (a change in _read()/_capture() on the core, to be filed there). Cap what known() sends at 250 characters and 100 postings, asking in chunks for a longer page.

Done when

  • In test/outbox.test.mjs, a record whose address is 600 characters with a long fragment is sent with the fragment removed.
  • In test/parse.test.mjs, tidy() on a posting with a 600-character url does not return a 500-character prefix of it.
  • In test/api.test.mjs, known() with 150 postings and a 400-character title sends requests within the server's limits.
Found on 2026-09-29 in a read-only review of postulo-chromium at 7998de372, following a capture from the popup to the core's `POST /api/v1/captures` at postulo 95348908d and running the core's parser and request schema on the snapshot. Related to #6. Two kinds of capture are refused by Postulo for reasons no edit in the extension can change, so they are marked Refused and stay so on every resend. The popup invites the first ("Fill in what you know"), and the second comes from the tab's own address, which the form does not show. ## 1. Nothing read from the page - **Where:** `src/popup.js:102` shows `t("nothingRead")` ("Nothing could be read from this page. Fill in what you know; nothing leaves this browser until you send it.", `src/_locales/en/messages.json:250-253`) and leaves Send enabled. In the core, `api/api.py:583-620`, `_read()`, raises 422 "Nothing resembling a job posting was found there." when `remembered.read_page` returns `None`, and `_capture()` (`api/api.py:451-466`) applies the corrections only after `_read()` has returned. - **What happens:** a posting published as plain text with no `<title>` and no heading, or the document a browser shows for a PDF advert, reads as nothing in the popup. The person types the title and company and presses Send. Postulo reads the same page, finds nothing (on the snapshot, `registry.parse_page` returns `None` for a page whose body is one `<pre>` or one `<embed>`), and answers 422 before looking at what they typed. The outbox marks the capture Refused (`kindOfFailure`, `src/lib/api.js:212-224`); Edit and Send gets the same answer until it is deleted. ## 2. An address over 500 characters - **Where:** `src/popup.js:80-81` keeps `tab.url` as the record's address, fragment included, and `src/lib/outbox.js:59` sends it as the capture's `url`. In the core, `api/api.py:185`, `PageIn.url: PageAddress = Field(max_length=500)`. For a ticked posting from a results page, `src/popup.js:300-301` uses `posting.data.url` instead, which `tidy()` (`src/lib/parse.js:690-701`) has already cut to 500 characters. - **What happens:** a posting opened from a long job-search address (a search engine's job panel or a board's tracking link, typically with a long fragment) is refused with "url: String should have at most 500 characters"; the snapshot's `CaptureIn` refuses a 561-character address the same way. The form has no address field, so nothing can fix it. A ticked posting whose own address is longer is instead accepted with an address cut at 500 characters, which leads nowhere. The core's `url=url[:500]` at `api/api.py:482` shows truncation was meant to happen there, but the schema refuses first. - Related: `known()` (`src/lib/api.js:193-198`) sends titles and companies up to 500 characters and any number of postings, while `KnownQueryIn` and `KnownIn` (`api/api.py:274-285`) cap them at 250 and 100. One long title, or a results page of more than 100 postings, makes the whole question fail and the "captured before" marks silently do not appear. ## Why it matters and the fix - **Why it matters:** the person corrects a capture as asked and still cannot send it; the refusal message does not say what to change, and a truncated address lands in their listings as a broken link. - **Fix:** in the extension, drop the fragment from the capture's `url` before sending (it never identifies a posting to the server); when the address is still over 500 characters, say so in a translated sentence at capture time rather than after a refusal. In `tidy()`, leave `url` out rather than cutting it. When nothing was read, either keep Send disabled with a sentence saying Postulo needs something to read, or, better, let the core accept a capture whose corrections carry a title when no source read the page (a change in `_read()`/`_capture()` on the core, to be filed there). Cap what `known()` sends at 250 characters and 100 postings, asking in chunks for a longer page. ## Done when - In `test/outbox.test.mjs`, a record whose address is 600 characters with a long fragment is sent with the fragment removed. - In `test/parse.test.mjs`, `tidy()` on a posting with a 600-character `url` does not return a 500-character prefix of it. - In `test/api.test.mjs`, `known()` with 150 postings and a 400-character title sends requests within the server's limits.
tiagoagueda added this to the 0.6.0 milestone 2026-10-01 10:47:18 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo-chromium#24
No description provided.