Extract TestReport and LintReport presenters from the brief and gate parsers #808

Closed
opened 2026-09-28 19:26:01 +00:00 by jared · 3 comments
Owner

Problem

Four parsers turn test or lint output into short reports, and they live in namespaces for one caller each:

parser/brief/red_tests.rb        Brief::RedTests        Minitest failures, test-reviewer brief only (ADR-0211)
parser/minitest_summary.rb       MinitestSummary        Minitest run summary line
parser/brief/lint_offense.rb     Brief::LintOffense     rubocop offenses for briefs
parser/gate/lint_violations.rb   Gate::LintViolations   rubocop offenses for gates

ADR-0211 measured the gain: dispatch 240 had 24,627 characters of gate output, and 71% of it was backtrace. Brief::RedTests keeps only the failure kind, name and message. Other readers still get raw output. The programmer node gets the full gate_results text with no cap (query/brief/facts.rb:49, presenter/brief/gate_output.rb). The orchestrator will need a short test report for the failure block in #806. A new reader must either find a parser in another caller's namespace or write its own.

Reproduce

n/a: design ticket.

Approach

One report object for each output type, independent of the caller:

TestReport.parse(output).lines(limit: 15)
# => ["F ImporterTest#test_skips_blank_rows [test/importer_test.rb:42]", "Expected 2 rows, got 3."]
TestReport.parse(output).summary
# => "3 runs, 5 assertions, 1 failures, 0 errors"

LintReport.parse(output).lines(limit: 15)
# => ["C lib/foo.rb:12 Metrics/MethodLength: Method has too many lines. [12/10]"]

TestReport takes over Brief::RedTests, RedTestLine and MinitestSummary. LintReport takes over Brief::LintOffense and Gate::LintViolations. The test-reviewer brief output does not change. When no failure block parses, for example a load error, TestReport#lines returns the first lines of the raw output so that no failure goes unseen.

Required work:

  1. Add TestReport with parse, lines(limit:) and summary. Move the Brief::RedTests, RedTestLine and MinitestSummary callers to it.
  2. Add LintReport with parse and lines(limit:). Move the Brief::LintOffense and Gate::LintViolations callers to it.
  3. Delete the replaced classes — check: grep -rnE "RedTests|RedTestLine|MinitestSummary|LintOffense\b|LintViolations" plugins/os-sdlc/lib prints nothing

Rejected: keep the parsers where they are and call Brief::RedTests from the orchestrator presenter — the name then describes the first caller, not the thing.

Acceptance criteria

  1. Given Minitest output with two failures and backtraces, when TestReport renders it, then it lists both test names and messages and no backtrace lines.
  2. Given Minitest output with more failure lines than the limit, when TestReport renders it with a limit, then it returns no more than the limit.
  3. Given Minitest output with a load error and no failure block, when TestReport renders it, then it returns the first lines of the raw output.
  4. Given Minitest output, when TestReport gives its summary, then it returns the runs, assertions, failures and errors line.
  5. Given rubocop output with three offenses, when LintReport renders it, then it lists each offense with its file, line, cop and message.
  6. Given the test-reviewer node, when its brief is built, then the red test section is the same as before.

Owner sketch

module OsSdlc
  class TestReport
    def self.parse(output)
    def lines(limit: nil)
    def summary
  end

  class LintReport
    def self.parse(output)
    def lines(limit: nil)
  end
end

Non-goals

Switching the programmer node from gate_results to TestReport. The programmer may need the full output; measure first.

Origin

  • Trigger: design review for #806; search for the ADR-0211 trimming work
  • Improvised this session: none
  • Chain: each new reader needs a short test report ← the parser lives in the Brief namespace for one caller ← DESIGN (ADR-0211, parser/brief/red_tests.rb)
  • Root candidate: this ticket
  • Where: plugins/os-sdlc/lib/os_sdlc/parser/brief/red_tests.rb, plugins/os-sdlc/lib/os_sdlc/parser/minitest_summary.rb, plugins/os-sdlc/lib/os_sdlc/parser/brief/lint_offense.rb, plugins/os-sdlc/lib/os_sdlc/parser/gate/lint_violations.rb
  • Session: b505a812-db25-4f85-8d52-ae7cda49eaab
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/b505a812-db25-4f85-8d52-ae7cda49eaab.jsonl
## Problem Four parsers turn test or lint output into short reports, and they live in namespaces for one caller each: ``` parser/brief/red_tests.rb Brief::RedTests Minitest failures, test-reviewer brief only (ADR-0211) parser/minitest_summary.rb MinitestSummary Minitest run summary line parser/brief/lint_offense.rb Brief::LintOffense rubocop offenses for briefs parser/gate/lint_violations.rb Gate::LintViolations rubocop offenses for gates ``` ADR-0211 measured the gain: dispatch 240 had 24,627 characters of gate output, and 71% of it was backtrace. `Brief::RedTests` keeps only the failure kind, name and message. Other readers still get raw output. The programmer node gets the full `gate_results` text with no cap (`query/brief/facts.rb:49`, `presenter/brief/gate_output.rb`). The orchestrator will need a short test report for the failure block in #806. A new reader must either find a parser in another caller's namespace or write its own. ## Reproduce n/a: design ticket. ## Approach One report object for each output type, independent of the caller: ```ruby TestReport.parse(output).lines(limit: 15) # => ["F ImporterTest#test_skips_blank_rows [test/importer_test.rb:42]", "Expected 2 rows, got 3."] TestReport.parse(output).summary # => "3 runs, 5 assertions, 1 failures, 0 errors" LintReport.parse(output).lines(limit: 15) # => ["C lib/foo.rb:12 Metrics/MethodLength: Method has too many lines. [12/10]"] ``` `TestReport` takes over `Brief::RedTests`, `RedTestLine` and `MinitestSummary`. `LintReport` takes over `Brief::LintOffense` and `Gate::LintViolations`. The test-reviewer brief output does not change. When no failure block parses, for example a load error, `TestReport#lines` returns the first lines of the raw output so that no failure goes unseen. Required work: 1. Add `TestReport` with `parse`, `lines(limit:)` and `summary`. Move the `Brief::RedTests`, `RedTestLine` and `MinitestSummary` callers to it. 2. Add `LintReport` with `parse` and `lines(limit:)`. Move the `Brief::LintOffense` and `Gate::LintViolations` callers to it. 3. Delete the replaced classes — check: `grep -rnE "RedTests|RedTestLine|MinitestSummary|LintOffense\b|LintViolations" plugins/os-sdlc/lib` prints nothing Rejected: keep the parsers where they are and call `Brief::RedTests` from the orchestrator presenter — the name then describes the first caller, not the thing. ## Acceptance criteria 1. Given Minitest output with two failures and backtraces, when `TestReport` renders it, then it lists both test names and messages and no backtrace lines. 2. Given Minitest output with more failure lines than the limit, when `TestReport` renders it with a limit, then it returns no more than the limit. 3. Given Minitest output with a load error and no failure block, when `TestReport` renders it, then it returns the first lines of the raw output. 4. Given Minitest output, when `TestReport` gives its summary, then it returns the runs, assertions, failures and errors line. 5. Given rubocop output with three offenses, when `LintReport` renders it, then it lists each offense with its file, line, cop and message. 6. Given the test-reviewer node, when its brief is built, then the red test section is the same as before. ## Owner sketch ```ruby module OsSdlc class TestReport def self.parse(output) def lines(limit: nil) def summary end class LintReport def self.parse(output) def lines(limit: nil) end end ``` ## Non-goals Switching the programmer node from `gate_results` to `TestReport`. The programmer may need the full output; measure first. ## Origin - Trigger: design review for #806; search for the ADR-0211 trimming work - Improvised this session: none - Chain: each new reader needs a short test report ← the parser lives in the `Brief` namespace for one caller ← DESIGN (ADR-0211, `parser/brief/red_tests.rb`) - Root candidate: this ticket - Where: `plugins/os-sdlc/lib/os_sdlc/parser/brief/red_tests.rb`, `plugins/os-sdlc/lib/os_sdlc/parser/minitest_summary.rb`, `plugins/os-sdlc/lib/os_sdlc/parser/brief/lint_offense.rb`, `plugins/os-sdlc/lib/os_sdlc/parser/gate/lint_violations.rb` - Session: b505a812-db25-4f85-8d52-ae7cda49eaab - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/b505a812-db25-4f85-8d52-ae7cda49eaab.jsonl
Author
Owner

Work started on branch ticket-808 via /os-sdlc:implement.

Work started on branch ticket-808 via /os-sdlc:implement.
Author
Owner

Resolution

Done: TestReport (parse, lines(limit:), summary) and LintReport (parse, lines(limit:)) added; all callers moved; Brief::RedTests, RedTestLine, MinitestSummary, Brief::LintOffense, Gate::LintViolations deleted; load-error fallback returns the first 15 raw lines; test-reviewer red_tests output unchanged. Implementation 67 escalated on the suite time budget under load (tests green) and required work 1-3 was hand-finished.

Evidence: main 5766b0ff (commit 5dcc15c7, merge 8eb9c66a). Ticket check grep on plugins/os-sdlc/lib prints nothing. Full os-sdlc suite: 1296 runs, 0 failures, 0 errors, 14.7 s. Rubocop: no offenses on changed files.

Follow-ups: none new; the suite budget under load is #813; the behavior-verifier passing without required work 1-3 was noted by session b505a812 for the #808 amendment and is not ticketed here

## Resolution **Done:** TestReport (parse, lines(limit:), summary) and LintReport (parse, lines(limit:)) added; all callers moved; Brief::RedTests, RedTestLine, MinitestSummary, Brief::LintOffense, Gate::LintViolations deleted; load-error fallback returns the first 15 raw lines; test-reviewer red_tests output unchanged. Implementation 67 escalated on the suite time budget under load (tests green) and required work 1-3 was hand-finished. **Evidence:** main 5766b0ff (commit 5dcc15c7, merge 8eb9c66a). Ticket check grep on plugins/os-sdlc/lib prints nothing. Full os-sdlc suite: 1296 runs, 0 failures, 0 errors, 14.7 s. Rubocop: no offenses on changed files. **Follow-ups:** none new; the suite budget under load is #813; the behavior-verifier passing without required work 1-3 was noted by session b505a812 for the #808 amendment and is not ticketed here
jared closed this issue 2026-09-28 20:45:23 +00:00
jared referenced this issue from a commit 2026-09-28 20:49:01 +00:00
Author
Owner

Follow-up for the behavior-verifier gap noted at close: #814 (required-work gate runs each check: command).

Follow-up for the behavior-verifier gap noted at close: #814 (required-work gate runs each check: command).
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
jared/cc-os#808
No description provided.