Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

BVP value leg scores narrative mentions as deliverables (fix + tests)

Đang mở
#53 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức phù hợp với người mới
38/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
python
Lĩnh vực
backend, testing

Hướng nghiên cứu

Start with agents/termlink/bvp-estimator/estimator.py, especially commitment_text() and the estimate_task() scoring flow; note that commitment sections must be sliced before template scaffolding is stripped. Read and run tests/test_bvp_commitment_scoping.py in the consumer repo, then check the estimator’s existing tests. Done means narrative-only mentions no longer raise scores, real commitments still score, ordering is covered, and legacy bodies remain unchanged.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Context

  • Framework version: 1.6.768
  • Project: 055-agentic-fleet-cockpit (shared-tooling mode)
  • Reported: 2026-09-21T23:03:35Z

Description

Summary

The BVP value leg scores what a task's prose mentions, not what the task
commits to deliver. A task that merely talks about a gate scores the same as
one that builds it — so the score tracks how much prose an author wrote.

This continues T-112 (which stripped template scaffolding). T-113 verified its
own premise, found the boilerplate already gone, and named the remaining defect
without filing it: "the score tracks how much prose someone wrote rather than
how much value the task carries."
This is that finding, measured and fixed.

Root cause

Every value scorer decides by trigger-phrase presence over the whole body:

has_gate = _has_any(body, [r"PreToolUse hook", r"completion gate", ...])
if has_gate:
    return 4

Run over the entire body, that cannot distinguish BUILDS-a-gate from
MENTIONS-a-gate.

Evidence (measured, not asserted)

1. Correlational — 155 tasks in a live corpus. Longest body quartile scores a
median summed D1–D4 of 3.0; shortest quartile 0.0. Pearson
r(body length, value) = +0.27. Confounded on its own: valuable tasks may
simply get written about more.

2. Causal — controlled mutation, the decisive one. Take a real task; append a
Context paragraph that mentions a completion gate, a PreToolUse hook, a
regression test, an RCA, and L-/G- references, while committing to none of
them:

CONTROL (real task)          D1-D4 = (3, 4, 0, 0)  sum = 7
MUTANT  (+narrative waffle)  D1-D4 = (4, 4, 0, 0)  sum = 8

Prose that promises nothing bought a point.

Fix

commitment_text() narrows the value leg's input to ## Acceptance Criteria
and ## Verification — the sections where a task states what it will do and how
that will be checked. Narrative sections describe; they do not promise.

Order is load-bearing. strip_template_scaffolding() deletes every column-0
# line — including the ## Acceptance Criteria heading the slice depends on.
Slicing after stripping finds no section, falls through the
backward-compatibility path, and the scoping becomes a silent no-op that still
passes a naive test
. My first version had exactly this bug; a dedicated test
now pins the ordering.

Bodies with no commitment sections (legacy tasks) are returned unchanged, so an
older corpus does not silently collapse to zero. That preserves the defect for
those tasks by design — the lesser of two harms, stated rather than hidden.

Results

before after
mutation delta (waffle) +1 0
genuine gate commitment (D1) 4 4 (unchanged — no false negative)
r(body length, value) +0.271 +0.068

Consumer's full suite: 516 passed, including 4 pre-existing estimator suites
(39 tests) as the regression net.

Limit — please read before merging

Distinct value totals went 10 → 8 and mean 2.30 → 1.46. This repairs the
signal's validity, not its spread. It does not by itself populate Q1,
and it should not be described as "BVP repaired". The remaining degeneracy has a
separate cause still to be characterised.

It is also a behavioural change to scoring semantics for every consumer:
tasks with thin acceptance criteria will score lower. That is arguably correct —
a task that does not say what it will deliver arguably should not score high
value, and G-020 already requires real ACs — but it is a judgement call for the
maintainer, not one a downstream consumer should make unilaterally.

Patch

diff --git a/agents/termlink/bvp-estimator/estimator.py b/agents/termlink/bvp-estimator/estimator.py
index d366afd..7839bf3 100644
--- a/agents/termlink/bvp-estimator/estimator.py
+++ b/agents/termlink/bvp-estimator/estimator.py
@@ -288,6 +288,57 @@ def strip_template_scaffolding(body: str) -> str:
     return "\n".join(kept)
 
 
+# ── Commitment scoping (value leg) ────────────────────────────────────────────
+_COMMITMENT_HEADINGS = ("acceptance criteria", "verification")
+
+
+def commitment_text(body: str) -> str:
+    """Keep only the sections in which a task COMMITS to deliver something.
+
+    The value scorers (score_d1 … score_d4) decide by trigger-phrase presence:
+    `_has_any(body, [r"PreToolUse hook", r"completion gate", ...])` -> 4. Run
+    over the whole body, that cannot distinguish a task that BUILDS a gate from
+    one that merely MENTIONS gates while narrating background — so the score
+    tracks how much prose an author wrote rather than how much value the task
+    carries.
+
+    Measured on this corpus before the change (155 tasks): the longest quartile
+    of task bodies scored a median summed D1-D4 of 3.0 against 0.0 for the
+    shortest, and a controlled mutation — appending a Context paragraph that
+    mentions mechanisms but promises none of them — raised a real task's D1 from
+    3 to 4. Prose that commits to nothing bought a point.
+
+    `## Acceptance Criteria` and `## Verification` are where a task states what
+    it will actually do and how that will be checked. Narrative sections
+    (`## Context`, `## Findings`, `## Decisions`, `## Updates`, `## Evolution`,
+    `## Recommendation`) describe, they do not promise.
+
+    Backward compatibility: a body with no commitment section at all (legacy
+    tasks predating the template) returns unchanged, so an older corpus does not
+    silently collapse to zero. That fallback preserves the defect for those
+    tasks by design — it is the lesser of two harms, and it is visible here
+    rather than hidden.
+    """
+    lines = body.splitlines()
+    kept: list[str] = []
+    in_commitment = False
+    found_any = False
+    for ln in lines:
+        m = re.match(r"^(#{2,3})\s+(.*)$", ln)
+        if m:
+            heading = m.group(2).strip().lower()
+            if m.group(1) == "##":
+                in_commitment = any(heading.startswith(h)
+                                    for h in _COMMITMENT_HEADINGS)
+                found_any = found_any or in_commitment
+            # A `###` under a commitment heading (### Agent / ### Human) stays.
+        if in_commitment:
+            kept.append(ln)
+    if not found_any:
+        return body
+    return "\n".join(kept)
+
+
 def score_d1_antifragility(fm: dict, body: str, tags: list[str]) -> tuple[int, list[str]]:
     """D1 — Antifragility: failure-class detection/prevention mechanisms."""
     ev: list[str] = []
@@ -2316,6 +2367,13 @@ def estimate_task(task_path: Path, drivers: dict[str, int]) -> dict:
     # resolving components from body text: the cost leg then read the very
     # boilerplate this strips. estimate_cost now strips too — keep the two in
     # step.
+    # Value leg scores COMMITMENTS, not narrative: a task that merely mentions
+    # a gate must not score as one that builds it.
+    # ORDER IS LOAD-BEARING: commitment_text() slices on `##` headings, and
+    # strip_template_scaffolding() deletes every column-0 `#` line — headings
+    # included. Slicing after stripping finds no sections, silently falls back
+    # to the whole body, and the scoping becomes a no-op. Slice first, then strip.
+    value_body = strip_template_scaffolding(commitment_text(body))
     body = strip_template_scaffolding(body)
     tags = list(fm.get("tags") or [])
     is_inception = (fm.get("workflow_type") or "").lower() == "inception"
@@ -2392,9 +2450,9 @@ def estimate_task(task_path: Path, drivers: dict[str, int]) -> dict:
         if is_inception:
             sc, ev = _score_inception_voi(fm, body, tags)
         elif driver_id in handlers:
-            sc, ev = handlers[driver_id](fm, body, tags)
+            sc, ev = handlers[driver_id](fm, value_body, tags)
         elif name_aliases.get(driver_id) in handlers:
-            sc, ev = handlers[name_aliases[driver_id]](fm, body, tags)
+            sc, ev = handlers[name_aliases[driver_id]](fm, value_body, tags)
         else:
             sc, ev = score_free_driver(driver_id, fm, body, tags)
         scores[driver_id] = sc

Regression test

Five tests, all of which fail against the pre-fix estimator. Full file at
tests/test_bvp_commitment_scoping.py in the consumer repo:

  • test_narrative_that_promises_nothing_does_not_raise_the_score — the mutation, as a standing check
  • test_a_real_commitment_still_scores — guard against a fix that zeroes everything and passes the above trivially
  • test_trigger_phrases_in_acceptance_criteria_outscore_the_same_words_in_prose — identical vocabulary, different commitment, different score
  • test_commitment_slice_must_be_taken_before_scaffolding_strip — pins the silent-no-op ordering bug
  • test_a_body_with_no_commitment_sections_is_left_alone — backward compatibility asserted, not assumed

Reported via fw upstream report from field installation

Ngôn ngữ chính
Shell
Star
16
Fork
6
Merge trung bình
6 giờ 24 phút
Pull request đã merge (30 ngày)
5

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của DimitriGeelen/agentic-engineering-framework

Tất cả issue của DimitriGeelen/agentic-engineering-framework

Issue tương tự

Thêm issue về Shell/Bash

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.