Three parser bugs in core/src/main/java/io/github/gabrielbbaldez/stacktale/idea/StReportParser.java, all of which end with the user looking at the wrong thing or at nothing. :core has no IntelliJ dependency, so each is testable with a plain unit test.
1. Truncated blocks are emitted, and the spec says they must not
FORMAT.md is explicit: a block whose closing line is absent is incomplete, and parsers must discard it rather than emit a partial entry.
The inner loop at :41-54 breaks on the next START or on end-of-input and then calls parseBlock unconditionally — there is no check that the block ended in END. The existing test aTruncatedTrailingBlockIsStillSurfaced asserts the wrong behaviour as if it were intended, so it needs flipping too.
Why it is visible: the writer emits the header, the session marker and the block as separate writes, and a multi-KB block is not an atomic append. A poll landing in that window shows a report with a headline, no culprit, no stack and no story; double-clicking it does nothing. It heals on the next poll, so it reads as random rather than reproducible.
Fix: only accept a block whose last line starts with END. Keep the trailing partial and re-evaluate it on the next refresh, so a genuinely killed process drops the tail instead of flickering it.
2. A frame with no line number navigates to the wrong file
The frame regex at :21 requires \d+. But the library writes getLineNumber() verbatim (StackDistiller.java:203 in the main repo), and StackTraceElement.getLineNumber() returns -1 when the class was compiled without -g:lines and -2 for a native method. A line such as at OrderService.confirm(OrderService.java:-1) <- YOUR CODE is legal, routinely produced, and matches nothing.
The marked culprit then yields no frame, and we fall back to the first frame (:77) — which for a wrapped exception is the frame on the wrapped by: line. The user double-clicks an IllegalStateException attributed to OrderService and silently lands in CheckoutService.java:88.
Fix: allow -?\d+; treat a line number <= 0 as found but not navigable; only fall back to the first frame when the block contained no marked frame at all.
Related, same method: Integer.parseInt at :70 throws out of parse() on an absurd line number, which — until the refresh loop is hardened — kills the poll for the session. Parse into a long and clamp.
3. Non-ASCII source file names are invisible
[\w$]+ is ASCII-only in Java without UNICODE_CHARACTER_CLASS. Names like Acao.java, Groesse.java or a CJK class name are legal Java source names — Java identifiers accept Unicode letters — so those frames match nothing and the report ends up with no culprit at all.
Fix: [\p{L}\p{N}_$]+ with Pattern.UNICODE_CHARACTER_CLASS, or simply [^\s:()]+\.\w+. Add .kts while you are there.
Verify
A case in core/src/test/java/.../StReportParserTest.java per bug, and flip aTruncatedTrailingBlockIsStillSurfaced. ./gradlew :core:test needs no IDE download.
Worth doing at the same time: the main repo ships conformance fixtures at stacktale-core/src/test/resources/golden/*.txt that FORMAT.md declares authoritative, and neither editor parser uses them. Vendoring those in would have caught all three of these.
The same three bugs exist in the VS Code extension — the parsers are deliberate twins, so please keep the fixes in step.
Three parser bugs in
core/src/main/java/io/github/gabrielbbaldez/stacktale/idea/StReportParser.java, all of which end with the user looking at the wrong thing or at nothing.:corehas no IntelliJ dependency, so each is testable with a plain unit test.1. Truncated blocks are emitted, and the spec says they must not
FORMAT.md is explicit: a block whose closing line is absent is incomplete, and parsers must discard it rather than emit a partial entry.
The inner loop at
:41-54breaks on the nextSTARTor on end-of-input and then callsparseBlockunconditionally — there is no check that the block ended inEND. The existing testaTruncatedTrailingBlockIsStillSurfacedasserts the wrong behaviour as if it were intended, so it needs flipping too.Why it is visible: the writer emits the header, the session marker and the block as separate writes, and a multi-KB block is not an atomic append. A poll landing in that window shows a report with a headline, no culprit, no stack and no story; double-clicking it does nothing. It heals on the next poll, so it reads as random rather than reproducible.
Fix: only accept a block whose last line starts with
END. Keep the trailing partial and re-evaluate it on the next refresh, so a genuinely killed process drops the tail instead of flickering it.2. A frame with no line number navigates to the wrong file
The frame regex at
:21requires\d+. But the library writesgetLineNumber()verbatim (StackDistiller.java:203in the main repo), andStackTraceElement.getLineNumber()returns -1 when the class was compiled without-g:linesand -2 for a native method. A line such asat OrderService.confirm(OrderService.java:-1) <- YOUR CODEis legal, routinely produced, and matches nothing.The marked culprit then yields no frame, and we fall back to the first frame (
:77) — which for a wrapped exception is the frame on thewrapped by:line. The user double-clicks an IllegalStateException attributed toOrderServiceand silently lands inCheckoutService.java:88.Fix: allow
-?\d+; treat a line number<= 0as found but not navigable; only fall back to the first frame when the block contained no marked frame at all.Related, same method:
Integer.parseIntat:70throws out ofparse()on an absurd line number, which — until the refresh loop is hardened — kills the poll for the session. Parse into alongand clamp.3. Non-ASCII source file names are invisible
[\w$]+is ASCII-only in Java withoutUNICODE_CHARACTER_CLASS. Names likeAcao.java,Groesse.javaor a CJK class name are legal Java source names — Java identifiers accept Unicode letters — so those frames match nothing and the report ends up with no culprit at all.Fix:
[\p{L}\p{N}_$]+withPattern.UNICODE_CHARACTER_CLASS, or simply[^\s:()]+\.\w+. Add.ktswhile you are there.Verify
A case in
core/src/test/java/.../StReportParserTest.javaper bug, and flipaTruncatedTrailingBlockIsStillSurfaced../gradlew :core:testneeds no IDE download.Worth doing at the same time: the main repo ships conformance fixtures at
stacktale-core/src/test/resources/golden/*.txtthat FORMAT.md declares authoritative, and neither editor parser uses them. Vendoring those in would have caught all three of these.The same three bugs exist in the VS Code extension — the parsers are deliberate twins, so please keep the fixes in step.