Skip to content

feat: streamlined output, failure detection, and call chain support for external errors#32

Open
gamescoot wants to merge 3 commits into
KyleKincer:mainfrom
gamescoot:less-errors-output
Open

feat: streamlined output, failure detection, and call chain support for external errors#32
gamescoot wants to merge 3 commits into
KyleKincer:mainfrom
gamescoot:less-errors-output

Conversation

@gamescoot
Copy link
Copy Markdown
Collaborator

@gamescoot gamescoot commented May 11, 2026

Summary

This PR improves the test framework's output behavior, failure detection, and error reporting:

Output Behavior Changes

  • Human-readable output always streams to stdout regardless of format parameter — you always see real-time test progress
  • format=json and format=junit now require outputPath — report is written to file only, never dumped to stdout
  • If outputPath is omitted for json/junit, the framework prints an error and falls back to human-only output
  • Removed the JSON stdout fallback path entirely

Failure Detection & Exit Codes

  • Added hasFailed() method: returns true when any tests fail OR external runtime errors are detected
  • Framework writes an error file when hasFailed() is true, which the Makefile checks to exit non-zero
  • make test now exits with code 1 on any failure (test failures or external runtime errors)
  • Clear "FAILED: X test(s) failed, Y external runtime error(s)" banner in human output
  • JUnit XML <testsuites> errors count incremented by 1 when external errors exist, ensuring CI tools correctly flag the run

Call Chain Support for External Errors

  • When callchain=true or verbose=true is set, external runtime error call stacks are now displayed in the human report
  • _groupGlobalErrors preserves callChainJSON from the first error in each deduplicated group
  • Call chains are formatted using the existing _formatCallChain utility

Makefile Improvements

  • Added PROJECT_DIR and ERROR_FILE variables for error file detection
  • All json/junit targets now include explicit outputPath parameter
  • FIFO-based cooperative-yield noise filtering (real-time, no buffering)
  • Robust Ctrl+C handling with disown to suppress "Killed: 9" messages

Documentation

  • Updated CLAUDE.md and AGENTS.md with new outputPath requirement in all examples
  • Added "Output Behavior" section explaining streaming, file output, and exit code semantics

Test Plan

  1. Basic test run — verify human output streams in real-time:

    make test test=_ExampleTest

    Expected: real-time ✓/✗ output, "All tests passed!" at end, exit 0

  2. JSON output requires outputPath:

    make test format=json

    Expected: error message about missing outputPath, falls back to human output

  3. JSON output with outputPath:

    make test format=json outputPath=test-results/report.json test=_ExampleTest

    Expected: human output streams to stdout AND json written to file

  4. Failure detection with external errors (requires host project with runtime errors):

    make test  # in a host project with external errors

    Expected: "FAILED: N external runtime error(s)" banner, exit code 1

  5. Call chain display for external errors:

    make test callchain=true  # in host project with external errors

    Expected: each grouped external error shows its "Call Stack:" with method names and line numbers

  6. Call chains hidden by default:

    make test  # without callchain=true or verbose=true

    Expected: external errors listed without call stacks

  7. JUnit XML failure flag:

    make test format=junit outputPath=test-results/junit.xml

    Expected: if external errors exist, <testsuites errors="N"> where N > 0

  8. Ctrl+C handling:

    make test  # then press Ctrl+C during execution

    Expected: immediate termination, no "Killed: 9" messages, exit code 130

Summary by CodeRabbit

  • New Features

    • Added debug=true option to show tool stderr during tests.
    • New make targets provide default JSON/JUnit report file locations.
  • Improvements

    • JSON/JUnit modes now require an outputPath and write reports to files only.
    • Console output cleans up noisy warnings; runtime/global errors are grouped and shown more readably.
    • Summary/failure lines are presented as informational (cleaner console severity).
  • Documentation

    • Updated docs with examples and notes for JSON/JUnit output, outputPath, and debugging.

Review Change Stack

Scott Harris and others added 2 commits May 11, 2026 17:36
Reorder the human-readable report so external errors and failed tests
print before the summary, making the summary the last section visible.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Route all test output to stdout (LOG EVENT Information message)
- Remove DEBUG log lines from TestRunner
- Filter tool4d cooperative-yield warnings via FIFO + grep for real-time output
- Add instant Ctrl+C handling (SIGKILL via trap on background PID)
- Suppress stderr by default (debug=true to re-enable)
- Deduplicate external runtime errors in human report (show count per unique error)

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 11, 2026

📝 Walkthrough

Walkthrough

Adds debug=true Makefile wiring with FIFO-based stdout filtering and required outputPath for json/junit; lowers failure/timeout log severity to informational; groups duplicate global runtime errors in reports; and removes noisy debug logs from TestRunner execution flow.

Changes

Test Output & Debug Logging Refinement

Layer / File(s) Summary
Makefile & documentation wiring
Makefile, AGENTS.md, CLAUDE.md
Set SHELL := /bin/bash; add PROJECT_DIR/ERROR_FILE; extend USER_PARAMS with outputPath, verbose, triggers; implement FIFO stdout filtering and conditional stderr suppression (debug=true); wrapper targets provide default outputPath; docs updated to show outputPath usage and make test debug=true.
TestRunner core flow & output format handling
testing/Project/Sources/Classes/TestRunner.4dm
Remove pre/post debug logs from run() and suite orchestration; always emit human per-test lines; require outputPath for json/junit (fallback to human with error); write JSON only when outputPath present; add hasFailed() helper; adjust JUnit counts.
Global error grouping & report rendering
testing/Project/Sources/Classes/TestRunner.4dm
Add _groupGlobalErrors() to aggregate duplicate runtime errors with counts and optional call-chain JSON; render grouped "Runtime Errors Outside Test Processes" in human report and include grouped entries in JUnit/system-err output.
ParallelTestRunner severity adjustments
testing/Project/Sources/Classes/ParallelTestRunner.4dm
Change parallel timeout and failed-test log events from error severity to informational severity; no control-flow changes.
Editor syntax metadata
testing/Resources/en.lproj/syntaxEN.json
Add TestRunner.hasFailed() method entry (Boolean return, no params).

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Makefile
  participant tool4d
  participant Filter
  User->>Makefile: make test [debug=true] + USER_PARAMS
  Makefile->>tool4d: launch tool4d (--user-param outputPath,...)
  tool4d->>Filter: stdout stream
  tool4d->>Makefile: stderr (suppressed unless debug=true)
  Filter->>Makefile: filtered stdout to console
  Makefile->>Makefile: trap -> cleanup & exit with tool4d status
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

codex

Poem

🐰 I nudged the logs and hushed the din,

Debug flag shows the secrets within.
Errors counted, grouped, and neat,
Quiet output feels complete.
A hop, a filter — tests now sing.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title directly describes the main change: streamlined output handling, failure detection via the new hasFailed() method, and call chain support for external errors—all of which are core objectives of the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
testing/Project/Sources/Classes/TestRunner.4dm (1)

410-428: 💤 Low value

Consider more robust key generation for error grouping.

The error grouping key uses underscore concatenation: String(code)+"_"+text+"_"+String(line). While functional, this could theoretically produce collisions if error text contains patterns like "123_Some error_45" that match the separator scheme.

For more robust deduplication, consider using a delimiter-free approach:

🔧 Alternative approaches

Option 1: Use JSON.stringify for key generation

-$key:=String:C10($error.code || 0)+"_"+($error.text || "")+"_"+String:C10($error.line || 0)
+$key:=JSON Stringify:C1217(New object:C1471("c"; $error.code || 0; "t"; $error.text || ""; "l"; $error.line || 0))

Option 2: Use a more unique delimiter

-$key:=String:C10($error.code || 0)+"_"+($error.text || "")+"_"+String:C10($error.line || 0)
+$key:=String:C10($error.code || 0)+"\t"+($error.text || "")+"\t"+String:C10($error.line || 0)

The current implementation works correctly for typical error messages, so this is primarily a defensive coding suggestion.

🤖 Prompt for 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.

In `@testing/Project/Sources/Classes/TestRunner.4dm` around lines 410 - 428, The
current key assembly in _groupGlobalErrors() using String:C10($error.code ||
0)+"_"+($error.text || "")+"_"+String:C10($error.line || 0) can collide when the
error text contains the separator; change the key to a delimiter-free
representation such as JSON.stringify of a small object or another unambiguous
encoding (e.g., base64 of concatenated fields) built from $error.code,
$error.text and $error.line so $grouped keys are unique; update the key
generation only (keep $grouped, the grouping logic and
This:C1470._formatGlobalErrorForLog unchanged).
testing/Project/Sources/Classes/ParallelTestRunner.4dm (1)

192-192: 💤 Low value

Consider whether timeout warrants higher visibility.

A 5-minute timeout for parallel test execution is a critical failure condition that indicates stuck or hanging tests. Logging it as Information message may make it too easy to miss in CI/CD pipelines or when reviewing logs, especially since the Makefile now suppresses stderr by default.

While this aligns with the PR's goal of routing all output to stdout, consider whether this particular failure mode deserves to remain at a higher severity or at least be prefixed with "ERROR:" in the message text itself.

🤖 Prompt for 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.

In `@testing/Project/Sources/Classes/ParallelTestRunner.4dm` at line 192, The
timeout message logged by LOG EVENT:C667 is currently emitted as an Information
message (Into system standard outputs:K38:9; Information message:K38:1) but
should be elevated for visibility; update the LOG EVENT:C667 invocation to
either use an error severity token instead of Information message or prepend the
text with an explicit "ERROR:" prefix (e.g., change the severity symbol from
Information message:K38:1 to Error message or alter the string to "ERROR:
Parallel test execution timeout after 5 minutes\r\n") so the timeout is clearly
visible in CI logs.
Makefile (1)

68-80: ⚡ Quick win

Consider safer FIFO creation and graceful signal handling.

  1. FIFO creation: The mktemp -u followed by mkfifo sequence has a narrow race window where another process could create a file with the same temporary name. Use mktemp -d to create a temporary directory first, then create the FIFO inside it: fifo=$(mktemp -d)/fifo; mkfifo "$fifo".

  2. Signal handling: The trap immediately uses kill -KILL, preventing the filter process from flushing buffered output. Try kill -TERM first with a brief grace period before falling back to kill -KILL:

trap 'disown $$pid $$filter_pid 2>/dev/null; kill -TERM $$filter_pid 2>/dev/null; sleep 0.1; kill -KILL $$pid $$filter_pid 2>/dev/null; rm -f $$fifo; exit 130' INT TERM; \

The rest of the logic correctly preserves exit codes and cleans up resources in both normal and error paths.

🤖 Prompt for 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.

In `@Makefile` around lines 68 - 80, The FIFO creation and trap should be made
race-free and allow graceful shutdown: replace the mktemp -u / mkfifo sequence
with creating a temp directory (dir=$$(mktemp -d)) and then fifo="$$dir/fifo";
mkfifo "$$fifo" (ensure you remove the fifo and rmdir "$$dir" in cleanup),
update uses of `@fifo` to the fifo variable, and harden quoting; update the trap
that currently does kill -KILL immediately to first disown $$pid $$filter_pid
2>/dev/null; kill -TERM $$filter_pid $$pid 2>/dev/null; sleep 0.1; kill -KILL
$$pid $$filter_pid 2>/dev/null; rm -f "$$fifo"; rmdir "$$dir" 2>/dev/null; exit
130 so the filter (YIELD_FILTER) and main tool (TOOL4D) get a chance to flush
before forcible kill.
🤖 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.

Nitpick comments:
In `@Makefile`:
- Around line 68-80: The FIFO creation and trap should be made race-free and
allow graceful shutdown: replace the mktemp -u / mkfifo sequence with creating a
temp directory (dir=$$(mktemp -d)) and then fifo="$$dir/fifo"; mkfifo "$$fifo"
(ensure you remove the fifo and rmdir "$$dir" in cleanup), update uses of `@fifo`
to the fifo variable, and harden quoting; update the trap that currently does
kill -KILL immediately to first disown $$pid $$filter_pid 2>/dev/null; kill
-TERM $$filter_pid $$pid 2>/dev/null; sleep 0.1; kill -KILL $$pid $$filter_pid
2>/dev/null; rm -f "$$fifo"; rmdir "$$dir" 2>/dev/null; exit 130 so the filter
(YIELD_FILTER) and main tool (TOOL4D) get a chance to flush before forcible
kill.

In `@testing/Project/Sources/Classes/ParallelTestRunner.4dm`:
- Line 192: The timeout message logged by LOG EVENT:C667 is currently emitted as
an Information message (Into system standard outputs:K38:9; Information
message:K38:1) but should be elevated for visibility; update the LOG EVENT:C667
invocation to either use an error severity token instead of Information message
or prepend the text with an explicit "ERROR:" prefix (e.g., change the severity
symbol from Information message:K38:1 to Error message or alter the string to
"ERROR: Parallel test execution timeout after 5 minutes\r\n") so the timeout is
clearly visible in CI logs.

In `@testing/Project/Sources/Classes/TestRunner.4dm`:
- Around line 410-428: The current key assembly in _groupGlobalErrors() using
String:C10($error.code || 0)+"_"+($error.text || "")+"_"+String:C10($error.line
|| 0) can collide when the error text contains the separator; change the key to
a delimiter-free representation such as JSON.stringify of a small object or
another unambiguous encoding (e.g., base64 of concatenated fields) built from
$error.code, $error.text and $error.line so $grouped keys are unique; update the
key generation only (keep $grouped, the grouping logic and
This:C1470._formatGlobalErrorForLog unchanged).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c50efbfc-2172-41d9-84eb-63982b595a3c

📥 Commits

Reviewing files that changed from the base of the PR and between 282283c and cef2eb2.

📒 Files selected for processing (5)
  • AGENTS.md
  • CLAUDE.md
  • Makefile
  • testing/Project/Sources/Classes/ParallelTestRunner.4dm
  • testing/Project/Sources/Classes/TestRunner.4dm

…add failure detection

- Always stream human-readable report to stdout regardless of format parameter
- Require outputPath for format=json and format=junit (error + fallback without it)
- Remove JSON stdout fallback (file-write only)
- Add hasFailed() method and write error file for non-zero exit propagation
- Update _logFooter with clear FAILED/passed banner
- Increment JUnit <testsuites> errors when external runtime errors detected
- Display call chains for external errors when callchain=true or verbose=true
- Add outputPath to all Makefile json/junit targets
- Filter cooperative-yield noise via FIFO without buffering
- Update docs with new output behavior and outputPath requirement

Co-authored-by: Cursor <cursoragent@cursor.com>
@gamescoot gamescoot changed the title feat: filter cooperative-yield noise and deduplicate global errors feat: streamlined output, failure detection, and call chain support for external errors May 12, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 `@Makefile`:
- Line 47: The current STDREDIRECT assignment uses a truthy check on the debug
variable so values like "false" disable stderr redirection; change the condition
to test explicitly for debug being "true" (e.g., use a Makefile equality/filter
check against the debug variable) so stderr is only left unredirected when debug
is exactly "true"; update the STDERROR_REDIRECT (STDERR_REDIRECT) assignment to
use this explicit check referencing the debug variable.
- Around line 70-83: The rule can fail from a stale "$(ERROR_FILE)" left by a
previous run; before creating the fifo and launching processes (the block that
uses mkfifo, $(YIELD_FILTER), $(TOOL4D), etc.) ensure you delete any existing
"$(ERROR_FILE)" at the start of the recipe so old markers don't trigger a false
exit; add a step that checks for and removes "$(ERROR_FILE)" (or truncates it)
prior to creating $$fifo and starting $(TOOL4D) and the filter, preserving the
rest of the trap/wait/cleanup logic.

In `@testing/Project/Sources/Classes/TestRunner.4dm`:
- Around line 671-673: The code is incorrectly folding global/external runtime
errors into the JUnit suite error count by incrementing $totalErrors when
This:C1470.results.hasGlobalErrors is true; remove that increment and instead
emit those global errors to the test runner's system-err output stream (where
other global/runtime diagnostics are written) so they are reported but not
included in testsuites/@errors; specifically, stop modifying $totalErrors in the
block that checks This:C1470.results.hasGlobalErrors and call the existing
system-err reporting routine (the same handler used for other global errors) or
append the error text to the global system-err output so JUnit consumers see the
message without inflating the `@errors` attribute.
🪄 Autofix (Beta)

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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 23ee19a9-fc72-4585-bb9f-820b5fbec18e

📥 Commits

Reviewing files that changed from the base of the PR and between cef2eb2 and 315a853.

📒 Files selected for processing (5)
  • AGENTS.md
  • CLAUDE.md
  • Makefile
  • testing/Project/Sources/Classes/TestRunner.4dm
  • testing/Resources/en.lproj/syntaxEN.json
✅ Files skipped from review due to trivial changes (2)
  • CLAUDE.md
  • AGENTS.md

Comment thread Makefile
# - stderr redirected to /dev/null (tool4d.4DRT errors)
# - stdout cooperative-yield warnings stripped via FIFO + grep
# Pass debug=true to disable stderr suppression.
STDERR_REDIRECT := $(if $(debug),,2>/dev/null)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Gate stderr suppression only on explicit debug=true.

Current condition treats any non-empty debug value (including debug=false) as debug mode.

Suggested fix
-STDERR_REDIRECT := $(if $(debug),,2>/dev/null)
+STDERR_REDIRECT := $(if $(filter true,$(debug)),,2>/dev/null)
🤖 Prompt for 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.

In `@Makefile` at line 47, The current STDREDIRECT assignment uses a truthy check
on the debug variable so values like "false" disable stderr redirection; change
the condition to test explicitly for debug being "true" (e.g., use a Makefile
equality/filter check against the debug variable) so stderr is only left
unredirected when debug is exactly "true"; update the STDERROR_REDIRECT
(STDERR_REDIRECT) assignment to use this explicit check referencing the debug
variable.

Comment thread Makefile
Comment on lines +70 to +83
@fifo=$$(mktemp -u).fifo; mkfifo $$fifo; \
$(YIELD_FILTER) < $$fifo & filter_pid=$$!; \
if [ -n "$(USER_PARAMS)" ]; then \
$(TOOL4D) $(BASE_OPTS) --user-param "$(USER_PARAMS)" $(STDERR_REDIRECT) > $$fifo & \
else \
$(TOOL4D) $(BASE_OPTS); \
fi
$(TOOL4D) $(BASE_OPTS) $(STDERR_REDIRECT) > $$fifo & \
fi; \
pid=$$!; \
trap 'disown $$pid $$filter_pid 2>/dev/null; kill -KILL $$pid $$filter_pid 2>/dev/null; rm -f $$fifo; exit 130' INT TERM; \
wait $$pid; ret=$$?; \
kill $$filter_pid 2>/dev/null; wait $$filter_pid 2>/dev/null; \
rm -f $$fifo; \
if [ -f "$(ERROR_FILE)" ]; then rm -f "$(ERROR_FILE)"; exit 1; fi; \
exit $$ret
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Clear stale $(ERROR_FILE) before each run to avoid false failures.

If a stale marker exists (e.g., interrupted previous run), this target exits 1 even when current tests pass.

Suggested fix
 test: $(TOOL4D)
-	`@fifo`=$$(mktemp -u).fifo; mkfifo $$fifo; \
+	`@rm` -f "$(ERROR_FILE)"; \
+	fifo=$$(mktemp -u).fifo; mkfifo $$fifo; \
 	$(YIELD_FILTER) < $$fifo & filter_pid=$$!; \
 	if [ -n "$(USER_PARAMS)" ]; then \
 	        $(TOOL4D) $(BASE_OPTS) --user-param "$(USER_PARAMS)" $(STDERR_REDIRECT) > $$fifo & \
 	else \
 	        $(TOOL4D) $(BASE_OPTS) $(STDERR_REDIRECT) > $$fifo & \
 	fi; \
 	pid=$$!; \
-	trap 'disown $$pid $$filter_pid 2>/dev/null; kill -KILL $$pid $$filter_pid 2>/dev/null; rm -f $$fifo; exit 130' INT TERM; \
+	trap 'disown $$pid $$filter_pid 2>/dev/null; kill -KILL $$pid $$filter_pid 2>/dev/null; rm -f $$fifo "$(ERROR_FILE)"; exit 130' INT TERM; \
 	wait $$pid; ret=$$?; \
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@fifo=$$(mktemp -u).fifo; mkfifo $$fifo; \
$(YIELD_FILTER) < $$fifo & filter_pid=$$!; \
if [ -n "$(USER_PARAMS)" ]; then \
$(TOOL4D) $(BASE_OPTS) --user-param "$(USER_PARAMS)" $(STDERR_REDIRECT) > $$fifo & \
else \
$(TOOL4D) $(BASE_OPTS); \
fi
$(TOOL4D) $(BASE_OPTS) $(STDERR_REDIRECT) > $$fifo & \
fi; \
pid=$$!; \
trap 'disown $$pid $$filter_pid 2>/dev/null; kill -KILL $$pid $$filter_pid 2>/dev/null; rm -f $$fifo; exit 130' INT TERM; \
wait $$pid; ret=$$?; \
kill $$filter_pid 2>/dev/null; wait $$filter_pid 2>/dev/null; \
rm -f $$fifo; \
if [ -f "$(ERROR_FILE)" ]; then rm -f "$(ERROR_FILE)"; exit 1; fi; \
exit $$ret
`@rm` -f "$(ERROR_FILE)"; \
fifo=$$(mktemp -u).fifo; mkfifo $$fifo; \
$(YIELD_FILTER) < $$fifo & filter_pid=$$!; \
if [ -n "$(USER_PARAMS)" ]; then \
$(TOOL4D) $(BASE_OPTS) --user-param "$(USER_PARAMS)" $(STDERR_REDIRECT) > $$fifo & \
else \
$(TOOL4D) $(BASE_OPTS) $(STDERR_REDIRECT) > $$fifo & \
fi; \
pid=$$!; \
trap 'disown $$pid $$filter_pid 2>/dev/null; kill -KILL $$pid $$filter_pid 2>/dev/null; rm -f $$fifo "$(ERROR_FILE)"; exit 130' INT TERM; \
wait $$pid; ret=$$?; \
kill $$filter_pid 2>/dev/null; wait $$filter_pid 2>/dev/null; \
rm -f $$fifo; \
if [ -f "$(ERROR_FILE)" ]; then rm -f "$(ERROR_FILE)"; exit 1; fi; \
exit $$ret
🤖 Prompt for 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.

In `@Makefile` around lines 70 - 83, The rule can fail from a stale
"$(ERROR_FILE)" left by a previous run; before creating the fifo and launching
processes (the block that uses mkfifo, $(YIELD_FILTER), $(TOOL4D), etc.) ensure
you delete any existing "$(ERROR_FILE)" at the start of the recipe so old
markers don't trigger a false exit; add a step that checks for and removes
"$(ERROR_FILE)" (or truncates it) prior to creating $$fifo and starting
$(TOOL4D) and the filter, preserving the rest of the trap/wait/cleanup logic.

Comment on lines +671 to +673
If (This:C1470.results.hasGlobalErrors)
$totalErrors:=$totalErrors+1
End if
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not fold global errors into JUnit testsuites/@errors.

This inflates suite error counts with non-test errors and breaks JUnit semantics for CI consumers.

Suggested fix
-	If (This:C1470.results.hasGlobalErrors)
-		$totalErrors:=$totalErrors+1
-	End if 
+	// Global/external runtime errors are reported in <system-err> only.
+	// Do not include them in <testsuites `@errors`>.

As per coding guidelines "**/TestRunner.4dm: Global/external runtime errors ... must be reported in ... <system-err> ... but NOT counted in <testsuites>/@errors."

🤖 Prompt for 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.

In `@testing/Project/Sources/Classes/TestRunner.4dm` around lines 671 - 673, The
code is incorrectly folding global/external runtime errors into the JUnit suite
error count by incrementing $totalErrors when This:C1470.results.hasGlobalErrors
is true; remove that increment and instead emit those global errors to the test
runner's system-err output stream (where other global/runtime diagnostics are
written) so they are reported but not included in testsuites/@errors;
specifically, stop modifying $totalErrors in the block that checks
This:C1470.results.hasGlobalErrors and call the existing system-err reporting
routine (the same handler used for other global errors) or append the error text
to the global system-err output so JUnit consumers see the message without
inflating the `@errors` attribute.

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