Skip to content

Guard ExecutionJournal#record against JSON::GeneratorError - #77

Open
minerva-sky wants to merge 1 commit into
codenamev:mainfrom
minerva-sky:fix/journal-generate-guard
Open

minerva-sky wants to merge 1 commit into
codenamev:mainfrom
minerva-sky:fix/journal-generate-guard

Conversation

@minerva-sky

Copy link
Copy Markdown
Collaborator

Closes the one unguarded spot called out in #76.

What

ExecutionJournal#record runs from after_task_success. If the json gem refuses the payload, the task that already succeeded blew up on its own logging. Concretely: a BINARY-encoded non-ASCII string, Float::NAN, and on json versions that reject it, a hash carrying both :k and "k".

The writer now rescues JSON::GeneratorError and lands a fallback line instead:

  • keeps event, at, task_id, description (the String fields replay keys on), so the task still counts as completed and mode: :strict replay does not trip on a missing task_id
  • adds payload_error (the exception class) and payload_inspect (first 500 chars of payload.inspect, scrubbed) so a recovery tool can see what was lost

Parsing stays strict, per the #76 lean. Only the writer changes.

Specs

Two new examples in spec/agentic/execution_journal_spec.rb: a BINARY "caf\xE9" output lands, carries payload_error, and replays strict as completed; a {:k => 1, "k" => 2} output lands and replays. The second one is deliberately version-agnostic: on the bundled json 2.7.1 it writes the ambiguous line as before, on newer json it takes the rescue path, and either way the task shows up in completed_task_ids.

bundle exec rspec spec/agentic/execution_journal_spec.rb → 11 examples, 0 failures. standardrb clean on both files.

Not in this PR

A fallback line means state.outputs[task_id] is nil for that task on replay. A resuming plan would treat it as done with no output. If that should instead surface on state.damage, that is a one-line follow-up in replay; I left it out to keep this to the writer.

🤖 Generated with Claude Code

A journal write runs from after_task_success, so a payload the json gem
refuses to serialize (a BINARY-encoded non-ASCII string, NaN, and on
newer json versions a payload with both :k and "k") raised after the
task had already succeeded. Rescue GeneratorError and write a fallback
line that keeps event, at, task_id and description so replay still
counts the task, plus payload_error and a 500-char scrubbed inspect of
what could not be written.

Follows the lean in codenamev#76: parsing stays strict, the writer alone must
never fail a finished task.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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