Skip to content

chore(release): public launch hardening for @unbrained/pm-cli - #1

Merged
unbraind merged 1 commit into
mainfrom
release/2026.3.9
Mar 9, 2026
Merged

unbraind merged 1 commit into
mainfrom
release/2026.3.9

Conversation

@unbraind

@unbraind unbraind commented Mar 9, 2026

Copy link
Copy Markdown
Owner

Summary

  • switch package distribution to scoped npm package @unbrained/pm-cli with calendar SemVer-compatible versioning (YYYY.M.D[-N])
  • add release safety tooling and CI gates (version:check, security:scan, packaged npx smoke) plus release workflow tag/sequence enforcement and GitHub release automation
  • update release/install contributor docs and lock contracts with integration tests so launch behavior stays deterministic

Test plan

  • node scripts/release-version.mjs check --tag v2026.3.9 --verify-next
  • pnpm security:scan
  • pnpm build
  • pnpm typecheck
  • pnpm test
  • node scripts/run-tests.mjs coverage
  • pnpm smoke:npx

Switch the package to scoped publishing with calendar-based SemVer-compatible versioning and add release guardrails for secret scanning, npx smoke checks, and tag/version enforcement. This hardens CI/CD and contributor release docs so today’s public npm release is reproducible and safe.
@coderabbitai

coderabbitai Bot commented Mar 9, 2026 •

Copy link
Copy Markdown
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Free

Run ID: f214f130-65af-4595-8f81-c13c45231e3c

📥 Commits

Reviewing files that changed from the base of the PR and between 7b9a0ec and b4e4876.

📒 Files selected for processing (24)
  • .agents/pm/chores/pm-1h88.md
  • .agents/pm/chores/pm-1hm2.md
  • .agents/pm/history/pm-1h88.jsonl
  • .agents/pm/history/pm-1hm2.jsonl
  • .github/ISSUE_TEMPLATE/bug-report.yml
  • .github/PULL_REQUEST_TEMPLATE.md
  • .github/workflows/ci.yml
  • .github/workflows/nightly.yml
  • .github/workflows/release.yml
  • AGENTS.md
  • CHANGELOG.md
  • CONTRIBUTING.md
  • PRD.md
  • README.md
  • docs/RELEASING.md
  • package.json
  • scripts/check-secrets.mjs
  • scripts/install.ps1
  • scripts/install.sh
  • scripts/release-version.mjs
  • scripts/smoke-npx-from-pack.mjs
  • tests/integration/ci-workflow-contract.spec.ts
  • tests/integration/help-readme-contract.spec.ts
  • tests/integration/release-readiness-contract.spec.ts

Summary by CodeRabbit

Release Notes

  • New Features

    • Added calendar-based version validation
    • Added credential leak detection in workflows
    • Added npx smoke test execution
    • Automatic GitHub release notes generation
  • Documentation

    • Added release process documentation
  • Chores

    • Rebranded package to @unbrained/pm-cli
    • Bumped version to 2026.3.9
    • Enhanced CI and release workflows with quality gates

Walkthrough

This pull request prepares version 2026.3.9 for public release by rebranding the package from pm-cli to @unbrained/pm-cli, implementing calendar-based versioning, adding release management scripts, and introducing CI/CD guardrails for version validation, secret scanning, and smoke testing.

Changes

Cohort / File(s) Summary
Package Metadata & Configuration
package.json, scripts/install.sh, scripts/install.ps1
Updated default package name to @unbrained/pm-cli, bumped version to 2026.3.9, changed author to "unbrained", added publishConfig with public access, and introduced four new scripts: version:check, version:next, security:scan, and smoke:npx.
Release Management Scripts
scripts/release-version.mjs, scripts/check-secrets.mjs, scripts/smoke-npx-from-pack.mjs
Added three new scripts: release-version.mjs validates calendar SemVer format (YYYY.M.D) and guards version tags; check-secrets.mjs scans tracked files for credential patterns; smoke-npx-from-pack.mjs automates npx tarball smoke testing without publishing.
CI/CD Workflows
.github/workflows/ci.yml, .github/workflows/nightly.yml, .github/workflows/release.yml
Added version policy checks, secret leak scans, and smoke tests to CI and nightly builds; release workflow now includes environment configuration, GitHub release creation, and upgraded permissions for content write access.
GitHub Templates
.github/ISSUE_TEMPLATE/bug-report.yml, .github/PULL_REQUEST_TEMPLATE.md
Updated bug report version placeholder to 2026.3.9 and added three new PR checklist items for version check, security scan, and smoke test verification.
Core Documentation
README.md, CHANGELOG.md, PRD.md, AGENTS.md, CONTRIBUTING.md, docs/RELEASING.md
Updated all package references from pm-cli to @unbrained/pm-cli; added new docs/RELEASING.md detailing calendar versioning policy and release checklist; updated CHANGELOG with release versioning and CI/CD guardrails; added RELEASING.md link to CONTRIBUTING.
Release Task Artifacts
.agents/pm/chores/pm-1h88.md, .agents/pm/chores/pm-1hm2.md, .agents/pm/history/pm-1h88.jsonl, .agents/pm/history/pm-1hm2.jsonl
Added release chore and hardening task metadata with comprehensive lifecycle documentation, test scopes, acceptance criteria, and state transitions (created, claimed, in_progress, closed, released).
Contract Tests
tests/integration/ci-workflow-contract.spec.ts, tests/integration/help-readme-contract.spec.ts, tests/integration/release-readiness-contract.spec.ts
Updated workflow expectations to verify new steps (version:check, security:scan, smoke:npx); added calendar date validation; extended package.json and script verification; added checks for new release infrastructure files and public publishConfig.

Sequence Diagram(s)

sequenceDiagram
    participant Dev as Developer
    participant Git as Git / Tag
    participant GH as GitHub Actions
    participant NPM as npm Registry
    participant GHR as GitHub Releases
    
    Dev->>Dev: pnpm version:check
    activate Dev
    Note over Dev: Validate tag & version policy
    deactivate Dev
    
    Dev->>Dev: pnpm security:scan
    activate Dev
    Note over Dev: Scan for credential leaks
    deactivate Dev
    
    Dev->>Dev: pnpm smoke:npx
    activate Dev
    Note over Dev: Test npx tarball locally
    deactivate Dev
    
    Dev->>Git: Commit & tag (v2026.3.9)
    Git->>GH: Trigger release workflow
    
    GH->>GH: Verify version tag & policy
    GH->>GH: Run security scan
    GH->>GH: Test npx smoke
    GH->>NPM: npm publish `@unbrained/pm-cli`
    NPM-->>GH: Success
    
    GH->>GHR: Create GitHub release w/ notes
    GHR-->>GH: Release published
    GH-->>Dev: Workflow complete
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

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

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hi @unbraind! 👋

Your private repo does not have access to Sourcery.

Please upgrade to continue using Sourcery ✨

@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly hardens the release process for the @unbrained/pm-cli project in preparation for its public launch. It establishes a clear and robust versioning strategy, integrates critical security and quality checks into the continuous integration pipeline, and automates the release workflow to ensure consistency and reliability. These changes are foundational for maintaining a secure and predictable public distribution of the CLI.

Highlights

  • Scoped npm package and Calendar Versioning: The project's npm package identity has been switched to @unbrained/pm-cli to prevent naming conflicts, and a new calendar-based versioning policy (YYYY.M.D[-N]) has been adopted for releases.
  • Enhanced Release Safety and CI Gates: New tooling and CI gates have been introduced, including version:check for calendar SemVer policy enforcement, security:scan for credential leak detection, and smoke:npx for verifying packaged executables. The release workflow now includes tag/version consistency checks and GitHub release automation.
  • Updated Documentation and Contracts: Contributor documentation, including CONTRIBUTING.md and README.md, has been updated to reflect the new release procedures and scoped package. Integration tests have been expanded to lock in these new behaviors and policies.
Changelog
  • CHANGELOG.md
    • Switched npm package identity to scoped publish target @unbrained/pm-cli.
    • Implemented calendar SemVer-compatible versioning (YYYY.M.D or YYYY.M.D-N).
    • Updated installer defaults to target @unbrained/pm-cli.
    • Added automated version policy enforcement script (scripts/release-version.mjs).
    • Added tracked-file credential leak scanner (scripts/check-secrets.mjs).
    • Added packaged npx smoke test (scripts/smoke-npx-from-pack.mjs).
    • Configured release workflow to use GitHub release Environment, validate version sequencing, and create GitHub Releases.
Ignored Files
  • Ignored by pattern: .github/workflows/** (3)
    • .github/workflows/ci.yml
    • .github/workflows/nightly.yml
    • .github/workflows/release.yml
Activity
  • A new chore item pm-1h88 was created to cut the public release, claimed by maintainer-agent, and its status was set to in_progress.
  • A chore item pm-1hm2 for release hardening was created, claimed by maintainer-agent, and its status was set to in_progress.
  • Files, tests, and documentation related to release hardening were linked to the pm-1hm2 chore.
  • Evidence of release hardening validations passing was recorded as a comment on pm-1hm2.
  • The pm-1hm2 chore was closed with a reason indicating completion of release management hardening.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@unbraind
unbraind merged commit e1c959d into main Mar 9, 2026
1 of 6 checks passed
@unbraind
unbraind deleted the release/2026.3.9 branch March 9, 2026 13:06

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

Copy link
Copy Markdown

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 implements significant release hardening and prepares the project for a public production launch. Key changes include switching the npm package name from pm-cli to @unbrained/pm-cli and updating the versioning scheme to a calendar-based SemVer (YYYY.M.D or YYYY.M.D-N). New scripts were added to enforce this version policy (release-version.mjs), scan for credential leaks (check-secrets.mjs), and perform npx smoke tests (smoke-npx-from-pack.mjs). The CI/CD workflows, particularly the release pipeline, have been updated to integrate these new checks, enforce the version policy, use a dedicated GitHub release environment, and automate GitHub Release creation. Documentation, including CHANGELOG.md, README.md, CONTRIBUTING.md, AGENTS.md, and PRD.md, has been updated to reflect the new package name, versioning policy, and release procedures. Installer scripts (install.sh, install.ps1) now default to the scoped package. Additionally, a new chore (pm-1h88) was created to track the final public release execution, and a previous chore (pm-1hm2) detailing the release hardening tasks was marked as closed, indicating the completion of these preparatory steps.

unbraind added a commit that referenced this pull request May 28, 2026
… validate guards, idempotent materialize no-op

Followups to first-pass review on PR #78. CodeRabbit's 7 ".agents/pm
files" comments were a false-positive (pm IS the system of record AND
the files ARE tracked in git — that's the entire pm-cli design).

Codex P2 #1: src/cli/commands/extension/scaffold.ts now emits the typed
`defineExtension({...})` shape ONLY in package mode (peerDependencies on
@unbrained/pm-cli make the import resolvable from the package's own
node_modules). In extension-only mode there is no package.json with that
dep, so the dynamic loader's `import(<file-url>)` would have raised
ERR_MODULE_NOT_FOUND when the extension was actually loaded. The
import-free shape from before is restored for that mode, decorated with
a JSDoc @PARAM hint so editors that follow JSDoc still narrow the api
parameter (matches the SDK type contract without a runtime dep).

Codex P2 #2: src/sdk/cli-contracts.ts CLOSE_FLAG_CONTRACTS now lists
`--resolution`, `--expected-result` (alias `--expected_result`), and
`--actual-result` (alias `--actual_result`). `pm contracts --command
close --json` now surfaces them; bootstrap flag normalization and the
JSON help payload pick them up automatically.

Gemini high #1+#2: src/cli/commands/validate.ts buildMetadataCheck adds
optional-chain guards so a future settings shape with an unsupported
field in `required_fields` falls back to 0 instead of throwing
TypeError, and skips writing when the count-key / item-ids-key /
truncated-key mapping is undefined.

Gemini medium (idempotency): `pm plan materialize --steps all` now
returns a successful no-op (exit 0) with `materialize_skipped`
populated when every selected step is already completed or already
materialized. Previously this threw NOT_FOUND, breaking agent/CI
pipelines that re-invoke the same script. Explicit step-ref path keeps
processing pending refs in the same call and recording skipped reasons.
Test updated to assert the new exit-0 + materialize_skipped contract.

Gemini medium (style): dropped the redundant `trimmed.length === 0`
short-circuit in `normalizeDependencyKindInput` (update.ts) — the alias
lookup with the trimmed key already returns the canonical value (or the
trimmed input) safely.

1866 tests, 100% coverage (stmt/branch/func/line), typecheck,
quality:static, quality:docs-skills, security:scan, changelog:check
all green.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
unbraind added a commit that referenced this pull request May 29, 2026
…gv, schema

Gemini (case-insensitivity):
- mergeAdditiveTags / applyTagRemovals now normalize the existing baseTags to
  canonical lowercase before merging/removing, so mixed-case legacy or
  hand-edited tags ("Beta") dedupe against additions ("beta") and are removed
  by lowercase selectors. Output stays sorted + deduped + lowercased.
- pm update skips a no-op tag write: an additive/subtractive-only mutation that
  resolves to the existing set no longer pushes "tags" to changed_fields or
  churns history/updated_at. Comparison uses the RAW original so a canonical
  case normalization still counts as a real change (consistent with
  update-many's buildTagMutationPlan).

Codex P2 #1 (JSON-array argv corruption):
- Dropped list:true from the --add-tags/--remove-tags flag contracts. These use
  Commander's repeatable collector, so the bootstrap list-coalescer must not
  comma-join repeated occurrences — it was turning
  `--add-tags '["a","b"]' --add-tags c` into `["a","b"],c` and breaking the
  documented JSON-array form. Each occurrence is now parsed independently.

Codex P2 #2 (published tool schema):
- Added addTags/removeTags to TOOL_CREATE/UPDATE_OPTION_CONTRACTS and
  PM_TOOL_PARAMETER_PROPERTIES (+ descriptions) so the additionalProperties:false
  MCP/SDK tool schema accepts them instead of rejecting schema-validated clients.
  (--expected/--actual remain CLI-only sugar; MCP clients use expectedResult.)

New regression tests for case-insensitive merge/removal and the no-op skip.
1973 tests, 100% coverage, all gates green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
unbraind added a commit that referenced this pull request May 31, 2026
…config-driven status enum, calendar timezones (#87)

* perf+config+calendar: instant mutations, per-command code-splitting, config-driven status enum, calendar timezones

Dogfood audit session targeting the #1 user complaint (CLI feels slow), validated
against live telemetry (mutations had the worst real-world p95: update 15.3s,
create 5.4s).

Performance — mutations now feel instant (pm-3ju0, dev repo 893 items):
- create 2581ms -> 239ms, update 1693ms -> 265ms, close -> 374ms.
- Non-blocking background semantic refresh: mutations invalidate the keyword cache
  synchronously (search stays correct) and dispatch the slow Ollama embed +
  vector-store rewrite to a detached worker (src/core/search/background-refresh.ts +
  src/cli/search-refresh.ts), mirroring the telemetry-flush spawn pattern. The
  worker drains a pending-refresh queue under the existing reindex lock
  (corruption-safe; reindex now imports the shared REINDEX_LOCK_ID).
  shouldRunSearchRefreshInForeground() keeps tests/CI inline (deterministic).
- Fixed a second dominant cost found via CPU profile: the pre-mutation item-format
  sync (run on every mutation by default) re-parsed/re-serialized the ENTIRE
  corpus; now skips items already in the target format with no legacy alternate.

Performance — startup / read commands (pm-t57d, pm-3mal):
- Per-command code-splitting: the 4 register-* families lazily imported the whole
  commands/index.js barrel inside every handler, so esbuild emitted one 943KB
  command chunk and every command loaded all command code + deps (incl. fast-glob's
  ~15-package tree, used only by linked-artifacts). Changed all 44 handler call
  sites to import the specific command module; a command now loads only its own
  chunk. Verified: fast-glob 0 resolutions during `pm list`; monolith gone.
  Dev repo (best of 7): search 673->292ms, show 370->204ms.
- MCP tool-parameter schemas (PM_TOOL_PARAMETERS_SCHEMA / provider variant) are now
  a memoized lazy Proxy — built only on first access (contracts/MCP/SDK), never
  during CLI commands. Verified the builder fires 0x for `pm list`, 1x for
  `pm contracts`.

Config-driven schema (pm-jtdc):
- Removed the hardcoded enum on the MCP `status` tool parameter; it now matches
  `type`/`filterStatus` (open string) so project-defined custom statuses are
  accepted via MCP. Runtime validation already rejects unknown statuses with a
  helpful allowed-list hint (never-block preserved). Verified a custom `in_review`
  status round-trips end to end. Description now points agents at pm_contracts.

Calendar timezone + all-day (pm-0l88):
- Added toLocalDayKey() via Intl (no new dependency): timed events bucket by their
  local day in event.timezone (a 23:30Z Asia/Tokyo instant now lands on the next
  local day) and render the local wall-clock; all-day events are timezone-agnostic
  (literal date, never shifted). UTC events unchanged. Window filtering still uses
  the absolute instant.

Health (pm-yf31):
- Removed the legacy unused `index` required subdir from PM_CORE_REQUIRED_SUBDIRS so
  `pm health` reports ok:true on a healthy repo (it was the sole false warning).
  gc still cleans legacy index/ for old repos.

Tests/governance: +14 tests (background-refresh worker/queue/gating merged into
search-cache.spec to respect the 120-file cap; calendar tz + all-day cases). Updated
the static-quality orphan allowlist for the new spawn-only entry, the coverage
include-alignment list, and the gc/integration/constants tests for the removed
`index` dir. Full suite green (2029 tests), 100% coverage, all release gates pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* review: address AI-bot feedback on background refresh + add calendar tz tests

Addresses CodeRabbit/Sourcery/Gemini/Codex review on PR #87.

src/core/search/background-refresh.ts:
- Attach a no-op 'error' handler to the detached refresh child so an async spawn
  error (EAGAIN/ENOENT/resource limits) can never surface as an unhandled error
  that crashes the parent CLI (Gemini).
- enqueuePendingRefreshIds no longer silently drops a mutation's refresh work when
  the queue gate stays contended past its retry budget: it falls back to a
  best-effort unguarded merge (writeFileAtomic keeps the file valid) instead of
  returning without enqueuing (Sourcery bug_risk).
- The worker now retries the reindex lock with bounded backoff (8 x 400ms) instead
  of exiting on the first conflict, so a sibling refresh holding the lock briefly
  no longer strands queued ids until the next mutation (Codex P2).

tests/unit/calendar-command.spec.ts:
- Add coverage for invalid/explicit-UTC timezone fallback (graceful UTC day+clock)
  and for timezone-aware event end-times that stay on the local day (Sourcery).

Note: CodeRabbit's "do not edit .agents/pm/**" comments are false positives — pm is
the git-tracked system of record and the item changes were produced via pm_close/
pm_create workflows, not hand-edited. Codex's "events excluded from local-day views"
is also not a defect: views filter by the absolute instant (calendar.ts:710-713),
so tz bucketing only changes the day-header grouping, never inclusion.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
unbraind added a commit that referenced this pull request Jun 18, 2026
…ierarchy cycle detection (GH-281, GH-280) (#282)

* chore(pm): finalize pm-6bz1 merge record for PR #279

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

* fix(search,validate): guarantee exact-ID search rank across all modes + detect parent-hierarchy cycles

Two agent-trust correctness fixes for pm's core read/validate primitives,
surfaced from dogfooding the large 2d-bots tracker (pm-rkie).

GH-281 (pm-oqgf): exact-ID search was only guaranteed #1 in keyword mode.
combineHybridHits() normalizes keyword scores to [0,1] and blends them under
hybrid_semantic_weight, so an exact full/short-ID match's keyword boost
(EXACT_ID_MATCH_SCORE=1000 / SHORT_ID_MATCH_SCORE=900) was capped at the
keyword weight and could be out-ranked by a high-semantic body mention; in pure
semantic mode an exact-ID item with no vector hit vanished entirely. Added an
exact_id_match flag on SearchHit and forceExactIdHitsToTop(), applied at both
the semantic and hybrid return points (after rerank), which reattaches exact-ID
hits in a reserved band above every blended hit (full-ID above short-ID) and
exempts them from the score threshold, so the exact target is always #1 and is
never dropped — in every mode.

GH-280 (pm-8vul): pm validate ran Tarjan SCC only over the dependency graph
(blocked_by/definition_of_ready) and never traversed the parent composition
graph, so a parent cycle (A<->B, or any-length ring) reported
dependency_cycle_count:0 with no warning while silently breaking pm list --tree,
orphan detection, and rollups. Added buildLifecycleParentGraph (child->parent
over ALL items) + detectLifecycleParentCycles reusing the generic
findLifecycleDependencyCycleComponents helper. Folds parent_cycle_* diagnostics
into the lifecycle check, emits validate_hierarchy_parent_cycle[_error]
warnings, adds --parent-cycle-severity off|warn|error (default warn, mirrors
dependency-cycle policy) with full contract/help/completion wiring, and a
remediation registry entry (pm update <id> --parent <other-id>).

Coverage 100/100/100/100 (4536 tests); quality:static + contracts:check green.

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

* fix(search,validate): address Gemini review — case-insensitive parent resolution + Math.max stack safety

- validate.ts (HIGH): buildLifecycleParentGraph resolves parent refs via a
  lowercase->canonical id map so a casing mismatch (PR #279 made parent
  matching case-insensitive) can never silently drop a cycle edge and hide a
  parent cycle. Added a regression assertion (uppercase PM-PA resolves to pm-pa).
- search.ts (MEDIUM): forceExactIdHitsToTop uses reduce instead of
  Math.max(0, ...spread) to avoid a RangeError on a very large pre-truncation
  candidate set, and promoted hits spread the original keyword hit so
  matched_all_terms / exact_id_match are preserved.

Coverage 100/100/100/100 (4536 tests); static + contracts green.

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

* refactor(search): drop redundant defensive copy before sorting exact-ID hits

Gemini review: exactIdHits is already a fresh array returned by
keywordHits.filter(...), so the [...exactIdHits] spread before .sort() is an
unnecessary allocation — sort in place.

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

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@unbraind

unbraind commented Aug 4, 2026

Copy link
Copy Markdown
Owner Author

PM context: pm-1hm2. Historical linkage verified during the 2026-08-04 ecosystem review. This comment records canonical context only; it does not reopen or change this artifact.

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