Skip to content

Add "Copy for LLM" button for error occurrences - #1

Merged
rickychilcott merged 1 commit into
mainfrom
copy-for-llm
Jul 31, 2026
Merged

Add "Copy for LLM" button for error occurrences#1
rickychilcott merged 1 commit into
mainfrom
copy-for-llm

Conversation

@rickychilcott

Copy link
Copy Markdown
Owner

A rework of upstream fractaledmind/solid_errors#97 by @bvalentino. Same idea — one click gets you an error in a form you can paste into an LLM — different plumbing.

What changed vs. fractaledmind#97

A real URL instead of an inline <template>. GET /errors/:error_id/occurrences/:id.md renders the prompt. fractaledmind#97 embedded the whole document in every error page, which meant a second Backtrace.parse plus a File.open per application frame on every page view whether or not anyone clicked. Now that work only happens when someone asks for it, and you can curl the URL or paste it to a coworker.

A view, not a model method. fractaledmind#97 added Error#to_markdown, 35 lines of md << "...". This uses app/views/solid_errors/occurrences/show.text.erb, so the formatting sits next to the HTML formatting it mirrors and the model is untouched.

XML-ish tags and instructions, matching the shape Honeybadger emits. Delimited blocks also dodge a real escaping problem: an exception message containing ## or a source snippet containing triple-backticks corrupts a heading-based markdown document, and solid_errors stores raw exception messages.

Per-occurrence, not "the latest one". A button in each occurrence's summary copies that failure; the action-bar button copies the newest.

Degrades instead of dying. fractaledmind#97's .catch never fires — on a non-secure origin navigator.clipboard is undefined, so navigator.clipboard.writeText throws a TypeError synchronously and the button silently does nothing. Plenty of people reach a mounted engine dashboard over plain HTTP. Here the buttons are anchors and the handler only calls preventDefault() when it can actually reach the clipboard, so a non-secure origin, a JS failure, or a cmd-click all fall through to the readable page.

Notes

  • Served as text/plain, not text/markdown — browsers have no renderer for text/markdown and download the file instead of showing it, which would break both the navigable URL and the fallback. GitHub serves raw .md the same way.
  • Rendering through the text format also means ActionView's ERB handler skips HTML escaping, so backtraces and messages survive verbatim.
  • The engine is now mounted in the dummy app, which is what makes request tests possible at all — there were none before.

Sample output

Fix this error from the Dummy application, reported by Solid Errors:

<fault id="2" environment="test">
<class>ArgumentError</class>
<message>kaboom</message>
<severity>warning</severity>
<source>application</source>
<occurred-at>2026-07-31T13:13:38Z</occurred-at>
<occurrence-count>1</occurrence-count>
<project-root>/path/to/app</project-root>
<backtrace>
[PROJECT_ROOT]/app/models/boom.rb:3:in `Boom.explode'
</backtrace>
<source-context>
<file path="[PROJECT_ROOT]/app/models/boom.rb" line="3">
1: class Boom
2:   def self.explode
3:     raise ArgumentError, "kaboom"
4:   end
</file>
</source-context>
<context>
{
  "controller": "UsersController",
  "action": "show"
}
</context>
</fault>

Investigate and fix the root cause of this error:

1. Use the backtrace and source context to locate where the error was raised in this codebase.
...

Testing

test/integration/solid_errors/markdown_test.rb covers the route, content type, unescaped output, the 404 on a mismatched error/occurrence pair, and the links on the error page. Full suite: 8 runs, 34 assertions, 0 failures.

🤖 Generated with Claude Code

Adds `GET /errors/:error_id/occurrences/:id.md`, which renders a single
occurrence as an LLM-ready prompt: the fault in XML-ish tags (class,
message, backtrace, source context for application frames, request
context) plus instructions to investigate and fix it.

Served as text/plain so browsers display it inline rather than
downloading it, and rendered through the `text` format so ActionView's
ERB handler skips HTML escaping.

The buttons are anchors, not buttons: the click handler only calls
preventDefault when it can actually reach the clipboard, so non-secure
origins, JS failures, and cmd-click all fall through to the readable
page. One appears in the error action bar (newest occurrence) and one
in each occurrence's summary.

Mounts the engine in the dummy app so request tests are possible.

Co-Authored-By: Bruno Valentino <brunovalentino@gmail.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@rickychilcott
rickychilcott merged commit 5a7a829 into main Jul 31, 2026
@rickychilcott
rickychilcott deleted the copy-for-llm branch July 31, 2026 14:46
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