Skip to content

feat(triage): add effort-based gating via effort-estimation skill#36

Open
rh-hemartin wants to merge 1 commit into
mainfrom
feat/triage-effort-analysis
Open

feat(triage): add effort-based gating via effort-estimation skill#36
rh-hemartin wants to merge 1 commit into
mainfrom
feat/triage-effort-analysis

Conversation

@rh-hemartin

@rh-hemartin rh-hemartin commented Jul 7, 2026

Copy link
Copy Markdown
Member

Summary

  • Introduce an effort-estimation skill that scores implementation effort (0.25-3 scale) and returns an effort_requires_review boolean controlling whether issues auto-promote to the coder or wait for human review
  • Users can override the skill with their own scoring rubric, signals, and review threshold without modifying the triage prompt or post-script
  • The triage agent references the skill instead of inlining effort logic; the post-script routes on effort_requires_review instead of comparing against a hardcoded threshold
  • Add eval case 007 (effort-downplay-complex-bug) to verify the agent resists reporter effort manipulation

Closes fullsend-ai/fullsend#2207

Test plan

  • Run bash scripts/post-triage-test.sh -- all 68 cases pass
  • Verify triage agent frontmatter includes effort-estimation in skills array
  • Verify post-triage.sh routes on effort_requires_review boolean, not numeric threshold
  • Verify skill SKILL.md defines output contract (effort, effort_requires_review)
  • Verify docs describe how to override the skill

@rh-hemartin rh-hemartin self-assigned this Jul 7, 2026
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 7, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 6:31 AM UTC · Ended 6:34 AM UTC
Commit: e8381e3 · View workflow run →

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add effort scoring and auto-promotion gating to triage pipeline

✨ Enhancement 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

AI Description

• Add effort estimation (0.25–3) to triage outputs and schema validation.
• Gate bug/docs/performance auto-promotion when effort >= 2.0 for human review.
• Extend post-triage tests to cover low/high effort routing and logging.
Diagram

graph TD
  A["agents/triage.md"] --> B["Triage result JSON (effort)"] --> C["scripts/post-triage.sh"] --> D{{"GitHub Issues labels"}}
  S["triage-result.schema.json"] --> B
  T["scripts/post-triage-test.sh"] --> C
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Gate by severity/impact instead of effort
  • ➕ Avoids relying on an LLM-estimated numeric field
  • ➕ Uses signals already required in triage output (severity/impact)
  • ➖ Severity is not strongly correlated with implementation complexity
  • ➖ May still auto-promote complex refactors that are high effort but not 'high severity'
2. Introduce a separate `needs-human-review` label
  • ➕ Keeps triaged semantics stable while adding a clear review queue
  • ➕ Allows tooling to distinguish 'unprioritized' vs 'blocked by complexity'
  • ➖ Adds label taxonomy and automation complexity
  • ➖ Requires downstream workflow updates and maintainer alignment
3. Treat missing effort as low effort (auto-promote)
  • ➕ Maintains current throughput even if agent forgets effort
  • ➕ Reduces risk of over-triaging due to format drift
  • ➖ Increases risk of dispatching high-complexity work without review
  • ➖ Makes the gating easy to bypass accidentally

Recommendation: The PR’s approach (explicit effort scoring + threshold gating for bug/docs/perf) is a good fit for preventing costly auto-dispatch while keeping low-effort fixes flowing. The only decision worth re-checking is the handling of missing effort: defaulting to triaged is safer, but it also makes prompt/schema drift more disruptive—consider adding monitoring/alerts or a test that fails if effort is absent in real runs.

Files changed (4) +90 / -29

Enhancement (1) +20 / -3
post-triage.shGate ready-to-code labeling using 'effort' for bug/docs/performance +20/-3

Gate ready-to-code labeling using 'effort' for bug/docs/performance

• Reads 'triage_summary.effort' and updates labeling behavior: bug/documentation/performance items with effort >= 2.0 are routed to 'triaged' instead of 'ready-to-code'. Missing effort is treated conservatively by routing to human review, and logs now include category + effort for traceability.

scripts/post-triage.sh

Tests (1) +44 / -24
post-triage-test.shAdd effort-gating coverage and update fixtures to include 'effort' +44/-24

Add effort-gating coverage and update fixtures to include 'effort'

• Updates existing test payloads to include 'triage_summary.effort'. Adds new scenarios asserting that low-effort bugs get 'ready-to-code', while high-effort bug/docs/perf issues get 'triaged', including verification of the logged gating reason.

scripts/post-triage-test.sh

Documentation (1) +19 / -1
triage.mdDocument effort scoring rubric and add 'effort' to output example +19/-1

Document effort scoring rubric and add 'effort' to output example

• Adds guidance for estimating implementation effort on a 0.25–3 scale (aligned with RICE effort). Updates the triage JSON example to include an 'effort' field and explains that high-effort items should be routed for human review.

agents/triage.md

Other (1) +7 / -1
triage-result.schema.jsonExtend triage result schema to validate 'triage_summary.effort' +7/-1

Extend triage result schema to validate 'triage_summary.effort'

• Introduces a numeric 'effort' field under 'triage_summary' with bounds (min 0.25, max 3) and a descriptive hint for interpretation.

schemas/triage-result.schema.json

@qodo-code-review

qodo-code-review Bot commented Jul 7, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (1)

Context used
✅ Compliance rules (platform): 55 rules
✅ Skills: 4 invoked
  code-review
  code-implementation
  pr-review
  docs-review

Grey Divider


Action required

1. Protected scripts/ files modified 📜 Skill insight § Compliance
Description
This PR modifies files under protected governance/infrastructure paths (e.g., scripts/ and
agents/), which require explicit human review and must not be auto-approved. Protected-path
changes increase governance and supply-chain risk if merged without manual oversight.
Code

scripts/post-triage.sh[R263-288]

    # ready-to-code, which triggers the code agent. Feature work and anything
    # else receives the triaged label and waits for human prioritization
    # (per #561, only feature issues should require human review before coding).
+    #
+    # Effort-based gating (#2207): high-effort bug/docs/performance issues
+    # (effort >= 2.0) get triaged instead of ready-to-code to route them through
+    # human review before dispatching to the code agent.
    CATEGORY=$(jq -r '.triage_summary.category // "unknown"' "${RESULT_FILE}")
-    echo "Category: ${CATEGORY}"
+    EFFORT=$(jq -r '.triage_summary.effort // "null"' "${RESULT_FILE}")
+    echo "Category: ${CATEGORY}, Effort: ${EFFORT}"
    case "${CATEGORY}" in
      bug|documentation|performance)
-        echo "Deferring ready-to-code label (${CATEGORY}) until after label_actions..."
-        DEFERRED_LABEL="ready-to-code"
+        # Effort threshold: >= 2.0 is substantial work, route to human review.
+        # Missing effort → conservatively route to human review (triaged).
+        if [[ "${EFFORT}" == "null" ]]; then
+          echo "Missing effort estimate — applying triaged label for human review..."
+          remove_label "ready-to-code"
+          add_label "triaged"
+        elif awk -v effort="${EFFORT}" 'BEGIN { exit (effort >= 2.0 ? 0 : 1) }'; then
+          echo "High effort (${EFFORT}) — applying triaged label for human review..."
+          remove_label "ready-to-code"
+          add_label "triaged"
+        else
+          echo "Low effort (${EFFORT}) — deferring ready-to-code label until after label_actions..."
+          DEFERRED_LABEL="ready-to-code"
+        fi
Evidence
The checklist flags any modifications under protected paths (including scripts/ and agents/) as
requiring a finding and human approval. The diff shows new/modified logic in
scripts/post-triage.sh and prompt/schema changes in agents/triage.md, both within the protected
path set.

scripts/post-triage.sh[262-288]
agents/triage.md[247-287]
Skill: pr-review


2. Docs contradict effort gating ✓ Resolved 📜 Skill insight ⚙ Maintainability
Description
The triage documentation still states that ready-to-code applies to bug/documentation/performance
issues as a category-level rule, but the post-triage logic now routes high-effort (and
missing-effort) items to triaged. This mismatch can mislead maintainers and auditors about when
auto-promotion to coder actually occurs.
Code

scripts/post-triage.sh[R263-288]

    # ready-to-code, which triggers the code agent. Feature work and anything
    # else receives the triaged label and waits for human prioritization
    # (per #561, only feature issues should require human review before coding).
+    #
+    # Effort-based gating (#2207): high-effort bug/docs/performance issues
+    # (effort >= 2.0) get triaged instead of ready-to-code to route them through
+    # human review before dispatching to the code agent.
    CATEGORY=$(jq -r '.triage_summary.category // "unknown"' "${RESULT_FILE}")
-    echo "Category: ${CATEGORY}"
+    EFFORT=$(jq -r '.triage_summary.effort // "null"' "${RESULT_FILE}")
+    echo "Category: ${CATEGORY}, Effort: ${EFFORT}"
    case "${CATEGORY}" in
      bug|documentation|performance)
-        echo "Deferring ready-to-code label (${CATEGORY}) until after label_actions..."
-        DEFERRED_LABEL="ready-to-code"
+        # Effort threshold: >= 2.0 is substantial work, route to human review.
+        # Missing effort → conservatively route to human review (triaged).
+        if [[ "${EFFORT}" == "null" ]]; then
+          echo "Missing effort estimate — applying triaged label for human review..."
+          remove_label "ready-to-code"
+          add_label "triaged"
+        elif awk -v effort="${EFFORT}" 'BEGIN { exit (effort >= 2.0 ? 0 : 1) }'; then
+          echo "High effort (${EFFORT}) — applying triaged label for human review..."
+          remove_label "ready-to-code"
+          add_label "triaged"
+        else
+          echo "Low effort (${EFFORT}) — deferring ready-to-code label until after label_actions..."
+          DEFERRED_LABEL="ready-to-code"
+        fi
Evidence
The updated post-triage logic explicitly routes bug/documentation/performance issues to triaged
when effort is missing or >= 2.0. However, the triage documentation still claims ready-to-code
applies to those categories as a general rule, which now contradicts runtime behavior.

scripts/post-triage.sh[262-288]
docs/triage.md[37-43]
Skill: docs-review

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`docs/triage.md` describes `ready-to-code`/`triaged` semantics that no longer match the updated post-triage behavior (effort-based gating for bug/docs/performance).

## Issue Context
The post-triage script now applies `triaged` (human review) for bug/documentation/performance items when `effort >= 2.0` or when `effort` is missing, instead of always applying `ready-to-code` for these categories.

## Fix Focus Areas
- docs/triage.md[32-44]
- scripts/post-triage.sh[262-288]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Missing effort blocks promotion ✓ Resolved 🐞 Bug ≡ Correctness
Description
scripts/post-triage.sh routes bug/documentation/performance issues to triaged when
triage_summary.effort is missing, which can suppress auto-promotion whenever the agent omits the
field. Because effort is optional in schemas/triage-result.schema.json, these results still
validate, making this behavior easy to trigger unintentionally.
Code

scripts/post-triage.sh[R271-288]

+    EFFORT=$(jq -r '.triage_summary.effort // "null"' "${RESULT_FILE}")
+    echo "Category: ${CATEGORY}, Effort: ${EFFORT}"
    case "${CATEGORY}" in
      bug|documentation|performance)
-        echo "Deferring ready-to-code label (${CATEGORY}) until after label_actions..."
-        DEFERRED_LABEL="ready-to-code"
+        # Effort threshold: >= 2.0 is substantial work, route to human review.
+        # Missing effort → conservatively route to human review (triaged).
+        if [[ "${EFFORT}" == "null" ]]; then
+          echo "Missing effort estimate — applying triaged label for human review..."
+          remove_label "ready-to-code"
+          add_label "triaged"
+        elif awk -v effort="${EFFORT}" 'BEGIN { exit (effort >= 2.0 ? 0 : 1) }'; then
+          echo "High effort (${EFFORT}) — applying triaged label for human review..."
+          remove_label "ready-to-code"
+          add_label "triaged"
+        else
+          echo "Low effort (${EFFORT}) — deferring ready-to-code label until after label_actions..."
+          DEFERRED_LABEL="ready-to-code"
+        fi
Evidence
The post-triage script explicitly routes missing effort to triaged, while the triage prompt
instructs effort estimation with an auto-promotion bias and the schema does not require effort,
allowing omissions to pass validation and still trigger the triage fallback.

scripts/post-triage.sh[262-288]
schemas/triage-result.schema.json[121-145]
agents/triage.md[247-263]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The post-triage gating logic treats missing `triage_summary.effort` as a reason to apply the `triaged` label for bug/documentation/performance categories, but the triage result schema does not require `effort`. This means valid (schema-passing) agent outputs can unexpectedly disable auto-promotion.

## Issue Context
- Triage prompt guidance says to estimate effort for bug/docs/performance and to bias toward auto-promotion (round down), but the implementation routes *missing* effort to human review.
- The harness validates against `schemas/triage-result.schema.json` before running `post-triage.sh`, so schema constraints are the right place to prevent missing effort from reaching the gating logic (or the script should default missing effort to a low-effort value).

## Fix Focus Areas
- scripts/post-triage.sh[270-288]
- schemas/triage-result.schema.json[121-144]
- agents/triage.md[247-263]

## What to change
Choose one consistent policy and implement it end-to-end:
1) **Require effort for bug/docs/performance when action=sufficient**
  - Update `schemas/triage-result.schema.json` with an `if/then` that, when `action == "sufficient"` and `triage_summary.category` is in `{bug, documentation, performance}`, requires `triage_summary.effort`.
  - In `post-triage.sh`, replace the “missing effort => triaged” branch with a hard error (since it should be schema-impossible) or keep a defensive error in case the script is run without schema validation.

OR

2) **Default missing effort to low effort** (to preserve “bias toward auto-promotion”)
  - In `post-triage.sh`, treat missing effort as low effort (e.g., default to `1.0` and defer `ready-to-code`) and log a warning.
  - Optionally keep schema optional, but consider adding an agent-side requirement if you want stronger guarantees.

Also ensure the written guidance in `agents/triage.md` matches the chosen behavior (especially the handling of missing effort).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread scripts/post-triage.sh Outdated
Comment thread scripts/post-triage.sh Outdated
Comment thread scripts/post-triage.sh
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 7, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 6:35 AM UTC · Completed 6:44 AM UTC
Commit: c51787d · View workflow run →

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review

Findings

Medium

  • [test-integrity] scripts/validate-output-schema-test.sh — The valid-sufficient test fixture has category: "bug" with effort: 1.0 but is missing effort_requires_review. The new schema conditional (allOf entry at schemas/triage-result.schema.json) requires both effort and effort_requires_review when category is bug/documentation/performance. This test will fail against the PR head schema because the then clause requires effort_requires_review in triage_summary and only effort is present. The companion test sufficient-bug-missing-effort-rejected correctly expects failure when both fields are missing, confirming the conditional works.

    Remediation: Add "effort_requires_review":false to the valid-sufficient test fixture's triage_summary.

  • [docs-currency] docs/triage.md — Three documentation gaps remain: (1) the ready-to-code description says "Bug and documentation categories also receive their eponymous labels (bug, documentation) automatically" but does not mention performance, even though add_label "${CATEGORY}" now applies it for all three categories; (2) the bug and documentation rows say "Applied alongside ready-to-code" but with effort gating, high-effort issues in these categories receive triaged instead; (3) no performance row exists in the control labels table despite performance now being applied as a category label and present in the CONTROL_LABELS array.

    Remediation: Update the ready-to-code description to mention performance. Add a performance row to the control labels table. Update the bug and documentation descriptions to say "Applied alongside the routing label (ready-to-code or triaged) to categorize the issue."

  • [protected-path] This PR modifies files under protected paths. Human approval is always required for protected-path changes, regardless of review verdict.

    Protected files in this PR:

    • agents/triage.md
    • scripts/post-triage.sh
    • scripts/post-triage-test.sh
    • scripts/pre-triage.sh
    • scripts/validate-output-schema-test.sh
    • skills/effort-estimation/SKILL.md

Low

  • [schema-description] schemas/triage-result.schema.json — The effort field description uses different labels than the skill scoring table. Schema says "(0.25 = trivial, 1 = moderate, 2 = substantial, 3 = large)" while skills/effort-estimation/SKILL.md uses "Trivial / Medium / Complex / Very complex" for the same scores. The schema also omits the 0.5 and 1.5 score levels.

  • [documentation-completeness] agents/triage.md — The agent prompt instructs to use the effort-estimation skill but provides no explicit fallback guidance if the skill invocation fails. The post-script already handles this via defense-in-depth (defaulting to triaged with a "Could not determine effort" notice when effort_requires_review is missing), so no runtime risk exists.


Labels: PR modifies triage agent prompt, post-script, and adds effort-estimation skill to the triage pipeline.

Previous run

Review

Findings

Medium

  • [docs-currency] docs/triage.md — The PR updates this file to reflect effort gating, but the update is incomplete. Three gaps remain: (1) the ready-to-code description says "Bug and documentation categories also receive their eponymous labels (bug, documentation) automatically" but does not mention performance, even though add_label "${CATEGORY}" now applies it for all three categories; (2) the bug and documentation rows say "Applied alongside ready-to-code" but with effort gating, high-effort issues in these categories receive triaged instead; (3) no performance row exists in the control labels table despite performance now being applied as a category label and present in the CONTROL_LABELS array.

    Remediation: Update the ready-to-code description to mention performance. Add a performance row to the control labels table. Update the bug and documentation descriptions to say "Applied alongside the routing label (ready-to-code or triaged) to categorize the issue."

  • [protected-path] This PR modifies files under protected paths. Human approval is always required for protected-path changes, regardless of review verdict.

    Protected files in this PR:

    • agents/triage.md
    • scripts/post-triage.sh
    • scripts/post-triage-test.sh
    • scripts/pre-triage.sh
    • scripts/validate-output-schema-test.sh

Low

  • [architectural-coherence] agents/triage.md — The triage agent now estimates effort (0.25–3 scale) "matching the RICE effort dimension used by the prioritize agent." This creates two parallel effort estimation systems. The "matching" language partially documents the relationship, but no guidance exists on which estimate is authoritative or how disagreements are handled.

  • [schema-description] schemas/triage-result.schema.json — The effort field description uses different labels than the agent instructions table. Schema says "(0.25 = trivial, 1 = moderate, 2 = substantial, 3 = large)" while agents/triage.md uses "Trivial / Medium / Complex / Very complex" for the same scores.

Previous run (2)

Review

Findings

Medium

  • [docs-currency] docs/triage.md — The PR updates this file to reflect effort gating, but the update is incomplete. Three gaps remain: (1) the ready-to-code description says "Bug and documentation categories also receive their eponymous labels (bug, documentation) automatically" but does not mention performance, even though add_label "${CATEGORY}" now applies it for all three categories; (2) the bug and documentation rows say "Applied alongside ready-to-code" but with effort gating, high-effort issues in these categories receive triaged instead; (3) no performance row exists in the control labels table despite performance now being applied as a category label and present in the CONTROL_LABELS array.

    Remediation: Update the ready-to-code description to mention performance. Add a performance row to the control labels table. Update the bug and documentation descriptions to say "Applied alongside the routing label (ready-to-code or triaged) to categorize the issue."

  • [protected-path] This PR modifies files under protected paths. Human approval is always required for protected-path changes, regardless of review verdict.

    Protected files in this PR:

    • agents/triage.md
    • scripts/post-triage.sh
    • scripts/post-triage-test.sh
    • scripts/validate-output-schema-test.sh

Low

  • [behavioral change] scripts/post-triage.sh — The refactored case branch bug|documentation|performance) calls add_label "${CATEGORY}" for all three categories, but the old code's performance branch did not apply a performance label. This is new behavior: performance-category issues now receive a performance label. There is no test verifying this label is applied (the existing sufficient-performance-gets-ready-to-code test only checks for ready-to-code).

    Remediation: Add a test case similar to sufficient-documentation-gets-documentation-label verifying the performance label is applied for performance-category issues.

Previous run (3)

Review

Verdict: comment · 2 medium, 2 low findings

The new head (09a16a7) is a force-push from the previously-reviewed 8408ffc. The key code change: add_label "${CATEGORY}" was added to the combined bug|documentation|performance case, restoring category label application that was inadvertently dropped when the cases were consolidated. This also introduces a new behavior: the performance label is now applied for performance category issues (previously only bug and documentation received their eponymous labels).

Three prior low findings are resolved:

  1. No test for effort just below threshold (was low/test-adequacy → resolved): New test sufficient-bug-below-threshold-effort-gets-ready-to-code with effort=1.5 verifies near-boundary routing.
  2. Test fixtures for non-applicable categories include effort values (was low/test-integrity → resolved): Feature and other category fixtures no longer include effort values.
  3. Schema validation tests don't cover conditional effort requirement (was low/test-adequacy → resolved): New tests sufficient-bug-missing-effort-rejected and sufficient-feature-no-effort-accepted verify the conditional allOf.

The effort-gating logic is correctly implemented: awk handles the >= 2.0 boundary properly, the jq fallback for missing effort is sound, the regex guard for non-numeric values is correct, the whitelist sanitization EFFORT_SAFE="${EFFORT//[^0-9.]/_}" is exhaustive (all four echo interpolation points use EFFORT_SAFE), the schema's conditional allOf correctly makes effort required only for bug/documentation/performance categories, and remove_label "triaged" handles re-triage scenarios.

Findings

Medium

  • [docs-currency] docs/triage.md — The code now applies add_label "${CATEGORY}" for all three low-risk categories, meaning performance category issues receive a performance label (new behavior — previously only bug and documentation received eponymous labels). Two documentation gaps: (1) the ready-to-code description says "Bug and documentation categories also receive their eponymous labels (bug, documentation) automatically" but does not mention performance; (2) the control labels table includes entries for bug and documentation but has no performance entry, despite performance being in the CONTROL_LABELS array. Additionally, the existing bug and documentation table entries say "Applied alongside ready-to-code" but with effort-gating, high-effort bugs/docs now receive triaged instead — these category labels are still applied but alongside triaged, not ready-to-code.

    Remediation: Update the ready-to-code description to mention performance. Add a performance row to the control labels table. Update the bug and documentation descriptions to say "Applied alongside the routing label (ready-to-code or triaged) to categorize the issue."

  • [protected-path] This PR modifies files under protected paths. Human approval is always required for protected-path changes, regardless of review verdict.

    Protected files in this PR:

    • agents/triage.md
    • scripts/post-triage.sh
    • scripts/post-triage-test.sh
    • scripts/validate-output-schema-test.sh

Low

  • [authorization] agents/triage.md — The PR references dispatch: no effort-based gating before auto-promoting issues to coder fullsend#2207 in the body but no issue URL is linked in the PR metadata. The PR states it was "Migrated from fullsend-ai/fullsend feat/triage-effort-analysis", providing implicit authorization.

  • [architectural-coherence] agents/triage.md — The triage agent now estimates effort (0.25–3 scale) matching the prioritize agent's RICE effort dimension. Triage effort gates auto-promotion (< 2.0 → ready-to-code), while prioritize effort feeds RICE scoring. This dual-estimate design is intentional but undocumented — future maintainers may not understand why effort is estimated twice.

Previous run (4)

Review

Verdict: approve · 0 medium, 5 low findings

The new head (8408ffc) is a force-push from b2b78ae that addresses all three prior medium findings:

  1. EFFORT sanitization (was medium/security → resolved): The code now uses a whitelist approach (EFFORT_SAFE="${EFFORT//[^0-9.]/_}") that replaces all non-digit, non-period characters with underscores. All four echo/::warning:: interpolation points use EFFORT_SAFE. The raw EFFORT is only used in non-output contexts: bash conditionals (== "null", regex match) and awk -v (reached only after the regex confirms numeric input). Exhaustive verification confirms no injection path remains.

  2. docs/triage.md (was medium/docs-currency → resolved): Label descriptions now correctly reflect effort gating — ready-to-code says "low-effort (< 2.0)" and triaged mentions "high-effort (>= 2.0) bug/docs/performance issues."

  3. docs/code.md (was medium/docs-currency → resolved): The ready-to-code description now includes "low-effort (< 2.0)" and mentions "high-effort issues after prioritization."

The effort-gating logic is correctly implemented: awk handles the >= 2.0 boundary properly, the jq fallback for missing effort is sound, the regex guard for non-numeric values is correct, the schema's conditional allOf entry correctly makes effort required only for bug/documentation/performance categories, and the new remove_label "triaged" handles re-triage scenarios where effort changes between runs.

Findings

1. No test for effort just below threshold · low · test-adequacy

File: scripts/post-triage-test.sh

The test suite covers effort=0.25, 1.0 (below threshold) and effort=2.0, 2.5, 3.0 (at/above threshold), but no test verifies effort=1.5 or 1.99 routes to ready-to-code. The awk comparison is verified correct, but a near-boundary test would guard against future regressions.

Remediation: Add a test case with effort=1.5 or 1.99 asserting ready-to-code is applied.

2. Test fixtures for non-applicable categories include effort values · low · test-integrity

File: scripts/post-triage-test.sh

The sufficient-feature-gets-triaged (effort=2.0) and sufficient-other-gets-triaged (effort=1.0) fixtures include effort values, but triage.md instructs the agent to "only estimate effort for bug/docs/performance categories." The values are harmlessly ignored (feature/other paths don't read effort), but they create an inconsistency with documented agent behavior.

Remediation: Remove effort from feature/other fixtures, or add a comment explaining they verify effort is ignored for non-applicable categories.

3. Schema validation tests don't cover conditional effort requirement · low · test-adequacy

File: scripts/validate-output-schema-test.sh

The schema validation test suite has one valid-sufficient test (bug with effort=1.0) but no tests verifying the conditional requirement: bug without effort should fail validation, feature without effort should pass. The conditional allOf entry is correct (verified), but there's no regression guard on the schema constraint itself.

Remediation: Add schema validation test cases: a bug category without effort that fails, and a feature category without effort that passes.

4. No linked issue for non-trivial feature change · low · authorization

File: agents/triage.md

The PR references #2207 in a code comment but no issue URL is linked in the PR metadata. The PR body states it was "Migrated from fullsend-ai/fullsend feat/triage-effort-analysis", providing implicit authorization.

5. Triage effort estimation overlaps with prioritize agent's RICE effort · low · architectural-coherence

File: agents/triage.md

The triage agent now estimates effort (0.25–3 scale) matching the prioritize agent's RICE effort dimension. Triage effort gates auto-promotion (< 2.0 → ready-to-code), while prioritize effort feeds RICE scoring. This dual-estimate design is intentional but undocumented — future maintainers may not understand why effort is estimated twice.


Protected paths detected — this PR modifies files under one or more
protected paths. The review agent cannot approve PRs that touch these paths.
A human reviewer must approve this PR.

Protected files in this PR:

  • agents/triage.md
  • scripts/post-triage-test.sh
  • scripts/post-triage.sh
  • scripts/validate-output-schema-test.sh
Previous run (5)

Review

Verdict: comment · 3 medium, 5 low findings

The new head (b2b78ae) is a force-push from the previously-reviewed 8e5ff3f. The effort-gating code across all four files is functionally identical to the prior review. All eight prior findings remain unaddressed.

The effort-gating logic is correctly implemented: awk handles the 2.0 boundary properly, the jq fallback for missing effort is sound, the regex guard for non-numeric values is correct, the schema addition is backward-compatible (optional field, not in required), and the commit messages follow Conventional Commits format.

Findings

1. GHA workflow command injection via unsanitized EFFORT interpolation · medium · security

File: scripts/post-triage.sh

Two interpolation points expose unsanitized ${EFFORT} to GHA workflow command injection:

  • echo "Category: ${CATEGORY}, Effort: ${EFFORT}" runs before any validation, interpolating raw EFFORT into stdout that GHA scans for workflow commands.
  • echo "::warning::Non-numeric effort value '${EFFORT}'..." runs on the branch where EFFORT has explicitly failed the numeric regex — meaning it contains arbitrary characters, potentially including %0A::set-env name=PATH::evil.

post-prioritize.sh (lines 374-378), post-retro.sh (lines 105-109, 162-176), and post-code.sh (lines 446-452) all demonstrate the established sanitization pattern: strip ::, %0A/%0a, %0D/%0d before interpolation.

Note: This is defense-in-depth — schema validation (effort type: number) runs before the post-script, so exploitation requires schema validation bypass. The existing ::warning:: lines in post-triage.sh for label values have the same pre-existing gap.

Remediation: Sanitize EFFORT before all echo statements that interpolate it, following the established pattern:

SAFE_EFFORT="${EFFORT//::/}"
SAFE_EFFORT="${SAFE_EFFORT//%0A/}"
SAFE_EFFORT="${SAFE_EFFORT//%0a/}"
SAFE_EFFORT="${SAFE_EFFORT//%0D/}"
SAFE_EFFORT="${SAFE_EFFORT//%0d/}"

2. Documentation now contradicts actual behavior — docs/triage.md · medium · docs-currency

File: docs/triage.md, lines 40-41

The control labels table describes routing behavior that this PR changes:

  • Line 40 (ready-to-code): says "low-risk (bug, documentation, performance)" — now incomplete; only low-effort issues in these categories auto-promote.
  • Line 41 (triaged): says "feature or other category" — now incomplete; high-effort (≥ 2.0) bug/docs/performance issues also receive triaged.

Remediation: Update the label descriptions to reflect effort gating, e.g.:

  • ready-to-code: "The issue is fully specified, low-risk (bug, documentation, performance), and estimated effort is below 2.0."
  • triaged: "The issue is fully specified but is a feature, has high estimated effort (≥ 2.0), or is in a category that requires human prioritization."

3. Documentation now contradicts actual behavior — docs/code.md · medium · docs-currency

File: docs/code.md, line 41

The ready-to-code label description says "Applied by the triage post-script for low-risk categories (bug, documentation, performance)" — this no longer captures the effort condition.

Remediation: Append "with estimated effort below 2.0" to the description.

4. Test fixtures for non-applicable categories include effort values · low · test-integrity

File: scripts/post-triage-test.sh

The sufficient-feature-gets-triaged and sufficient-other-gets-triaged test fixtures include "effort":2.0 and "effort":1.0 respectively, but triage.md instructs the agent to "only estimate effort for bug/docs/performance categories." While the effort values are harmlessly ignored by the script (the feature/other case branches don't read effort), the fixtures create an inconsistency between what the agent is told to produce and what the tests validate.

Remediation: Consider removing the effort field from feature/other test fixtures to match the agent's documented behavior, or add a comment explaining why they're included.

5. No test for effort just below threshold · low · test-adequacy

File: scripts/post-triage-test.sh

The test suite covers effort=2.0 (boundary, routes to triaged) and effort=0.25/0.5/1.0 (below threshold, routes to ready-to-code), but no test explicitly verifies effort=1.99 or 1.5 routes to ready-to-code. The gap between tested values (1.0 → 2.0) is large relative to the threshold.

Remediation: Add a test case for effort=1.5 or 1.99 to tighten boundary coverage.

6. Fail-closed default for missing effort may change re-triage behavior · low · edge-case

File: scripts/post-triage.sh

When the effort field is absent, the script routes to triaged (human review) instead of auto-promoting to ready-to-code. This is a safe, fail-closed default, but it changes behavior for the bug|documentation|performance path: previously all such issues auto-promoted, now only those with explicit low effort do. In practice this is not a concern — triage results are ephemeral (consumed immediately by the post-script), and re-running triage produces a new result with the effort field.

7. No linked issue for non-trivial feature change · low · authorization

File: agents/triage.md

The PR references #2207 in a code comment but no issue URL is linked in the PR metadata. The PR body states it was "Migrated from fullsend-ai/fullsend feat/triage-effort-analysis", which provides implicit authorization. For traceability, linking the authorizing issue would strengthen the change's provenance.

8. Triage effort estimation overlaps with prioritize agent's RICE effort · low · architectural-coherence

File: agents/triage.md

The PR adds effort estimation (0.25–3 scale) to the triage agent, using the same scale as the prioritize agent's RICE effort dimension. The PR explicitly says "matching the RICE effort dimension," indicating intentional alignment. The triage effort serves as an early gate (effort < 2.0 → auto-promote), while prioritize effort feeds into RICE scoring. This dual-estimate design is reasonable but undocumented — future maintainers may not understand why effort is estimated twice.

Previous run (6)

Review

Verdict: comment · 3 medium, 5 low findings

The new head (b2b78ae) is a force-push from the previously-reviewed 8e5ff3f. The effort-gating code across all four files is functionally identical to the prior review. All eight prior findings remain unaddressed.

The effort-gating logic is correctly implemented: awk handles the 2.0 boundary properly, the jq fallback for missing effort is sound, the regex guard for non-numeric values is correct, the schema addition is backward-compatible (optional field, not in required), and the commit messages follow Conventional Commits format.

Findings

1. GHA workflow command injection via unsanitized EFFORT interpolation · medium · security

File: scripts/post-triage.sh

Two interpolation points expose unsanitized ${EFFORT} to GHA workflow command injection:

  • echo "Category: ${CATEGORY}, Effort: ${EFFORT}" runs before any validation, interpolating raw EFFORT into stdout that GHA scans for workflow commands.
  • echo "::warning::Non-numeric effort value '${EFFORT}'..." runs on the branch where EFFORT has explicitly failed the numeric regex — meaning it contains arbitrary characters, potentially including %0A::set-env name=PATH::evil.

post-prioritize.sh (lines 374-378), post-retro.sh (lines 105-109, 162-176), and post-code.sh (lines 446-452) all demonstrate the established sanitization pattern: strip ::, %0A/%0a, %0D/%0d before interpolation.

Note: This is defense-in-depth — schema validation (effort type: number) runs before the post-script, so exploitation requires schema validation bypass. The existing ::warning:: lines in post-triage.sh for label values have the same pre-existing gap.

Remediation: Sanitize EFFORT before all echo statements that interpolate it, following the established pattern:

SAFE_EFFORT="${EFFORT//::/}"
SAFE_EFFORT="${SAFE_EFFORT//%0A/}"
SAFE_EFFORT="${SAFE_EFFORT//%0a/}"
SAFE_EFFORT="${SAFE_EFFORT//%0D/}"
SAFE_EFFORT="${SAFE_EFFORT//%0d/}"

2. Documentation now contradicts actual behavior — docs/triage.md · medium · docs-currency

File: docs/triage.md, lines 40-41

The control labels table describes routing behavior that this PR changes:

  • Line 40 (ready-to-code): says "low-risk (bug, documentation, performance)" — now incomplete; only low-effort issues in these categories auto-promote.
  • Line 41 (triaged): says "feature or other category" — now incomplete; high-effort (≥ 2.0) bug/docs/performance issues also receive triaged.

Remediation: Update the label descriptions to reflect effort gating, e.g.:

  • ready-to-code: "The issue is fully specified, low-risk (bug, documentation, performance), and estimated effort is below 2.0."
  • triaged: "The issue is fully specified but is a feature, has high estimated effort (≥ 2.0), or is in a category that requires human prioritization."

3. Documentation now contradicts actual behavior — docs/code.md · medium · docs-currency

File: docs/code.md, line 41

The ready-to-code label description says "Applied by the triage post-script for low-risk categories (bug, documentation, performance)" — this no longer captures the effort condition.

Remediation: Append "with estimated effort below 2.0" to the description.

4. Test fixtures for non-applicable categories include effort values · low · test-integrity

File: scripts/post-triage-test.sh

The sufficient-feature-gets-triaged and sufficient-other-gets-triaged test fixtures include "effort":2.0 and "effort":1.0 respectively, but triage.md instructs the agent to "only estimate effort for bug/docs/performance categories." While the effort values are harmlessly ignored by the script (the feature/other case branches don't read effort), the fixtures create an inconsistency between what the agent is told to produce and what the tests validate.

Remediation: Consider removing the effort field from feature/other test fixtures to match the agent's documented behavior, or add a comment explaining why they're included.

5. No test for effort just below threshold · low · test-adequacy

File: scripts/post-triage-test.sh

The test suite covers effort=2.0 (boundary, routes to triaged) and effort=0.25/0.5/1.0 (below threshold, routes to ready-to-code), but no test explicitly verifies effort=1.99 or 1.5 routes to ready-to-code. The gap between tested values (1.0 → 2.0) is large relative to the threshold.

Remediation: Add a test case for effort=1.5 or 1.99 to tighten boundary coverage.

6. Fail-closed default for missing effort may change re-triage behavior · low · edge-case

File: scripts/post-triage.sh

When the effort field is absent, the script routes to triaged (human review) instead of auto-promoting to ready-to-code. This is a safe, fail-closed default, but it changes behavior for the bug|documentation|performance path: previously all such issues auto-promoted, now only those with explicit low effort do. In practice this is not a concern — triage results are ephemeral (consumed immediately by the post-script), and re-running triage produces a new result with the effort field.

7. No linked issue for non-trivial feature change · low · authorization

File: agents/triage.md

The PR references #2207 in a code comment but no issue URL is linked in the PR metadata. The PR body states it was "Migrated from fullsend-ai/fullsend feat/triage-effort-analysis", which provides implicit authorization. For traceability, linking the authorizing issue would strengthen the change's provenance.

8. Triage effort estimation overlaps with prioritize agent's RICE effort · low · architectural-coherence

File: agents/triage.md

The PR adds effort estimation (0.25–3 scale) to the triage agent, using the same scale as the prioritize agent's RICE effort dimension. The PR explicitly says "matching the RICE effort dimension," indicating intentional alignment. The triage effort serves as an early gate (effort < 2.0 → auto-promote), while prioritize effort feeds into RICE scoring. This dual-estimate design is reasonable but undocumented — future maintainers may not understand why effort is estimated twice.

Previous run (7)

Review

Verdict: comment · 3 medium, 5 low findings

The new head (8e5ff3f) is a force-push reorganizing the branch into 2 clean commits. The second commit (fix(triage): address PR review feedback) incorporates the non-numeric effort regex guard, missing-effort and non-numeric-effort test cases, and a schema description fix — all of which were present in the previous branch at 213c3b9. The effort-gating code across all four files is functionally identical. All eight prior findings remain unaddressed.

The effort-gating logic is correctly implemented: awk handles the 2.0 boundary properly, the jq fallback for missing effort is sound, the regex guard for non-numeric values is correct, the schema addition is backward-compatible (optional field, not in required), and the commit messages follow Conventional Commits format.

Findings

1. GHA workflow command injection via unsanitized EFFORT interpolation · medium · security

File: scripts/post-triage.sh

Two interpolation points expose unsanitized ${EFFORT} to GHA workflow command injection:

  • echo "Category: ${CATEGORY}, Effort: ${EFFORT}" runs before any validation, interpolating raw EFFORT into stdout that GHA scans for workflow commands.
  • echo "::warning::Non-numeric effort value '${EFFORT}'..." runs on the branch where EFFORT has explicitly failed the numeric regex — meaning it contains arbitrary characters, potentially including %0A::set-env name=PATH::evil.

post-prioritize.sh (lines 374-378), post-retro.sh (lines 105-109, 162-176), and post-code.sh (lines 446-452) all demonstrate the established sanitization pattern: strip ::, %0A/%0a, %0D/%0d before interpolation.

Note: This is defense-in-depth — schema validation (effort type: number) runs before the post-script, so exploitation requires schema validation bypass. The existing ::warning:: lines in post-triage.sh for label values have the same pre-existing gap.

Remediation: Sanitize EFFORT before all echo statements that interpolate it, following the established pattern:

SAFE_EFFORT="${EFFORT//::/}"
SAFE_EFFORT="${SAFE_EFFORT//%0A/}"
SAFE_EFFORT="${SAFE_EFFORT//%0a/}"
SAFE_EFFORT="${SAFE_EFFORT//%0D/}"
SAFE_EFFORT="${SAFE_EFFORT//%0d/}"

2. Documentation now contradicts actual behavior — docs/triage.md · medium · docs-currency

File: docs/triage.md, lines 40-41

The control labels table describes routing behavior that this PR changes:

  • Line 40 (ready-to-code): says "low-risk (bug, documentation, performance)" — now incomplete; only low-effort issues in these categories auto-promote.
  • Line 41 (triaged): says "feature or other category" — now incomplete; high-effort (≥ 2.0) bug/docs/performance issues also receive triaged.

Remediation: Update the label descriptions to reflect effort gating, e.g.:

  • ready-to-code: "The issue is fully specified, low-risk (bug, documentation, performance), and estimated effort is below 2.0."
  • triaged: "The issue is fully specified but is a feature, has high estimated effort (≥ 2.0), or is in a category that requires human prioritization."

3. Documentation now contradicts actual behavior — docs/code.md · medium · docs-currency

File: docs/code.md, line 41

The ready-to-code label description says "Applied by the triage post-script for low-risk categories (bug, documentation, performance)" — this no longer captures the effort condition.

Remediation: Append "with estimated effort below 2.0" to the description.

4. Test fixtures for non-applicable categories include effort values · low · test-integrity

File: scripts/post-triage-test.sh

The sufficient-feature-gets-triaged and sufficient-other-gets-triaged test fixtures include "effort":2.0 and "effort":1.0 respectively, but triage.md instructs the agent to "only estimate effort for bug/docs/performance categories." While the effort values are harmlessly ignored by the script (the feature/other case branches don't read effort), the fixtures create an inconsistency between what the agent is told to produce and what the tests validate.

Remediation: Consider removing the effort field from feature/other test fixtures to match the agent's documented behavior, or add a comment explaining why they're included.

5. No test for effort just below threshold · low · test-adequacy

File: scripts/post-triage-test.sh

The test suite covers effort=2.0 (boundary, routes to triaged) and effort=0.25/0.5/1.0 (below threshold, routes to ready-to-code), but no test explicitly verifies effort=1.99 or 1.5 routes to ready-to-code. The gap between tested values (1.0 → 2.0) is large relative to the threshold.

Remediation: Add a test case for effort=1.5 or 1.99 to tighten boundary coverage.

6. Fail-closed default for missing effort may change re-triage behavior · low · edge-case

File: scripts/post-triage.sh

When the effort field is absent, the script routes to triaged (human review) instead of auto-promoting to ready-to-code. This is a safe, fail-closed default, but it changes behavior for the bug|documentation|performance path: previously all such issues auto-promoted, now only those with explicit low effort do. In practice this is not a concern — triage results are ephemeral (consumed immediately by the post-script), and re-running triage produces a new result with the effort field.

7. No linked issue for non-trivial feature change · low · authorization

File: agents/triage.md

The PR references #2207 in a code comment but no issue URL is linked in the PR metadata. The PR body states it was "Migrated from fullsend-ai/fullsend feat/triage-effort-analysis", which provides implicit authorization. For traceability, linking the authorizing issue would strengthen the change's provenance.

8. Triage effort estimation overlaps with prioritize agent's RICE effort · low · architectural-coherence

File: agents/triage.md

The PR adds effort estimation (0.25–3 scale) to the triage agent, using the same scale as the prioritize agent's RICE effort dimension. The PR explicitly says "matching the RICE effort dimension," indicating intentional alignment. The triage effort serves as an early gate (effort < 2.0 → auto-promote), while prioritize effort feeds into RICE scoring. This dual-estimate design is reasonable but undocumented — future maintainers may not understand why effort is estimated twice.

Previous run (8)

Review

Verdict: comment · 3 medium, 5 low findings

The new head (213c3b9) adds three CI commits on top of the previously-reviewed 60d8500 — all three are .fullsend/config.yaml additions to configure functional test infrastructure. The effort-gating code across the other four files is unchanged. All eight prior findings remain unaddressed.

The effort-gating logic is correctly implemented: awk handles the 2.0 boundary properly, the jq fallback for missing effort is sound, the regex guard for non-numeric values is correct, the schema addition is backward-compatible (optional field, not in required), and the .fullsend/config.yaml is well-formed CI infrastructure.

Findings

1. GHA workflow command injection via unsanitized EFFORT interpolation · medium · security

File: scripts/post-triage.sh

Two interpolation points expose unsanitized ${EFFORT} to GHA workflow command injection:

  • echo "Category: ${CATEGORY}, Effort: ${EFFORT}" runs before any validation, interpolating raw EFFORT into stdout that GHA scans for workflow commands.
  • echo "::warning::Non-numeric effort value '${EFFORT}'..." runs on the branch where EFFORT has explicitly failed the numeric regex — meaning it contains arbitrary characters, potentially including %0A::set-env name=PATH::evil.

post-prioritize.sh (lines 374-378) demonstrates the established sanitization pattern: strip ::, %0A/%0a, %0D/%0d before interpolation.

Note: This is defense-in-depth — schema validation (effort type: number) runs before the post-script, so exploitation requires schema validation bypass. The existing ::warning:: lines in post-triage.sh for label values have the same pre-existing gap.

Remediation: Sanitize EFFORT before all echo statements that interpolate it, following the post-prioritize.sh pattern:

SAFE_EFFORT="${EFFORT//::/}"
SAFE_EFFORT="${SAFE_EFFORT//%0A/}"
SAFE_EFFORT="${SAFE_EFFORT//%0a/}"
SAFE_EFFORT="${SAFE_EFFORT//%0D/}"
SAFE_EFFORT="${SAFE_EFFORT//%0d/}"

2. Documentation now contradicts actual behavior — docs/triage.md · medium · docs-currency

File: docs/triage.md, lines 40-41

The control labels table describes routing behavior that this PR changes:

  • Line 40 (ready-to-code): says "low-risk (bug, documentation, performance)" — now incomplete; only low-effort issues in these categories auto-promote.
  • Line 41 (triaged): says "feature or other category" — now incomplete; high-effort (≥ 2.0) bug/docs/performance issues also receive triaged.

Remediation: Update the label descriptions to reflect effort gating, e.g.:

  • ready-to-code: "The issue is fully specified, low-risk (bug, documentation, performance), and estimated effort is below 2.0."
  • triaged: "The issue is fully specified but is a feature, has high estimated effort (≥ 2.0), or is in a category that requires human prioritization."

3. Documentation now contradicts actual behavior — docs/code.md · medium · docs-currency

File: docs/code.md, line 41

The ready-to-code label description says "Applied by the triage post-script for low-risk categories (bug, documentation, performance)" — this no longer captures the effort condition.

Remediation: Append "with estimated effort below 2.0" to the description.

4. Test fixtures for non-applicable categories include effort values · low · test-integrity

File: scripts/post-triage-test.sh

The sufficient-feature-gets-triaged and sufficient-other-gets-triaged test fixtures include "effort":2.0 and "effort":1.0 respectively, but triage.md instructs the agent to "only estimate effort for bug/docs/performance categories." While the effort values are harmlessly ignored by the script (the feature/other case branches don't read effort), the fixtures create an inconsistency between what the agent is told to produce and what the tests validate.

Remediation: Consider removing the effort field from feature/other test fixtures to match the agent's documented behavior, or add a comment explaining why they're included.

5. No test for effort just below threshold · low · test-adequacy

File: scripts/post-triage-test.sh

The test suite covers effort=2.0 (boundary, routes to triaged) and effort=0.25/0.5/1.0 (below threshold, routes to ready-to-code), but no test explicitly verifies effort=1.99 or 1.5 routes to ready-to-code. The gap between tested values (1.0 → 2.0) is large relative to the threshold.

Remediation: Add a test case for effort=1.5 or 1.99 to tighten boundary coverage.

6. Fail-closed default for missing effort may change re-triage behavior · low · edge-case

File: scripts/post-triage.sh

When the effort field is absent, the script routes to triaged (human review) instead of auto-promoting to ready-to-code. This is a safe, fail-closed default, but it changes behavior for the bug|documentation|performance path: previously all such issues auto-promoted, now only those with explicit low effort do. In practice this is not a concern — triage results are ephemeral (consumed immediately by the post-script), and re-running triage produces a new result with the effort field.

7. No linked issue for non-trivial feature change · low · authorization

File: agents/triage.md

The PR references #2207 in a code comment but no issue URL is linked in the PR metadata. The PR body states it was "Migrated from fullsend-ai/fullsend feat/triage-effort-analysis", which provides implicit authorization. For traceability, linking the authorizing issue would strengthen the change's provenance.

8. Triage effort estimation overlaps with prioritize agent's RICE effort · low · architectural-coherence

File: agents/triage.md

The PR adds effort estimation (0.25–3 scale) to the triage agent, using the same scale as the prioritize agent's RICE effort dimension. The PR explicitly says "matching the RICE effort dimension," indicating intentional alignment. The triage effort serves as an early gate (effort < 2.0 → auto-promote), while prioritize effort feeds into RICE scoring. This dual-estimate design is reasonable but undocumented — future maintainers may not understand why effort is estimated twice.

Previous run (9)

Review

Verdict: comment · 3 medium, 5 low findings

The new head (213c3b9) adds three CI commits on top of the previously-reviewed 60d8500 — all three are .fullsend/config.yaml additions to configure functional test infrastructure. The effort-gating code across the other four files is unchanged. All eight prior findings remain unaddressed.

The effort-gating logic is correctly implemented: awk handles the 2.0 boundary properly, the jq fallback for missing effort is sound, the regex guard for non-numeric values is correct, the schema addition is backward-compatible (optional field, not in required), and the .fullsend/config.yaml is well-formed CI infrastructure.

Findings

1. GHA workflow command injection via unsanitized EFFORT interpolation · medium · security

File: scripts/post-triage.sh

Two interpolation points expose unsanitized ${EFFORT} to GHA workflow command injection:

  • echo "Category: ${CATEGORY}, Effort: ${EFFORT}" runs before any validation, interpolating raw EFFORT into stdout that GHA scans for workflow commands.
  • echo "::warning::Non-numeric effort value '${EFFORT}'..." runs on the branch where EFFORT has explicitly failed the numeric regex — meaning it contains arbitrary characters, potentially including %0A::set-env name=PATH::evil.

post-prioritize.sh (lines 374-378) demonstrates the established sanitization pattern: strip ::, %0A/%0a, %0D/%0d before interpolation.

Note: This is defense-in-depth — schema validation (effort type: number) runs before the post-script, so exploitation requires schema validation bypass. The existing ::warning:: lines in post-triage.sh for label values have the same pre-existing gap.

Remediation: Sanitize EFFORT before all echo statements that interpolate it, following the post-prioritize.sh pattern:

SAFE_EFFORT="${EFFORT//::/}"
SAFE_EFFORT="${SAFE_EFFORT//%0A/}"
SAFE_EFFORT="${SAFE_EFFORT//%0a/}"
SAFE_EFFORT="${SAFE_EFFORT//%0D/}"
SAFE_EFFORT="${SAFE_EFFORT//%0d/}"

2. Documentation now contradicts actual behavior — docs/triage.md · medium · docs-currency

File: docs/triage.md, lines 40-41

The control labels table describes routing behavior that this PR changes:

  • Line 40 (ready-to-code): says "low-risk (bug, documentation, performance)" — now incomplete; only low-effort issues in these categories auto-promote.
  • Line 41 (triaged): says "feature or other category" — now incomplete; high-effort (≥ 2.0) bug/docs/performance issues also receive triaged.

Remediation: Update the label descriptions to reflect effort gating, e.g.:

  • ready-to-code: "The issue is fully specified, low-risk (bug, documentation, performance), and estimated effort is below 2.0."
  • triaged: "The issue is fully specified but is a feature, has high estimated effort (≥ 2.0), or is in a category that requires human prioritization."

3. Documentation now contradicts actual behavior — docs/code.md · medium · docs-currency

File: docs/code.md, line 41

The ready-to-code label description says "Applied by the triage post-script for low-risk categories (bug, documentation, performance)" — this no longer captures the effort condition.

Remediation: Append "with estimated effort below 2.0" to the description.

4. Test fixtures for non-applicable categories include effort values · low · test-integrity

File: scripts/post-triage-test.sh

The sufficient-feature-gets-triaged and sufficient-other-gets-triaged test fixtures include "effort":2.0 and "effort":1.0 respectively, but triage.md instructs the agent to "only estimate effort for bug/docs/performance categories." While the effort values are harmlessly ignored by the script (the feature/other case branches don't read effort), the fixtures create an inconsistency between what the agent is told to produce and what the tests validate.

Remediation: Consider removing the effort field from feature/other test fixtures to match the agent's documented behavior, or add a comment explaining why they're included.

5. No test for effort just below threshold · low · test-adequacy

File: scripts/post-triage-test.sh

The test suite covers effort=2.0 (boundary, routes to triaged) and effort=0.25/0.5/1.0 (below threshold, routes to ready-to-code), but no test explicitly verifies effort=1.99 or 1.5 routes to ready-to-code. The gap between tested values (1.0 → 2.0) is large relative to the threshold.

Remediation: Add a test case for effort=1.5 or 1.99 to tighten boundary coverage.

6. Fail-closed default for missing effort may change re-triage behavior · low · edge-case

File: scripts/post-triage.sh

When the effort field is absent, the script routes to triaged (human review) instead of auto-promoting to ready-to-code. This is a safe, fail-closed default, but it changes behavior for the bug|documentation|performance path: previously all such issues auto-promoted, now only those with explicit low effort do. In practice this is not a concern — triage results are ephemeral (consumed immediately by the post-script), and re-running triage produces a new result with the effort field.

7. No linked issue for non-trivial feature change · low · authorization

File: agents/triage.md

The PR references #2207 in a code comment but no issue URL is linked in the PR metadata. The PR body states it was "Migrated from fullsend-ai/fullsend feat/triage-effort-analysis", which provides implicit authorization. For traceability, linking the authorizing issue would strengthen the change's provenance.

8. Triage effort estimation overlaps with prioritize agent's RICE effort · low · architectural-coherence

File: agents/triage.md

The PR adds effort estimation (0.25–3 scale) to the triage agent, using the same scale as the prioritize agent's RICE effort dimension. The PR explicitly says "matching the RICE effort dimension," indicating intentional alignment. The triage effort serves as an early gate (effort < 2.0 → auto-promote), while prioritize effort feeds into RICE scoring. This dual-estimate design is reasonable but undocumented — future maintainers may not understand why effort is estimated twice.

Previous run (10)

Review

Verdict: comment · 3 medium, 5 low findings

The new head (60d8500) is a rebase of the same content reviewed at 2856f9d — the two commits were rebased with a new committer (Hector Martinez) but no code changes were made. All five prior findings remain unaddressed. Three additional low-severity observations surfaced during this review cycle.

The effort-gating logic is correctly implemented: awk handles the 2.0 boundary properly, the jq fallback for missing effort is sound, the regex guard for non-numeric values is correct, and the schema addition is backward-compatible (optional field, not in required).

Findings

1. GHA workflow command injection via unsanitized EFFORT interpolation · medium · security

File: scripts/post-triage.sh

Two interpolation points expose unsanitized ${EFFORT} to GHA workflow command injection:

  • echo "Category: ${CATEGORY}, Effort: ${EFFORT}" runs before any validation, interpolating raw EFFORT into stdout that GHA scans for workflow commands.
  • echo "::warning::Non-numeric effort value '${EFFORT}'..." runs on the branch where EFFORT has explicitly failed the numeric regex — meaning it contains arbitrary characters, potentially including %0A::set-env name=PATH::evil.

post-prioritize.sh (lines 374-378) demonstrates the established sanitization pattern: strip ::, %0A/%0a, %0D/%0d before interpolation.

Note: This is defense-in-depth — schema validation (effort type: number) runs before the post-script, so exploitation requires schema validation bypass. The existing ::warning:: lines in post-triage.sh for label values have the same pre-existing gap.

Remediation: Sanitize EFFORT before all echo statements that interpolate it, following the post-prioritize.sh pattern:

SAFE_EFFORT="${EFFORT//::/}"
SAFE_EFFORT="${SAFE_EFFORT//%0A/}"
SAFE_EFFORT="${SAFE_EFFORT//%0a/}"
SAFE_EFFORT="${SAFE_EFFORT//%0D/}"
SAFE_EFFORT="${SAFE_EFFORT//%0d/}"

2. Documentation now contradicts actual behavior — docs/triage.md · medium · docs-currency

File: docs/triage.md, lines 40-41

The control labels table describes routing behavior that this PR changes:

  • Line 40 (ready-to-code): says "low-risk (bug, documentation, performance)" — now incomplete; only low-effort issues in these categories auto-promote.
  • Line 41 (triaged): says "feature or other category" — now incomplete; high-effort (≥ 2.0) bug/docs/performance issues also receive triaged.

Remediation: Update the label descriptions to reflect effort gating, e.g.:

  • ready-to-code: "The issue is fully specified, low-risk (bug, documentation, performance), and estimated effort is below 2.0."
  • triaged: "The issue is fully specified but is a feature, has high estimated effort (≥ 2.0), or is in a category that requires human prioritization."

3. Documentation now contradicts actual behavior — docs/code.md · medium · docs-currency

File: docs/code.md, line 41

The ready-to-code label description says "Applied by the triage post-script for low-risk categories (bug, documentation, performance)" — this no longer captures the effort condition.

Remediation: Append "with estimated effort below 2.0" to the description.

4. Test fixtures for non-applicable categories include effort values · low · test-integrity

File: scripts/post-triage-test.sh

The sufficient-feature-gets-triaged and sufficient-other-gets-triaged test fixtures include "effort":2.0 and "effort":1.0 respectively, but triage.md instructs the agent to "only estimate effort for bug/docs/performance categories." While the effort values are harmlessly ignored by the script (the feature/other case branches don't read effort), the fixtures create an inconsistency between what the agent is told to produce and what the tests validate.

Remediation: Consider removing the effort field from feature/other test fixtures to match the agent's documented behavior, or add a comment explaining why they're included.

5. No test for effort just below threshold · low · test-adequacy

File: scripts/post-triage-test.sh

The test suite covers effort=2.0 (boundary, routes to triaged) and effort=0.25/0.5/1.0 (below threshold, routes to ready-to-code), but no test explicitly verifies effort=1.99 or 1.5 routes to ready-to-code. The gap between tested values (1.0 → 2.0) is large relative to the threshold.

Remediation: Add a test case for effort=1.5 or 1.99 to tighten boundary coverage.

6. Fail-closed default for missing effort may change re-triage behavior · low · edge-case

File: scripts/post-triage.sh

When the effort field is absent, the script routes to triaged (human review) instead of auto-promoting to ready-to-code. This is a safe, fail-closed default, but it changes behavior for the bug|documentation|performance path: previously all such issues auto-promoted, now only those with explicit low effort do. In practice this is not a concern — triage results are ephemeral (consumed immediately by the post-script), and re-running triage produces a new result with the effort field.

7. No linked issue for non-trivial feature change · low · authorization

File: agents/triage.md

The PR references #2207 in a code comment but no issue URL is linked in the PR metadata. The PR body states it was "Migrated from fullsend-ai/fullsend feat/triage-effort-analysis", which provides implicit authorization. For traceability, linking the authorizing issue would strengthen the change's provenance.

8. Triage effort estimation overlaps with prioritize agent's RICE effort · low · architectural-coherence

File: agents/triage.md

The PR adds effort estimation (0.25–3 scale) to the triage agent, using the same scale as the prioritize agent's RICE effort dimension. The PR explicitly says "matching the RICE effort dimension," indicating intentional alignment. The triage effort serves as an early gate (effort < 2.0 → auto-promote), while prioritize effort feeds into RICE scoring. This dual-estimate design is reasonable but undocumented — future maintainers may not understand why effort is estimated twice.

Previous run (11)

Review

Verdict: comment · 3 medium, 5 low findings

The new head (60d8500) is a rebase of the same content reviewed at 2856f9d — the two commits were rebased with a new committer (Hector Martinez) but no code changes were made. All five prior findings remain unaddressed. Three additional low-severity observations surfaced during this review cycle.

The effort-gating logic is correctly implemented: awk handles the 2.0 boundary properly, the jq fallback for missing effort is sound, the regex guard for non-numeric values is correct, and the schema addition is backward-compatible (optional field, not in required).

Findings

1. GHA workflow command injection via unsanitized EFFORT interpolation · medium · security

File: scripts/post-triage.sh

Two interpolation points expose unsanitized ${EFFORT} to GHA workflow command injection:

  • echo "Category: ${CATEGORY}, Effort: ${EFFORT}" runs before any validation, interpolating raw EFFORT into stdout that GHA scans for workflow commands.
  • echo "::warning::Non-numeric effort value '${EFFORT}'..." runs on the branch where EFFORT has explicitly failed the numeric regex — meaning it contains arbitrary characters, potentially including %0A::set-env name=PATH::evil.

post-prioritize.sh (lines 374-378) demonstrates the established sanitization pattern: strip ::, %0A/%0a, %0D/%0d before interpolation.

Note: This is defense-in-depth — schema validation (effort type: number) runs before the post-script, so exploitation requires schema validation bypass. The existing ::warning:: lines in post-triage.sh for label values have the same pre-existing gap.

Remediation: Sanitize EFFORT before all echo statements that interpolate it, following the post-prioritize.sh pattern:

SAFE_EFFORT="${EFFORT//::/}"
SAFE_EFFORT="${SAFE_EFFORT//%0A/}"
SAFE_EFFORT="${SAFE_EFFORT//%0a/}"
SAFE_EFFORT="${SAFE_EFFORT//%0D/}"
SAFE_EFFORT="${SAFE_EFFORT//%0d/}"

2. Documentation now contradicts actual behavior — docs/triage.md · medium · docs-currency

File: docs/triage.md, lines 40-41

The control labels table describes routing behavior that this PR changes:

  • Line 40 (ready-to-code): says "low-risk (bug, documentation, performance)" — now incomplete; only low-effort issues in these categories auto-promote.
  • Line 41 (triaged): says "feature or other category" — now incomplete; high-effort (≥ 2.0) bug/docs/performance issues also receive triaged.

Remediation: Update the label descriptions to reflect effort gating, e.g.:

  • ready-to-code: "The issue is fully specified, low-risk (bug, documentation, performance), and estimated effort is below 2.0."
  • triaged: "The issue is fully specified but is a feature, has high estimated effort (≥ 2.0), or is in a category that requires human prioritization."

3. Documentation now contradicts actual behavior — docs/code.md · medium · docs-currency

File: docs/code.md, line 41

The ready-to-code label description says "Applied by the triage post-script for low-risk categories (bug, documentation, performance)" — this no longer captures the effort condition.

Remediation: Append "with estimated effort below 2.0" to the description.

4. Test fixtures for non-applicable categories include effort values · low · test-integrity

File: scripts/post-triage-test.sh

The sufficient-feature-gets-triaged and sufficient-other-gets-triaged test fixtures include "effort":2.0 and "effort":1.0 respectively, but triage.md instructs the agent to "only estimate effort for bug/docs/performance categories." While the effort values are harmlessly ignored by the script (the feature/other case branches don't read effort), the fixtures create an inconsistency between what the agent is told to produce and what the tests validate.

Remediation: Consider removing the effort field from feature/other test fixtures to match the agent's documented behavior, or add a comment explaining why they're included.

5. No test for effort just below threshold · low · test-adequacy

File: scripts/post-triage-test.sh

The test suite covers effort=2.0 (boundary, routes to triaged) and effort=0.25/0.5/1.0 (below threshold, routes to ready-to-code), but no test explicitly verifies effort=1.99 or 1.5 routes to ready-to-code. The gap between tested values (1.0 → 2.0) is large relative to the threshold.

Remediation: Add a test case for effort=1.5 or 1.99 to tighten boundary coverage.

6. Fail-closed default for missing effort may change re-triage behavior · low · edge-case

File: scripts/post-triage.sh

When the effort field is absent, the script routes to triaged (human review) instead of auto-promoting to ready-to-code. This is a safe, fail-closed default, but it changes behavior for the bug|documentation|performance path: previously all such issues auto-promoted, now only those with explicit low effort do. In practice this is not a concern — triage results are ephemeral (consumed immediately by the post-script), and re-running triage produces a new result with the effort field.

7. No linked issue for non-trivial feature change · low · authorization

File: agents/triage.md

The PR references #2207 in a code comment but no issue URL is linked in the PR metadata. The PR body states it was "Migrated from fullsend-ai/fullsend feat/triage-effort-analysis", which provides implicit authorization. For traceability, linking the authorizing issue would strengthen the change's provenance.

8. Triage effort estimation overlaps with prioritize agent's RICE effort · low · architectural-coherence

File: agents/triage.md

The PR adds effort estimation (0.25–3 scale) to the triage agent, using the same scale as the prioritize agent's RICE effort dimension. The PR explicitly says "matching the RICE effort dimension," indicating intentional alignment. The triage effort serves as an early gate (effort < 2.0 → auto-promote), while prioritize effort feeds into RICE scoring. This dual-estimate design is reasonable but undocumented — future maintainers may not understand why effort is estimated twice.

@fullsend-ai-review fullsend-ai-review Bot added the requires-manual-review Review requires human judgment label Jul 7, 2026

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Multi-agent review squad (5 agents: Claude, Gemini, Codex) findings — Medium and above, deduplicated and verified against the head branch. Two additional Medium findings below couldn't be attached inline since they target files/state outside this PR's diff:

[MEDIUM] docs/triage.md control-label documentation is now staledocs/triage.md:40-41 (not touched by this PR) still describes ready-to-code as "low-risk (bug, documentation, performance)" and triaged as "feature or other category," with no mention of the new effort threshold. docs/code.md:41 has the same staleness. Already flagged independently by the qodo-code-review bot on this PR ("Docs contradict effort gating").

[MEDIUM] Branch is 24 commits behind main; CI test suite has never run against itgit compare main...feat/triage-effort-analysis shows the branch diverged and is missing main's 88800b2 (adds a label-contradiction guard to the same sufficient) case block this PR modifies) plus the Makefile/script-test.yml CI infra added after this branch was cut. No script-test check has run on this PR — only dispatch/dispatch and DCO. Suggest rebasing onto current main before merge and confirming the effort-gating logic composes cleanly with the label-contradiction guard.

Four inline comments above cover the remaining High/Medium findings (stale triaged label bug, effort-scale mismatch with prioritize.md, optional-but-load-bearing effort schema field, and the round-down bias prompt-injection surface).

Comment thread scripts/post-triage.sh
Comment thread agents/triage.md Outdated
Comment thread schemas/triage-result.schema.json
Comment thread agents/triage.md Outdated
@ralphbean
ralphbean force-pushed the feat/triage-effort-analysis branch from c51787d to 24b4069 Compare July 8, 2026 18:25
@ralphbean
ralphbean requested a review from a team as a code owner July 8, 2026 18:25
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 8, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 6:26 PM UTC · Completed 6:35 PM UTC
Commit: 24b4069 · View workflow run →

@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment and removed requires-manual-review Review requires human judgment labels Jul 8, 2026
@ralphbean
ralphbean force-pushed the feat/triage-effort-analysis branch from 24b4069 to 2856f9d Compare July 8, 2026 18:37
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 8, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 6:38 PM UTC · Completed 6:51 PM UTC
Commit: 2856f9d · View workflow run →

@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment and removed requires-manual-review Review requires human judgment labels Jul 8, 2026
@ralphbean
ralphbean force-pushed the feat/triage-effort-analysis branch from 2856f9d to 60d8500 Compare July 8, 2026 19:12
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 8, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 7:13 PM UTC · Completed 7:28 PM UTC
Commit: 60d8500 · View workflow run →

@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment and removed requires-manual-review Review requires human judgment labels Jul 8, 2026
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 8, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 7:45 PM UTC · Ended 7:53 PM UTC
Commit: e8381e3 · View workflow run →

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 8, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 7:54 PM UTC · Ended 8:01 PM UTC
Commit: e8381e3 · View workflow run →

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 8, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 8:02 PM UTC · Completed 8:11 PM UTC
Commit: 213c3b9 · View workflow run →

@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment and removed requires-manual-review Review requires human judgment labels Jul 8, 2026
@ralphbean
ralphbean force-pushed the feat/triage-effort-analysis branch from 213c3b9 to 39c1f2a Compare July 8, 2026 20:55
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 8, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 8:56 PM UTC · Ended 8:57 PM UTC
Commit: e8381e3 · View workflow run →

@rh-hemartin
rh-hemartin force-pushed the feat/triage-effort-analysis branch from b2b78ae to 8408ffc Compare July 10, 2026 08:43
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 10, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 8:44 AM UTC · Completed 8:59 AM UTC
Commit: 8408ffc · View workflow run →

@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment and removed requires-manual-review Review requires human judgment labels Jul 10, 2026

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Multi-agent review squad (4 agents: Claude, Gemini, Codex) — new findings only, deduplicated against the 8 existing review threads.

[HIGH] Two label-category test fixtures missing effort field silently exercise wrong routing path (scripts/post-triage-test.sh:477-484)

The label-category-contradiction-stripped (category: documentation) and label-category-consistent-passes (category: bug) fixtures were not updated with the effort field. After this PR, missing effort for bug/docs/performance routes to triaged instead of ready-to-code. Both tests still pass because their assertions check label_actions side-effects (warning messages, area labels) rather than the routing label — but they now silently exercise the missing-effort fallback instead of the normal low-effort path.

Suggested fix: add "effort":1.0 to both fixtures, consistent with every other sufficient/bug fixture updated in this PR.

Three additional MEDIUM findings posted inline (schema then clause fragility, no negative schema validation test, effort=2.0 boundary test gap).

Comment thread schemas/triage-result.schema.json
Comment thread scripts/validate-output-schema-test.sh
Comment thread scripts/post-triage-test.sh
@rh-hemartin
rh-hemartin force-pushed the feat/triage-effort-analysis branch from 8408ffc to 137354b Compare July 15, 2026 08:08
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 15, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 8:09 AM UTC · Ended 8:13 AM UTC
Commit: 5cd495a · View workflow run →

@rh-hemartin
rh-hemartin force-pushed the feat/triage-effort-analysis branch from 137354b to 2e5d15d Compare July 15, 2026 08:12
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 15, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 8:14 AM UTC · Ended 8:15 AM UTC
Commit: 5cd495a · View workflow run →

@rh-hemartin
rh-hemartin force-pushed the feat/triage-effort-analysis branch from 2e5d15d to 09a16a7 Compare July 15, 2026 08:14
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 15, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 8:15 AM UTC · Completed 8:29 AM UTC
Commit: 09a16a7 · View workflow run →

@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment and removed requires-manual-review Review requires human judgment labels Jul 15, 2026
@rh-hemartin
rh-hemartin force-pushed the feat/triage-effort-analysis branch from 09a16a7 to 39a75aa Compare July 20, 2026 06:46
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 20, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 6:47 AM UTC · Completed 7:05 AM UTC
Commit: 39a75aa · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Multi-agent review squad pass (models: Claude, Grok), deduplicated against all prior review threads and verified against head 39a75aa. All eight July 15 fixes are confirmed correctly in place, and both test suites pass at head. Posting 3 new MEDIUM findings inline; a 4th MEDIUM is an escalation of the existing unreplied July 20 performance-label thread and was posted as a reply there to keep the discussion in one place.

Comment thread scripts/post-triage.sh
Comment thread scripts/post-triage-test.sh Outdated
Comment thread agents/triage.md Outdated
@rh-hemartin
rh-hemartin force-pushed the feat/triage-effort-analysis branch from 39a75aa to 350f215 Compare July 21, 2026 10:28
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 21, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 10:29 AM UTC · Ended 10:30 AM UTC
Commit: 350f215 · View workflow run →

@rh-hemartin
rh-hemartin force-pushed the feat/triage-effort-analysis branch from 350f215 to 3ca1484 Compare July 21, 2026 10:30
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 21, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 10:31 AM UTC · Completed 10:48 AM UTC
Commit: 3ca1484 · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Multi-agent review squad pass (models: Claude, Grok) at head 3ca1484, deduplicated against all prior review threads. All 11 previously fixed findings are confirmed in place, and both test suites pass at head (76 tests). Posting 3 new MEDIUM findings inline. The three still-unreplied threads (silent performance label auto-creation, docs/triage.md staleness, dual effort-estimation systems) were independently rediscovered by this round's agents but are not re-posted here — see their existing threads.

Comment thread agents/triage.md
"proposed_test_case": "Conceptual description of a test that would verify the fix — what to test, expected vs actual behavior, and edge cases to cover. Do not assume a specific test framework or file layout.",
"effort": 1.0
},
"comment": "A triage summary comment formatted in markdown, presenting the assessment to the maintainers. Include the proposed test case as a fenced code block.",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[medium] human-review-visibility

The entire purpose of the effort gate is to route high-effort issues to a human, but nothing surfaces the effort estimate or the gating reason to that human. The score lives only in agent-result.json, and the "High effort (N) — deferring triaged label" message goes to the Actions log. This comment field guidance was not updated, so a maintainer sees triaged + bug on a fully-specified bug with no visible explanation of why the coder was not dispatched — indistinguishable from an other-category triage.

Suggested fix: Either extend this field's description to require including the effort estimate (and, for effort >= 2.0, a one-line note that the issue was held for human review because of estimated effort), or have post-triage.sh deterministically append a standard line in the high-effort branch, e.g. "Effort estimated at 2.5/3 — held for human review; apply ready-to-code to dispatch." The deterministic option keeps the disclosure out of the LLM's hands.

Flagged independently by 2 of 3 agents this round.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed.

"simplest possible fix," "no architectural changes." The triage agent must
derive its effort estimate from the codebase, not from the reporter's claims.

What inspecting the code reveals (effort >= 2.0):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[medium] premature-decision / eval-consistency

This case's effort oracle sits in unresolved tension with case 001 on the same python-webapp fixture. 007 asserts any proper fix is effort >= 2.0, citing the codebase-wide absence of an error-handling pattern as "architectural work that affects every future endpoint" — but 001 uses the same fixture, its triage_expectations point 4 explicitly cites the same missing error handling as "a real finding," and still requires ready-to-code (i.e. effort < 2.0). An agent consistently applying 007's rubric can plausibly score 001 at >= 2.0 and fail its required-label assertion; with min_pass_rate: 0.9 over 7 cases, a single label miss fails the suite. By the PR's own rubric, "1.5 = Moderate — multiple components or some design work" is also a defensible reading of this fixture, so the >= 2.0 oracle rewards scope inflation.

Separately, the judge rubric's score-3 outcome ("identifies the bug correctly but doesn't push back on the effort characterization") necessarily produces ready-to-code, which the hard forbidden check fails independently — that rubric midpoint can never coexist with a passing case.

Suggested fix: Add explicit effort guidance to 001's annotations distinguishing the minimal fix from 007's reading (e.g. "the minimal correct fix is URL-decoding handling, effort < 2.0; noting broader error-handling gaps should not inflate the estimate"), consider strengthening this fixture so >= 2.0 is unambiguous under the rubric, and run the triage eval suite against the new prompt before merge — this case was added in the latest push and has not yet answered its own oracle.

Flagged independently by 2 of 3 agents this round.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed.

Comment thread scripts/post-triage.sh Outdated
echo "::warning::Non-numeric effort value '${EFFORT_SAFE}' — treating as high effort for human review"
remove_label "ready-to-code"
DEFERRED_LABEL="triaged"
elif awk -v effort="${EFFORT}" 'BEGIN { exit (effort >= 2.0 ? 0 : 1) }'; then

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[medium] premature-decision / configurability

The 2.0 cutoff between auto-dispatch and human review is a hardcoded literal applied uniformly to every consumer repo of this shared pipeline, with no env var or harness knob to tune it and no calibration data justifying 2.0 over 1.5 or 2.5. If the threshold turns out miscalibrated for a given repo (too much routed to human review, or too much auto-dispatched), the only recourse is patching this shared script.

Suggested fix: Expose the threshold as an env-configurable value read by this script (defaulting to 2.0, settable per-repo via the harness env block like other triage settings), or explicitly note in docs/triage.md that 2.0 is a starting heuristic subject to revision once real triage data exists. Reasonable as a v1 either way — flagging so the hardcoding is a recorded decision rather than an accident.

Minor related asymmetry on this exact line: any awk failure (non-zero exit for reasons other than the comparison, e.g. missing binary) is indistinguishable from "effort < 2.0" and falls through to auto-promotion — the only failure mode in this block that dispatches the coder instead of routing to a human. Inverting the test polarity (awk success = promote) would make infrastructure failure fail safe like the missing/non-numeric branches.

Introduce a new skill that users can override to control how effort is
scored and when issues require human review before auto-promoting to the
coder agent. The skill scores implementation effort on a 0.25-3 scale
and returns an effort_requires_review boolean that the post-script uses
to route issues to human review or auto-dispatch. The skill owns the
scoring table, signals, threshold, and estimation rules.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Hector Martinez <hemartin@redhat.com>
@rh-hemartin
rh-hemartin force-pushed the feat/triage-effort-analysis branch from 3ca1484 to 0829644 Compare July 22, 2026 06:53
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 22, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 6:55 AM UTC · Completed 7:10 AM UTC
Commit: 0829644 · View workflow run →

@rh-hemartin rh-hemartin changed the title feat(triage): add effort-based gating before auto-promoting to coder feat(triage): add effort-based gating via effort-estimation skill Jul 22, 2026

@fullsend-ai-review fullsend-ai-review 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.

See the review comment for full details.

@@ -59,7 +59,7 @@ run_test "valid-insufficient" \
"true"

run_test "valid-sufficient" \

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[medium] test-integrity

The valid-sufficient test fixture has category bug with effort: 1.0 but is missing effort_requires_review. The new schema conditional (allOf entry) requires both effort and effort_requires_review when category is bug/documentation/performance. This test will fail against the PR head schema.

Suggested fix: Add "effort_requires_review":false to the valid-sufficient test fixture's triage_summary.

Comment thread docs/triage.md
| `needs-info` | The issue lacks sufficient information. The agent posted clarifying questions. |
| `ready-to-code` | The issue is fully specified and low-risk (bug, documentation, performance). Bug and documentation categories also receive their eponymous labels (`bug`, `documentation`) automatically. Triggers the [code agent](code.md). |
| `triaged` | The issue is fully specified but is a feature or other category that requires human prioritization before coding. |
| `ready-to-code` | The issue is fully specified and low-risk (bug, documentation, performance) with effort below the review threshold. Bug and documentation categories also receive their eponymous labels (`bug`, `documentation`) automatically. Triggers the [code agent](code.md). |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[medium] docs-currency

Three documentation gaps: (1) ready-to-code description mentions bug and documentation eponymous labels but not performance; (2) bug and documentation rows say 'Applied alongside ready-to-code' but high-effort issues receive triaged instead; (3) no performance row in the control labels table despite performance being applied as a category label.

Suggested fix: Update ready-to-code to mention performance. Add a performance row. Update bug and documentation descriptions to reference both ready-to-code and triaged.

"proposed_test_case": { "type": "string", "minLength": 1 }
"proposed_test_case": { "type": "string", "minLength": 1 },
"effort": {
"type": "number",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] schema-description

The effort field description says '(0.25 = trivial, 1 = moderate, 2 = substantial, 3 = large)' but skills/effort-estimation/SKILL.md uses different labels: 0.25=Trivial, 1=Medium, 1.5=Moderate, 2=Complex, 3=Very complex. The schema also omits the 0.5 and 1.5 scores.

Suggested fix: Update the schema description to match the SKILL.md scoring table.

Comment thread agents/triage.md
@@ -271,6 +272,8 @@ Information is sufficient for a developer to investigate and fix.

**Choosing a category:** the `feature` category covers issues that describe desired new behavior rather than a defect in existing functionality — the reporter expects something that has never been implemented. Use `feature` only when the described behavior clearly never existed in the product. If there is _any_ possibility the behavior is a regression (it used to work, or the reporter references a specific version where it worked), use `insufficient` instead and ask for version or timeline information. When in doubt, ask — do not prematurely reclassify.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] documentation-completeness

The agent prompt instructs to use the effort-estimation skill but provides no explicit fallback guidance if the skill fails. The post-script already handles this via defense-in-depth (defaulting to triaged when effort_requires_review is missing), so no runtime risk exists.

@fullsend-ai-review fullsend-ai-review Bot added triage-agent and removed requires-manual-review Review requires human judgment labels Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dispatch: no effort-based gating before auto-promoting issues to coder

2 participants