fix(readiness): separate canonical buyer gaps from capability maturity - #131
Conversation
|
Warning Review limit reached
Next review available in: 56 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughCanonical buyer gap 레지스트리와 GitHub 이슈 스냅샷 검증을 추가했습니다. Buyer gap 상태를 readiness 보고서에 별도 집계하고 렌더링합니다. CI는 PR head SHA와 새 buyer-gap CLI를 사용합니다. Changes상업적 Readiness 감사
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (3)
packages/commercial-readiness/src/buyer-gaps.mjs (1)
332-334: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value초기
localeCompare정렬은 결과에 영향을 주지 않습니다.Line 332-334은
gap_id기준으로 정렬합니다. Line 354-356은 세 배열을 모두byIssue로 다시 정렬합니다. 따라서 첫 정렬은 최종 순서를 바꾸지 않습니다. 결정성은 두 번째 정렬만으로 확보됩니다. 첫 정렬을 제거하면 의도가 더 명확해집니다.♻️ 제안 리팩터
- for (const gap of [...registry.gaps].sort((left, right) => - left.gap_id.localeCompare(right.gap_id), - )) { + for (const gap of registry.gaps) {Also applies to: 352-356
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/commercial-readiness/src/buyer-gaps.mjs` around lines 332 - 334, Remove the initial gap_id localeCompare sort in the loop over registry.gaps, since the later byIssue sorting of all three arrays determines the final order. Preserve the existing byIssue sorting behavior in the arrays beginning around the later sorting block, including deterministic ordering for each result.packages/commercial-readiness/src/buyer-gaps.test.mjs (1)
35-45: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win테스트 픽스처가 실제 buyer-gap 스냅샷 계약과 다릅니다.
snapshot()헬퍼는life-os.github-snapshot.v1스키마와commit_sha,truncated,pull_requests, 이슈별title필드를 만듭니다. 실제 경로에서evaluateBuyerGaps가 받는 값은collectBuyerGapSnapshot이 반환한life-os.commercial-buyer-gap-snapshot.v1스냅샷입니다. 그 스냅샷에는title이 없고 필드 집합이 고정되어 있습니다.evaluateBuyerGaps가 입력을 검증하지 않기 때문에 이 불일치가 드러나지 않습니다.픽스처를
validateBuyerGapSnapshot을 통과한 값으로 만들면 테스트가 실제 계약을 증명합니다.♻️ 제안 리팩터
+import { validateBuyerGapSnapshot } from './buyer-gaps.mjs'; + function snapshot(issues) { - return { - schema: 'life-os.github-snapshot.v1', - repository: 'ContextualWisdomLab/life-os', - commit_sha: 'a'.repeat(40), - generated_at: '2026-08-09T11:00:00.000Z', - truncated: false, - pull_requests: [], - issues, - }; + return validateBuyerGapSnapshot({ + schema: 'life-os.commercial-buyer-gap-snapshot.v1', + repository: 'ContextualWisdomLab/life-os', + generated_at: '2026-08-09T11:00:00.000Z', + issues, + }); }각 테스트의 이슈 객체에서
title필드도 제거하십시오.validateBuyerGapSnapshot은 허용 키만 받습니다.As per path instructions: "Tests must prove realistic domain accuracy and failure behavior, not only mocked call counts."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/commercial-readiness/src/buyer-gaps.test.mjs` around lines 35 - 45, Update the snapshot() test fixture to match the life-os.commercial-buyer-gap-snapshot.v1 contract returned by collectBuyerGapSnapshot, using the fixed allowed field set and ensuring it passes validateBuyerGapSnapshot. Remove commit_sha, truncated, and pull_requests from the fixture, and remove title from every issue object so the tests exercise realistic validated buyer-gap snapshots.Source: Path instructions
packages/commercial-readiness/src/render.mjs (1)
61-73: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value목록이
maxGaps로 잘릴 때 잘림을 표시하십시오.두 루프는 각각
maxGaps항목만 출력합니다. 항목이 더 많으면 남은 gap이 조용히 사라집니다. 독자는 목록을 전체 목록으로 오해할 수 있습니다. 요약 줄의 카운트와 목록 길이가 달라집니다.♻️ 제안 리팩터
for (const gap of unknown.slice(0, maxGaps)) { lines.push( `- **${sanitizeUntrustedText(gap.gap_id)}** — ${issueLink(gap.issue_number)} — **state unknown**`, ` - Capability links: ${capabilityList(gap.capability_ids) || 'none'}`, ); } + const hidden = + Math.max(0, unresolved.length - maxGaps) + + Math.max(0, unknown.length - maxGaps); + if (hidden > 0) { + lines.push(`- … ${hidden} more registered gap(s) not shown.`); + } lines.push('');🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/commercial-readiness/src/render.mjs` around lines 61 - 73, Update the unresolved and unknown gap list rendering to indicate when slicing by maxGaps omits additional entries. After each truncated list, add a clear continuation marker or equivalent text showing how many gaps remain, while preserving the existing entries and summary counts.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/commercial-readiness/src/audit.mjs`:
- Around line 121-123: Document the evaluateCapabilities contract with JSDoc,
specifically describing the legacy report schema and summary behavior when
buyerGapEvidence is undefined, and the additional report fields and changed
summary semantics when buyerGapEvidence is provided. Place the documentation
with the function declaration and cover all relevant parameters and return-shape
differences without changing implementation behavior.
In `@packages/commercial-readiness/src/buyer-gap-report.test.mjs`:
- Line 63: Update the assertion in the buyer-gap report rendering test to match
the renderer’s actual “Unresolved canonical buyer gaps:” output, so the test
fails when registered open gaps are incorrectly reported as zero. Keep the
assertion focused on the issue `#21` failure behavior rather than the nonexistent
“Unresolved buyer gaps:” wording.
In `@packages/commercial-readiness/src/buyer-gaps.mjs`:
- Line 187: Update the generated_at validation in the buyer-gap validation flow
and the corresponding check in collectBuyerGapSnapshot to first require a string
before calling Date.parse. Preserve the existing invalid-date rejection and
ensure only string timestamps reach subsequent Date normalization.
---
Nitpick comments:
In `@packages/commercial-readiness/src/buyer-gaps.mjs`:
- Around line 332-334: Remove the initial gap_id localeCompare sort in the loop
over registry.gaps, since the later byIssue sorting of all three arrays
determines the final order. Preserve the existing byIssue sorting behavior in
the arrays beginning around the later sorting block, including deterministic
ordering for each result.
In `@packages/commercial-readiness/src/buyer-gaps.test.mjs`:
- Around line 35-45: Update the snapshot() test fixture to match the
life-os.commercial-buyer-gap-snapshot.v1 contract returned by
collectBuyerGapSnapshot, using the fixed allowed field set and ensuring it
passes validateBuyerGapSnapshot. Remove commit_sha, truncated, and pull_requests
from the fixture, and remove title from every issue object so the tests exercise
realistic validated buyer-gap snapshots.
In `@packages/commercial-readiness/src/render.mjs`:
- Around line 61-73: Update the unresolved and unknown gap list rendering to
indicate when slicing by maxGaps omits additional entries. After each truncated
list, add a clear continuation marker or equivalent text showing how many gaps
remain, while preserving the existing entries and summary counts.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: c4ca1a2a-d5b0-4bf5-8710-04804af1e6e2
📒 Files selected for processing (13)
.github/workflows/commercial-readiness.ymlpackages/commercial-readiness/package.jsonpackages/commercial-readiness/src/audit.mjspackages/commercial-readiness/src/buyer-gap-audit.test.mjspackages/commercial-readiness/src/buyer-gap-cli.mjspackages/commercial-readiness/src/buyer-gap-cli.test.mjspackages/commercial-readiness/src/buyer-gap-report.test.mjspackages/commercial-readiness/src/buyer-gap-validation.test.mjspackages/commercial-readiness/src/buyer-gaps.mjspackages/commercial-readiness/src/buyer-gaps.test.mjspackages/commercial-readiness/src/exact-head-workflow.test.mjspackages/commercial-readiness/src/render.mjsproduct/buyer-gaps.json
…134) * test(identity): define durable authentication-age provenance * feat(identity): preserve authentication instant in session lifecycle * feat(identity): expose credential-free authentication age * feat(identity): persist session authentication provenance * feat(identity): migrate session authentication age * test(identity): cover persisted authentication age * test(identity): prove authentication age survives PostgreSQL rotation * fix(readiness): separate canonical buyer gaps from capability maturity (#131) * test(readiness): define canonical buyer-gap registry contract * feat(readiness): evaluate canonical buyer-gap evidence * feat(readiness): register canonical buyer-visible gaps * feat(readiness): attach canonical buyer-gap evidence * feat(readiness): add live buyer-gap audit entrypoint * fix(readiness): render capability and buyer gaps separately * build(readiness): verify buyer-gap audit modules * ci(readiness): reconcile canonical buyer-gap state * test(readiness): cover bounded buyer-gap collection * test(readiness): verify separated buyer-gap reporting * test(readiness): verify buyer-gap CLI boundary * test(readiness): harden buyer-gap snapshot validation * test(readiness): preserve capability maturity under buyer-gap evidence * fix(readiness): bind audit evidence to exact PR head * test(readiness): require exact-head PR audit checkout * style(readiness): format buyer-gap renderer * test(readiness): assert canonical buyer-gap exhaustion failures * test(readiness): reject coerced buyer-gap timestamps * docs(readiness): explain capability and buyer-gap report contract * test(readiness): reject non-string buyer-gap timestamps * fix(readiness): require string buyer-gap timestamps * fix(agent): verify explicit model catalog and Compose runtime (#133) * fix(agent): verify model and compose runtime * fix(ci): use supported Compose exec TTY flag * fix(agent): allow bounded OpenCode catalog probe runtime * test(agent): avoid secret-shaped catalog fixtures * test(agent): generate an ephemeral catalog credential * test(agent): derive non-secret catalog probe value * test(agent): exercise operational OpenCode config path * fix(identity): preserve legacy session authentication lineage * test(identity): prove legacy authentication-age migration * fix(identity): narrow callback session dependency * test(identity): isolate migration regression as test code * test(identity): move migration regression under tests * test(readiness): reject malformed buyer-gap evidence * docs(readiness): explain buyer-gap renderer contracts * test(identity): require staged authentication-age validation * fix(identity): stage authentication-age constraints before validation * fix(identity): finalize validated authentication-age constraint * test(identity): verify staged authentication-age finalization * fix(readiness): validate buyer-gap evidence boundary * test(identity): reject cross-boundary rotation lineage * test(identity): align invalid lineage cases with existing tenant FK * test(identity): keep migration policy regressions out of app-code scan * test(identity): remove migration contract from production source * test(identity): remove dynamic SQL from migration fixture * test(identity): clarify staged authentication migration assertions * test(identity): normalize migration layout before assertions * test(agent): resolve installed OpenCode through pnpm exec * test(identity): use neutral disposable database name * test(identity): serialize migration fixture database * test(readiness): reject malformed buyer gap items * chore(agent): restore protected-main workflow contracts * fix(readiness): validate attached buyer gap evidence * test(identity): always release migration fixture lock * docs(readiness): document buyer gap validation helpers
Intent
Fix #128 by separating configured capability-evidence maturity from the repository-owned canonical buyer-gap ledger. A product can therefore remain at
22/22configured capability maturity while still reporting open or unknown buyer-visible gaps.Test-first evidence
The first commit added RED contracts importing a deliberately missing
buyer-gaps.mjs. The runner for that predecessor head remained queued/cancelled as the branch advanced, so no predecessor-run success is claimed. The current branch now contains the causal implementation and must prove GREEN on one unchanged exact head before Ready.Implemented on this Draft
product/buyer-gaps.jsonregistry mapping durable gap IDs to canonical issue numbers and existing capability IDsopen,resolved, andunknownreconciliation semantics; fetch failures and ambiguous closed evidence fail closed tounknownsummary.unresolved_gapsas capability-evidence gapscapability_evidence_gaps,unresolved_buyer_gaps, andunknown_buyer_gap_statesreport dimensionsissues: readauthority and no inherited secretsCanonical current buyer-gap registry
data.portability-completion→data.portability-rightstoday.multi-device-sync→planning.durable-data,today.action-loopcalendar.per-user-credentials→calendar.time-blockingplugins.runtime-delivery→integrations.plugin-surfaceGuardrails
Remaining before Ready
Refs #128, #21, #55, #121, #129, #130.
Summary by CodeRabbit
새로운 기능
개선 사항