Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
afe9dc9
feat(api)!: normalize getNodeProps() to return Record (B100)
flyingrobots Mar 3, 2026
243713a
refactor(types): unify CorePersistence/FullPersistence typedefs (B146)
flyingrobots Mar 3, 2026
4e20ea3
feat(api): stabilize Observer API — subscribe() and watch() (B3)
flyingrobots Mar 3, 2026
42e5377
feat(api): add graph.patchMany() batch patch API (B11)
flyingrobots Mar 3, 2026
a8c241b
feat(bisect): add BisectService for binary search over WARP history
flyingrobots Mar 3, 2026
138f03b
feat(bisect): implement causality bisect CLI and service (B2)
flyingrobots Mar 3, 2026
774d697
test(subscribe): add unsubscribe-during-callback E2E tests (B44)
flyingrobots Mar 3, 2026
b07d64d
test(trust): add CLI vs service payload parity tests (B124)
flyingrobots Mar 3, 2026
815e6e2
test(CachedValue): add null-payload semantic tests (B125)
flyingrobots Mar 3, 2026
001d0c1
release: v13.0.0
flyingrobots Mar 3, 2026
1ea6bc4
fix(release): resolve TypeScript and declaration surface errors for v…
flyingrobots Mar 3, 2026
b87b83b
fix(bisect): harden CLI validation and remove dead code (B148)
flyingrobots Mar 3, 2026
d7cf956
fix(docs): reconcile inventory counts and fix review nits (B148)
flyingrobots Mar 3, 2026
c1d73ad
docs(changelog): add B148 follow-up details
flyingrobots Mar 4, 2026
367efdf
fix(docs,types): address code review round 2 findings (B148)
flyingrobots Mar 4, 2026
1b3cfcc
fix(security,cli,docs): address CodeRabbit review feedback (B148)
flyingrobots Mar 4, 2026
65f0f56
fix(docs,security): address CodeRabbit round 4 nits (B148)
flyingrobots Mar 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [13.0.0] — 2026-03-03

### Added

- **Observer API stabilized (B3)** — `subscribe()` and `watch()` promoted to `@stability stable` with `@since 13.0.0` annotations. Fixed `onError` callback type from `(error: Error)` to `(error: unknown)` to match runtime catch semantics. `watch()` pattern param now correctly typed as `string | string[]` in `_wiredMethods.d.ts`.
- **`graph.patchMany()` batch patch API (B11)** — applies multiple patch callbacks sequentially. Each callback sees state from prior commits. Returns array of commit SHAs. Inherits reentrancy guard from `graph.patch()`.
- **Causality bisect (B2)** — `BisectService` performs binary search over a writer's patch chain to find the first bad patch. CLI: `git warp bisect --good <sha> --bad <sha> --test <cmd> --writer <id>`. O(log N) materializations. Exit codes: 0=found, 1=usage, 2=range error, 3=internal.

### Changed

- **BREAKING: `getNodeProps()` returns `Record<string, unknown>` instead of `Map<string, unknown>` (B100)** — aligns with `getEdgeProps()` which already returns a plain object. Callers must replace `.get('key')` with `.key` or `['key']`, `.has('key')` with `'key' in props`, and `.size` with `Object.keys(props).length`. `ObserverView.getNodeProps()` follows the same change.
- **GraphPersistencePort narrowing (B145)** — domain services now declare focused port intersections (`CommitPort & BlobPort`, etc.) in JSDoc instead of the 23-method composite `GraphPersistencePort`. Removed `ConfigPort` from the composite (23 → 21 methods); adapters still implement `configGet`/`configSet` on their prototypes. Zero behavioral change.
- **Codec trailer validation extraction (B134, B138)** — created `TrailerValidation.js` with `requireTrailer()`, `parsePositiveIntTrailer()`, `validateKindDiscriminator()`. All 4 message codec decoders now use shared helpers exclusively. Patch and Checkpoint decoders now also perform semantic field validation (graph name, writer ID, OID, SHA-256) matching the Audit decoder pattern. Internal refactor for valid inputs, with stricter rejection of malformed messages.
- **HTTP adapter shared utilities (B135)** — created `httpAdapterUtils.js` with `MAX_BODY_BYTES`, `readStreamBody()`, `noopLogger`. Eliminates duplication across Node/Bun/Deno HTTP adapters. Internal refactor, no behavioral change.
Expand All @@ -25,6 +32,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Fake timer lifecycle (B131)** — moved `vi.useFakeTimers()` from `beforeAll` to `beforeEach` and `vi.useRealTimers()` into `afterEach` in `WarpGraph.watch.test.js`.
- **Test determinism (B132)** — seeded `Math.random()` in benchmarks with Mulberry32 RNG (`0xDEADBEEF`), added `seed: 42` to all fast-check property tests, replaced random delays in stress test with deterministic values.
- **Global mutation documentation (B133)** — documented intentional `globalThis.Buffer` mutation in `noBufferGlobal.test.js` and `crypto.randomUUID()` usage in `SyncAuthService.test.js`.
- **Code review fixes (B148):**
- **CLI hardening** — added `--writer` validation to bisect, SHA format regex on `--good`/`--bad`, rethrow ENOENT/EACCES from test command runner instead of swallowing.
- **BisectService cleanup** — removed dead code, added invariant comment, replaced `BisectResult` interface with discriminated union type, fixed exit code constant.
- **Prototype-pollution hardening** — `Object.create(null)` for property bags in `getNodeProps`, `getEdgeProps`, `getEdges`, `buildPropsSnapshot`; fixed indexed-path null masking in `getNodeProps`.
- **Docs housekeeping** — reconciled ROADMAP inventory counts (24→29 done), fixed M11 sequencing, removed done items from priority tiers, fixed stale test vector counts (6→9), corrected Deno test name, moved B100 to `### Changed`.

## [12.4.1] — 2026-02-28

Expand Down Expand Up @@ -1528,7 +1540,7 @@ Implements [Paper III](https://doi.org/10.5281/zenodo.17963669) (Computational H

#### Query API (V7 Task 7)
- **`graph.hasNode(nodeId)`** - Check if node exists in materialized state
- **`graph.getNodeProps(nodeId)`** - Get all properties for a node as Map
- **`graph.getNodeProps(nodeId)`** - Get all properties for a node (returns `Record<string, unknown>` since v13.0.0)
- **`graph.neighbors(nodeId, dir?, label?)`** - Get neighbors with direction/label filtering
- **`graph.getNodes()`** - Get all visible node IDs
- **`graph.getEdges()`** - Get all visible edges as `{from, to, label}` array
Expand Down
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
<img src="docs/images/hero.gif" alt="git-warp CLI demo" width="600">
</p>

## What's New in v12.4.1
## What's New in v13.0.0

- **JSDoc total coverage** — eliminated all unsafe `{Object}`, `{Function}`, `{*}` type patterns across 135 files (190+ sites), replacing them with precise inline typed shapes.
- **Zero tsc errors** — fixed tsconfig split-config includes and type divergences; 0 errors across all three tsconfig targets.
- **JSR dry-run fix** — worked around a deno_ast 0.52.0 panic caused by overlapping text-change entries for duplicate import specifiers.
- **`check-dts-surface.js` regex fix** — default-export parsing now correctly captures identifiers instead of keywords for `export default class/function` patterns.
- **BREAKING: `getNodeProps()` returns `Record<string, unknown>`** — aligns with `getEdgeProps()`. Replace `.get('key')` with `.key`, `.has('key')` with `'key' in props`, `.size` with `Object.keys(props).length`.
- **BREAKING: Removed `PerformanceClockAdapter` and `GlobalClockAdapter`** — use `ClockAdapter` directly.
- **`graph.patchMany()`** — batch multiple patches sequentially; each callback sees prior state.
- **`git warp bisect`** — binary search over writer patch history to find the first bad commit. O(log N) materializations.
- **Observer API stable** — `subscribe()` and `watch()` promoted to stable with `@since 13.0.0`.
- **`BisectService`** — domain service exported for programmatic use.

See the [full changelog](CHANGELOG.md) for details.

Expand Down Expand Up @@ -183,7 +185,7 @@ Query methods auto-materialize by default. Just open a graph and start querying:
```javascript
await graph.getNodes(); // ['user:alice', 'user:bob']
await graph.hasNode('user:alice'); // true
await graph.getNodeProps('user:alice'); // Map { 'name' => 'Alice', 'role' => 'admin' }
await graph.getNodeProps('user:alice'); // { name: 'Alice', role: 'admin' }
await graph.neighbors('user:alice', 'outgoing'); // [{ nodeId: 'user:bob', label: 'manages', direction: 'outgoing' }]
await graph.getEdges(); // [{ from: 'user:alice', to: 'user:bob', label: 'manages', props: {} }]
await graph.getEdgeProps('user:alice', 'user:bob', 'manages'); // { weight: 0.9 } or null
Expand Down Expand Up @@ -371,7 +373,7 @@ const view = await graph.observer('publicApi', {
});

const users = await view.getNodes(); // only user:* nodes
const props = await view.getNodeProps('user:alice'); // Map without ssn/password
const props = await view.getNodeProps('user:alice'); // { name: 'Alice', ... } without ssn/password
const result = await view.query().match('user:*').where({ role: 'admin' }).run();

// Measure information loss between two observer perspectives
Expand Down
74 changes: 23 additions & 51 deletions ROADMAP.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# ROADMAP — @git-stunts/git-warp

> **Current version:** v12.4.1
> **Last reconciled:** 2026-03-02 (M14 HYGIENE added from HEX_AUDIT; completed items archived to COMPLETED.md; BACKLOG.md retired)
> **Current version:** v13.0.0
> **Last reconciled:** 2026-03-03 (v13.0.0 release: M11 COMPASS II complete, B100/B140 breaking, B44/B124/B125/B146 done)
> **Completed milestones:** [docs/ROADMAP/COMPLETED.md](docs/ROADMAP/COMPLETED.md)

---
Expand All @@ -25,11 +25,11 @@

### M10.T4 — Causality Bisect Spec

- **Status:** `PENDING`
- **Status:** `DONE` (spec existed; implementation completed in M11)

**Items:**

- **B2 (spec only)** (CAUSALITY BISECT) — design the bisect CLI contract + data model. Commit spec with test vectors. Full implementation deferred to M11 — but the spec lands here so bisect is available as a debugging tool during M10 trust hardening.
- **B2 (spec only)** (CAUSALITY BISECT) — Spec committed at `docs/specs/BISECT_V1.md`. Full implementation shipped in M11/v13.0.0.

**M10 Gate:** Signed ingress enforced end-to-end; trust E2E receipts green; B63 GC isolation verified under concurrent writes; B64 sync payload validation green; B65 divergence logging verified; B2 spec committed with test vectors.

Expand Down Expand Up @@ -165,37 +165,9 @@ Design-only items. RFCs filed — implementation deferred to future milestones.

---

## Milestone 11 — COMPASS II
## Milestone 11 — COMPASS II ✅ COMPLETE (v13.0.0)

**Theme:** Developer experience
**Objective:** Ship bisect, public observer API, and batch patch ergonomics.
**Triage date:** 2026-02-17

### M11.T1 — Causality Bisect (Implementation)

- **Status:** `PENDING`

**Items:**

- **B2 (implementation)** (CAUSALITY BISECT) — full implementation building on M10 spec. Binary search for first bad tick/invariant failure. `git bisect` for WARP.

### M11.T2 — Observer API

- **Status:** `PENDING`

**Items:**

- **B3** (OBSERVER API) — public event contract. Internal soak period over (shipped in PULSE, used internally since). Stabilize the public surface.

### M11.T3 — Batch Patch API

- **Status:** `PENDING`

**Items:**

- **B11** (`graph.patchMany(fns)` BATCH API) — sequence multiple patch callbacks atomically, each seeing the ref left by the previous. Natural complement to `graph.patch()`.

**M11 Gate:** Bisect correctness verified on seeded regressions; observer contract snapshot-tested; patchMany passes no-coordination suite.
Archived to [COMPLETED.md](docs/ROADMAP/COMPLETED.md#milestone-11--compass-ii).

---

Expand All @@ -209,10 +181,10 @@ Items picked up opportunistically without blocking milestones. No milestone assi

| ID | Item |
|----|------|
| B124 | **TRUST PAYLOAD PARITY TESTS** — assert CLI `trust` and `AuditVerifierService.evaluateTrust()` emit shape-compatible error payloads. From BACKLOG 2026-02-27. |
| B125 | **`CachedValue` NULL-PAYLOAD SEMANTIC TESTS** — document and test whether `null` is a valid cached value. From BACKLOG 2026-02-27. |
| ~~B124~~ | ✅ ~~**TRUST PAYLOAD PARITY TESTS**~~22 tests verifying CLI vs service shape parity. Done in v13.0.0. |
| ~~B125~~ | ✅ ~~**`CachedValue` NULL-PAYLOAD SEMANTIC TESTS**~~3 tests documenting null = "no value" sentinel. Done in v13.0.0. |
| B127 | **DENO SMOKE TEST** — `npm run test:deno:smoke` for fast local pre-push confidence without full Docker matrix. From BACKLOG 2026-02-25. |
| B44 | **SUBSCRIBER UNSUBSCRIBE-DURING-CALLBACK E2E** — event system edge case; known bug class that bites silently |
| ~~B44~~ | ✅ ~~**SUBSCRIBER UNSUBSCRIBE-DURING-CALLBACK E2E**~~3 edge-case tests (cross-unsubscribe, subscribe-during-callback, unsubscribe-in-onError). Done in v13.0.0. |
| B34 | **DOCS: SECURITY_SYNC.md** — extract threat model from JSDoc into operator doc |
| B35 | **DOCS: README INSTALL SECTION** — Quick Install with Docker + native paths |
| B36 | **FLUENT STATE BUILDER FOR TESTS** — `StateBuilder` helper replacing manual `WarpStateV5` literals |
Expand All @@ -229,7 +201,7 @@ Items picked up opportunistically without blocking milestones. No milestone assi
| B79 | **WARPGRAPH CONSTRUCTOR LIFECYCLE DOCS** — document cache invalidation strategy for 25 instance variables: which operations dirty which caches, which flush them. From B-AUDIT-16 (TSK TSK). **File:** `src/domain/WarpGraph.js:69-198` |
| B80 | **CHECKPOINTSERVICE CONTENT BLOB UNBOUNDED MEMORY** — iterates all properties into single `Set` before tree serialization. Stream content OIDs in batches. From B-AUDIT-10 (JANK). **File:** `src/domain/services/CheckpointService.js:224-226` |
| B81 | **`attachContent` ORPHAN BLOB GUARD** — `attachContent()` unconditionally writes blob before `setProperty()`. Validate before push to prevent orphan blobs. From B-CODE-2. **File:** `src/domain/services/PatchBuilderV2.js` |
| B146 | **UNIFY `CorePersistence` / `FullPersistence` TYPEDEFS** — `CorePersistence` (`WarpPersistence.js`) and `FullPersistence` (`WarpGraph.js`) are identical `CommitPort & BlobPort & TreePort & RefPort` intersections. Consolidate into one canonical typedef and update all import sites. From B145 PR review. |
| ~~B146~~ | ✅ ~~**UNIFY `CorePersistence` / `FullPersistence` TYPEDEFS**~~replaced `FullPersistence` with imported `CorePersistence`. Done in v13.0.0. |
| B147 | **RFC FIELD COUNT DRIFT DETECTOR** — script that counts WarpGraph instance fields (grep `this._` in constructor) and warns if design RFC field counts diverge. Prevents stale numbers in `warpgraph-decomposition.md`. From B145 PR review. |

### CI & Tooling Pack
Expand Down Expand Up @@ -299,7 +271,7 @@ Items parked with explicit conditions for promotion.
| B20 | **TRUST RECORD ROUND-TRIP SNAPSHOT TEST** | Promote if trust record schema changes |
| B21 | **TRUST SCHEMA DISCRIMINATED UNION** | Promote if superRefine causes a bug or blocks a feature |
| B27 | **`TrustKeyStore` PRE-VALIDATED KEY CACHE** | Promote when `verifySignature` appears in any p95 flame graph above 5% of call time |
| B100 | **MAP vs RECORD ASYMMETRY** — `getNodeProps()` returns Map, `getEdgeProps()` returns Record. Breaking change either way. From B-FEAT-3. | Promote with next major version RFC |
| ~~B100~~ | ✅ ~~**MAP vs RECORD ASYMMETRY**~~ — `getNodeProps()` now returns `Record<string, unknown>`. Done in v13.0.0. | ~~Promote with next major version RFC~~ |
| B101 | **MERMAID `~~~` INVISIBLE-LINK FRAGILITY** — undocumented Mermaid feature for positioning. From B-DIAG-3. | Promote if Mermaid renderer update breaks `~~~` positioning |

---
Expand All @@ -312,21 +284,21 @@ B5, B6, B13, B17, B18, B25, B45 — rejected 2026-02-17 with cause recorded in `

## Execution Order

### Milestones: M10 → M12 → M13 → M14M11
### Milestones: M10 → M12 → M13 → M11M14

1. **M10 SENTINEL** — Trust + sync safety + correctness — DONE except B2 spec
1. **M10 SENTINEL** — Trust + sync safety + correctness — **DONE**
2. **M12 SCALPEL** — STANK audit cleanup (minus edge prop encoding) — **DONE** (all tasks complete, gate verified)
3. **M13 SCALPEL II** — Edge property canonicalization — **DONE** (internal model complete; wire-format cutover deferred by ADR 3)
4. **M14 HYGIENE** — Test quality, DRY extraction, SOLID quick-wins**NEXT** (from HEX_AUDIT)
5. **M11 COMPASS II** — Developer experience (B2 impl, B3, B11)after M14
4. **M11 COMPASS II** — Developer experience (B2 impl, B3, B11)✅ **DONE** (v13.0.0), archived
5. **M14 HYGIENE** — Test quality, DRY extraction, SOLID quick-wins**NEXT** (from HEX_AUDIT)

### Standalone Priority Sequence

Pick opportunistically between milestones. Recommended order within tiers:

1. ~~**Immediate** (B46, B47, B26, B71, B126)~~ — **ALL DONE.**
2. **Near-term correctness** (B44, B76, B80, B81, B124) — prioritize items touching core services
3. **Near-term DX** (B36, B37, B43, B125, B127) — test ergonomics and developer velocity
2. **Near-term correctness** (B76, B80, B81) — prioritize items touching core services
3. **Near-term DX** (B36, B37, B43, B127) — test ergonomics and developer velocity
4. **Near-term docs/types** (B34, B35) — alignment and documentation
5. **Near-term tooling** (B12, B48, B49, B53, B54, B57, B28) — remaining type safety items
6. **CI & Tooling Pack** (B83, B85–B88, B119, B123, B128) — batch as one PR
Expand All @@ -349,11 +321,11 @@ Pick opportunistically between milestones. Recommended order within tiers:
| **Milestone (M12)** | 18 | B66, B67, B70, B73, B75, B105–B115, B117, B118 |
| **Milestone (M13)** | 1 | B116 (internal: DONE; wire-format: DEFERRED) |
| **Milestone (M14)** | 16 | B130–B145 |
| **Standalone** | 39 | B12, B19, B22, B28, B34–B37, B43, B44, B48, B49, B53, B54, B57, B76, B79–B81, B83, B85–B88, B95–B99, B102–B104, B119, B123–B125, B127–B129, B146, B147 |
| **Standalone (done)** | 23 | B26, B46, B47, B50–B52, B55, B71, B72, B77, B78, B82, B84, B89–B94, B120–B122, B126 |
| **Deferred** | 8 | B4, B7, B16, B20, B21, B27, B100, B101 |
| **Standalone** | 35 | B12, B19, B22, B28, B34–B37, B43, B48, B49, B53, B54, B57, B76, B79–B81, B83, B85–B88, B95–B99, B102–B104, B119, B123, B127–B129, B147 |
| **Standalone (done)** | 29 | B26, B44, B46, B47, B50–B52, B55, B71, B72, B77, B78, B82, B84, B89–B94, B100, B120–B122, B124, B125, B126, B146, B148 |
| **Deferred** | 7 | B4, B7, B16, B20, B21, B27, B101 |
| **Rejected** | 7 | B5, B6, B13, B17, B18, B25, B45 |
| **Total tracked** | **122** (23 done) | |
| **Total tracked** | **123** total; 29 standalone done | |

### STANK.md Cross-Reference

Expand Down Expand Up @@ -455,11 +427,11 @@ Pick opportunistically between milestones. Recommended order within tiers:
## Final Command

Every milestone has a hard gate. No milestone blurs into the next.
Execution: M10 SENTINEL → **M12 SCALPEL** → **M13 SCALPEL II** → **M14 HYGIENE** → M11 COMPASS II. Standalone items fill the gaps.
Execution: M10 SENTINEL → **M12 SCALPEL** → **M13 SCALPEL II** → **M11 COMPASS II** → **M14 HYGIENE**. M11 is complete and archived. Standalone items fill the gaps.

M12 is complete (including T8/T9). M13 internal canonicalization (ADR 1) is complete — canonical `NodePropSet`/`EdgePropSet` semantics, wire gate split, reserved-byte validation, version namespace separation. The persisted wire-format half of B116 is deferred by ADR 2 and governed by ADR 3 readiness gates.

M14 HYGIENE is the current priority — test hardening, DRY extraction, and SOLID quick-wins from the HEX_AUDIT. M11 follows after M14.
M14 HYGIENE is the current priority — test hardening, DRY extraction, and SOLID quick-wins from the HEX_AUDIT. M11 is complete and archived in COMPLETED.md.

Rejected items live in `GRAVEYARD.md`. Resurrections require an RFC.
`BACKLOG.md` retired — all intake goes directly into this file (policy in `CLAUDE.md`).
Expand Down
Loading
Loading