Skip to content

frontend: open a .txt/.md file, read exactly as the CLI reads it - #12

Merged
thorwhalen merged 2 commits into
mainfrom
feat/frontend-open-a-file
Sep 22, 2026
Merged

thorwhalen merged 2 commits into
mainfrom
feat/frontend-open-a-file

Conversation

@thorwhalen

Copy link
Copy Markdown
Owner

Advances #1 ("Left open after Phase 5: Upload (md/txt/pdf)") — the text-file half. PDF stays deliberately unbuilt, now with the reason shown to the user.

What

  • "Open a file…" button and drop-on-editor in the example frontend. The file is read in the browser and put in the editor like a paste; nothing is sent until "Read".
  • frontend/src/upload.ts — the one rule: an opened file yields exactly the text ductus gauge <file> reads (open(path, encoding='utf-8').read()): invalid UTF-8 refused (never � substituted — that would be invented evidence), \r\n/lone \r folded to \n (Python universal newlines; also what paste does), BOM kept as U+FEFF. .txt/.md/.markdown/.text only; PDF refused with its reason (extracted line breaks and hyphenation would be scored as the writer's); 2 MB cap as a named constant.
  • Docs: frontend/README.md file table and "Not built", misc/docs/frontend-stack-decision.md "deliberately not built" entry.

Behaviour around it (from review)

  • A refused file is a notice banner, not status: 'error': the text, the reading and the verdict stay as they were, and Read is not re-enabled mid-request.
  • Open and Load-sample are disabled while reading, and a report that returns for text no longer in the editor (typed during the read) is dropped instead of being anchored onto different text — a pre-existing race the new button made easier to hit.
  • Replacing non-empty text asks first (setText builds a fresh editor state, so it is not undoable).
  • Last requested file wins, not last to finish reading.
  • A file dropped outside the editor no longer makes the browser navigate away from unsaved text.

Verification

  • vitest: 21 passed (11 new in upload.test.ts); tsc --noEmit clean; vite build clean.
  • Headless Chromium against ductus-http serving the build: PDF and Latin-1 files refused with their messages and the current text kept; a CRLF file arrives as LF; Read produces a verdict and highlights; re-opening the same file resets findings; verdict survives a refusal; Open/Sample disabled while a (delayed) read is in flight; replace confirmation shown; no page errors.
  • Reviewer additionally checked 11 byte-level cases (surrogates, overlong, truncated, double BOM, U+2028/U+0085/\v/\f, NUL) against real Python: identical.

Pre-existing bug found in review and filed rather than widened here: #11 (highlight offsets are code points, the editor counts UTF-16 units — shifts after any emoji; paste has it too).

Review

Independent adversarial sub-agent review (browser-driven). Findings 1–4, 6, 7 and the empty-state copy fixed here; 5 filed as #11.

Gate: hosted CI (Python workflow + frontend workflow).

🤖 Generated with Claude Code

thorwhalen and others added 2 commits September 22, 2026 13:59
A button and drop-on-editor open a local text file in the browser; nothing
is sent until Read. upload.ts decodes as Python's open(path, encoding='utf-8')
does: invalid UTF-8 refused, CRLF/CR folded to LF, BOM kept. PDF and other
types are refused with a reason; a refusal never discards the current text.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…eplace and mid-read opens

Review findings: a refusal no longer hides a valid verdict or re-enables
Read mid-request (separate notice banner); a report for text no longer in
the editor is dropped; Open/Sample disabled while reading; last requested
file wins; replacing non-empty text asks first (setText is not undoable);
a file dropped outside the editor no longer navigates away.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@thorwhalen
thorwhalen merged commit 5158942 into main Sep 22, 2026
17 of 20 checks passed
@thorwhalen
thorwhalen deleted the feat/frontend-open-a-file branch September 22, 2026 14:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant