feat(unic-spec-review): skeleton tracer bullet (classify URL, fetch page, Gaps agent, report)#210
Conversation
…age, Gaps agent, report) Wire the first end-to-end /review-spec path so a real Confluence review can run and serve as the foundation for later slices. The plugin was scaffold-only with stub commands and no test harness. Changes: - Vendor atlassian-fetch.mjs and credentials.mjs from unic-pr-review (ADR-0001 self-containment); only the missing-creds plugin name is changed - Add pure modules: args (URL + --post parsing), link-classifier (URL routing + page id extraction), report-renderer (timestamped .spec-review/ report) - Add gaps-agent (Gaps/Completeness dimension agent prompt) - Implement /review-spec S1 orchestration and register the agent in plugin.json - Restore the test harness: test/typecheck scripts, tsconfig.json, scripts/ and tests/ dirs; node:test unit tests cover every pure module with injected deps Fixes #202 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…(Windows compat)
path.split('/') is not cross-platform; Windows paths use backslash, so the
full path was returned unchanged, failing the regex assertion on Windows CI.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
🔍 Comprehensive PR ReviewPR: #210 — SummaryThe S1 skeleton is architecturally clean: ADR-0001 self-containment respected, injectable-deps pattern applied consistently, vendor copies verified, 54 tests green on macOS/Ubuntu/Windows. No blockers. The action items are a documentation refresh (three stale "scaffolding" banners), two defensive additions to Verdict:
🟠 HIGH IssuesH1 — AGENTS.md says "scaffolding only — not yet implemented"📍 The status banner still reads "not yet implemented". S1 is live. Any agent/dev reading this will believe the plugin is a stub. Fix (one line): > Status: S1 skeleton implemented (URL classify → Confluence fetch → Gaps agent → report). Full design (traversal, Figma, live-system, Approval Loop, de-dup) is specified in the [PRD](docs/issues/unic-spec-review/PRD.md) and lands in later slices.🟡 MEDIUM IssuesM1 — Single-quote shell wrapping breaks for pages with apostrophes📍
View fix (temp-file approach, mirrors unic-pr-review pattern)Write JSON to a temp file first: node -e "const{writeFileSync}=require('node:fs');writeFileSync(process.argv[1],process.argv[2])" /tmp/spec-review-report.json '<REPORT_JSON>'
REPORT_OUTPUT_DIR=".spec-review" node "${CLAUDE_PLUGIN_ROOT}/scripts/lib/report-renderer.mjs" /tmp/spec-review-report.jsonAlso update M2 —
|
| # | Issue | Location | Recommendation |
|---|---|---|---|
| L1 | AGENTS.md Commands footnote: "pnpm test/typecheck will be added later" — already added | AGENTS.md:44-46 |
Remove note; add both to Commands table |
| L2 | any type in vendored atlassian-fetch.mjs JSDoc |
:343,:497 |
Leave as-is (intentional vendor carryover) |
| L3 | Duplicate extractPageId in link-classifier + atlassian-fetch |
both files | Leave as-is (intentional per ADR-0001) |
| L4 | Jira exports in atlassian-fetch have no tests here | :428+ |
One-liner comment: "Jira path untested in unic-spec-review; coverage in unic-pr-review" |
| L5 | loadAzureCreds untested (dead code in this plugin) |
credentials.mjs:96 |
Leave as-is |
| L6 | anchor field in renderFinding not tested |
report-renderer.mjs:62 |
One test: assert > Anchor: block rendered when f.anchor truthy |
| L7 | figma.com bare domain not tested in classifyUrl |
link-classifier.mjs:67 |
One assertion: classifyUrl('https://figma.com/…') → kind: 'figma-page' |
| L8 | Three inline comments still say "Intent Checker agent" / "ADR-0004" | :81,:506,:621 |
Fix alongside M7 |
| L9 | CONTEXT.md status banner says "scaffolding — not yet implemented" | CONTEXT.md:4 |
"S1 implemented; terms marked (S1) are active" |
| L10 | README.md status banner says "scaffolding — not yet implemented" | README.md:9 |
"S1 available: single Confluence page review" |
✅ What's Good
- Vendor integrity confirmed —
atlassian-fetch.mjsdiffers fromunic-pr-reviewin exactly one line (thesetup-confluencereference).credentials.mjsis bit-for-bit identical. - New abstractions are genuinely new —
classifyUrl,parseReviewSpecArgs,renderReporthave no equivalent inunic-pr-review. No primitive duplication introduced. - ADR-0001 respected throughout — zero cross-plugin imports; all new files are
node:*only. - Injectable deps everywhere —
renderReport,collectIntent,fetchConfluencePageall accept optional deps objects. Fully testable without global mocks. collectIntentnever-throws contract is exemplary — all per-URL failures collected intoerrors[]; global cred errors use theurl === ''sentinel.- Windows fix applied cleanly —
path.split('/').pop()→path.basename()in the test; production code unchanged. - 54 tests, 0 failures on macOS, Ubuntu, and Windows.
- CHANGELOG —
## [0.1.1] — 2026-06-05✓ passesverify:changelog.
📋 Suggested Follow-up Issues (if not fixing in this PR)
| Issue Title | Priority |
|---|---|
| guard report-renderer CLI against FS errors (M2 + M3) | P2 |
| fix Step 6 shell-quoting fragility in review-spec.md (M1) | P2 |
| add missing edge-case tests: 403, unsupported URL, bad creds (M4–M6) | P2 |
| update atlassian-fetch.mjs vendor docstring for spec-review context (M7 + L8) | P3 |
Reviewed by Archon comprehensive-pr-review workflow · 5 agents · artifacts
Docs (H1, L1, L9, L10): - AGENTS.md: update status banner to S1-implemented; add pnpm test/typecheck to Commands - CONTEXT.md: update status banner to S1-implemented - README.md: replace scaffolding note with S1-available message Error handling (M2, M3): - report-renderer.mjs: add shape validation (findings, timestamp) after JSON.parse - report-renderer.mjs: wrap renderReport call in try/catch for FS errors (EPERM/ENOSPC) Shell-quoting (M1): - review-spec.md: use Write tool + argv[2] file-path approach for Step 6 - report-renderer.mjs: accept optional file path as process.argv[2] to avoid single-quote shell issues with apostrophes in page titles Tests (M4, M5, M6, L6, L7): - atlassian-fetch.test.mjs: add 403 auth-error test - atlassian-fetch.test.mjs: add unsupported URL collectIntent test - atlassian-fetch.test.mjs: add malformed creds collectIntent test - report-renderer.test.mjs: add anchor quote-block rendering test - link-classifier.test.mjs: add bare figma.com (no www) test Comments (M7, L4, L8): - atlassian-fetch.mjs: update module docstring from unic-pr-review domain vocabulary to spec-review context - atlassian-fetch.mjs: replace "Intent Checker / ADR-0004" with "Gaps agent / /review-spec command" in 3 inline comments - atlassian-fetch.mjs: add note that Jira exports are untested in this plugin Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
⚡ Self-Fix Report (Aggressive)Status: COMPLETE Fixes Applied (15 total)
View all fixes
Tests Added
Total: 59 tests (was 54) Skipped (3)
Suggested Follow-up Issues(none — all non-skipped findings addressed) Validation✅ Type check | ✅ Lint | ✅ Tests (59 passed) Self-fix by Archon · aggressive mode · fixes pushed to |
… URL parse pattern Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR turns unic-spec-review from a scaffold into a minimal end-to-end “S1 tracer bullet” for /review-spec: classify one URL, fetch one Confluence page read-only, run a single Gaps/Completeness agent, print findings, and write a durable markdown report under .spec-review/. It also restores the plugin’s local test/typecheck harness so future slices can iterate safely.
Changes:
- Added core pure modules (
args,link-classifier,report-renderer) plus a vendored Confluence fetcher (atlassian-fetch.mjs) and credential loader (credentials.mjs) to support a real S1 run. - Added
gaps-agentand registered it in the plugin manifest. - Restored
node:testcoverage for the pure modules and the Confluence page-read path, plus TypeScriptcheckJstypechecking for.mjs.
Reviewed changes
Copilot reviewed 20 out of 21 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm-lock.yaml | Adds TypeScript + Node types + shared tsconfig workspace deps for this plugin. |
| apps/claude-code/unic-spec-review/tsconfig.json | Enables repo-standard TS checkJs typechecking over scripts/ and tests/. |
| apps/claude-code/unic-spec-review/package.json | Bumps version, restores test/typecheck, adds devDeps needed for checkJs. |
| apps/claude-code/unic-spec-review/scripts/atlassian-fetch.mjs | Vendored Atlassian read fetcher; provides Confluence page fetch used by S1. |
| apps/claude-code/unic-spec-review/scripts/lib/credentials.mjs | Vendored credential loader for Confluence/Jira (+ ADO creds for future slices). |
| apps/claude-code/unic-spec-review/scripts/lib/link-classifier.mjs | Classifies pasted URLs and extracts Confluence page IDs. |
| apps/claude-code/unic-spec-review/scripts/lib/args.mjs | Parses /review-spec arguments into { urls, post }. |
| apps/claude-code/unic-spec-review/scripts/lib/report-renderer.mjs | Renders + writes timestamped markdown report (default .spec-review/). |
| apps/claude-code/unic-spec-review/commands/review-spec.md | Implements the S1 command flow as a Claude Code command script. |
| apps/claude-code/unic-spec-review/agents/gaps-agent.md | Adds the Gaps/Completeness agent prompt with JSON output contract. |
| apps/claude-code/unic-spec-review/tests/atlassian-fetch.test.mjs | Unit tests for Confluence page-read path + error mapping + credential resolution. |
| apps/claude-code/unic-spec-review/tests/credentials.test.mjs | Unit tests for env/file credential loading and malformed JSON errors. |
| apps/claude-code/unic-spec-review/tests/link-classifier.test.mjs | Unit tests for URL classification behaviors. |
| apps/claude-code/unic-spec-review/tests/args.test.mjs | Unit tests for argument parsing (--post recognition, URL extraction). |
| apps/claude-code/unic-spec-review/tests/report-renderer.test.mjs | Unit tests for report rendering + output path/slug behavior. |
| apps/claude-code/unic-spec-review/.claude-plugin/plugin.json | Registers the new agent and bumps plugin version. |
| apps/claude-code/unic-spec-review/.claude-plugin/marketplace.json | Bumps marketplace version to match plugin/package version. |
| apps/claude-code/unic-spec-review/CHANGELOG.md | Adds the 0.1.1 release entry describing S1 tracer bullet and harness restore. |
| apps/claude-code/unic-spec-review/README.md | Updates status copy to reflect S1 availability and future-slice scope. |
| apps/claude-code/unic-spec-review/AGENTS.md | Updates plugin status + documents restored test/typecheck commands. |
| apps/claude-code/unic-spec-review/CONTEXT.md | Updates vocabulary doc status note to reflect S1 being active. |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…elds Filter arg parsing and link classification to http(s) only so ftp/file/mailto tokens are dropped, and guard pageTitle/pageUrl in the report-renderer CLI entry so missing values no longer render as literal undefined. Adds node:test coverage for each path. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…urface fetch errors Write scratch report JSON into gitignored .spec-review/ instead of the POSIX-only /tmp path (breaks on Windows CI), and surface the structured errors[].kind/message from the fetch script so the real failure cause is shown. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ove em dashes Drop the render-summary.mjs, doctor.mjs, and inaccurate ADR-0001 citations from code comments, reword the CONTEXT.md status line so it no longer promises an unused (S1) per-term marking, and replace em dashes with hyphens in authored comments and messages per the org typography rule. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Close coverage gaps flagged in PR #210 review: env-over-file credential precedence and the 800-char Confluence excerpt cap. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Biome organizeImports ordering for node:test before node:url. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Why
unic-spec-reviewwas scaffold-only: stub commands, no.mjsscripts, no test harness, no real Confluence fetch or review logic. This slice (S1) wires the first end-to-end/review-specpath so a real review can run and serve as the foundation every later slice builds on. Closes #202 (Epic #200).What
The deliberately minimal tracer bullet: one source, one page, one agent. No traversal, comments, Figma, live-system, or posting.
atlassian-fetch.mjsandcredentials.mjsfromunic-pr-review(ADR-0001 self-containment). Copied verbatim; the only change is the missing-creds message pointing at/unic-spec-review:setup-confluence. Nothing is cross-imported at runtime.args— parse/review-specarguments (URL list +--postrecognition;--postis inert in S1)link-classifier— route a URL toconfluence/figma-page/figma-frame/live/unknownand extract the Confluence page idreport-renderer— render a timestamped markdown report and write it under.spec-review/(gitignored)gaps-agent— Gaps/Completeness dimension agent prompt; registered inplugin.json./review-specS1 orchestration — classify URL → fetch one Confluence page → run Gaps agent → print findings → write report. Read-only.test/typecheckscripts,tsconfig.json,scripts/+tests/dirs;node:testunit tests cover every pure module with injectedfetch/homedir/env/fs deps. The agent prompt and thin command orchestrator are not unit-tested (per AC).pnpm bump patch; CHANGELOG entry added.Validation
pnpm --filter unic-spec-review typecheckpnpm --filter unic-spec-review testpnpm --filter unic-spec-review verify:changelogpnpm check(root Biome + Prettier)Notes
LICENSEfiles were created or deleted (maintainer-managed).🤖 Generated with Claude Code