Skip to content

feat: add comment_detail input for the PR comment diagram - #163

Open
Svilen-Stefanov wants to merge 2 commits into
mainfrom
feat/comment-depth
Open

Svilen-Stefanov wants to merge 2 commits into
mainfrom
feat/comment-depth

Conversation

@Svilen-Stefanov

@Svilen-Stefanov Svilen-Stefanov commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

A trial user on a Java repo (3 top-level components, 7 nested) found that most changes light up the same box in the PR comment. This adds comment_detail, a small opt-in input with two views. The default top is byte-identical to today, so nobody's comment changes.

with:
  comment_detail: specific
  • top (default): every top-level component, as now.
  • specific: only the most specific components that changed, flat, joined by the relations that changed. An unchanged component appears only where a changed relation ends at it.

This replaces the numeric comment_depth from the first version of this PR. No free number remains and the action cannot select nested subgraphs, because the full map is unreadable at comment width (table below).

Real comparison

render-review.sh on the pinned Core 0.15.3, on two consecutive stored analyses from CodeBoarding/CodeBoarding's codeboarding/baseline branch (25ba872e3 to 38ea16301, 5 components changed). Drawn by Mermaid 11.4.1 in Chromium at 850px, about a GitHub comment's width, with no syntax errors.

View Nodes Boxes Edges Changed relations shown Characters Label size at 850px
top 6 0 14 0 of 3 2,437 6px
specific 4 0 3 3 of 3 1,171 16px
old depth 2 (removed) 23 6 45 0 of 3 8,287 2.6px

Label size is Mermaid's 16px default times the scale needed to fit. So specific labels read at full size, top is small but legible, and depth 2 was not readable without zooming. GitHub's own renderer may differ a little; the diagram at the bottom of this description shows it.

All 3 changed relations cross parents, so neither top nor depth 2 could show them. They roll up onto parent edges that did not change.

Decisions worth a look

  • The unprojected relations are kept. Each level holds only relations with both ends inside it, so 1.1 to 2.1 exists only as a rolled-up 1 to 2. Here 71 of the 102 relations cross parents. load_analysis now keeps that list and build_diff runs it through the existing _diff_relations.
  • Ownership of changed code is marked at every level. build_diff only checked it at the top level, so a body edit in a nested component left that component reading as unchanged. On the real pair, Diagram Analysis Pipeline would have been drawn whole instead of Diagram Generation Orchestrator and Scope Planning and Assembly. It is a separate owns_change field rather than a status, so n_changed and top do not move.
  • The view is a pure transform. _specific_view produces a one-level diff and the existing render_mermaid draws it, so the emit code is unchanged. I did not reuse _filter_changed: it keeps ancestors and works per level, which is the opposite of what this view needs.
  • Fallback lives in the renderer. specific falls back to top if nothing changed (silently) or it overflows Mermaid's caps (with a warning and truncated=true), so a rendering choice can never fail a review. render-review.sh stays one call. On real data repeated 4x with everything changed it falls back; at 2x it fits.
  • Validated in the event guard, so a typo fails in seconds rather than after an LLM run, and the failure comment shows the reason. Empty means the default, as with depth_cap.
  • Rendering only. inputs.comment_detail reaches the guard and the render step, not depth_cap, the cache keys, the engine or the stored analysis. test_comment_detail_reaches_rendering_and_nothing_else holds that in place.
  • review-preview-pr.sh is untouched: nothing reads the diagram it writes.

Known limits of specific

  • Relabels show as changes. Two of the three edges above are modified only because the LLM reworded them ("analyzes CFGs and extracts static analysis results" became "reads static analysis results and call graph structures"). The dependency did not change. The new view makes this more visible, because those edges are now most of the picture.
  • A sweeping PR is still large. The caps are the only fallback trigger, so a PR touching everything draws up to the whole leaf graph: 23 nodes and 102 edges at 16,527 characters on this analysis. That fits and would be hard to read. A readability limit would be a small follow-up if wanted.
  • Flat labels lose their parent. Nothing says which top-level component a node belongs to, and edges join by name, so two nested components sharing a name would share edges. This analysis has no duplicate names (29 components).

Verification

Tests cover the default, specific, the fallback, nothing changed, cross-parent relations, nested owners, neighbours and six invalid values. They fail against main's code. Locally, unit tests (299, with bytecode on to match CI), provider drift, the Core render step, black, shellcheck and actionlint pass.

The first version of this PR failed CI: a test read .pyc files as UTF-8, which Codex flagged, and my machine hid it by disabling bytecode. The rewritten test scans source files only.

Not tested: a real workflow run of the action end to end, or a real Java analysis (the render uses a Python repo's stored analyses, same format).

comment_detail: specific on the real pair above
graph LR
    n_Architecture_Clustering_Service["Architecture Clustering Service"]
    n_LLM_Scope_Analysis_and_Invocation["LLM Scope Analysis and Invocation"]
    n_Diagram_Generation_Orchestrator["Diagram Generation Orchestrator"]
    n_Scope_Planning_and_Assembly["Scope Planning and Assembly"]
    n_LLM_Scope_Analysis_and_Invocation -- "extracts graph nodes and edges for agent prompt…" --> n_Architecture_Clustering_Service
    n_Diagram_Generation_Orchestrator -- "reads static analysis results and call graph st…" --> n_Architecture_Clustering_Service
    n_Scope_Planning_and_Assembly -- "reads static analysis results and call graph st…" --> n_Architecture_Clustering_Service
    classDef added fill:#1f883d,stroke:#0b5d23,color:#ffffff;
    classDef modified fill:#bf8700,stroke:#7d4e00,color:#ffffff;
    classDef deleted fill:#cf222e,stroke:#82071e,color:#ffffff,stroke-dasharray:5 3;
    class n_Architecture_Clustering_Service,n_LLM_Scope_Analysis_and_Invocation,n_Diagram_Generation_Orchestrator,n_Scope_Planning_and_Assembly modified;
    linkStyle 0 stroke:#0b5d23,stroke-width:2px;
    linkStyle 1,2 stroke:#7d4e00,stroke-width:2px;
Loading

🤖 Generated with Claude Code

The comment's diagram was fixed at the top level, so on a repository with
few top-level components most changes lit up the same box. comment_depth
draws deeper levels as subgraphs; the default of 1 keeps today's diagram.

It changes rendering only: it reaches the event guard and the render step,
not depth_cap, the cache keys or the stored analysis. A bad value fails in
the guard, before any analysis is paid for. A diagram too large to draw at
the requested depth falls back to the top level with a warning rather than
failing a review whose analysis already succeeded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-02T01:20:21.894726Z 58dd77d New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@codeboarding-review

codeboarding-review Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

CodeBoarding review

Status: 1 changed component

See the full change in CodeBoarding.

graph LR
    n_action_support_scripts["action_support_scripts"]
    classDef added fill:#1f883d,stroke:#0b5d23,color:#ffffff;
    classDef modified fill:#bf8700,stroke:#7d4e00,color:#ffffff;
    classDef deleted fill:#cf222e,stroke:#82071e,color:#ffffff,stroke-dasharray:5 3;
    class n_action_support_scripts modified;
Loading

download artifacts · run 41371621823

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4b4f9d0150

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread tests/test_action_inputs.py Outdated
start = ACTION.index(identifier)
block = ACTION[start : ACTION.index("\n run:", start)]
self.assertIn("COMMENT_DEPTH: ${{ inputs.comment_depth }}", block)
readers = {p.name for p in (ROOT / "scripts").rglob("*.*") if "COMMENT_DEPTH" in p.read_text(encoding="utf-8")}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Exclude bytecode files before reading scripts as UTF-8

In the repository's python -m unittest discover -s tests -v CI job, test discovery imports test_diff_to_mermaid.py and creates scripts/__pycache__/diff_to_mermaid.*.pyc before this test runs. Because rglob("*.*") includes that binary file, read_text(encoding="utf-8") raises UnicodeDecodeError, causing the full suite to fail; restrict the scan to known text/source files or otherwise skip binary and cache files.

Useful? React with 👍 / 👎.

A free depth let the comment draw the whole nested map, which is unreadable
at comment width: labels came out at 2.6px on a real analysis. comment_detail
offers two views instead. top is today's diagram, byte for byte. specific
draws only the deepest changed components, flat, joined by the relations
that changed, with an unchanged component only where such a relation ends.

A level only holds relations with both ends inside it, so the loader now
keeps the unprojected ones: most relations cross parents and exist nowhere
else. Ownership of changed code is marked at every level, because a body
edit otherwise leaves the nested component that owns it reading as unchanged.
It stays out of diff_status, so counts and the top view do not move.

specific falls back to top when nothing changed or it overflows Mermaid's
caps. That lives in the renderer, so render-review.sh stays one call.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Svilen-Stefanov Svilen-Stefanov changed the title feat: add comment_depth input for the PR comment diagram feat: add comment_detail input for the PR comment diagram Nov 2, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 58dd77dd9e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

for name in (rel.get("src_name"), rel.get("dst_name")):
if name in known and name not in drawn:
drawn.add(name)
components.append(_flat(known[name], "unchanged"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve the actual status of relation endpoints

When a changed parent has changed descendants and a changed relation ends at that parent, _deepest_changed initially includes only the descendants, so this branch re-adds the parent but unconditionally marks it unchanged. For example, deleting a parent with children and one of its relations produces a normal, uncolored parent node attached to a red deleted edge; use the endpoint component's existing diff_status rather than forcing unchanged.

Useful? React with 👍 / 👎.


def index(comps: list) -> None:
for comp in comps:
known[_comp_name(comp)] = comp

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep component IDs when flattening duplicate names

When separate parents contain children with the same name and a changed leaf relation targets one of them, this name-only index overwrites one component with the other. The flattened renderer then resolves the relation by that duplicate name before considering its distinct component_id, so the specific diagram can omit the intended endpoint and attach the edge to the wrong component; index and track flattened endpoints by ID as well as name.

Useful? React with 👍 / 👎.

@ivanmilevtues
ivanmilevtues self-requested a review November 2, 2026 15:26
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