[PR #2682] [CLOSED] fix(snapshot): classify non-object JSON roots as invalid structure #5306

Closed
opened 2026-10-31 01:05:37 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/2682
Author: @kaoru0822-kitauji
Created: 10/13/2026
Status: ❌ Closed

Base: main ← Head: fix/issue-2675


📝 Commits (2)

  • 957a256 fix(snapshot): classify non-object JSON roots as invalid structure
  • 641b022 test(snapshot): pin whitespace-only snapshots as malformed JSON

📊 Changes

3 files changed (+63 additions, -6 deletions)

View changed files

📝 src/application/JsonFiles.ts (+9 -3)
📝 src/application/JsonInputFile.ts (+14 -3)
📝 tests/boundary/filesystem/analysisSnapshot.test.ts (+40 -0)

📄 Description

Fixes #2675.

Problem

A readable snapshot file whose JSON root is not an object was reported as a file-access failure. The affected roots are [], null, 5, "x" and true. Reproduced on current main through the public CLI:

$ printf '[]' > s.json
$ rea inspect-native-dispatch-metadata /bin/ls --snapshot "$PWD/s.json" --format json
… "code":"execution_failure", "message":"Evidence file could not be accessed. Check file permissions and try again.", … "reason":"io"

By contrast, {} gives evidence_integrity_mismatch (missing snapshot members) and {bad gives evidence_integrity_mismatch/invalid-json.

Root cause: readJsonObjectFile (src/application/JsonInputFile.ts) owns the root-shape check. On both its native JSON.parse path and its streaming path, it threw a plain TypeError("JSON document root must be an object"). jsonReadFailure recognizes only syntax, encoding and resource errors, so the error was rethrown. readJsonFileInput then classified it with missingOrIo, which gave io.

Fix

  • The producer now returns a typed AnalysisInputError from both paths: invalid_type, expected: "object", with message JSON document root must be an object. It no longer throws an untyped error.
  • readJsonFileInput already maps reader input errors to EvidenceFileError("read", "invalid-json"). It now keeps the typed issue's meaning in the user message: "Evidence file root must be a JSON object. Repair or recreate the file and try again." Syntax errors keep "Evidence file is not valid JSON…".

After:

[] / null / 5 / "x" / true → evidence_integrity_mismatch, reason invalid-json, "Evidence file root must be a JSON object. …"
{}   → unchanged (EvidenceIntegrityError: Analysis snapshot entries is missing)
{bad → unchanged (invalid-json, "Evidence file is not valid JSON. …")

readJsonObjectMembersFile has one caller, the analysis snapshot reader, so no other input changes classification. Real access failures (missing path, non-file, I/O) still go through missingOrIo/not-file.

Validation

  • New boundary test, analysisSnapshot.test.ts > classifies readable non-object roots as invalid snapshot structure, covers the five roots plus a 9 MiB array that goes through the streaming parser. It asserts EvidenceFileError/invalid-json and the projected evidence_integrity_mismatch code and message. It fails on main and passes here.
  • npm run test:focused over 10 snapshot-related files: 56 tests passed, 131 skipped. The skips are environment-gated suites.
  • npm run check:fast and format:check pass.

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/2682 **Author:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Created:** 10/13/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix/issue-2675` --- ### 📝 Commits (2) - [`957a256`](https://github.com/morluto/rea/commit/957a2560192775a617cfb937c62bdd997022d723) fix(snapshot): classify non-object JSON roots as invalid structure - [`641b022`](https://github.com/morluto/rea/commit/641b0221efc33c752f1b28b847c915f0f76d98f5) test(snapshot): pin whitespace-only snapshots as malformed JSON ### 📊 Changes **3 files changed** (+63 additions, -6 deletions) <details> <summary>View changed files</summary> 📝 `src/application/JsonFiles.ts` (+9 -3) 📝 `src/application/JsonInputFile.ts` (+14 -3) 📝 `tests/boundary/filesystem/analysisSnapshot.test.ts` (+40 -0) </details> ### 📄 Description Fixes #2675. ## Problem A readable snapshot file whose JSON root is not an object was reported as a file-access failure. The affected roots are `[]`, `null`, `5`, `"x"` and `true`. Reproduced on current main through the public CLI: ```console $ printf '[]' > s.json $ rea inspect-native-dispatch-metadata /bin/ls --snapshot "$PWD/s.json" --format json … "code":"execution_failure", "message":"Evidence file could not be accessed. Check file permissions and try again.", … "reason":"io" ``` By contrast, `{}` gives `evidence_integrity_mismatch` (missing snapshot members) and `{bad` gives `evidence_integrity_mismatch`/`invalid-json`. **Root cause:** `readJsonObjectFile` (`src/application/JsonInputFile.ts`) owns the root-shape check. On both its native `JSON.parse` path and its streaming path, it threw a plain `TypeError("JSON document root must be an object")`. `jsonReadFailure` recognizes only syntax, encoding and resource errors, so the error was rethrown. `readJsonFileInput` then classified it with `missingOrIo`, which gave `io`. ## Fix - The producer now returns a typed `AnalysisInputError` from both paths: `invalid_type`, `expected: "object"`, with message `JSON document root must be an object`. It no longer throws an untyped error. - `readJsonFileInput` already maps reader input errors to `EvidenceFileError("read", "invalid-json")`. It now keeps the typed issue's meaning in the user message: "Evidence file root must be a JSON object. Repair or recreate the file and try again." Syntax errors keep "Evidence file is not valid JSON…". After: ``` [] / null / 5 / "x" / true → evidence_integrity_mismatch, reason invalid-json, "Evidence file root must be a JSON object. …" {} → unchanged (EvidenceIntegrityError: Analysis snapshot entries is missing) {bad → unchanged (invalid-json, "Evidence file is not valid JSON. …") ``` `readJsonObjectMembersFile` has one caller, the analysis snapshot reader, so no other input changes classification. Real access failures (missing path, non-file, I/O) still go through `missingOrIo`/`not-file`. ## Validation - New boundary test, `analysisSnapshot.test.ts > classifies readable non-object roots as invalid snapshot structure`, covers the five roots plus a 9 MiB array that goes through the streaming parser. It asserts `EvidenceFileError`/`invalid-json` and the projected `evidence_integrity_mismatch` code and message. It fails on main and passes here. - `npm run test:focused` over 10 snapshot-related files: 56 tests passed, 131 skipped. The skips are environment-gated suites. - `npm run check:fast` and `format:check` pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:05:37 +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
morluto/rea#5306
No description provided.