Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
608b36a
fix: Lane 8 lint compliance — zero errors across 22 files
flyingrobots Apr 1, 2026
1bd0573
fix: Lane 9 lint compliance — zero errors across 22 files
flyingrobots Apr 1, 2026
49d69c1
fix: Lane 10 lint compliance — zero errors across 22 files (FINAL LANE)
flyingrobots Apr 1, 2026
c1ad505
fix: mop up final 13 lint stragglers — zero errors codebase-wide
flyingrobots Apr 1, 2026
11433b2
chore: add lint ratchet — zero-error invariant enforced at every gate
flyingrobots Apr 1, 2026
7eb9c0a
fix: TS4111 bracket-access compliance — 614 index-signature errors el…
flyingrobots Apr 1, 2026
03d3efa
fix: TSC Lane 2 — zero errors across 8 files
flyingrobots Apr 1, 2026
ae9f2fa
fix: TSC Lane 1 — zero errors across 6 files
flyingrobots Apr 1, 2026
aa66935
fix: TSC Lane 4 — zero errors across 15 files
flyingrobots Apr 1, 2026
95e5693
fix: TSC Lane 3 — zero errors across 11 files
flyingrobots Apr 1, 2026
c9671d5
Merge branch 'worktree-agent-a3c8ac74'
flyingrobots Apr 1, 2026
b4d2b0b
Merge branch 'worktree-agent-aa22fb83'
flyingrobots Apr 1, 2026
f6d5c06
Merge branch 'worktree-agent-a81ab056'
flyingrobots Apr 1, 2026
a7c6e7b
Merge branch 'worktree-agent-a90cb614'
flyingrobots Apr 1, 2026
a535cbb
fix: TSC Lane 5 — zero errors across 21 files
flyingrobots Apr 1, 2026
acc1755
fix: TSC Lane 6 — zero errors across 31 files
flyingrobots Apr 1, 2026
7a3d5d7
fix: TSC Lane 7 — zero errors across 55 files
flyingrobots Apr 1, 2026
d0b6e7e
fix: TSC Lane 8 — zero errors across 100 files
flyingrobots Apr 1, 2026
4562ab9
Merge branch 'worktree-agent-a6c61824'
flyingrobots Apr 1, 2026
b4bdd83
Merge branch 'worktree-agent-a9f2120f'
flyingrobots Apr 1, 2026
ab782c7
Merge branch 'worktree-agent-a752bfa8'
flyingrobots Apr 1, 2026
ff39b13
Merge branch 'worktree-agent-ae175dcf'
flyingrobots Apr 1, 2026
6130201
fix: ESLint cleanup group B — 7 files
flyingrobots Apr 1, 2026
a975664
fix: ESLint cleanup group A — 7 files
flyingrobots Apr 1, 2026
4fd9b64
fix: partial ESLint cleanup from interrupted agent
flyingrobots Apr 1, 2026
98588d3
Merge branch 'worktree-agent-a7651f20'
flyingrobots Apr 1, 2026
3bb3b43
Merge branch 'worktree-agent-a3ae68f1'
flyingrobots Apr 1, 2026
98ca1ff
fix: TSC zero — 1707 type errors eliminated codebase-wide
flyingrobots Apr 1, 2026
d4cc2aa
fix: restore 4 over-refactored files + minimal type fixes
flyingrobots Apr 1, 2026
cfafa92
test: failing spec for JoinReducer OpStrategy registry
flyingrobots Apr 1, 2026
3c6562a
refactor: JoinReducer OpStrategy registry — structurally coupled appl…
flyingrobots Apr 1, 2026
ca2ffba
fix: remove any casts from path equivalence test
flyingrobots Apr 1, 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
65 changes: 36 additions & 29 deletions bin/cli/commands/debug/conflicts.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,14 @@ function buildTargetSelector(val) {
if (val['target-kind'] === undefined) {
return null;
}
const typed = /** @type {{ from?: string, to?: string, label?: string, 'target-kind': string, 'entity-id'?: string, 'property-key'?: string }} */ (val);
return {
targetKind: val['target-kind'],
entityId: val['entity-id'],
propertyKey: val['property-key'],
from: val['from'],
to: val['to'],
label: val['label'],
targetKind: typed['target-kind'],
entityId: typed['entity-id'],
propertyKey: typed['property-key'],
from: typed.from,
to: typed.to,
label: typed.label,
};
}

Expand All @@ -202,15 +203,16 @@ function orNull(value) {
* @returns {{strandId: string|null, entityId: string|null, target: object|null, kinds: string[], writerId: string|null, lamportCeiling: number|null, evidence: string, maxPatches: number|null}}
*/
function transformConflictValues(val) {
const typed = /** @type {{ strand?: string, 'entity-id'?: string, kind?: string|string[], 'writer-id'?: string, 'lamport-ceiling'?: number, evidence?: string, 'max-patches'?: number }} */ (val);
return {
strandId: orNull(/** @type {string|undefined} */ (val['strand'])),
entityId: orNull(/** @type {string|undefined} */ (val['entity-id'])),
strandId: orNull(typed.strand),
entityId: orNull(typed['entity-id']),
target: buildTargetSelector(val),
kinds: normalizeKinds(/** @type {string|string[]|undefined} */ (val['kind'])),
writerId: orNull(/** @type {string|undefined} */ (val['writer-id'])),
lamportCeiling: orNull(/** @type {number|undefined} */ (val['lamport-ceiling'])),
evidence: /** @type {string|undefined} */ (val['evidence']) ?? 'standard',
maxPatches: orNull(/** @type {number|undefined} */ (val['max-patches'])),
kinds: normalizeKinds(typed.kind),
writerId: orNull(typed['writer-id']),
lamportCeiling: orNull(typed['lamport-ceiling']),
evidence: typed.evidence ?? 'standard',
maxPatches: orNull(typed['max-patches']),
};
}

Expand All @@ -233,30 +235,33 @@ const debugConflictsSchema = z.object({
}).strict().superRefine((val, ctx) => validateConflictSelectorShape(val, ctx)).transform(transformConflictValues);

/**
* Convert a nullable value to undefined for optional API fields.
* @param {unknown} value - Value that may be null.
* @returns {unknown}
* Spreads a key-value pair only if the value is not null.
* @template T
* @param {string} key - Property name
* @param {T|null} value - Nullable value
* @returns {Record<string, T>}
*/
function nullToUndefined(value) {
return value === null ? undefined : value;
function spreadNonNull(key, value) {
if (value === null) { return {}; }
return { [key]: value };
}

/**
* Build ConflictAnalyzeOptions from the parsed CLI spec and resolved lamport ceiling.
* @param {ReturnType<typeof debugConflictsSchema.parse>} spec - Parsed conflict filter spec.
* @param {{ strandId: string|null, entityId: string|null, target: { targetKind: "node"|"edge"|"node_property"|"edge_property", entityId?: string, propertyKey?: string, from?: string, to?: string, label?: string }|null, kinds: string[], writerId: string|null, evidence: "full"|"summary"|"standard", maxPatches: number|null }} spec - Parsed conflict filter spec.
* @param {number|null} lamportCeiling - Resolved lamport ceiling.
* @returns {import('../../../../src/domain/services/ConflictAnalyzerService.js').ConflictAnalyzeOptions}
*/
function buildConflictAnalyzeOptions(spec, lamportCeiling) {
return {
strandId: nullToUndefined(spec.strandId),
at: lamportCeiling === null ? undefined : { lamportCeiling },
entityId: nullToUndefined(spec.entityId),
target: nullToUndefined(spec.target),
kind: spec.kinds.length === 0 ? undefined : spec.kinds,
writerId: nullToUndefined(spec.writerId),
...spreadNonNull('strandId', spec.strandId),
...(lamportCeiling !== null ? { at: { lamportCeiling } } : {}),
...spreadNonNull('entityId', spec.entityId),
...spreadNonNull('target', spec.target),
...(spec.kinds.length > 0 ? { kind: spec.kinds } : {}),
...spreadNonNull('writerId', spec.writerId),
evidence: spec.evidence,
scanBudget: spec.maxPatches === null ? undefined : { maxPatches: spec.maxPatches },
...(spec.maxPatches !== null ? { scanBudget: { maxPatches: spec.maxPatches } } : {}),
};
}

Expand All @@ -267,15 +272,17 @@ function buildConflictAnalyzeOptions(spec, lamportCeiling) {
*/
export async function handleDebugTopic({ options, args }) {
const { values } = parseCommandArgs(args, DEBUG_CONFLICT_OPTIONS, debugConflictsSchema);
/** @type {{ strandId: string|null, entityId: string|null, target: { targetKind: "node"|"edge"|"node_property"|"edge_property", entityId?: string, propertyKey?: string, from?: string, to?: string, label?: string }|null, kinds: string[], writerId: string|null, lamportCeiling: number|null, evidence: "full"|"summary"|"standard", maxPatches: number|null }} */
const spec = /** @type {*} */ (values);
const { graph, graphName, activeCursor } = await openDebugContext(options);
const lamportCeiling = resolveLamportCeiling(values.lamportCeiling, activeCursor);
const analysis = await graph.analyzeConflicts(buildConflictAnalyzeOptions(values, lamportCeiling));
const lamportCeiling = resolveLamportCeiling(spec.lamportCeiling, activeCursor);
const analysis = await graph.analyzeConflicts(buildConflictAnalyzeOptions(spec, lamportCeiling));

return {
payload: {
graph: graphName,
debugTopic: 'conflicts',
...(values.strandId !== null ? { strandId: values.strandId } : {}),
...(spec.strandId !== null ? { strandId: spec.strandId } : {}),
...analysis,
},
exitCode: EXIT_CODES.OK,
Expand Down
12 changes: 6 additions & 6 deletions bin/cli/commands/strand/materialize.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ const materializeStrandSchema = z.object({
* @returns {{payload: unknown, exitCode: number}}
*/
function buildMaterializePayload(graphName, strand, materialized) {
const mat = /** @type {Record<string, unknown>} */ (materialized);
const mat = /** @type {{ state?: { nodeAlive: unknown, edgeAlive: unknown, prop: Map<string, unknown> }, receipts?: unknown[] }} */ (materialized);
const state = /** @type {{ nodeAlive: unknown, edgeAlive: unknown, prop: Map<string, unknown> }} */ (
'state' in mat ? mat['state'] : mat
mat.state !== undefined ? mat.state : mat
);
const receipts = 'state' in mat ? /** @type {unknown[]|undefined} */ (mat['receipts']) : undefined;
const receipts = mat.state !== undefined ? mat.receipts : undefined;

return {
payload: {
Expand All @@ -41,8 +41,8 @@ function buildMaterializePayload(graphName, strand, materialized) {
state,
receipts,
summary: {
nodeCount: orsetElements(state.nodeAlive).length,
edgeCount: orsetElements(state.edgeAlive).length,
nodeCount: orsetElements(/** @type {import('../../../../src/domain/crdt/ORSet.js').ORSet} */ (state.nodeAlive)).length,
edgeCount: orsetElements(/** @type {import('../../../../src/domain/crdt/ORSet.js').ORSet} */ (state.edgeAlive)).length,
propertyCount: state.prop.size,
receiptCount: receipts?.length ?? 0,
},
Expand All @@ -62,7 +62,7 @@ export async function handleStrandSubcommand({ options, args }) {
throw usageError('Usage: warp-graph strand materialize <id> [--receipts]');
}

const strandId = positionals[0];
const strandId = /** @type {string} */ (positionals[0]);
const { graph, graphName } = await openGraph(options);
const strand = await graph.getStrand(strandId);
if (!strand) {
Expand Down
10 changes: 5 additions & 5 deletions scripts/check-dts-surface.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export function parseExportBlock(blockBody) {
const withoutTypeKeyword = trimmed.replace(/^type\s+/, '');
// Handle `Foo as Bar` — the exported name is Bar
const asParts = withoutTypeKeyword.split(/\s+as\s+/);
const exportedName = (asParts.length > 1 ? asParts[1] : asParts[0]).trim();
const exportedName = (asParts.length > 1 ? asParts[1] ?? '' : asParts[0] ?? '').trim();
if (exportedName) {
names.add(exportedName);
}
Expand All @@ -78,7 +78,7 @@ export function parseExportBlock(blockBody) {
function collectExportBlocks(src) {
const names = new Set();
for (const m of src.matchAll(/export\s*\{([^}]+)\}/g)) {
for (const name of parseExportBlock(m[1])) {
for (const name of parseExportBlock(m[1] ?? '')) {
names.add(name);
}
}
Expand All @@ -94,15 +94,15 @@ export function extractJsExports(src) {
const names = collectExportBlocks(src);
// Match standalone `export const Foo` / `export function Foo` / `export class Foo`
for (const m of src.matchAll(/export\s+(?:const|function|class)\s+(\w+)/g)) {
names.add(m[1]);
names.add(m[1] ?? '');
}
// Match `export default class Foo` / `export default function Foo`
for (const m of src.matchAll(/export\s+default\s+(?:class|function)\s+(\w+)/g)) {
names.add(m[1]);
names.add(m[1] ?? '');
}
// Match `export default Foo` (standalone identifier)
for (const m of src.matchAll(/export\s+default\s+([A-Z_$][\w$]*)/g)) {
names.add(m[1]);
names.add(m[1] ?? '');
}
return names;
}
Expand Down
5 changes: 3 additions & 2 deletions src/domain/services/BisectService.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,12 @@ export default class BisectService {

// Single candidate — it must be the first bad patch
if (candidates.length === 1) {
return foundResult({ writerId, entry: candidates[0], steps: 0, totalCandidates: 1 });
return foundResult({ writerId, entry: /** @type {typeof candidates[0] & {}} */ (candidates[0]), steps: 0, totalCandidates: 1 });
}

// Binary search over the candidate range
const { index, steps } = await this._binarySearch(candidates, testFn);
return foundResult({ writerId, entry: candidates[index], steps, totalCandidates: candidates.length });
return foundResult({ writerId, entry: /** @type {typeof candidates[0] & {}} */ (candidates[index]), steps, totalCandidates: candidates.length });
}

/**
Expand All @@ -134,6 +134,7 @@ export default class BisectService {
while (lo < hi) {
const mid = Math.floor((lo + hi) / 2);
const candidate = candidates[mid];
if (candidate === undefined) { break; }
steps++;

const state = await this._graph.materialize({ ceiling: candidate.patch.lamport });
Expand Down
73 changes: 24 additions & 49 deletions src/domain/services/BitmapIndexBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ export function resetNativeRoaringFlag() {
_nativeRoaringAvailable = null;
}

/**
* Lazily initializes and returns the RoaringBitmap32 constructor.
* @returns {typeof import('roaring').RoaringBitmap32}
*/
const ensureRoaringBitmap32 = () => {
const RoaringBitmap32 = getRoaringBitmap32();
if (_nativeRoaringAvailable === null) {
Expand Down Expand Up @@ -147,23 +143,7 @@ export default class BitmapIndexBuilder {
/** @type {Record<string, Uint8Array>} */
const tree = {};

await this._serializeIdShards(tree);
await this._serializeBitmapShards(tree);

if (frontier) {
serializeFrontierToTree(frontier, tree, this._codec);
}

return tree;
}

/**
* Shards SHA→ID mappings by prefix and writes them to the tree.
* @param {Record<string, Uint8Array>} tree
* @returns {Promise<void>}
* @private
*/
async _serializeIdShards(tree) {
// Serialize ID mappings (sharded by prefix)
/** @type {Record<string, Record<string, number>>} */
const idShards = {};
for (const [sha, id] of this.shaToId) {
Expand All @@ -176,41 +156,36 @@ export default class BitmapIndexBuilder {
for (const [prefix, map] of Object.entries(idShards)) {
tree[`meta_${prefix}.json`] = textEncode(JSON.stringify(await wrapShard(map, this._crypto)));
}
}

/**
* Shards bitmap data by type and prefix, then writes to the tree.
* @param {Record<string, Uint8Array>} tree
* @returns {Promise<void>}
* @private
*/
async _serializeBitmapShards(tree) {
const bitmapShards = this._groupBitmapsByTypeAndPrefix();
for (const type of ['fwd', 'rev']) {
// Serialize bitmaps (sharded by prefix, per-node within shard)
// Keys are constructed as '${type}_${sha}' by _addToBitmap (e.g., 'fwd_abc123', 'rev_def456')
/** @type {{ fwd: Record<string, Record<string, string>>, rev: Record<string, Record<string, string>> }} */
const bitmapShards = { fwd: {}, rev: {} };
for (const [key, bitmap] of this.bitmaps) {
const [type, sha] = [key.substring(0, 3), key.substring(4)];
const prefix = sha.substring(0, 2);

const typeShard = type === 'fwd' ? bitmapShards.fwd : bitmapShards.rev;
if (!typeShard[prefix]) {
typeShard[prefix] = {};
}
// Encode bitmap as base64 for JSON storage
/** @type {Record<string, string>} */
const prefixShard = (typeShard[prefix] ?? {});
prefixShard[sha] = base64Encode(new Uint8Array(bitmap.serialize(true)));
}

for (const type of /** @type {const} */ (['fwd', 'rev'])) {
for (const [prefix, shardData] of Object.entries(bitmapShards[type])) {
tree[`shards_${type}_${prefix}.json`] = textEncode(JSON.stringify(await wrapShard(shardData, this._crypto)));
}
}
}

/**
* Groups bitmap entries by type (fwd/rev) and SHA prefix.
* @returns {Record<string, Record<string, Record<string, string>>>}
* @private
*/
_groupBitmapsByTypeAndPrefix() {
/** @type {Record<string, Record<string, Record<string, string>>>} */
const bitmapShards = { fwd: {}, rev: {} };
for (const [key, bitmap] of this.bitmaps) {
const type = key.substring(0, 3);
const sha = key.substring(4);
const prefix = sha.substring(0, 2);
if (!bitmapShards[type][prefix]) {
bitmapShards[type][prefix] = {};
}
bitmapShards[type][prefix][sha] = base64Encode(new Uint8Array(bitmap.serialize(true)));
if (frontier) {
serializeFrontierToTree(frontier, tree, this._codec);
}
return bitmapShards;

return tree;
}

/**
Expand Down
13 changes: 7 additions & 6 deletions src/domain/services/DagTraversal.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,9 @@ export default class DagTraversal {
const neighbors = await this._getNeighbors(current.sha, direction);
// Push in reverse order so first neighbor is processed first
for (let i = neighbors.length - 1; i >= 0; i--) {
if (!visited.has(neighbors[i])) {
stack.push({ sha: neighbors[i], depth: current.depth + 1, parent: current.sha });
const neighbor = neighbors[i];
if (neighbor !== undefined && !visited.has(neighbor)) {
stack.push({ sha: neighbor, depth: current.depth + 1, parent: current.sha });
}
}
}
Expand All @@ -172,7 +173,7 @@ export default class DagTraversal {
* @yields {TraversalNode} Ancestor nodes in BFS order
*/
async *ancestors({ sha, maxNodes = DEFAULT_MAX_NODES, maxDepth = DEFAULT_MAX_DEPTH, signal }) {
yield* this.bfs({ start: sha, maxNodes, maxDepth, direction: 'reverse', signal });
yield* this.bfs({ start: sha, maxNodes, maxDepth, direction: 'reverse', ...(signal !== undefined ? { signal } : {}) });
}

/**
Expand All @@ -182,7 +183,7 @@ export default class DagTraversal {
* @yields {TraversalNode} Descendant nodes in BFS order
*/
async *descendants({ sha, maxNodes = DEFAULT_MAX_NODES, maxDepth = DEFAULT_MAX_DEPTH, signal }) {
yield* this.bfs({ start: sha, maxNodes, maxDepth, direction: 'forward', signal });
yield* this.bfs({ start: sha, maxNodes, maxDepth, direction: 'forward', ...(signal !== undefined ? { signal } : {}) });
}

/**
Expand All @@ -196,14 +197,14 @@ export default class DagTraversal {
*/
async isReachable({ from, to, maxDepth = DEFAULT_MAX_DEPTH, signal }) {
if (this._pathFinder) {
const result = await this._pathFinder.findPath({ from, to, maxDepth, signal });
const result = await this._pathFinder.findPath({ from, to, maxDepth, ...(signal !== undefined ? { signal } : {}) });
return result.found;
}
// Fallback: BFS-based reachability
if (from === to) {
return true;
}
for await (const node of this.bfs({ start: from, maxDepth, direction: 'forward', signal })) {
for await (const node of this.bfs({ start: from, maxDepth, direction: 'forward', ...(signal !== undefined ? { signal } : {}) })) {
if (node.sha === to) {
return true;
}
Expand Down
Loading