Skip to content

Deduplicate item-record casts and tighten docs/package hygiene#65

Merged
unbraind merged 2 commits into
mainfrom
chore/docs-hygiene-and-item-record-cast-dedupe
May 25, 2026
Merged

Deduplicate item-record casts and tighten docs/package hygiene#65
unbraind merged 2 commits into
mainfrom
chore/docs-hygiene-and-item-record-cast-dedupe

Conversation

@unbraind
Copy link
Copy Markdown
Owner

Summary

Two coordinated, zero-behavior-change hygiene workstreams (continuation of active work under the pm-rnpb remediation feature), each implemented by a specialized sub-agent and tracked end-to-end in the pm CLI.

1. Item-record cast dedup — pm-p5if (slice of pm-mbdu)

The repeated <x> as unknown as Record<string, unknown> type-widening casts that bridge a typed ItemMetadata into the generic record shape were scattered across the codebase. These are distinct from the runtime asRecord* guards already consolidated in pm-why9 (those validate typeof at runtime; this is a compile-time-only widening that returns the same reference).

  • New src/core/item/item-record.tstoItemRecord(item: ItemMetadata): Record<string, unknown> — one documented home for the widening.
  • Replaced 16 homogeneous casts across 13 files: append, claim, close, delete, get, list, normalize, search, update-many, update (commands) + history, replay (core).
  • Heterogeneous casts (frontMatter/normalized/event/definition/frame/plan/hit/settings) intentionally left as-is.
  • New tests/unit/item-record.spec.ts; module added to vitest include at 100% coverage.

2. Docs / packaging hygiene — pm-rjgh

  • Drop PRD.md (~117KB) from package.json files[] — it shipped to every npm install and duplicated docs/. Still tracked in the repo; no publish-files test required it.
  • Reconcile the drifted marketplace.json to the canonical .claude-plugin/marketplace.json schema (metadata.{description,version} + plugin category). The two files are now byte-identical; the claude-plugin contract + smoke assertions are unchanged and green.
  • AGENTS.md left as-is (already a low-context entrypoint deferring to docs/AGENT_GUIDE.md; its quickstart block is injector-managed).
  • The original "slim CHANGELOG" sub-goal is superseded: CHANGELOG.md is now a fully pm-changelog-generated artifact (Use pm-changelog for full historical CHANGELOG #62), regenerated here so the two new items land under [Unreleased].

Verification

  • Full release gate green: build, typecheck, docs-skills, static-quality, coverage (1740 tests / 115 files, 100%), version-policy, secret-scan, npx-smoke, package-first-dogfood, npm-pack-dry-run, compatibility, sentry-telemetry.
  • Sentry: critical=0 / high=4 (under thresholds); telemetry: finish_error_rate 2.49% (required mode, ok).
  • Manual temp-dir dogfood exercised every toItemRecord path (get --fields/claim/update/append/list/search/history/normalize/close/delete) — no broken functionality.
  • npm pack --dry-run confirms PRD.md gone and both marketplace files still shipped.

pm tracking

  • pm-p5if (closed), pm-rjgh (closed) with full resolution/expected/actual.
  • pm-mbdu kept open for the remaining work (barrel-split the 3 files still >2000 LOC: extension.ts, loader.ts, sdk/cli-contracts.ts).

🤖 Generated with Claude Code

Two coordinated, zero-behavior-change hygiene workstreams tracked under the
pm-rnpb remediation feature, delivered by specialized sub-agents.

Code dedup (pm-p5if, slice of pm-mbdu):
- Add src/core/item/item-record.ts exporting toItemRecord(item: ItemMetadata):
  Record<string, unknown> — a single documented home for the item/metadata ->
  generic-record TYPE widening that was scattered as `as unknown as
  Record<string, unknown>` across the codebase. This is distinct from the
  runtime asRecord* guards consolidated earlier in pm-why9 (those validate
  typeof at runtime; this is a compile-time-only widening returning the same
  reference).
- Replace 16 homogeneous widening casts across 13 files: append, claim, close,
  delete, get, list, normalize, search, update-many, update (commands) plus
  history and replay (core). Heterogeneous casts (frontMatter/normalized/event/
  definition/frame/plan/hit/settings) intentionally left as-is.
- Add tests/unit/item-record.spec.ts and register the module in vitest `include`
  (100% statements/branches/functions/lines).

Docs/packaging hygiene (pm-rjgh):
- Drop PRD.md (~117KB) from package.json `files[]` so it no longer ships to
  every npm install (still tracked in the repo). No publish-files test required
  it.
- Reconcile the drifted root marketplace.json to the canonical
  .claude-plugin/marketplace.json schema (metadata.{description,version} +
  plugin `category`); the two files are now byte-identical. claude-plugin
  contract + smoke assertions unchanged and green.
- AGENTS.md left as-is (already a low-context entrypoint deferring to
  docs/AGENT_GUIDE.md; its quickstart block is injector-managed).
- The "slim CHANGELOG" sub-goal is superseded: CHANGELOG.md is now a fully
  pm-changelog-generated artifact (PR #62); regenerated here so pm-p5if/pm-rjgh
  appear under [Unreleased].

Verification: full release gate green — build, typecheck, docs-skills,
static-quality, coverage (1740 tests / 115 files, 100%), version-policy,
secret-scan, npx-smoke, package-first-dogfood, npm-pack-dry-run, compatibility,
and sentry-telemetry (Sentry critical=0/high=4 under thresholds; telemetry
finish_error_rate 2.49%, required mode). Manual temp-dir dogfood exercised every
toItemRecord path (get --fields/claim/update/append/list/search/history/
normalize/close/delete) with no broken functionality.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Sorry @unbraind, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 25, 2026

Review Change Stack

Warning

Review limit reached

@unbraind, we couldn't start this review because you've used your available PR reviews for now.

Your plan includes 1 review of capacity. Refill in 35 minutes and 10 seconds.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

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

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than trial, open-source, and free plans. In all cases, review capacity refills continuously over time.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 02d8fa10-6086-4494-8212-32f3eb4cdfeb

📥 Commits

Reviewing files that changed from the base of the PR and between 94e2e2a and 1ae62cb.

📒 Files selected for processing (8)
  • .agents/pm/chores/pm-p5if.toon
  • .agents/pm/chores/pm-rjgh.toon
  • .agents/pm/features/pm-rnpb.toon
  • .agents/pm/history/pm-p5if.jsonl
  • .agents/pm/history/pm-rjgh.jsonl
  • .agents/pm/history/pm-rnpb.jsonl
  • src/cli/commands/update.ts
  • tests/integration/claude-plugin-contract.spec.ts
📝 Walkthrough

Walkthrough

This PR consolidates homogeneous ItemMetadataRecord<string, unknown> type-widening casts into a shared toItemRecord helper across 11 CLI and core history modules, adds the helper with unit tests, updates package publishing and marketplace manifest structure, and documents completion of cast-dedup and packaging-hygiene tasks.

Changes

Type-widening cast centralization

Layer / File(s) Summary
toItemRecord helper, tests, and coverage configuration
src/core/item/item-record.ts, tests/unit/item-record.spec.ts, vitest.config.ts
New toItemRecord function provides a compile-time-only type bridge from ItemMetadata to Record<string, unknown> via double cast. Unit tests verify reference identity, field exposure via generic record shape, and mutation reflection. Coverage config updated to include the helper.
CLI commands migration to toItemRecord
src/cli/commands/append.ts, src/cli/commands/claim.ts, src/cli/commands/close.ts, src/cli/commands/delete.ts, src/cli/commands/get.ts, src/cli/commands/list.ts, src/cli/commands/normalize.ts, src/cli/commands/search.ts, src/cli/commands/update-many.ts, src/cli/commands/update.ts
Ten CLI command modules replace inline type casts with toItemRecord calls when converting item/metadata to Record<string, unknown> for return values and internal field-access logic. No exported signatures changed.
Core history modules migration to toItemRecord
src/core/history/history.ts, src/core/history/replay.ts
History canonicalization functions (canonicalHashDocument, canonicalPatchDocument, replay metadata normalization) import and use toItemRecord before front-matter key ordering, replacing explicit record type casts.

Publishing and marketplace updates

Layer / File(s) Summary
Package publishing and marketplace schema updates
package.json, marketplace.json
Removed PRD.md from package.json files whitelist. Restructured marketplace.json to wrap description and version under a new top-level metadata object; added category: "productivity" field to the pm-claude plugin entry.
Changelog and work coordination metadata
CHANGELOG.md, .agents/pm/chores/*, .agents/pm/history/*
Updated CHANGELOG with cast-dedup and docs-hygiene entries. Task and chore records document completion of cast-dedup refactor, closure of packaging/docs task with verification evidence, and reassessment of remaining LOC-splitting work.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • unbraind/pm-cli#44: Both PRs modify src/core/history/replay.ts's ItemDocument canonicalization and metadata ordering logic, making the changes closely connected at the same code path.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title directly summarizes the main changes: deduplicating item-record casts and addressing docs/package hygiene, which align with the two primary workstreams in the changeset.
Description check ✅ Passed The description comprehensively explains both workstreams (cast deduplication and docs hygiene), lists specific files changed, details verification steps, and references related tracking items.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

❤️ Share

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

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request centralizes TypeScript type-widening casts by introducing a toItemRecord helper, replacing numerous inline 'as unknown as Record' casts across the CLI and core modules. It also performs documentation and packaging hygiene, including the reconciliation of marketplace.json and the removal of PRD.md from the published npm package. Feedback suggests reusing an existing variable in the update command to avoid redundant helper calls.

Comment thread src/cli/commands/update.ts Outdated
try {
applyRegisteredItemFieldDefaultsAndValidation(
document.metadata as unknown as Record<string, unknown>,
toItemRecord(document.metadata),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The metadataRecord variable (defined at line 1552) already holds the widened reference to document.metadata. You can use it here instead of calling toItemRecord again, which is more efficient and consistent with the rest of the mutate callback.

Suggested change
toItemRecord(document.metadata),
metadataRecord,

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
marketplace.json (1)

7-10: ⚡ Quick win

Add contract assertions for the newly introduced manifest fields.

Current contract/smoke checks (from tests/integration/claude-plugin-contract.spec.ts and scripts/smoke-claude-plugin.mjs) validate name/plugin wiring but do not assert metadata.version, metadata.description, or plugin category. Please add explicit assertions so this schema change can’t silently drift again.

Also applies to: 35-35

🤖 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 `@marketplace.json` around lines 7 - 10, Update the Claude plugin
contract/smoke tests to assert the new manifest fields: add explicit checks for
metadata.version and metadata.description and for the plugin's category value;
e.g., in tests/integration/claude-plugin-contract.spec.ts add assertions that
manifest.metadata.version equals the expected version and
manifest.metadata.description is non-empty (or matches the expected string) and
that manifest.category equals the expected category, and mirror the same
assertions in scripts/smoke-claude-plugin.mjs so both integration and smoke
checks fail if those fields drift.
🤖 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.

Nitpick comments:
In `@marketplace.json`:
- Around line 7-10: Update the Claude plugin contract/smoke tests to assert the
new manifest fields: add explicit checks for metadata.version and
metadata.description and for the plugin's category value; e.g., in
tests/integration/claude-plugin-contract.spec.ts add assertions that
manifest.metadata.version equals the expected version and
manifest.metadata.description is non-empty (or matches the expected string) and
that manifest.category equals the expected category, and mirror the same
assertions in scripts/smoke-claude-plugin.mjs so both integration and smoke
checks fail if those fields drift.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: a455f8a3-0d02-42ff-ae41-606febdc3856

📥 Commits

Reviewing files that changed from the base of the PR and between c036f23 and 94e2e2a.

📒 Files selected for processing (24)
  • .agents/pm/chores/pm-mbdu.toon
  • .agents/pm/chores/pm-p5if.toon
  • .agents/pm/chores/pm-rjgh.toon
  • .agents/pm/history/pm-mbdu.jsonl
  • .agents/pm/history/pm-p5if.jsonl
  • .agents/pm/history/pm-rjgh.jsonl
  • CHANGELOG.md
  • marketplace.json
  • package.json
  • src/cli/commands/append.ts
  • src/cli/commands/claim.ts
  • src/cli/commands/close.ts
  • src/cli/commands/delete.ts
  • src/cli/commands/get.ts
  • src/cli/commands/list.ts
  • src/cli/commands/normalize.ts
  • src/cli/commands/search.ts
  • src/cli/commands/update-many.ts
  • src/cli/commands/update.ts
  • src/core/history/history.ts
  • src/core/history/replay.ts
  • src/core/item/item-record.ts
  • tests/unit/item-record.spec.ts
  • vitest.config.ts
💤 Files with no reviewable changes (1)
  • package.json

- update.ts (Gemini): reuse the in-scope `metadataRecord` (the widened
  `document.metadata` reference held since the start of the mutate callback)
  instead of re-calling `toItemRecord(document.metadata)` at the registered-
  field validation site, and at the 4 sibling `(document.metadata as Record)`
  index casts. Removes 5 more inline casts; behavior-identical (same reference,
  never reassigned). The out-of-callback cast at the result-projection site is
  left as-is.
- claude-plugin-contract test (CodeRabbit): assert the reconciled
  marketplace.json manifest fields (metadata block + description + version ===
  plugin version, plugin category) and add an invariant test that root
  marketplace.json deep-equals .claude-plugin/marketplace.json so the two
  manifests can never drift again.

Local gate green: build, typecheck, docs-skills, static-quality, coverage
(1741 tests / 115 files, 100%), version-policy, secret-scan, npx-smoke,
package-first-dogfood, npm-pack-dry-run, compatibility.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@unbraind unbraind merged commit 6200784 into main May 25, 2026
13 checks passed
@unbraind unbraind deleted the chore/docs-hygiene-and-item-record-cast-dedupe branch May 25, 2026 08:10
unbraind added a commit that referenced this pull request May 25, 2026
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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.

1 participant