feat(unic-pr-review): Intent Check overlay-merge helper#168
Conversation
The Intent Checker emits an intentCheck skeleton with every AC verdict hardcoded to unaddressed. Overlaying the Intent Assessor's live verdicts needs a deterministic helper so the Assessor can colour in verdicts but never add, drop, rename, or reorder ACs — and a malformed response degrades gracefully to today's all-unaddressed behaviour. Changes: - Add pure mergeIntentCheck(skeleton, assessed) in scripts/lib/intent-check-merger.mjs - Reuse isAcVerdict from review-summary-renderer as the single verdict-validation source - Pass note-bearing skeleton items through verbatim (ADR-0004 hard-stop signal) - Return skeleton unchanged on total-failure inputs (null, non-array, empty) - Add tests/intent-check-merger.test.mjs covering all 10 cases (node:test) Fixes #164 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The workflow runtime writes markdown artifacts under artifacts/ at the repo root. Prettier scanned them via "**/*.md", causing false CI failures. Adding to .prettierignore prevents this. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
🔍 Comprehensive PR ReviewPR: #168 SummaryPR #168 adds a focused, pure Verdict:
🟢 Low Issues (All optional)All 5 LOW findings recommend either keeping current behaviour or adding small test cases. No functional changes are needed. L1: Type cast on
|
Pins two graceful-degradation paths surfaced by review: - assessed item with no `verdicts` property → skeleton stands - mixed note-bearing + normal items in same skeleton → note passthrough does not block adjacent merge Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
⚡ Self-Fix Report (Aggressive)Status: COMPLETE Fixes Applied (2 total)
View all fixes
Tests Added
Test suite: 302 tests, 0 failures. Skipped (3)All three were explicitly recommended as "keep as-is" by the review agents:
Suggested Follow-up Issues
Validation✅ Type check | ✅ Lint | ✅ Tests (302 passed) Self-fix by Archon · aggressive mode · fixes pushed to |
The deepEqual on the full verdicts object already proves no extra keys exist, making the preceding Object.keys assertion redundant. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a pure, deterministic helper to overlay the Intent Assessor’s AC verdicts onto the Intent Checker’s intentCheck skeleton (skeleton remains the structural source of truth), plus unit tests to validate the merge semantics. This supports the upcoming “live” Intent Check rendering while preserving graceful degradation to today’s all-unaddressed behavior.
Changes:
- Introduces
mergeIntentCheck(skeleton, assessed)helper that overlays only valid verdicts on matchingid+ AC key and preserves note-bearing skeleton items. - Adds a dedicated
node:testsuite covering the intended acceptance criteria and edge cases. - Updates Prettier ignore rules to exclude
artifacts/.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| apps/claude-code/unic-pr-review/scripts/lib/intent-check-merger.mjs | New merge helper that overlays assessed verdicts onto the skeleton using renderer-sourced verdict validation. |
| apps/claude-code/unic-pr-review/tests/intent-check-merger.test.mjs | Unit tests for the merge helper across happy path + failure/ignore scenarios. |
| .prettierignore | Ignores artifacts/ from Prettier formatting. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ed elements Building the id->item Map via assessed.map((item) => [item.id, item]) threw a TypeError when assessed was a non-empty array containing null, undefined, or non-object elements, breaking the documented graceful- degradation goal (ADR-0011). The Map is now built defensively, including only non-null objects with a string id; malformed elements are ignored and the skeleton's unaddressed verdicts stand. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
mergeIntentCheck now returns { items, diagnostics } instead of a bare
array. diagnostics carries mechanical counts — assessedReceived, applied,
droppedElements, rejectedVerdicts, unmatchedItems — so a downstream
orchestrator can tell a genuine all-`unaddressed` assessment apart from a
silent total fallback (e.g. Assessor schema drift renaming `id`), which
otherwise render identically. Per the corrected ADR-0011 §Consequences,
structural safety is free but verdict provenance is not: the counts let
the orchestrator raise a reviewer-facing Notice on zero applied verdicts
and log a maintainer-facing stderr diagnostic on any drop.
Also folds in the toolkit-review findings on the same lines: the element
guard now narrows to a local AssessedItem type (was an over-broad
IntentCheckItem cast), the {@link AcVerdict} doc link resolves via the
@import, and a purity/no-mutation test pins the module's headline
contract. The merger stays pure and context-free (no I/O, no spawn
knowledge); input-shape detection and channel decisions live in the
orchestrator (#165).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…iewer glossary
The ADR-0011 §Consequences bullet "graceful degradation is free"
conflated two things: structural safety (a drifted-but-well-formed
response cannot corrupt the block — genuinely free, by construction) and
verdict provenance (a silent fallback to `unaddressed` is
indistinguishable, to the Reviewer, from a real "not covered" — not
free). Split into two bullets; the second specifies the merger returns
diagnostics and the orchestrator surfaces them via a Notice (zero applied)
and stderr (any drop). Reword the Decision overlay-merge bullet to the
{ items, diagnostics } contract and the merger/orchestrator seam.
Add a Reviewer glossary entry to CONTEXT.md — the sole human persona —
pinning that stderr diagnostics are not addressed to the Reviewer, so the
retired ad-hoc term "operator" does not creep back in.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
What & why
Closes #164 (parent: #160 — Intent Check verdicts are static, always
unaddressed).The Intent Checker emits an
intentCheckskeleton with every AC verdict hardcoded tounaddressed. To render live verdicts, the Intent Assessor's output must be overlaid onto that skeleton deterministically — so the Assessor can only colour in verdicts, never add, drop, rename, or reorder ACs, and a malformed/missing response degrades gracefully to today's behaviour. This PR adds that pure, isolated, fully unit-tested helper (US 13 / ADR-0011). No agent or orchestrator wiring lands here — those are separate slices.Changes
scripts/lib/intent-check-merger.mjs— puremergeIntentCheck(skeleton, assessed):id+ AC key.isAcVerdict(single source of truth — verdict set not re-defined).unaddressed.null, non-array,[]) return the skeleton unchanged — free graceful degradation.tests/intent-check-merger.test.mjs— 10node:testcases covering all 10 acceptance criteria + edge subcases.Clean-slate doctrine respected: every module re-derived from the PRD + ADR-0011; zero reference to
apps/claude-code/pr-review/.Validation
pnpm typechecknode --test tests/intent-check-merger.test.mjspnpm test(full suite)pnpm check(Biome + Prettier)🤖 Generated with Claude Code