Skip to content

chore(release): bump version to 0.15.0 and rebuild dist - #183

Merged
kalwalt merged 5 commits into
devfrom
chore/release-0.15.0
Sep 3, 2026
Merged

chore(release): bump version to 0.15.0 and rebuild dist#183
kalwalt merged 5 commits into
devfrom
chore/release-0.15.0

Conversation

@kalwalt

@kalwalt kalwalt commented Sep 2, 2026

Copy link
Copy Markdown
Member

Phase A of the release runbook for 0.15.0 (MAINTAINERS.md). Version bump, regenerated lockfile, rebuilt dist//types/, and the git-cliff changelog section.

Why this release matters beyond the version number

dist/ and types/ are only rebuilt at release time, so the artifacts committed on dev were still the 0.14.0 build. They contained none of the three modules merged since:

module issue in the old committed dist
bfmatcher + match_t #133
pose_estimator #83
orb.ic_angle #96

Anything consuming jsfeatNext from a git ref was therefore getting the old bundle with no warning — including the pre-release testing route, and the CvBackend adapter now being written against this library over in webarkit/webarkit. That adapter is blocked until these artifacts ship, which is what makes this release a prerequisite rather than routine housekeeping.

Contents

Features since 0.14.0:

Plus the two dependabot bumps merged since: vite 8.2.2 (the build tool, so it produced these artifacts) and actions/upload-artifact v7.

Notes

  • The lockfile was regenerated with npm 11 per AGENTS.md. An npm 10 install omits other-platform optional native binaries and produces a lockfile that fails npm ci in CI — which is exactly what happened locally while preparing this, and is worth knowing about.
  • types/src/bfmatcher/ and types/src/pose_estimator/ are new directories: those modules had never been through a release build before.

Verification

  • npm test — 305 passed
  • npm run typecheck — clean
  • npm run format-check — clean
  • npm run license-check — 100 files OK
  • rebuilt bundle carries VERSION 0.15.0 and all three new modules

After merge

Steps 6–7 of the runbook, which are not part of this PR: promote dev to main, then tag 0.15.0 (bare, no v prefix) to trigger the automated release and npm publish.

First release since 0.14.0, carrying three additions that complete the
natural-feature pipeline: the bfmatcher brute-force Hamming matcher with
match_t (#133), the closed-form planar pose_estimator (#83), and orb.ic_angle,
the keypoint orientation step (#96).

Those three are also what makes this release necessary rather than routine.
dist/ and types/ are only rebuilt at release time, so the artifacts committed
on dev still carried the 0.14.0 build and contained none of them. Anything
consuming jsfeatNext from a git ref - the pre-release testing route, and the
CvBackend adapter now being written against this library - was silently
getting the old bundle. Rebuilding here is what closes that gap.

Also picks up the two dependabot bumps merged since: vite 8.2.2 (the build
tool, so it produced these artifacts) and actions/upload-artifact v7.

The lockfile was regenerated with npm 11 per AGENTS.md; an npm 10 install
omits other-platform optional binaries and breaks npm ci in CI.

Verified: 305 tests, typecheck, prettier and the license-header check all
green, and the rebuilt bundle carries VERSION 0.15.0 plus all three new
modules.
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Release 0.15.0 with rebuilt bundles and type declarations

✨ Enhancement ⚙️ Configuration changes 📝 Documentation 🕐 20-40 Minutes

Grey Divider

AI Description

• Bumps package metadata and lockfile to 0.15.0 for release preparation.
• Rebuilds UMD, ESM, and declarations with matcher, pose, and ORB orientation APIs.
• Prepends generated 0.15.0 release notes to the changelog.
Diagram

graph TD
  S["Merged Modules"] --> B["Vite Build"] --> U["UMD Bundle"] --> C["Git Consumers"]
  P["Package 0.15"] --> B --> E["ESM Bundle"] --> C
  B --> T["Type Declarations"] --> C
  P --> L["npm 11 Lockfile"]
Loading
High-Level Assessment

The PR follows the documented release runbook and is the appropriate approach. Omitting committed artifacts would leave git-ref consumers on the stale 0.14.0 bundle, while introducing release automation is a separate architectural change rather than an improvement to this release preparation.

Files changed (11) +528 / -69

Enhancement (6) +233 / -10
bfmatcher.d.tsPublish declarations for the brute-force Hamming matcher +69/-0

Publish declarations for the brute-force Hamming matcher

• Adds the bfmatcher declaration with nearest-neighbor matching, cross-check support, k-nearest matching, and Lowe ratio filtering for binary descriptors.

types/src/bfmatcher/bfmatcher.d.ts

match_t.d.tsPublish descriptor-match result declarations +19/-0

Publish descriptor-match result declarations

• Adds the IMatch_T interface and match_t class describing query index, train index, and Hamming distance.

types/src/bfmatcher/match_t.d.ts

constants.d.tsDeclare the NORM_HAMMING public constant +2/-0

Declare the NORM_HAMMING public constant

• Extends the generated constants declaration with the Hamming norm used by bfmatcher.

types/src/constants/constants.d.ts

core.d.tsExpose matcher and pose APIs on the typed namespace +8/-0

Expose matcher and pose APIs on the typed namespace

• Adds bfmatcher, match_t, pose_estimator, pose_t, and NORM_HAMMING to the generated jsfeatNext namespace declaration.

types/src/core/core.d.ts

orb.d.tsDeclare ORB intensity-centroid orientation support +36/-10

Declare ORB intensity-centroid orientation support

• Adds the orb.ic_angle declaration and guidance for computing keypoint orientation before descriptor extraction, including image-border requirements.

types/src/orb/orb.d.ts

pose_estimator.d.tsPublish planar pose estimation declarations +99/-0

Publish planar pose estimation declarations

• Adds pose_t and pose_estimator declarations for constructing intrinsics, replacing calibration, and recovering a camera rotation and translation from a homography.

types/src/pose_estimator/pose_estimator.d.ts

Documentation (1) +42 / -0
CHANGELOG.mdAdd generated 0.15.0 release notes +42/-0

Add generated 0.15.0 release notes

• Prepends the 0.15.0 changelog section covering fixes, documentation, build updates, features, and tests since 0.14.0.

CHANGELOG.md

Other (4) +253 / -59
jsfeatNext.jsRebuild the minified UMD bundle for 0.15.0 +2/-2

Rebuild the minified UMD bundle for 0.15.0

• Updates the bundled version and exposes the Hamming matcher, match type, planar pose estimator, pose type, ORB intensity-centroid orientation, and NORM_HAMMING constant. This makes previously merged functionality available to UMD and CommonJS git-ref consumers.

dist/jsfeatNext.js

jsfeatNext.mjsRebuild the ESM bundle with new computer-vision APIs +248/-54

Rebuild the ESM bundle with new computer-vision APIs

• Regenerates the readable ESM artifact for version 0.15.0, including bfmatcher, pose estimation, orb.ic_angle, and associated public constructors and constants. Build-time symbol renaming also changes throughout the generated output.

dist/jsfeatNext.mjs

package-lock.jsonSynchronize lockfile metadata with version 0.15.0 +2/-2

Synchronize lockfile metadata with version 0.15.0

• Updates the root package and workspace package records from 0.14.0 to 0.15.0 in the npm lockfile.

package-lock.json

package.jsonBump the package version to 0.15.0 +1/-1

Bump the package version to 0.15.0

• Sets the published package version to 0.15.0 for the upcoming release and generated bundle metadata.

package.json

@qodo-code-review

qodo-code-review Bot commented Sep 2, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. New types unreachable from root ✓ Resolved 🐞 Bug ≡ Correctness
Description
The generated root declaration does not re-export match_t, IMatch_T, pose_t, or IPose_T, so
normal named type imports for the newly public data structures fail. Deep imports cannot compensate
because the package export map exposes only the root and package.json.
Code

types/src/core/core.d.ts[R67-69]

+    static match_t: typeof match_t;
+    static pose_estimator: typeof pose_estimator;
+    static pose_t: typeof pose_t;
Evidence
The generated declarations define the new public classes and interfaces, and the core namespace
exposes their constructors. However, types/src/index.d.ts is the package's sole declaration entry
point and its root re-export list omits all four data types; package.json does not export their
deep declaration paths.

types/src/bfmatcher/match_t.d.ts[1-19]
types/src/pose_estimator/pose_estimator.d.ts[1-27]
types/src/core/core.d.ts[63-69]
types/src/index.d.ts[14-35]
package.json[7-16]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The release exposes match and pose constructors on the runtime namespace and generates their declarations, but omits their data types and public interfaces from the package-root type exports. Package consumers therefore cannot import these types through the supported package entry point.

## Issue Context
The package exports map blocks undeclared deep subpaths. Existing public data structures and interfaces are explicitly re-exported from `src/index.ts`, but the newly introduced match and pose equivalents were not added to that list.

## Fix Focus Areas
- src/index.ts[55-75]
- types/src/index.d.ts[15-35]
- types/src/bfmatcher/match_t.d.ts[1-19]
- types/src/pose_estimator/pose_estimator.d.ts[1-27]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. estimate bypasses shared cache 📘 Rule violation ⌂ Architecture
Description
Each pose_estimator.estimate call directly allocates a new nine-element Float64Array for
temporary matrix B. Repeated pose estimation therefore bypasses the mandated shared scratch-buffer
pool.
Code

dist/jsfeatNext.mjs[R2743-2745]

+	estimate(t, n) {
+		let r = n || new Y(), i = t.data, a = this.Kinv, o = /* @__PURE__ */ new Float64Array(9);
+		for (let e = 0; e < 3; ++e) for (let t = 0; t < 3; ++t) o[e * 3 + t] = a[e * 3] * i[t] + a[e * 3 + 1] * i[3 + t] + a[e * 3 + 2] * i[6 + t];
Evidence
Rule 2966049 requires temporary algorithm buffers to come from the shared cache. The newly
distributed implementation creates new Float64Array(9) inside estimate, and the source confirms
that this array is the temporary K⁻¹H matrix used during each call.

Rule 2966049: Algorithm modules must use the shared_cache from src/core/core.ts for scratch buffers
dist/jsfeatNext.mjs[2743-2745]
src/pose_estimator/pose_estimator.ts[178-188]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`pose_estimator.estimate` allocates its temporary `B` matrix directly on every invocation instead of borrowing scratch storage from the shared cache.

## Issue Context
Acquire an appropriately sized shared-cache buffer, use its `f64` view, and guarantee a matching release on successful, degenerate, and exceptional paths. Rebuild `dist/` after changing the source.

## Fix Focus Areas
- src/pose_estimator/pose_estimator.ts[178-188]
- src/pose_estimator/pose_estimator.ts[197-202]
- dist/jsfeatNext.mjs[2743-2745]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. pose_estimator requires instantiation ✗ Dismissed 📘 Rule violation ≡ Correctness
Description
The new public API explicitly requires consumers to construct the pose_estimator algorithm with
new rather than invoke it through a provided singleton namespace. This conflicts with the required
algorithm-module usage convention.
Code

types/src/pose_estimator/pose_estimator.d.ts[R58-60]

+ * const K = jsfeatNext.pose_estimator.intrinsics(640, 480);
+ * const estimator = new jsfeatNext.pose_estimator(K);
+ * const pose = new jsfeatNext.pose_t();
Evidence
Rule 2965977 prohibits constructing algorithm modules and requires singleton namespace calls. The
added API example uses new jsfeatNext.pose_estimator(K), while the declaration exposes
pose_estimator as a constructor rather than a singleton instance.

Rule 2965977: Do not instantiate algorithm modules; use provided singleton namespace functions
types/src/pose_estimator/pose_estimator.d.ts[33-42]
types/src/pose_estimator/pose_estimator.d.ts[56-65]
types/src/core/core.d.ts[66-69]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The published API instructs consumers to instantiate `jsfeatNext.pose_estimator`, while algorithm modules must be exposed through singleton namespace functions.

## Issue Context
Move mutable intrinsics into a singleton-compatible API, or accept intrinsics as operation input, and update the declaration, namespace wiring, examples, and generated bundles accordingly.

## Fix Focus Areas
- src/pose_estimator/pose_estimator.ts[80-89]
- src/pose_estimator/pose_estimator.ts[103-112]
- types/src/core/core.d.ts[66-69]
- types/src/pose_estimator/pose_estimator.d.ts[33-42]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View medium (2)
4. Mismatched widths corrupt matches ✓ Resolved 🐞 Bug ≡ Correctness
Description
match and knnMatch derive the row stride only from query.cols, so a train matrix with a
different width is read using incorrect row boundaries and produces silently invalid Hamming
distances. The documented same-width requirement is not validated at runtime.
Code

dist/jsfeatNext.mjs[R2656-2657]

+	match(t, n, r = 256) {
+		let i = t.rows, a = n.rows, o = t.cols >> 2, s = e.words(t), c = e.words(n), l = [];
Evidence
The source contract requires the train matrix to have the same row width, but words() only checks
divisibility by four. Both matching methods calculate word_len from query.cols and then use it
to index train rows, so differing widths necessarily use the wrong train offsets; this
implementation is newly shipped by the rebuilt distribution artifact.

src/bfmatcher/bfmatcher.ts[85-104]
src/bfmatcher/bfmatcher.ts[115-134]
src/bfmatcher/bfmatcher.ts[192-204]
dist/jsfeatNext.mjs[2651-2663]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`bfmatcher.match` and `knnMatch` use the query descriptor width as the stride for both matrices. If train descriptors have a different width, the matcher reads across row boundaries or beyond the logical train data and returns incorrect matches rather than rejecting incompatible input.

## Issue Context
The API documentation says query and train descriptors must have the same row width. The existing `words` helper only verifies that each individual width is divisible by four.

## Fix Focus Areas
- src/bfmatcher/bfmatcher.ts[91-124]
- src/bfmatcher/bfmatcher.ts[192-204]
- tests/properties/bfmatcher.test.ts[120-200]
- dist/jsfeatNext.mjs[2656-2695]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. pose_estimator skips core base ✗ Dismissed 📘 Rule violation ⌂ Architecture
Description
The newly published pose_estimator algorithm class does not extend the shared core base, unlike
conforming algorithm modules. This bypasses the required common algorithm structure.
Code

types/src/pose_estimator/pose_estimator.d.ts[65]

+export declare class pose_estimator {
Evidence
Compliance rule 2965935 requires every main algorithm class to extend the core base. The new
declaration has no extends clause, and the corresponding source class is likewise declared
directly as export class pose_estimator.

Rule 2965935: Algorithms must be defined in dedicated modules and subclass the core base
types/src/pose_estimator/pose_estimator.d.ts[65-68]
src/pose_estimator/pose_estimator.ts[112-118]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`pose_estimator` is an algorithm class but does not extend the base exported by `src/core/core.ts`.

## Issue Context
The release adds the implementation and public declaration to the distributed artifacts. Other algorithm modules, including `bfmatcher`, inherit from the shared core base.

## Fix Focus Areas
- src/pose_estimator/pose_estimator.ts[112-118]
- types/src/pose_estimator/pose_estimator.d.ts[65-68]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 25 rules
Review mode: ⚖️ Balanced: Although release artifacts dominate the diff, the rebuilt public bundle exposes multiple new runtime modules and API changes, creating genuine compatibility and behavioral risk best assessed in one careful pass.

Grey Divider

Tip of the day
💡 Did you know, you can add REVIEW.md to your repo root and Qodo follows it on every PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread types/src/pose_estimator/pose_estimator.d.ts
Comment thread types/src/pose_estimator/pose_estimator.d.ts
Comment thread dist/jsfeatNext.mjs
Comment thread dist/jsfeatNext.mjs Outdated
Comment thread types/src/core/core.d.ts
…ange

Adding the module-scope u_max table in #182 inserted it between the orb
class's JSDoc block and the class declaration, which orphaned the comment:
TSDoc binds a block to the declaration immediately following it, and that was
now u_max, which carries its own.

The effect reached the published artifacts. The ORB description was absent
from types/src/orb/orb.d.ts entirely, so editors showed nothing on hover and
TypeDoc would have rendered the class undocumented - and 0.15.0 was about to
ship that. Moving u_max above the class doc restores the binding.

Swept every other exported class in types/ for the same pattern; orb was the
only one affected.

Also drops a {@link u_max} from the ic_angle docs. u_max is module-private
and not exported, so the link had no resolvable target.

Reported by the Qodo review on #183.
The section was generated before the docs commit landed, so CHANGELOG.md and
the release notes the tag workflow generates would have disagreed. Both derive
from the same conventional commits; regenerating keeps them in sync.
kalwalt added a commit that referenced this pull request Sep 3, 2026
…the new types

Three findings from the Qodo review on #183, all of which would otherwise
ship in 0.15.0.

bfmatcher silently corrupted matches on mismatched widths. match() and
knnMatch() derived one stride from query.cols and used it to address BOTH
matrices, so a train set of a different width was read at offsets computed
from the query. The reads walk across train row boundaries and, past the end,
an out-of-range Int32Array index yields undefined, which XOR coerces to 0.
Nothing threw: the matcher returned a full set of confident, meaningless
Hamming distances. The existing check only verified each width was a multiple
of 4 and never compared the two. A new pairWords() validates the pair in one
place for both methods.

The new public types were unreachable. src/index.ts re-exports the data
structures so consumers can annotate without deep paths, but match_t/IMatch_T
and pose_t/IPose_T were never added, and the exports map only exposes the root
and package.json - so deep imports cannot compensate. There was no way for a
consumer to name those types at all. This is not hypothetical: the CvBackend
adapter being written against this library needs both.

pose_estimator allocated its B scratch every call. An estimator is built once
and reused across frames, so at 30-60 fps that was a fresh array per frame;
it is now an instance field. The review suggested the shared cache instead,
which is the wrong tool here - that pool is for image-sized buffers, and
balancing a get/put across the degenerate early return to save 72 bytes costs
more in bookkeeping than it saves.

Two further findings in the same review - that pose_estimator must extend core
and must not require `new` - are rejected. It is a stateful class constructed
with a K, so it belongs with matrix_t and keypoint_t rather than the stateless
algorithm singletons, and its static intrinsics() factory depends on the class
itself sitting on the namespace. AGENTS.md listed the constructor classes
without mentioning it, which is what invited the misreading, so it now says so
explicitly.

Tests cover the new guard on both methods, that the message names both widths,
and a reproduction of the wrong distances the old stride produced.
@kalwalt kalwalt self-assigned this Sep 3, 2026
@kalwalt kalwalt added enhancement New feature or request new-release labels Sep 3, 2026
Merges dev and regenerates dist/ and types/, so the published artifacts carry
the correctness fixes rather than the build made before them:

  - bfmatcher now rejects mismatched descriptor row widths instead of reading
    train rows at a query-derived stride and returning silently wrong Hamming
    distances
  - match_t/IMatch_T and pose_t/IPose_T are reachable from the package root,
    which they were not - with the exports map limited to the root, consumers
    had no way to name the types of two of the modules this release exists to
    publish
  - pose_estimator no longer allocates its B scratch per frame

Also refreshes the 0.15.0 changelog section to cover those commits, keeping
CHANGELOG.md in agreement with the notes the tag workflow generates.
@kalwalt
kalwalt merged commit 3dc9ea6 into dev Sep 3, 2026
5 checks passed
kalwalt added a commit that referenced this pull request Sep 3, 2026
…ange

Adding the module-scope u_max table in #182 inserted it between the orb
class's JSDoc block and the class declaration, which orphaned the comment:
TSDoc binds a block to the declaration immediately following it, and that was
now u_max, which carries its own.

The effect reached the published artifacts. The ORB description was absent
from types/src/orb/orb.d.ts entirely, so editors showed nothing on hover and
TypeDoc would have rendered the class undocumented - and 0.15.0 was about to
ship that. Moving u_max above the class doc restores the binding.

Swept every other exported class in types/ for the same pattern; orb was the
only one affected.

Also drops a {@link u_max} from the ic_angle docs. u_max is module-private
and not exported, so the link had no resolvable target.

Reported by the Qodo review on #183.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request new-release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant