Skip to content

Probe panel: fixed-function call line, and container item-type validation on both sides - #182

Merged
CoffeePoweredComputers merged 3 commits into
masterfrom
feat/probe-call-line
Oct 16, 2026
Merged

CoffeePoweredComputers merged 3 commits into
masterfrom
feat/probe-call-line

Conversation

@CoffeePoweredComputers

Copy link
Copy Markdown
Owner

Replaces the one-text-box-per-parameter probe input with a call line, and fixes the validation gap that made list[str] accept integers.

Why

The per-parameter boxes were 72px wide, so lists and strings scrolled out of view, and three or more arguments wrapped into an unreadable line. The maintainer chose the call-line design from an interactive comparison of four options. While prototyping it we found that a list[str] parameter accepted integers with no error, on both the frontend and the backend.

What changes

Call line (ProbePanel.vue, useProbeState.ts, new probeArgs.ts and pythonLiteral.ts)

  • The function name and parentheses are fixed text; the student edits one inline, wrapping argument list between them, as Python literals, positional or keyword: mystery([3, 1, 2]), greet("Ann", times=2).
  • Tab on an empty line or a button fills in name= placeholders. Enter probes. Shift+Enter does nothing. Tab on a filled line leaves the editable. Paste is plain text.
  • role=textbox, aria-label, aria-placeholder, aria-invalid, aria-describedby to the error list and a help line; disabled state is announced; focus ring survives forced-colors mode.
  • Parsing: top-level comma split honouring nesting and quotes; keyword/positional mapping with line errors for unknown, duplicate, too many positional, positional-after-keyword and empty arguments; a Python-literal reader for True/False/None, quotes and escapes, tuples, sets, trailing commas. Unicode parameter names work.
  • Mapped values go through the existing per-parameter parser, so the error list (li#probe-err-<name>) and every other selector and behaviour (badge, hint, history, duplicate detection, exhausted state) are unchanged. The request body is unchanged.

Container item validation, matching rules on both sides

  • Backend validate_probe_input: list/tuple/set[T] and dict[K, V] with primitive item types are checked item by item (bool is not int, int accepted for float); bare forms by shape; nested and Any items unchecked as before. Messages: Parameter 'items' must be a list of str, a dict of str to int; hidden signatures keep the generic text. dict keys are checked only for str, since JSON keys always arrive as strings.
  • Backend parse_function_signature now splits on top-level commas, so dict[str, int] is one parameter (parse_function_signature splits on commas naively; breaks probing for container/tuple/default signatures (3 duplicate parsers) #160 on the probe path; both probeable handlers delegate to it). The instructor authoring parser still has the naive split and is not touched here.
  • Frontend mirrors the same rules; an untyped value that starts with a bracket or quote and fails to parse is now an error instead of silently becoming a string.

E2E: all probe specs moved to the call line via a shared helper; a seeded tag(items: list[str], prefix: str) problem reproduces the bug in the UI (A12) and at the API (A16); new tests for keyword/positional mapping and each line error, the Tab template, quoted str arguments, Shift+Enter and Tab leaving, the closing parenthesis trailing a wrapped line, and phone width.

Verification

  • pytest -m unit, probe integration tests, Vitest (597), ESLint, stylelint, i18n:check: all green.
  • Probeable e2e suite, 5 specs, twice with two workers: green. 16/16 in the probing spec on a separate run.
  • Three Fable review rounds; the one blocker found (a single-quoted str argument was sent with its quotes) is fixed with unit and e2e coverage.

Known limits

  • tuple[int, str] is validated by shape only.
  • ProbePanel.vue is over the ESLint max-lines warning threshold, as it already was on master.
  • vue-tsc still crashes locally; CI runs it with continue-on-error.

🤖 Generated with Claude Code

…et-aware (#160)

validate_probe_input skipped every parameter whose hint was not a bare
primitive, so list[str] accepted integers and bare list accepted a
string. It now checks list/tuple/set[T] and dict[K, V] with primitive
item types (bool is not int, int is accepted for float), bare forms by
shape, and leaves nested and Any items unchecked as before. Hidden
signatures keep the generic message. dict keys are checked only when the
key type is str, because JSON object keys always arrive as strings.

parse_function_signature split the parameter list on every comma, so
dict[str, int] became two parameters. It now splits on top-level commas
only, honouring brackets and quotes, and both probeable handlers
delegate to it instead of carrying their own copy.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The probe panel showed one 72px text box per parameter inside a rendered
call, which clipped lists and strings and wrapped badly past two
arguments. The function name and parentheses are now fixed text and the
student edits one inline, wrapping argument list between them, as Python
literals, positional or keyword: mystery([3, 1, 2]) or
greet("Ann", times=2). Tab on an empty line or the "Fill in argument
names" button drops in name= placeholders; Enter probes; paste is plain
text. The region is a role=textbox with aria-label, aria-placeholder,
aria-invalid and aria-describedby, and the closing parenthesis trails
the last character.

Parsing lives in probeArgs.ts and pythonLiteral.ts: a top-level comma
split that honours nesting and quotes, keyword/positional mapping with
line errors (unknown, duplicate, too many positional, positional after
keyword, empty argument), and a Python-literal reader (True/False/None,
single quotes, escapes, tuples, sets, trailing commas). Mapped values go
through the existing per-parameter parser, which now validates container
item types to match the backend, so list[str] given integers shows
"Every item must be str" and Probe stays disabled; a quoted str argument
is read as the Python literal, not kept with its quotes. The request
body is unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…n both sides

All probe specs type into #probe-args through a shared helper instead of
the removed per-parameter inputs, keeping each test's assertions. A
seeded tag(items: list[str], prefix: str) problem reproduces the bug
that started this: A12 proves integers in a list[str] show the item
error in the UI and A16 proves the API rejects the same input with
"Parameter 'items' must be a list of str". Further tests cover keyword
and positional mapping with each line error, the Tab template, quoted
str arguments, Shift+Enter and Tab leaving the editable, the closing
parenthesis trailing a wrapped line, and the panel at phone width.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@codecov-commenter

codecov-commenter commented Oct 16, 2026 •

Copy link
Copy Markdown

@CoffeePoweredComputers
CoffeePoweredComputers merged commit 4cd9b32 into master Oct 16, 2026
18 checks passed
@CoffeePoweredComputers
CoffeePoweredComputers deleted the feat/probe-call-line branch October 16, 2026 04:03
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.

2 participants