mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-09-17 00:26:26 +00:00
* fix(gmail-sync): strip CSV-breaking characters from the email subject Step 7a interpolated the raw subject line of a received email into the `notes` column of job_search_tracker.csv. No writer here emits a quoted tracker field, so an unescaped comma splits the row - for csv.DictReader just as much as for a naive split, which matters because tools/rank_state.py is the repo's only machine reader and uses exactly that. `notes` is column 10 of 14, so a subject as ordinary as "Re: Your application, Data Scientist" shifted cv_file, cover_letter_file and source a column left. A line break is worse: it ends the row and starts a second one. The rule now sits on the append instruction itself rather than in a general note a writer can miss. The subject survives verbatim in the archive's outcome.md, which is Markdown and carries no such constraint. /outcome Step 4 (outcome.md:195) is also free-form and has the same exposure, but its text is model-authored in a turn the user is watching rather than copied from third-party mail unattended. Left out deliberately, to be filed separately. * fix(outcome): keep the Step 4 tracker note free of CSV-breaking characters /outcome Step 4 appended "a short dated note" to `notes` with no constraint on its content, the same exposure /gmail-sync Step 7a had: nothing quotes a tracker field, so `rejected, no feedback given` shifts cv_file, cover_letter_file and source a column left under csv.DictReader, and a line break ends the row. The append instruction now requires a note with no commas, double quotes or line breaks. Folded in at the maintainer's request on #455 so one entry and one rule cover both free-form writers. The CSV-safety tests move out of test_gmail_sync_command.py into test_tracker_notes_csv_safe.py, where a CASES table pins the rule on each writer's append line.
This commit is contained in:
@@ -118,6 +118,26 @@ per-file diff commands.
|
||||
wrappers, plus a new `detail-backoff.test.ts` that exercises the handler path itself -
|
||||
its retry cases fail against the bare `fetch()`.
|
||||
|
||||
- **Free-form tracker notes no longer break the CSV row** (#454) (`.claude/commands/gmail-sync.md`,
|
||||
`.claude/commands/outcome.md`, `tests/test_tracker_notes_csv_safe.py`) - two writers put
|
||||
free-form text into the `notes` column of `job_search_tracker.csv`: `/gmail-sync` Step 7a
|
||||
copied the raw subject of a received email, and `/outcome` Step 4 appended "a short dated
|
||||
note" with no constraint on its content. No writer in the framework emits a quoted tracker
|
||||
field, so an unescaped comma splits the row for a naive split and for `csv.DictReader` alike -
|
||||
the latter being what the repo's only machine reader of the tracker uses
|
||||
(`tools/rank_state.py`). `notes` is column 10 of 14, so a subject as ordinary as
|
||||
`Re: Your application, Data Scientist`, or a note as natural as `rejected, no feedback given`,
|
||||
shifted `cv_file`, `cover_letter_file` and `source` a column left. A line break is worse: it
|
||||
ends the row and starts a second one. Nothing validated the row afterwards, and the
|
||||
`/gmail-sync` half was written unattended, so the corruption was silent. Both append
|
||||
instructions now carry the rule themselves - `/gmail-sync` deletes commas, double quotes and
|
||||
line breaks from the subject, `/outcome` writes its note without them - rather than a general
|
||||
note a writer can miss. Nothing is lost on the `/gmail-sync` side: Step 7a item 2 still
|
||||
records the subject verbatim in the archive's `outcome.md`, which is Markdown and carries no
|
||||
such constraint. The fixed-format writers (`followed up YYYY-MM-DD`,
|
||||
`stale resolved no_response (YYYY-MM-DD)`, `redrafted`) could never contain these characters
|
||||
and are unchanged.
|
||||
|
||||
- **`jobindex-search detail` no longer fetches arbitrary URLs or invents posting-shaped
|
||||
output** (#447) - the command fetched any `http(s)` input verbatim (no host check) and,
|
||||
when the path didn't match its one pattern, silently used the whole input URL as the job
|
||||
|
||||
Reference in New Issue
Block a user