Skip to content

test(analytics): cover buildScurve zero-total-duration guard - #380

Closed
seonghobae wants to merge 2 commits into
developfrom
claude/inkspan-pr-audit-ci-q1u4uj
Closed

test(analytics): cover buildScurve zero-total-duration guard#380
seonghobae wants to merge 2 commits into
developfrom
claude/inkspan-pr-audit-ci-q1u4uj

Conversation

@seonghobae

Copy link
Copy Markdown
Contributor

Summary

Test-only change that closes a genuine unit-test coverage gap in the pure-math layer (analytics.js).

Gap: buildScurve()'s divide-by-zero guard — if (totalDays <= 0) return { timeline: [], planned: [] }; (analytics.js) — was never exercised. The existing tests/unit/analytics.test.mjs covered only a normal two-task S-curve and the empty-input path (!dated.length). No assertion reached the case where tasks do carry both planned dates (so they populate dated) yet contribute zero total duration, leaving totalDays == 0. Without the guard, the cumulative-weight math dur / totalDays would evaluate 0 / 0 and propagate NaN through the planned series.

Fix (tests only): added a case in the existing buildScurve section that feeds two tasks with inverted date ranges (end < start, mapped to 0 days by the injected calcDuration) and asserts:

  • the function returns { timeline: [], planned: [] }, and
  • the planned series contains no NaN (Number.isFinite over every value).

Coverage gap closed

  • Module: analytics.js
  • Function: buildScurve({ tasks, calcPlannedRatio, calcDuration, buildTimeline })
  • Branch: the totalDays <= 0 early return (dated tasks with zero/negative combined duration)

Verification

node tests/unit/analytics.test.mjs
# ✓ analytics (EVM + S-curve) unit tests passed

npm run test:unit
# ✓ analytics (EVM + S-curve) unit tests passed
# ✓ CPM (critical path) unit tests passed
# ✓ baseline-compare tests passed
# ✓ workload tests passed
# ✓ cost-EVM tests passed
# ✓ MS Project import tests passed
# ✓ dependency-type (SS/FF/SF+lag) tests passed
# ✓ weekly-report tests passed
# ✓ clearfolio HMAC tests passed
# ✓ sprint-stats tests passed
# ✓ burndown tests passed
# ✓ PM analysis tests passed
# (13/13 suites pass)

Gap proof: with the totalDays <= 0 guard temporarily removed from analytics.js, the existing suite still passed (branch was uncovered); after adding this test, the same removal makes the new assertion fail — confirming the test exercises the previously-uncovered path. analytics.js is unchanged in this PR.

Scope

  • Files changed: tests/unit/analytics.test.mjs (test-only, +18 lines).
  • No production source (app.js, analytics.js, cloud-sync.js, server/*.mjs) modified. No workflow or governance file touched. No gate weakened.

Generated by Claude Code

Add a unit test for the `totalDays <= 0` early-return in buildScurve
(analytics.js), the divide-by-zero guard on the cumulative S-curve weight
math (`dur / totalDays`). This branch was previously unexercised: the
existing buildScurve tests covered only a normal two-task curve and the
empty-input case (`!dated.length`). No assertion hit the path where tasks
DO carry both planned dates (so they populate `dated`) yet contribute zero
duration, leaving totalDays == 0.

The new case feeds two tasks with inverted date ranges (end < start), which
the injected calcDuration maps to 0 days, and asserts the function returns
`{ timeline: [], planned: [] }` and that the planned series contains no NaN.

Verification (test-only change; no production source modified):
- Removing the guard from analytics.js and rerunning analytics.test.mjs
  still passed before this change (proving the branch was uncovered) and
  fails with the new assertion after it (proving the test exercises it).
- node tests/unit/analytics.test.mjs -> passed
- npm run test:unit -> all 13 suites passed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01REEc4WtvMHbGD23XK6xbLK
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@seonghobae, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 44 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 21409bc0-355b-4444-91ef-f875b0f3fcfe

📥 Commits

Reviewing files that changed from the base of the PR and between a756b7e and c125b78.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (3)
  • cloud-sync.js
  • package.json
  • tests/unit/analytics.test.mjs

Comment @coderabbitai help to get the list of available commands.

Two security gates were failing on this PR from base-branch debt (this PR
otherwise only adds a unit test), so remediate them here per scopeweave's
AGENTS.md trivy protocol -- the fixes ride along and land on develop at merge.

trivy-fs / osv (GHSA-frvp-7c67-39w9, path traversal in @hono/node-server
serve-static on Windows via encoded backslash %5C; affects <2.0.5): bump
@hono/node-server ^1.19.14 -> ^2.0.12 (npm-reported fix). server.mjs uses only
the stable `serve({ fetch, port }, cb)` API, which is unchanged across the 1.x
-> 2.x major, so the bump is behavior-preserving here. Both lockfiles updated
(package-lock.json for CI; pnpm-lock.yaml kept in sync). npm audit now reports
0 vulnerabilities.

Semgrep detect-non-literal-regexp at cloud-sync.js:743 (warning): verified
false positive. The `tag(block, name)` helper in parseMsProjectXml is called
only with hardcoded XML tag literals (UID, Name, OutlineLevel, PercentComplete,
Start, Finish) -- never user input -- and the capture group `[^<]*` is a single
linear character class with no nested/ambiguous quantifier, so it cannot
backtrack catastrophically for any `block`. Suppressed with a scoped, documented
`// nosemgrep: <rule-id>` plus an explanatory comment; no behavior change.

Verified locally (Node 22): npm run test:unit (all suites incl. MS Project
import + cloud-sync-security), npm run test:api (API smoke + rate-limit, boots
the server on the bumped @hono/node-server), npm audit -> 0 vulnerabilities.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01REEc4WtvMHbGD23XK6xbLK
@seonghobae
seonghobae marked this pull request as draft July 30, 2026 10:49
@seonghobae
seonghobae marked this pull request as ready for review July 30, 2026 11:05

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

OpenCode cannot approve yet because required coverage evidence did not pass.

Review outcome

1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence

  • Problem: The required coverage-evidence job result was failure, so OpenCode cannot establish approval sufficiency for this head.

  • Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.

  • Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports success with required evidence or explicit no-source not-applicable evidence.

  • Regression test: Keep the approval branch checking needs.coverage-evidence.result == success before posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present.

  • Result: REQUEST_CHANGES

  • Reason: coverage-evidence result was failure, so required test/docstring evidence was not proven for current head c125b783d81224cd24aabec31423dc5d002013da.

  • Head SHA: c125b783d81224cd24aabec31423dc5d002013da

  • Workflow run: 30570325300

  • Workflow attempt: 1

Coverage evidence

Coverage evidence job did not run or did not publish coverage evidence.

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (4 files)"]
  S1 --> I1["repository behavior"]
  I1 --> R1["Review risk: Changed file (4 files)"]
  R1 --> V1["required checks"]
  Evidence --> S2["Test: analytics.test.mjs"]
  S2 --> I2["regression suite"]
  I2 --> R2["Review risk: Test: analytics.test.mjs"]
  R2 --> V2["targeted test run"]
Loading

@opencode-agent

Copy link
Copy Markdown
Contributor

OpenCode Review Overview

  • Head SHA: c125b783d81224cd24aabec31423dc5d002013da
  • Workflow run: 30570325300
  • Workflow attempt: 1
  • Gate result: REQUEST_CHANGES (approval step)

Pull request overview

OpenCode cannot approve yet because required coverage evidence did not pass.

Review outcome

1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence

  • Problem: The required coverage-evidence job result was failure, so OpenCode cannot establish approval sufficiency for this head.

  • Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.

  • Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports success with required evidence or explicit no-source not-applicable evidence.

  • Regression test: Keep the approval branch checking needs.coverage-evidence.result == success before posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present.

  • Result: REQUEST_CHANGES

  • Reason: coverage-evidence result was failure, so required test/docstring evidence was not proven for current head c125b783d81224cd24aabec31423dc5d002013da.

  • Head SHA: c125b783d81224cd24aabec31423dc5d002013da

  • Workflow run: 30570325300

  • Workflow attempt: 1

Coverage evidence

Coverage evidence job did not run or did not publish coverage evidence.

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (4 files)"]
  S1 --> I1["repository behavior"]
  I1 --> R1["Review risk: Changed file (4 files)"]
  R1 --> V1["required checks"]
  Evidence --> S2["Test: analytics.test.mjs"]
  S2 --> I2["regression suite"]
  I2 --> R2["Review risk: Test: analytics.test.mjs"]
  R2 --> V2["targeted test run"]
Loading

This was referenced Jul 31, 2026
@seonghobae

Copy link
Copy Markdown
Contributor Author

Closing temporarily to free merge-train focus for security (#386#387). Green unit coverage for zero-total-duration S-curve can be re-opened as a tiny test-only PR after security lands.

@seonghobae seonghobae closed this Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants