Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

audit D2: FAIL message enumerates 41 task ids beside a count of 33 (shared details accumulator across two severity branches)

オープン
#62 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
70/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
shell
領域
devtools

調査の方向性

Start with the D2 "Human review queue" block in agents/audit/audit.sh and trace how severity buckets build their counts and detail lists. Review the suggested per-bucket-list approach and the regression-test description; add functional coverage that extracts and runs the D2 block against synthetic queues. Done means each emitted count matches its listed IDs and the listed ages meet the stated threshold, with the full bats suite passing.

索引モデルが issue の本文から書いたものです。

説明

Context

  • Framework version: 1.6.258
  • Project: 050-email-archive (shared-tooling mode)
  • Reported: 2026-09-24T22:35:14Z

Description

Summary

agents/audit/audit.sh's D2 "Human review queue" check emits a FAIL message whose
enumerated id list does not match its own stated count, because the count is
partitioned by severity and the list is not.

Measured on a consumer project (Pen) 2026-09-25:

before:  stated_count=33  ids_listed=41  ids_under_30d=8
after:   stated_count=33  ids_listed=33  min_listed_age=39d  (threshold 30d)

Root cause

The block maintained three counters (d2_fail, d2_warn, d2_info) but one
shared detail string
d2_details, appended by both the >= 720 (FAIL, >30d)
branch and the >= 336 (WARN, 14-30d) branch:

if [ "$age_hours" -ge 720 ]; then
    d2_fail=$((d2_fail + 1))
    d2_details="$d2_details $t_id(${age_days}d)"    # <-- shared
elif [ "$age_hours" -ge 336 ]; then
    d2_warn=$((d2_warn + 1))
    d2_details="$d2_details $t_id(${age_days}d)"    # <-- same string

The FAIL emitter then interpolated that union list beside the fail-only count:

fail "D2: Human review queue - $d2_fail task(s) waiting >30d:$d2_details"

Neither predicate is wrong. The defect is that the count and the list are two
independently-maintained representations of one fact
, and only one of them is
partitioned by severity. 33 fail + 8 warn = 41 listed.

Consequence: a reader triaging "the 33 overdue tasks" works 8 tasks that are not
overdue, and the message's self-consistency cannot be relied on for the audit's
other reported figures.

Suggested fix - the general form, not a D2-only filter

Please avoid the narrow fix of adding a >= 720 guard to the string append. That
leaves count and list still independently maintained. The shape that makes the
divergence unrepresentable is per-bucket lists with counts derived from them:

d2_fail_ids=(); d2_warn_ids=()
...
d2_fail_ids+=("$t_id(${age_days}d)")     # per severity
...
d2_fail=${#d2_fail_ids[@]}               # count DERIVED from the list
d2_warn=${#d2_warn_ids[@]}

No second number is left to drift. The same reasoning applies anywhere else in
audit.sh where a count and an enumerated list are built side by side.

Two notes from applying it:

  1. Use if-blocks, not [ "$d2_fail" -gt 0 ] && d2_fail_details=... - the
    short-circuit form returns 1 on an empty bucket, which would abort the audit if
    audit.sh is ever run under set -e.
  2. Dropping the warn ids from the FAIL output is a deliberate scope call, not a
    regression: D2 is an if/elif severity escalation that has always reported only
    the worst bucket, and its count has always been fail-only. Those ids were never
    intentionally emitted there.

Regression test

Consumer-side patch adds tests/unit/d2_review_queue.bats (9 cases). Six are
functional
, not static greps: they awk-extract the real D2 block from audit.sh
between new # D2-BLOCK-START/END markers, stub fail/warn/pass, run it against
synthetic review queues, and assert stated count == len(enumerated list) plus
"youngest listed age > stated threshold" against the message the audit would print.

A static-only test would NOT have caught this bug - the offending line was an
ordinary string interpolation with nothing greppable to forbid. Please do not adopt
the tests/unit/c001_single_emitter.bats static-pin pattern for this one. The new
test was verified to discriminate: replayed against the pre-fix block verbatim it
reports stated=3 ids_listed=5 min_listed_age=18d and both assertions fail.

Three additional static pins forbid the shared accumulator returning (no bare
d2_details outside comments; no d2_fail=$((d2_fail + 1)); the two emitters must
interpolate different variables and never each other's).

Full vendored bats suite after the change: 236 pass, 0 fail (227 before, +9).

Unrelated, found while filing this

fw upstream report --attach-patch REF builds the patch with
git diff "$attach_patch" (lib/upstream.sh:258) - a single-ref diff, i.e. working
tree vs that commit
, not the commit's own change. On any repo with unrelated
uncommitted files that silently attaches them to a public issue. It probably wants
git diff "$attach_patch~1" "$attach_patch" or git show. I dropped the flag rather
than publish unrelated working-tree content.

Context

Filed from a consumer project under a standing condition that every vendored
.agentic-framework/ patch is paired with an upstream request. Continues #57-#61.
Consumer task: T-2148, arc-009. Class concern there: the audit surface reports
figures that fail independent verification - this is the third instance (cf. #61
duplicate C-001 emitters, #57 fabric-drift false positives).


Reported via fw upstream report from field installation

主要言語
Shell
スター
16
フォーク
6
平均マージ
6時間 24分
マージ済み PR(30日)
5

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

DimitriGeelen/agentic-engineering-framework のほかの issue

DimitriGeelen/agentic-engineering-framework の issue をすべて見る

似ている issue

Shell/Bash の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。