Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ jobs:
run: npm run typecheck:surface
- name: 'Gate 6: Markdown lint (fenced code blocks require language)'
run: npm run lint:md
- name: 'Gate 7: Security audit (runtime deps, advisory)'
- name: 'Gate 7: Markdown JS/TS code-sample syntax check'
run: npm run lint:md:code
- name: 'Gate 8: Security audit (runtime deps, advisory)'
continue-on-error: true
run: npm audit --omit=dev --audit-level=high

Expand Down
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Fluent `WarpStateV5` test builder** — Added `createStateBuilder()` in `test/helpers/stateBuilder.js` so state-heavy tests can seed nodes, edges, removals, properties, frontier state, and graph materialization through one fluent helper instead of ad hoc OR-Set/LWW mutation.
- **Seeded tree-construction determinism fuzzer** — Added property-based coverage for patch and checkpoint tree construction, proving stable tree OIDs across internal content-anchor permutations in `PatchBuilderV2` and shuffled content-property insertion order in `CheckpointService.createV5()`.
- **Focused markdownlint gate** — Added `npm run lint:md` backed by `markdownlint-cli` and a repo config that enforces fenced code-block languages (`MD040`) across Markdown files.
- **Markdown JS/TS code-sample linter** — Added `npm run lint:md:code`, which scans fenced JavaScript and TypeScript blocks in Markdown and syntax-checks them with the TypeScript parser for file/line-accurate diagnostics.

### Changed

- **Large-graph traversal memory profile** — `topologicalSort()` now has a lightweight mode that avoids retaining discovery adjacency when callers do not need it. `levels()` and `transitiveReduction()` were refactored to re-fetch neighbors on demand instead of pinning full topo adjacency in memory, reducing steady-state large-graph working sets.
- **Surface validation accounting** — The declaration surface checker now distinguishes runtime-backed exports from type-only manifest entries and understands namespace declarations, which makes the type-surface contract tighter without forcing runtime exports for pure types.
- **Local push firewall now matches CI surface checks** — `scripts/hooks/pre-push` now runs `npm run typecheck:surface` alongside lint, strict typecheck, policy, and consumer surface checks before unit tests, so declaration-surface drift is blocked locally instead of waiting for CI.
- **Local push firewall now matches CI surface and docs checks** — `scripts/hooks/pre-push` now runs `npm run typecheck:surface`, `npm run lint:md`, and `npm run lint:md:code` alongside lint, strict typecheck, policy, and consumer surface checks before unit tests, so declaration-surface drift and Markdown sample regressions are blocked locally instead of waiting for CI.
- **Trust test infrastructure deduplicated** — The TrustRecordService suites now share a single in-memory ref/blob/tree/commit fixture and JSON codec via `test/helpers/trustTestUtils.js`, eliminating the four forked mock implementations that had started to drift.
- **Explicit type-only export manifest section** — `type-surface.m8.json` now separates runtime `exports` from declaration-only `typeExports`, and the surface checker now fails on misplaced or duplicate entries across those sections.
- **Constructor option-bag defaults made explicit** — Added an ESLint rule banning `constructor({ ... } = {})` in source files and rewrote the remaining constructors to destructure an explicit `options` bag inside the constructor body. This avoids accidentally marking required constructor params optional in JSDoc and strict type checking.
- **Checkpoint content-anchor batching** — `CheckpointService.createV5()` now folds content blob OIDs into sorted anchor entries in batches instead of building one monolithic `Set` before tree serialization. Added direct checkpoint coverage for anchor dedupe, deterministic ordering, and load-path indifference to `_content_*` anchor entries.
- **CI gate dedupe** — Folded the duplicate `lint` workflow job into `type-firewall` and carried forward the advisory runtime `npm audit` step there, leaving one authoritative lint/type gate in the main CI workflow.
- **Markdown fence labeling sweep** — Unlabeled Markdown code fences now declare a language such as `text`, letting the new markdown gate verify docs/examples without broad style-rule churn.
- **Docs static firewall extended** — The CI fast gate now runs both markdown fence-language checks and JavaScript/TypeScript code-sample syntax validation before the runtime matrix jobs.

### Fixed

- **Deno CI resolver drift** — The Deno test image now imports a Node 22 npm toolchain from `node:22-slim`, installs dependencies with `npm ci`, and runs tests with `--node-modules-dir=manual`, avoiding runtime npm re-resolution of `cbor-extract` optional platform packages while keeping the container on the repo’s supported Node engine line.
- **Markdown code-sample linter edge cases** — The Markdown JS/TS sample linter now recognizes fenced code blocks indented by up to three spaces, rejects malformed mixed-marker fences, fails on unterminated JS/TS fences, and parses snippets with the repository’s configured TypeScript target from `tsconfig.base.json`.
- **B87 review follow-ups** — Clarified the ADR folds snippet as a wholly proposed `graph.view()` sketch, corrected the pre-push quick-mode gate label to Gate 8, aligned the local hook’s gate numbers with CI for faster failure triage, and removed the self-expiring `pending merge` wording from the completed-roadmap archive entry.
- **Signed trust verification now performs real crypto checks** — Trust evaluation now verifies Ed25519 signatures and key fingerprints during evidence processing instead of stopping at envelope/shape validation.
- **Browser/WebSocket serve payload parity for edge properties** — `WarpServeService` state payloads now include edge properties, so served graph views no longer drop part of the graph model.
- **`attachContent()` / `attachEdgeContent()` orphan blob writes** — Content attachment now validates the target node/edge before writing blob content, preventing orphaned blob storage on invalid mutations.
Expand Down
16 changes: 8 additions & 8 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,15 +204,15 @@ P1 is complete on `v15`: B36 and B37 landed as the shared test-foundation pass,

### P2 — CI & Tooling (one batch PR)

`B83`, `B85`, `B57`, and `B86` are complete on `v15`: the redundant `lint` workflow job was folded into `type-firewall`, the declaration surface manifest now splits runtime `exports` from type-only `typeExports`, the local pre-push firewall now runs `typecheck:surface` alongside the other type gates, and CI now runs markdownlint for fenced-code language coverage. Remaining P2 work now starts at B87. B123 is still the largest item and may need to split out if the PR gets too big.
`B83`, `B85`, `B57`, and `B86` are already merged. `B87` is complete in `feature/b87-markdown-code-lint`: the new script syntax-checks fenced JavaScript/TypeScript samples in Markdown, the CI fast gate runs it after markdownlint, the local pre-push firewall mirrors that coverage, and malformed/unterminated JS/TS fences now fail with file/line diagnostics. If this branch lands, remaining P2 work starts at B88. B123 is still the largest item and may need to split out if the PR gets too big.

| ID | Item | Depends on | Effort |
| ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------- | ------ |
| B83 | ✅ **DEDUP CI `type-firewall` AND `lint` JOBS** — Folded the duplicate `lint` job into `type-firewall` and carried forward the advisory runtime `npm audit` step there, leaving one authoritative lint/type gate in CI. **File:** `.github/workflows/ci.yml` | — | S |
| B85 | ✅ **TYPE-ONLY EXPORT MANIFEST SECTION** — Added explicit `typeExports` to `type-surface.m8.json` and taught `check-dts-surface` to fail on misplaced or duplicate entries across `exports` and `typeExports`, so type-only declaration drift is validated directly instead of inferred from `kind`. | B97 (P0) | S |
| B57 | ✅ **AUTO-VALIDATE `type-surface.m8.json` AGAINST `index.d.ts`** — `typecheck:surface` now runs in CI, release preflight, and the local `scripts/hooks/pre-push` firewall, so declaration-surface drift is blocked before push instead of only after CI starts. | B97, B85 | M |
| B86 | ✅ **MARKDOWNLINT CI GATE** — Added `npm run lint:md` with focused `MD040` enforcement and wired it into `.github/workflows/ci.yml`, so fenced code blocks in Markdown must declare a language before CI passes. | — | S |
| B87 | **CODE SAMPLE LINTER** — syntax-check JS/TS code blocks in markdown files via `eslint-plugin-markdown` or custom extractor. From B-DOC-2. **Files:** new script, `docs/**/*.md` | — | M |
| B87 | **CODE SAMPLE LINTER** — Added `scripts/lint-markdown-code-samples.js` plus `npm run lint:md:code`, which extracts fenced JavaScript/TypeScript samples from Markdown and syntax-checks them with file/line diagnostics. Wired into `.github/workflows/ci.yml` and the local `scripts/hooks/pre-push` firewall, with explicit failures for malformed mixed-marker fences and unterminated JS/TS blocks. | — | M |
| B88 | **MERMAID RENDERING SMOKE TEST** — parse all ` ```mermaid ` blocks with `@mermaid-js/mermaid-cli` in CI. From B-DIAG-2. **File:** `.github/workflows/ci.yml` or `scripts/` | — | S |
| B119 | **`scripts/pr-ready` MERGE-READINESS CLI** — single tool aggregating unresolved review threads, pending/failed checks, CodeRabbit status/cooldown, and human-review count into one deterministic verdict. From BACKLOG 2026-02-27/28. | — | M |
| B123 | **BENCHMARK BUDGETS + CI REGRESSION GATE** — define perf thresholds for eager post-commit and materialize hash cost; fail CI on agreed regression. From BACKLOG 2026-02-27. | — | L |
Expand Down Expand Up @@ -335,9 +335,9 @@ Complete on `v15`: **B80** and **B99**.

#### Wave 2: CI & Tooling (P2, one batch PR)

3. **B87, B88, B119, B123, B128, B12, B43**
3. **B88, B119, B123, B128, B12, B43**

Internal chain: **B97 already resolved on v15** → B85 → B57. That chain is complete on `v15`; B86 closed the first docs-quality gate in the remaining P2 pack. B123 remains the largest remaining item and may need to split out.
Internal chain: **B97 already resolved** → B85 → B57. That chain is complete, and this branch adds B87 on top of the existing B86 markdown gate to cover JS/TS sample syntax. B123 remains the largest remaining item and may need to split out.

#### Wave 3: Type Surface (P3)

Expand Down Expand Up @@ -395,11 +395,11 @@ B158 (P7) ──→ B159 (P7) CDC seek cache
| **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** | 25 | B12, B28, B34–B35, B43, B53, B54, B76, B79, B87–B88, B96, B98, B102–B104, B119, B123, B127–B129, B147, B152, B155–B156 |
| **Standalone (done)** | 60 | B19, B22, B26, B36–B37, B44, B46, B47, B48–B52, B55, B57, B71, B72, B77, B78, B80–B86, B89–B95, B97, B99–B100, B120–B122, B124, B125, B126, B146, B148–B151, B153, B154, B157–B165, B167 |
| **Standalone** | 24 | B12, B28, B34–B35, B43, B53, B54, B76, B79, B88, B96, B98, B102–B104, B119, B123, B127–B129, B147, B152, B155–B156 |
| **Standalone (done)** | 61 | B19, B22, B26, B36–B37, B44, B46, B47, B48–B52, B55, B57, B71, B72, B77, B78, B80–B87, B89–B95, B97, B99–B100, B120–B122, B124, B125, B126, B146, B148–B151, B153, B154, B157–B165, B167 |
| **Deferred** | 7 | B4, B7, B16, B20, B21, B27, B101 |
| **Rejected** | 7 | B5, B6, B13, B17, B18, B25, B45 |
| **Total tracked** | **144** total; 60 standalone done | |
| **Total tracked** | **144** total; 61 standalone done | |

### STANK.md Cross-Reference

Expand Down Expand Up @@ -503,7 +503,7 @@ B158 (P7) ──→ B159 (P7) CDC seek cache
Every milestone has a hard gate. No milestone blurs into the next.
All milestones are complete: M10 → M12 → M13 (internal) → M11 → M14. M13 wire-format cutover remains deferred by ADR 3 readiness gates.

The active backlog is **25 standalone items** sorted into **8 priority tiers** (P0–P7) with **6 execution waves**. Wave 1 is complete on `v15`, and Wave 2 now starts at B87 in the CI & Tooling pack. See [Execution Order](#execution-order) for the full sequence.
The active backlog is **24 standalone items** sorted into **8 priority tiers** (P0–P7) with **6 execution waves**. Wave 1 is complete, and with B87 in this branch, Wave 2 now starts at B88 in the CI & Tooling pack. See [Execution Order](#execution-order) for the full sequence.

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
2 changes: 1 addition & 1 deletion docker-compose.test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,5 @@ services:
environment:
- GIT_STUNTS_DOCKER=1
# Keep allow-scripts package names aligned with package.json dependencies.
command: ["deno", "test", "--allow-all", "--allow-scripts=npm:roaring,npm:cbor-extract", "--node-modules-dir=auto", "test/runtime/deno/"]
command: ["deno", "test", "--allow-all", "--allow-scripts=npm:roaring,npm:cbor-extract", "--node-modules-dir=manual", "test/runtime/deno/"]
profiles: [deno, full]
29 changes: 15 additions & 14 deletions docker/Dockerfile.deno
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,41 @@
# Runs: API integration tests using Deno.test() wrappers.
# CLI and unit tests are excluded — they depend on vitest / node: built-ins.
# Build context is the parent monorepo directory (context: ..).
FROM node:22-slim AS node22

FROM denoland/deno:2.1.9
ARG DENO_ALLOW_SCRIPTS="npm:roaring,npm:cbor-extract"
USER root
COPY --from=node22 /usr/local/bin/node /usr/local/bin/node
COPY --from=node22 /usr/local/bin/npm /usr/local/bin/npm
COPY --from=node22 /usr/local/bin/npx /usr/local/bin/npx
COPY --from=node22 /usr/local/lib/node_modules /usr/local/lib/node_modules
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
python3 \
make \
g++ \
# Needed on PATH for Deno npm lifecycle fallback builds (roaring/cbor-extract).
node-gyp \
&& rm -rf /var/lib/apt/lists/*
RUN ln -sf /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
&& ln -sf /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx \
# Needed on PATH for Deno npm lifecycle fallback builds (roaring/cbor-extract).
&& ln -sf /usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js /usr/local/bin/node-gyp
WORKDIR /app
COPY git-warp/package*.json ./
COPY git-warp/scripts ./scripts
COPY git-warp/patches ./patches
RUN npm ci
COPY git-warp/ .
# Init a git repo so plumbing operations work inside the container.
RUN git init -q \
&& git config user.email "container@git-warp.local" \
&& git config user.name "Git Warp Container" \
&& git add -A \
&& git commit --allow-empty -m "seed git-warp" >/dev/null
# Install npm dependencies for Deno test entrypoints and allow native addon
# lifecycle scripts so roaring/cbor-extract are prepared before test execution.
RUN printf '%s\n' \
"import 'npm:roaring';" \
"import 'npm:cbor-extract';" \
> /tmp/deno-npm-bootstrap.ts \
&& deno install \
--allow-scripts=${DENO_ALLOW_SCRIPTS} \
--node-modules-dir=auto \
--entrypoint /tmp/deno-npm-bootstrap.ts \
&& rm /tmp/deno-npm-bootstrap.ts
# Run tests as non-root to mirror CI and catch permission issues.
# Also chown Deno's global cache so the deno user can fetch npm packages at runtime.
RUN chown -R deno:deno /app /deno-dir
USER deno
ENV GIT_STUNTS_DOCKER=1
ENV DENO_ALLOW_SCRIPTS=${DENO_ALLOW_SCRIPTS}
CMD ["sh", "-lc", "deno test --allow-all --allow-scripts=${DENO_ALLOW_SCRIPTS} --node-modules-dir=auto test/runtime/deno/"]
CMD ["sh", "-lc", "deno test --allow-all --allow-scripts=${DENO_ALLOW_SCRIPTS} --node-modules-dir=manual test/runtime/deno/"]
12 changes: 7 additions & 5 deletions docs/ADR-001-Folds.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,14 @@ Folds should be exposed as explicit view operations, not implicit traversal surp

#### 3.1 View API

```javascript
const view = graph.view({ fold: { mode: "shallow", maxDepth: 1 } });
_Proposed API sketch: the entire `graph.view()` flow shown below, including `view.traverse()`, `view.query().match().run()`, and `view.renderAscii()`, is not implemented yet._

```ts
const view = graph.view({ fold: { mode: 'shallow', maxDepth: 1 } });

await view.traverse(startNodeId);
await view.query(...);
await view.renderAscii(...);
await view.query().match('doc:*').run();
await view.renderAscii();
```

`graph.view()` returns a wrapper that:
Expand All @@ -134,7 +136,7 @@ await view.renderAscii(...);

#### 3.2 Attachment Graph Accessors

```javascript
```text
// returns fold root id (even if fold is empty)
graph.getFoldRootForNode(nodeId) -> string

Expand Down
Loading
Loading