Apply Development Effort Calculator to real pilot candidates (WP-0010-T03)

Adds since/until date-range scoping to cluster_commit_hours() and
workplan_task_counts() (threaded through calculate_target_basis()),
needed whenever a candidate is one bounded workplan within a repo
whose overall history spans much more (net-kingdom, railiance-apps)
rather than the whole repo being the candidate (vergabe-teilnahme,
info-tech-canon).

Fixes a real bug found along the way: workplan_task_counts() only
scanned the top level of workplans/, missing net-kingdom's
workplans/archived/ convention entirely - silently reported zero
finished workplans for NK-WP-0002, which lives there. Fixed to scan
recursively; added a regression test.

Updates all three draft pilot-candidate manifests with calculator-
derived target_basis/initial_target values, replacing the hand-picked
placeholders:
  net-kingdom-local-identity:      200,000 -> 10,000 EUR (floor + sanity warnings)
  railiance-vergabe-teilnahme:   3,500,000 -> 648,800 EUR (no warnings)
  info-tech-canon-service-surface: 2,500,000 -> 141,800 EUR (sanity warning)

history/260730-EffortCalculator-CandidateApplication.md records full
derivation, warnings, and the judgment calls made explicit rather than
silently picked (date-scoping windows; measuring vergabe-teilnahme's
own repo rather than railiance-apps' deployment-only wiring, with both
figures shown). Still draft/non-binding - WP-0008-T05 unaffected.

5 new tests (20 -> now covering since/until scoping and the
archived-subdirectory fix). Full suite: 84 passing offline.
This commit is contained in:
tegwick 2026-07-30 13:29:06 +02:00
parent 78a5e72bbf
commit 6eec4f6634
9 changed files with 405 additions and 25 deletions

View file

@ -86,6 +86,27 @@ def test_cluster_commit_hours_gap_splits_into_two_sessions(git_repo):
# --- workplan_task_counts ------------------------------------------------
def test_workplan_task_counts_scans_archived_subdirectory(tmp_path):
archived = tmp_path / "workplans" / "archived"
archived.mkdir(parents=True)
(archived / "old-finished.md").write_text(
"""---
id: OLD-0001
status: finished
---
```task
id: OLD-0001-T01
status: done
```
"""
)
result = ec.workplan_task_counts(tmp_path)
assert result.finished_workplans == 1
assert result.total_tasks == 1
assert result.finished_tasks == 1
def test_workplan_task_counts_no_workplans_dir(tmp_path):
result = ec.workplan_task_counts(tmp_path)
assert result == ec.WorkplanTaskCounts(0, 0, 0)
@ -244,3 +265,78 @@ def test_calculate_target_basis_end_to_end(git_repo):
ec.token_cost_usd(1000, 1000), abs=0.01
)
assert isinstance(result.estimated_effort_days, float)
# --- since/until date-range scoping ---------------------------------------
def test_cluster_commit_hours_since_until_excludes_outside_window(git_repo):
_commit(git_repo, "outside-early", 1_577_836_800) # 2020-01-01
_commit(git_repo, "inside", 1_614_556_800) # 2021-03-01
_commit(git_repo, "outside-late", 1_672_531_200) # 2023-01-01
result = ec.cluster_commit_hours(git_repo, since="2021-01-01", until="2021-06-01")
assert result.commit_count == 1
def test_workplan_task_counts_since_until_filters_by_updated_date(tmp_path):
workplans = tmp_path / "workplans"
workplans.mkdir()
(workplans / "old.md").write_text(
"""---
id: OLD-0001
status: finished
updated: "2020-01-01"
---
```task
id: OLD-0001-T01
status: done
```
"""
)
(workplans / "recent.md").write_text(
"""---
id: NEW-0001
status: finished
updated: "2026-03-03"
---
```task
id: NEW-0001-T01
status: done
```
"""
)
result = ec.workplan_task_counts(tmp_path, since="2026-01-01", until="2026-06-01")
assert result.finished_workplans == 1
assert result.total_tasks == 1
def test_workplan_task_counts_no_date_field_always_counted(tmp_path):
workplans = tmp_path / "workplans"
workplans.mkdir()
(workplans / "undated.md").write_text(
"""---
id: UND-0001
status: finished
---
```task
id: UND-0001-T01
status: done
```
"""
)
result = ec.workplan_task_counts(tmp_path, since="2026-01-01", until="2026-06-01")
assert result.finished_workplans == 1
assert result.total_tasks == 1
def test_calculate_target_basis_threads_since_until(git_repo):
base = 1_577_836_800 # 2020-01-01
_commit(git_repo, "outside", base)
_commit(git_repo, "inside", base + 86400 * 400) # ~2021-02-04
result = ec.calculate_target_basis(
git_repo, daily_rate=1000.0, since="2021-01-01", until="2021-06-01"
)
assert result.derivation["commits"] == 1