Skip to content

Handle invalid dashboard inputs without crashing the Streamlit app - #113

Merged
dipeshbabu merged 3 commits into
dipeshbabu:mainfrom
dchaudhari7177:fix/dashboard-input-validation
Aug 24, 2026
Merged

Handle invalid dashboard inputs without crashing the Streamlit app#113
dipeshbabu merged 3 commits into
dipeshbabu:mainfrom
dchaudhari7177:fix/dashboard-input-validation

Conversation

@dchaudhari7177

@dchaudhari7177 dchaudhari7177 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Closes #21.

What changed

Two of the three paths in the issue were still unguarded. The quality-fixture path (json.loads at what is now line 615) has since been fixed and already has the try / st.error treatment — I followed its shape rather than inventing a second one.

path raised now
Patch Plan → build_patch_plan(trace, repo_path=…) ValueError from _resolve_repository_path — "must identify an existing directory" or "must remain within the allowed root" st.error("Fix the repository path: …") then st.stop()
Ingest → AgentTrace.from_dict(json.loads(…)) JSONDecodeError, UnicodeError, or TraceValidationError st.error naming the parse position, or the validation message

Note the line numbers in the issue have shifted; the call sites are now dashboard/app.py:457 and :739.

Two details worth calling out:

  • The upload's store button moved into the else branch. Previously it sat in the same block as the parse, so a failed parse would leave a "Store uploaded trace" button referring to a trace that was never bound. Now it only exists when there is something to store.
  • st.stop() rather than wrapping 36 lines in try/else. The Patch Plan body that consumes plan runs to the end of the page section. Re-indenting it would have made the diff mostly whitespace and hidden the actual change. st.stop() ends the rerun with the error rendered, which is the same observable result.

Tests

Six, in tests/test_dashboard_input_validation.py, using streamlit.testing.v1.AppTest — the pattern test_dashboard_quality.py already establishes:

  • repository path that does not exist
  • repository path escaping the allowed root (../../..) — the traversal refusal should be legible, not a crash
  • upload with malformed JSON
  • upload that is valid JSON but fails schema validation (a different exception from a different layer)
  • a control for each: the Patch Plan page still renders for a valid path, and a real trace still reaches the store button

Revert-verified: with dashboard/app.py reverted, the four failure cases fail and both controls pass — so the controls are not quietly passing for the wrong reason.

One test-authoring note, since it nearly produced a test that passed against nothing: app.text_input[-1] is the sidebar Project field, not the repository path. Setting it switched project, emptied the page, and the assertion then held against a page with no content at all. The helper selects by label instead, and there's a comment saying why.

Verification

tests/test_dashboard_input_validation.py .....  6 passed

Full suite is 51 pre-existing failures on this machine, unrelated to this change — my Python 3.12 environment has newer FastAPI/Starlette than the project expects, so tests/test_client.py, test_server.py and test_migrations.py do not even collect (Router.__init__() got an unexpected keyword). Rather than quote a total, I diffed the failure sets:

before: 55 failures    after: 51 failures
diff: only the 4 new dashboard tests, failing before and passing after

Nothing else moved.

Separately: running the dashboard tests needs a newer Streamlit than pyproject.toml's streamlit>=1.34.0 floor. st.dataframe(df, width="stretch") raises TypeError: 'str' object cannot be interpreted as an integer on 1.43.2 — the string form of width is much newer. The existing dashboard tests don't catch it because they never render a populated dataframe. That looks like a real floor bug, but it is not this issue, so I left it alone; happy to file it.

ruff check and ruff format clean at the project's line-length = 100. Changelog entry added under Unreleased → Fixed.

AI assistance

Substantial, and disclosed per CONTRIBUTING: written with Claude Code (Claude Opus 5). It located the call sites, wrote the guards and the tests, and drafted this description. I ran the suite, the revert check and the before/after failure diff, and traced the exception types back to _resolve_repository_path and TraceValidationError in the source rather than assuming them.

Summary by CodeRabbit

  • Bug Fixes

    • Invalid, missing, or inaccessible repository paths now show clear inline errors without disrupting the dashboard.
    • Malformed, empty, non-UTF-8, or schema-invalid trace uploads display actionable details, including parsing locations where available.
    • Storage controls remain unavailable until an uploaded trace is valid.
    • Valid repository paths and trace uploads continue to work as expected.
  • Documentation

    • Added an Unreleased changelog entry describing dashboard input-validation improvements.
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review available on request

  • 🔍 Trigger review

Reviews should be triggered manually for repositories with fewer than 10 stars. Select Trigger review above or comment @coderabbitai review to review the latest changes. For a full review, comment @coderabbitai full review.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0f795a62-a83c-403e-b1ec-8b4c4795c854

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e2cbe7dc-b64d-4fad-986c-ce4d6bdf3df7

📥 Commits

Reviewing files that changed from the base of the PR and between b51375d and a6166ea.

📒 Files selected for processing (2)
  • tests/test_dashboard_input_validation.py
  • tests/test_dashboard_trace_upload.py

📝 Walkthrough

Walkthrough

The dashboard now reports invalid repository paths and malformed uploaded traces inline. Uploaded traces are stored only after successful parsing. New tests cover validation errors, storage gating, valid uploads, and persistence.

Changes

Dashboard input validation

Layer / File(s) Summary
Repository path validation
agentloop/patches.py, agentloop/__init__.py, dashboard/app.py, tests/test_dashboard_input_validation.py
RepositoryPathError identifies unusable repository paths. Patch-plan generation displays this error inline. Tests cover missing, disallowed, and valid paths.
Trace upload validation and storage
dashboard/trace_upload.py, dashboard/app.py, tests/test_dashboard_trace_upload.py, tests/test_dashboard_input_validation.py
Uploaded bytes are decoded, parsed, and schema-validated into an AgentTrace. Invalid uploads display errors and hide storage controls. Valid uploads can be stored and retrieved.
Validation documentation and test isolation
CHANGELOG.md, tests/test_dashboard_input_validation.py
The changelog documents the validation behavior. Dashboard tests isolate cached store state and provide helpers for Streamlit interactions.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to a6166

The PR adds guarded handling for invalid repository paths and uploaded traces so the dashboard reports errors instead of crashing; no actionable merge-blocking risk remains beyond normal checks and review.

Suggested reviewers: dipeshbabu

Sequence Diagram(s)

sequenceDiagram
  participant Operator
  participant Dashboard
  participant TraceParser
  participant TraceStore
  Operator->>Dashboard: Upload trace bytes
  Dashboard->>TraceParser: parse_uploaded_trace(payload)
  TraceParser-->>Dashboard: AgentTrace or TraceUploadError
  Dashboard-->>Operator: Show error or storage control
  Operator->>Dashboard: Store valid trace
  Dashboard->>TraceStore: Persist AgentTrace
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The changes address repository paths and trace uploads, but do not show handling for malformed fixture JSON required by issue #21. Add a validation boundary and inline error handling for malformed fixture JSON on the Quality Gates page, with tests for rerun safety and input preservation.
Docstring Coverage ⚠️ Warning Docstring coverage is 54.17% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the primary change: preventing invalid dashboard inputs from crashing the Streamlit app.
Out of Scope Changes check ✅ Passed The changelog, parser, exception, dashboard handling, and tests directly support the input-validation objectives in issue #21.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CHANGELOG.md`:
- Around line 102-107: Update the changelog entry to state that parse positions
are shown only for malformed JSON uploads; describe schema-invalid uploads as
displaying the TraceValidationError field and reason without claiming a parse
position.

In `@dashboard/app.py`:
- Around line 458-464: The try/except around build_patch_plan must only handle
repository-path validation failures, not internal ValueError instances from
diagnosis or source indexing. Validate repo_path before calling build_patch_plan
or have path resolution raise a dedicated exception, catch only that exception,
and allow all other failures to remain observable.

In `@tests/test_dashboard_input_validation.py`:
- Around line 85-107: Add coverage in the uploaded-trace validation tests for
invalid UTF-8 bytes, asserting no uncaught app exception and an inline error.
Strengthen test_uploaded_trace_with_malformed_json_reports_the_position to
assert the reported JSON parse error includes its line and column details, while
preserving the existing error-message assertion.
- Around line 85-121: Update the three upload tests around _upload and the
“Store uploaded trace” control: assert the control is absent or unusable for
malformed JSON and schema-invalid uploads, and visible/usable for a valid
upload. In test_a_valid_uploaded_trace_is_accepted, activate the store control
and verify the resulting success state or persisted trace using the existing
test helpers and public behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e6cea28a-f5b8-4b42-8374-76d471806748

📥 Commits

Reviewing files that changed from the base of the PR and between 38845c7 and f5b3935.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • dashboard/app.py
  • tests/test_dashboard_input_validation.py
Comment thread CHANGELOG.md Outdated
Comment thread dashboard/app.py
Comment thread tests/test_dashboard_input_validation.py Outdated
Comment thread tests/test_dashboard_input_validation.py Outdated

@dipeshbabu dipeshbabu left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tackling this — the direction is good, but this is not ready to merge yet. Please address the following before re-requesting review:

  1. Fix the new dashboard-test cache leakage (tests/test_dashboard_input_validation.py). The full CI suite now fails on Python 3.10, 3.13, and 3.14. On 3.13 the existing tests/test_dashboard_quality.py::test_quality_gate_dashboard_reports_empty_fixture_suite_inline reaches app.text_area[0] with no text area rendered. dashboard/app.py uses @st.cache_resource for load_store(), while each new test points AGENTLOOP_SQLITE_PATH at a different temporary DB; the cached store survives across AppTest instances and contaminates later dashboard tests. Add deterministic cache isolation — e.g. an autouse fixture for these AppTests that calls st.cache_resource.clear() before and after each test (or a shared dashboard-test fixture with equivalent cleanup). Then run the full suite and make all Python matrix jobs green, not just the six new tests.

  2. Restrict the repository-path exception boundary (dashboard/app.py, Patch Plan). except ValueError currently wraps the entire build_patch_plan(...) call. _resolve_repository_path() intentionally raises ValueError, but build_patch_plan() continues through diagnosis/source indexing and any later internal ValueError would be mislabeled as “Fix the repository path” and hidden by st.stop(). That conflicts with #21’s requirement that unexpected internal failures remain observable. Please either introduce a dedicated repository-path exception (for example RepositoryPathError(ValueError)) in agentloop.patches and catch only that, or validate the repository path in a dedicated helper before calling build_patch_plan. Add a regression proving an unrelated/internal ValueError is not converted into a repository-path validation message.

  3. Finish the upload validation contract in the tests. Add invalid-UTF-8 coverage for the UnicodeError branch; strengthen malformed-JSON coverage to assert the reported line and column; assert Store uploaded trace is absent/disabled for malformed and schema-invalid uploads; and for a valid upload, click the store control and verify the success state or persisted trace. These are currently unverified public behaviors.

  4. Meet #21’s shared-helper acceptance criterion. The issue explicitly requires shared parsing/validation helpers to be unit tested. The new trace-upload parsing is still embedded directly in page code. Please extract the upload decode/JSON/schema-validation boundary into a small reusable helper (with structured/safe errors) and unit-test it independently; keep representative AppTest coverage for the page behavior.

  5. Correct the changelog wording. Parse line/column is available for malformed JSON only. TraceValidationError reports the schema field/reason, not a JSON parse position.

Once these are fixed, please rerun the complete repository CI matrix. CodeQL, dependency review, Docker, package, and standalone jobs are already green on this head; the Python test jobs are the current blocker.

dipeshbabu commented Aug 9, 2026

Copy link
Copy Markdown
Owner

No description provided.

@dipeshbabu
dipeshbabu dismissed their stale review August 9, 2026 07:22

Replacing this with a shorter review that tags the contributor directly.

@dipeshbabu dipeshbabu left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dchaudhari7177 thanks for this. A few things still need fixing before merge:

  • Full CI is failing on Python 3.10, 3.13, and 3.14 because the new dashboard AppTests leak the cached Streamlit store between tests. Please clear st.cache_resource before and after each dashboard test.
  • Catch only repository-path validation errors. The current except ValueError can hide unrelated internal errors from build_patch_plan().
  • Add tests for invalid UTF-8, JSON line/column, invalid uploads hiding the store button, and valid upload persistence.
  • Please extract the trace upload parsing into a small helper and unit test it, as required by #21.
  • Fix the changelog wording so parse positions are only claimed for malformed JSON.

Once these are fixed and the full CI matrix is green, re-request review.

dchaudhari7177 added a commit to dchaudhari7177/agentloop that referenced this pull request Aug 10, 2026
…solate the cache

Five changes requested on dipeshbabu#113.

Cache isolation. dashboard/app.py builds its store under @st.cache_resource, whose
key is the load_store function rather than the database path, so the store outlived
each AppTest and the second test in a process read the first test's database -- by
which time that tmp_path was gone. An autouse fixture clears st.cache_resource on
both sides of every test, so neither a leftover from an earlier module nor one this
module leaves can decide a result. This is what reddened 3.10, 3.13 and 3.14.

Narrower catch. _resolve_repository_path raised a bare ValueError, so the Patch Plan
page's except ValueError also swallowed anything build_patch_plan raised beneath it.
It now raises RepositoryPathError, a ValueError subclass (matching TraceValidationError),
exported from the package; the page catches only that, and a bug in planning surfaces
instead of being reported as a path the operator should fix.

Extracted parser. The three ways an upload can be unusable -- not UTF-8, not JSON,
not a trace -- arrive from three layers, and translating them inline left the only
copy of that logic inside a page reachable only through AppTest. dashboard/trace_upload.py
holds parse_uploaded_trace() raising TraceUploadError, unit tested in
tests/test_dashboard_trace_upload.py (6 cases), which is what dipeshbabu#21 asks for. It also
closes a gap the inline version had: json.loads returns a list for "[]", and
from_dict then failed on subscripting rather than on the schema.

Tests. Added invalid UTF-8, the line-3-column-1 assertion for malformed JSON, a
parametrized case pinning that all three invalid uploads leave the store button
unrendered, and one that clicks through a valid upload and asserts the trace is
readable from the store afterwards. 11 AppTest cases and 6 unit cases pass locally.

Changelog. The entry claimed a parse position for schema violations too; positions
are now claimed for malformed JSON alone, with the other two located by byte offset
and by field.

tests/test_patch_plan.py has two failures (tool_oscillation missing from
SUPPORTED_PATCH_TYPES) that reproduce unchanged on upstream/main and are untouched
by this branch.

Refs dipeshbabu#21

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@dchaudhari7177

Copy link
Copy Markdown
Contributor Author

Thanks for the detailed review — all five are addressed in b51375d.

Cache leak (the CI failure). You were right about the mechanism. @st.cache_resource's key is the load_store function, not the database path, so the store outlived each AppTest and the second test in a process read the first test's database — by which point that tmp_path was gone. An autouse fixture now clears st.cache_resource on both sides of every test, so neither a leftover from an earlier module nor one this module leaves can decide a result.

Narrower catch. _resolve_repository_path raised a bare ValueError, so except ValueError also swallowed anything build_patch_plan raised beneath it. It now raises RepositoryPathError — a ValueError subclass, so existing broad handlers keep working, and exported from the package the same way TraceValidationError is. The page catches only that, and a bug in planning surfaces as a bug instead of being reported to the operator as a path they should fix.

Extracted parser (#21). dashboard/trace_upload.py holds parse_uploaded_trace() raising TraceUploadError, unit tested in tests/test_dashboard_trace_upload.py — 6 cases pinning the message each rejection layer produces. Extracting it also closed a gap the inline version had: json.loads("[]") returns a list, and from_dict then failed on subscripting rather than on the schema, so the operator got an IndexError-shaped message about a file that was simply the wrong shape.

Tests. Added invalid UTF-8, an explicit line 3, column 1 assertion for malformed JSON, a parametrized case pinning that all three invalid uploads leave the store button unrendered (rendering it and failing on click would put the failure a page away from the field that caused it), and one that clicks through a valid upload and asserts the trace is readable from the store afterwards.

Changelog. It claimed a parse position for schema violations too. Positions are now claimed for malformed JSON alone — the other two are located by byte offset and by field, and neither has a line/column to give.

Local: 11 AppTest cases + 6 unit cases pass, ruff check/format clean, mypy clean on both changed modules.

One thing to flag, unrelated to this branch: tests/test_patch_plan.py::test_cli_patch_dry_run_writes_markdown_and_json and ::test_patch_plan_supports_next_generation_rewrite_types fail with tool_oscillation missing from the expected SUPPORTED_PATCH_TYPES set. I checked out upstream/main clean and they fail there identically, so this branch neither causes nor fixes them — happy to open a separate issue if that's useful.

Re-requesting review.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/test_dashboard_input_validation.py`:
- Around line 152-171: Add the zero-byte payload case to
tests/test_dashboard_input_validation.py lines 152-171, preserving assertions
that an inline error is shown and no “Store uploaded trace” button is rendered.
Add a parser-layer test in tests/test_dashboard_trace_upload.py lines 38-44
asserting that b"" raises TraceUploadError with the expected JSON line and
column location.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0f796169-0a76-4139-85db-c342cf9dfeb3

📥 Commits

Reviewing files that changed from the base of the PR and between f5b3935 and b51375d.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • agentloop/__init__.py
  • agentloop/patches.py
  • dashboard/app.py
  • dashboard/trace_upload.py
  • tests/test_dashboard_input_validation.py
  • tests/test_dashboard_trace_upload.py
Comment thread tests/test_dashboard_input_validation.py
@dchaudhari7177

Copy link
Copy Markdown
Contributor Author

All five points are addressed — b51375d for the first four, a6166ea for the zero-byte case CodeRabbit raised afterwards. Walking them in your order:

1. Cache leakage. An autouse fixture in the dashboard tests clears st.cache_resource both before and after each test, so the store built under one AGENTLOOP_SQLITE_PATH can't outlive its AppTest and reach test_dashboard_quality.py. Full suite locally: 523 passed, 41 skipped, 1 failed — and that one failure (test_patch_plan_supports_next_generation_rewrite_types, extra tool_oscillation in the left set) reproduces on the base commit 38845c7 with my branch stashed, so it's pre-existing and not something this PR introduced.

2. Exception boundary. agentloop.patches now defines RepositoryPathError(ValueError), raised only by _resolve_repository_path(), and the page catches exactly that. Any other ValueError from diagnosis or source indexing propagates and stays observable, per #21.

3. Upload validation contract. Now covered: invalid UTF-8, malformed JSON asserting line and column, schema-invalid, JSON that parses to a non-object, and the zero-byte file. A parametrised test asserts the store button is unrendered for every invalid payload; the valid path asserts it is rendered, clicks it, and checks the trace reaches the store under the shown run_id.

4. Shared helper. The decode/JSON/schema boundary moved to dashboard/trace_upload.pyparse_uploaded_trace() raising TraceUploadError(ValueError) — unit tested directly in tests/test_dashboard_trace_upload.py, with the AppTest coverage kept for page behaviour.

5. Changelog. Reworded: parse position is claimed for malformed JSON only; schema violations are described as reporting the TraceValidationError field and reason.

One design note worth flagging, since it's the one place I made a judgement call: parse_uploaded_trace reports a position for the empty file (line 1, column 1) because json.loads("") genuinely locates the failure at the first character. That's consistent with the rule in point 5 rather than an exception to it — the position is real, not synthesised.

Re-requesting review.

dchaudhari7177 and others added 3 commits August 15, 2026 16:38
Streamlit reruns the whole script on every widget change, so a control that
parses or executes user-controlled input has no natural moment to wait for
the input to be finished. Two paths reached the library directly:

- Patch Plan passed a free-text repository path to build_patch_plan on every
  rerun. _resolve_repository_path raises ValueError for a path that does not
  exist or escapes the allowed root, so a half-typed path replaced the page
  with a traceback before the operator could finish typing it.
- Ingest decoded an uploaded file with json.loads and AgentTrace.from_dict
  with nothing around them, so malformed JSON or a schema violation did the
  same on the Ingest page.

Both now report inline, following the pattern the quality-fixture path
already uses: JSONDecodeError reported with its position, then the narrower
UnicodeError/TraceValidationError pair. The upload's store button moves into
the else branch so it cannot act on a trace that failed to parse.

Six tests via streamlit.testing AppTest: both repository-path failures, both
upload failures, and a control for each that the valid path still works.
Revert-verified -- the four failure cases fail without the guards, the two
controls pass either way.

Closes dipeshbabu#21
…solate the cache

Five changes requested on dipeshbabu#113.

Cache isolation. dashboard/app.py builds its store under @st.cache_resource, whose
key is the load_store function rather than the database path, so the store outlived
each AppTest and the second test in a process read the first test's database -- by
which time that tmp_path was gone. An autouse fixture clears st.cache_resource on
both sides of every test, so neither a leftover from an earlier module nor one this
module leaves can decide a result. This is what reddened 3.10, 3.13 and 3.14.

Narrower catch. _resolve_repository_path raised a bare ValueError, so the Patch Plan
page's except ValueError also swallowed anything build_patch_plan raised beneath it.
It now raises RepositoryPathError, a ValueError subclass (matching TraceValidationError),
exported from the package; the page catches only that, and a bug in planning surfaces
instead of being reported as a path the operator should fix.

Extracted parser. The three ways an upload can be unusable -- not UTF-8, not JSON,
not a trace -- arrive from three layers, and translating them inline left the only
copy of that logic inside a page reachable only through AppTest. dashboard/trace_upload.py
holds parse_uploaded_trace() raising TraceUploadError, unit tested in
tests/test_dashboard_trace_upload.py (6 cases), which is what dipeshbabu#21 asks for. It also
closes a gap the inline version had: json.loads returns a list for "[]", and
from_dict then failed on subscripting rather than on the schema.

Tests. Added invalid UTF-8, the line-3-column-1 assertion for malformed JSON, a
parametrized case pinning that all three invalid uploads leave the store button
unrendered, and one that clicks through a valid upload and asserts the trace is
readable from the store afterwards. 11 AppTest cases and 6 unit cases pass locally.

Changelog. The entry claimed a parse position for schema violations too; positions
are now claimed for malformed JSON alone, with the other two located by byte offset
and by field.

tests/test_patch_plan.py has two failures (tool_oscillation missing from
SUPPORTED_PATCH_TYPES) that reproduce unchanged on upstream/main and are untouched
by this branch.

Refs dipeshbabu#21

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
An empty file is one click away in any file picker, and it takes a different
path through the parser than the other rejections: empty bytes are valid
UTF-8, so it falls past the decode layer and fails as JSON at the first
character. That position is real rather than fabricated, so the page test
asserts it verbatim.

Parser-layer test pins the message; the page-level parametrised case pins
that the store button stays unrendered, same as the other invalid payloads.
@dipeshbabu
dipeshbabu force-pushed the fix/dashboard-input-validation branch from a6166ea to 7e0419d Compare August 15, 2026 20:38

@dipeshbabu dipeshbabu left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dchaudhari7177 looks good now. The requested fixes are in and all checks pass. Thanks for following through on this.

@dipeshbabu
dipeshbabu merged commit 435a9b3 into dipeshbabu:main Aug 24, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants