Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
ad7fd8f
feat: checkpoint
indietyp Jun 30, 2026
4c7c562
fix: suggestions from code review
indietyp Jul 1, 2026
c2c0728
fix: spawn blocking for clustering
indietyp Jul 1, 2026
a63a05a
fix: regenerate
indietyp Jul 1, 2026
c1c0f7f
fix: unnest sql query
indietyp Jul 1, 2026
3b5b26e
fix: lints
indietyp Jul 1, 2026
d1c214e
fix: lints
indietyp Jul 1, 2026
2249f1b
fix: openapi schema
indietyp Jul 1, 2026
30a58fb
feat: performance + code review
indietyp Jul 1, 2026
f3b9ccf
feat: performance + code review
indietyp Jul 1, 2026
0791385
feat: code review
indietyp Jul 1, 2026
fdb2988
feat: code review
indietyp Jul 1, 2026
70b32b7
feat: code review
indietyp Jul 1, 2026
14c6038
feat: code review
indietyp Jul 1, 2026
35fbfc5
feat: code review
indietyp Jul 1, 2026
709e97f
feat: code review
indietyp Jul 1, 2026
e7492d4
feat: checkpoint
indietyp Jul 2, 2026
3828582
feat: checkpoint
indietyp Jul 2, 2026
409c127
feat: checkpoint
indietyp Jul 2, 2026
c5a376b
chore: docs
indietyp Jul 2, 2026
817f459
feat: checkpoint
indietyp Jul 2, 2026
9e54d3e
feat: checkpoint
indietyp Jul 2, 2026
829669e
feat: checkpoint
indietyp Jul 2, 2026
980cf0f
feat: checkpoint
indietyp Jul 2, 2026
1be5405
feat: explode components
indietyp Jul 2, 2026
c9664ab
feat: checkpoint
indietyp Jul 2, 2026
59a86d7
feat: v2 -> v1
indietyp Jul 2, 2026
cc848aa
feat: docs + atlas
indietyp Jul 2, 2026
9efcf70
feat: make everything configurable!
indietyp Jul 2, 2026
1a9ab8e
feat: remove the old
indietyp Jul 2, 2026
8115158
temp: snapshot
indietyp Jul 2, 2026
9189bda
temp: snapshot II
indietyp Jul 2, 2026
8bfb19d
feat: majorization improvements + UI
indietyp Jul 3, 2026
9b7fef6
fix: docs
indietyp Jul 3, 2026
121cd22
fix: docs
indietyp Jul 3, 2026
106d8b6
Split worker into entity lifecycle: EntityGraphWorker under worker/en…
indietyp Jul 3, 2026
b640a53
Add type-graph worker lifecycle (INIT_TYPE): TypeGraphWorker, shared …
indietyp Jul 3, 2026
b73b95e
Split worker connection into FrameConnection base + entity/type subcl…
indietyp Jul 3, 2026
5acc1b9
Parameterize the scene pipeline over node identity via SceneHandle
indietyp Jul 3, 2026
40bf969
Restructure React bridges: entity bridge under entity-graph/, scene i…
indietyp Jul 3, 2026
37a5afc
Add the type-graph bridge: types page Graph view on the new visualizer
indietyp Jul 3, 2026
ef03e7a
Migrate the flow outputs graph to the new EntityGraphVisualizer
indietyp Jul 3, 2026
7f0801a
Remove the sigma-based visualizers and their dependencies
indietyp Jul 3, 2026
9bffac9
feat: embedding clustering review
indietyp Jul 3, 2026
0a40786
fix: double mount
indietyp Jul 3, 2026
6865e31
chore: diagram
indietyp Jul 3, 2026
fa9b35a
chore: lockfile
indietyp Jul 3, 2026
43c3fc0
feat: do not loosely type
indietyp Jul 3, 2026
d3bcecd
chore: remove fixture
indietyp Jul 3, 2026
2bfd8ba
chore: fix schema
indietyp Jul 3, 2026
41072dd
chore: remove straggler
indietyp Jul 3, 2026
48ce240
chore: remove straggler
indietyp Jul 3, 2026
3cc5897
feat: add scripts
indietyp Jul 6, 2026
7a8ddad
fix: warm up repository on CI
indietyp Jul 6, 2026
336dd2f
fix: docs
indietyp Jul 6, 2026
4685963
chore: bound the threads inside of benchmarking + thread pool limit
indietyp Jul 6, 2026
fa9c9da
feat: limit request + remove clustering unsafe
indietyp Jul 6, 2026
505d16a
fix: wording
indietyp Jul 6, 2026
7ebfe44
chore: regen openapi
indietyp Jul 6, 2026
60603e4
chore: docs
indietyp Jul 6, 2026
7c1dcbe
feat: change the accumulate clusters method
indietyp Jul 6, 2026
0138056
chore: docs
indietyp Jul 6, 2026
2dafd88
feat: move into embeddings crate
indietyp Jul 7, 2026
aff3317
fix: CI
indietyp Jul 7, 2026
eb38f87
chore: regenerate files
indietyp Jul 7, 2026
5f7fd58
fix: the darn yarn lockfile
indietyp Jul 7, 2026
77ada17
chore: remove tautological tests
indietyp Jul 7, 2026
02d2958
feat: only initialize once.
indietyp Jul 7, 2026
1d4a1f7
fix: docs
indietyp Jul 7, 2026
4a31268
chore: remove file
indietyp Jul 7, 2026
0bb8726
feat: move to rayon spawns
indietyp Jul 7, 2026
4119460
feat: test
indietyp Jul 7, 2026
3fd0938
chore: lockfile
indietyp Jul 7, 2026
464e3b0
fix: suggestions from (external) code review
indietyp Jul 8, 2026
0aa7d67
feat: dedupe query and make it deterministic
indietyp Jul 8, 2026
90538eb
fix: docs
indietyp Jul 8, 2026
50be867
fix: schema
indietyp Jul 8, 2026
e1e9473
feat: checkpoint
indietyp Jun 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
275 changes: 275 additions & 0 deletions .claude/skills/documenting-typescript-code/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
---
name: documenting-typescript-code
description: TypeScript documentation and comment-writing guide for doc comments (TSDoc), file headers, and inline comments. Use when writing or reviewing doc comments, documenting functions/types/modules, writing inline comments, explaining invariants, or auditing comment quality in TypeScript code.
license: AGPL-3.0
metadata:
triggers:
type: domain
enforcement: suggest
priority: high
keywords:
- tsdoc
- jsdoc
- doc comment
- inline comment
- documentation
intent-patterns:
- "\\bdocument(ing|ation)?\\b.*?\\b(typescript|function|type|interface|class|module)\\b"
- "\\b(write|add|create|review|clean)\\b.*?\\bcomments?\\b"
---

# TypeScript Documentation Guide

## Purpose

Use this skill to write or revise TypeScript documentation β€” TSDoc comments, file headers, and inline `//` comments β€” that is practical, user-oriented, explicit about contracts, and honest about tradeoffs. The goal is documentation that helps a reader make a correct decision quickly, then gives them enough detail to avoid surprises later.

The key trait is explicitness without fuss. Docs should feel like an experienced maintainer sitting next to the reader saying, "Here is the thing, here is how you use it, and here are the traps."

## Maintaining this skill

This is a living document. When a doc comment gets corrected or reworded in review, or a pattern emerges that is not captured here, update the skill to reflect it. The same applies in reverse: if a rule consistently produces worse docs than ignoring it, rework or remove that section. The goal is a skill that stays useful, not one that stays unchanged.

## The three comment layers

TypeScript code has three distinct documentation layers, each with its own job:

1. **File header block** β€” a `/** ... */` (or plain block) comment at the top of a module. States what the module owns, the mental model, and the invariants that span the whole file. Required for modules with non-trivial responsibilities; skip for trivial re-export or single-component files.
2. **TSDoc on exported items** β€” `/** ... */` on exported functions, classes, interfaces, and non-obvious constants. This is the contract surface.
3. **Inline `//` comments** β€” explain _why_, record invariants and non-obvious behavior at the point where a reader would otherwise be surprised. Never narrate _what_ the code already says.

The test for what goes where: **"Would a maintainer need to understand this to judge whether a change is safe?"** If yes, it belongs in the doc comment or file header. If it just explains how the sausage is made, it belongs inline β€” or nowhere.

## Doc comments (TSDoc)

### Shape

Use this structure for exported items, in order, dropping sections that do not apply:

1. Summary sentence.
2. Behavior paragraph β€” the mental model, in terms of caller intent.
3. Guarantees, defaults, and caveats.
4. Failure modes (`@throws`), invariants, complexity.
5. `@example` when the usage is non-obvious.
6. `@see` links to alternatives.

### Summary sentence

Everything before the first blank line is the reader's first impression. Make it say what the item _is_ (types: noun phrase) or _does_ (functions: verb phrase) without restating the name.

Good:

```ts
/** Returns the index of the first entity whose circle contains the point. */
```

Weak (restates the signature):

```ts
/** Gets the entity index. */
```

### Behavior paragraph

Explain the operation in terms of caller intent. Include what is returned when nothing is found, whether returned values are copies or live views, whether the operation mutates its input, and whether it allocates when that matters.

Do not restate what the signature already shows. Instead of "returns a `number | undefined`", say "Returns `undefined` when the entity has not been assigned a cluster yet."

### Guarantees

State guarantees explicitly and sparingly β€” a guarantee is a contract:

- "The returned array is sorted by entity index."
- "The view remains valid across in-place buffer growth; it is republished only on reallocation."
- "This runs in `O(members)` time and does not allocate."
- "Safe to call before `init`; the call is a no-op until the worker is ready."

### `@throws` and rejection

Document concrete conditions for thrown errors and rejected promises. TypeScript has no checked errors, so the doc comment is the only place a caller learns what can fail:

```ts
/**
* @throws When `byteLength` exceeds the buffer's `maxByteLength`;
* callers must republish through {@link RepublishHandler} instead.
*/
```

Avoid "Throws an error if something goes wrong."

### Invariants

TypeScript's unsafe corners β€” `as` casts, non-null `!`, `SharedArrayBuffer`/`Atomics` protocols, index arithmetic into typed arrays, branded-type constructions β€” need caller obligations stated as invariants, not suggestions:

```ts
/**
* Invariant: callers must only pass indices previously returned by
* `insert`; the store does not bounds-check in production builds.
*/
```

Every `as` cast at a boundary needs a comment justifying why it is sound. An unexplained cast is a review defect.

### Tags

- `{@link TypeName}` on first mention of a type, function, or module in prose. Plain backticks are for code snippets, keywords, and literal values β€” not type references.
- `@param` only when the parameter's role is not obvious from its name and type. Never write `@param count - The count`.
- `@returns` only when the return needs explanation beyond the behavior paragraph. Prefer describing the return inline in prose.
- `@defaultValue` on configuration fields and options.
- `@example` for non-obvious usage; examples should demonstrate why the API matters, not just that it can be called. App-internal code rarely needs them; shared utilities and tricky pure functions often do.
- `@deprecated` with a pointer to the replacement.
- `@internal` for private/internal APIs that are not part of the public interface.

### Configuration and options

Every config knob documents three things: what the setting changes, its default, and the tradeoff of turning it. If enabling a mode worsens some behavior, say so directly:

```ts
/**
* Maximum solver epochs spent in the separation phase before giving up.
*
* @defaultValue 40. Raising it improves overlap removal on dense graphs
* at the cost of longer settle times; lowering it can leave residual
* overlaps that the renderer must tolerate.
*/
```

## Inline comments

Inline comments are the highest-leverage and most abused layer. The rules:

### Why, not what

A comment that narrates the next line is noise. A comment that explains why the code is shaped this way β€” the constraint, the bug it avoids, the profile that motivated it β€” is load-bearing.

Weak:

```ts
// Increment the version counter.
version += 1;
```

Good:

```ts
// Bump version before writing positions so a torn read on the main
// thread fails the seqlock check and retries, rather than rendering
// a half-written frame.
version += 1;
```

### Affirmative, present tense

State what IS, not what WAS or what ISN'T. Never comment what was removed or changed (`// removed X`, `// previously…`, `// no longer needed`) β€” history is git's job. Never describe roads not taken in code comments; contrastive rationale ("we chose X over Y because…") is fine when the alternative is the _obvious_ choice a maintainer would otherwise reach for.

This includes "current state framed as a change". The reader was not there for the change; describe the role, not the transition:

Weak (narrates the transition):

```ts
/** Only exercised by benches/tests now that production's community-force
* tier runs the stress layout instead of FA2. */
```

Good (states the present role and where to look):

```ts
/** FA2 reference engine for the community-force tier, reachable from benches
* and tests only: production selects `stress-layout.ts` for this tier. */
```

### Place comments at the point of surprise

- Per-branch comments beat a block comment above a `switch`/`if`-chain when each branch needs its own explanation.
- A magic number gets its justification on the same line or the line above β€” including where it came from ("matches Deck.gl's default pick radius", "empirically flat above 8 on M1/Chrome profiles").
- Performance-motivated distortions (loop hoisting, manual inlining, typed-array pooling, avoiding closures in hot paths) get a comment naming the hot path and why the straightforward version was not used. Otherwise the next maintainer will "clean it up".

### Concurrency and protocol comments

Code that coordinates across threads (workers, `SharedArrayBuffer`, `Atomics`) documents its protocol where the coordination happens: who writes, who reads, what ordering guarantees hold, and what happens on the failure path. A memory-ordering decision without a comment is unreviewable.

### Comment hygiene

- No ASCII banners or decorative separators.
- No ALL-CAPS emphasis in prose (keep legitimate acronyms such as `SAB`, `LOD`, `GPU`).
- Section labels and inline emphasis use sentence case; domain terms may use backticks (e.g. `packing-bound`).
- Debug hook and flag names in comments use kebab-case to match the code.
- No commented-out code. Delete it; git remembers.
- No caller narration ("Used by Scene to…"). Describe what the code provides.
- No composition narration ("wraps a Foo", "this is a thin wrapper around"). State the semantic purpose.
- Comments must be self-contained; do not defer essential context to external markdown or spec files (`PERFORMANCE.md`, `MANIFESTO.md`, `LAYOUT-MODES.md`, and similar). When migrating legacy comments that cite such docs, inline the contract or invariant instead of deleting the pointer.
- TODOs name the condition under which they get resolved, not just a wish: `// TODO: fold into CutIndex once link entities join type-set groups.` A TODO with no trigger is a lie with a timestamp.
- Prose punctuation must be ASCII. When a comment used Unicode dashes or ellipses, rewrite the sentence in plain English rather than substituting `---`, `--`, spaced hyphens, or semicolons as stand-ins for em dashes. Split into two sentences, use commas or parentheses, or rephrase so the comment reads naturally.

### Math notation in comments

**Math and formula notation are exempt from ASCII-only hygiene.** Keep standard mathematical symbols wherever they make a formula easier to read. Do not "flatten" them into prose.

Symbols that belong in formulas include:

- Set operators: `∩`, `βˆͺ`
- Relations and mappings: `≀`, `β‰₯`, `β‰ˆ`, `β‰ͺ`, `≫`, `β†’`, `↔`, `β‡’`, `⇔`, `←`
- Operators: `Γ—`, `Β·`, `Ξ£`, `-` (do not use unicode minus inside a formula)
- Superscripts, subscripts, and constants in formulas: `dΒ²`, `rα΅’`, `2²⁢`, `Ξ΅`, `Ο€`, `normΒ²`, etc.

Examples:

```ts
/** Jaccard similarity: |A ∩ B| / |A βˆͺ B|. Returns 1 if both empty. */
/** separation w β†’ Γ—(1 + 2w); cohesion w β†’ Γ—1/(1 + 2w) */
/** L·x = b_x solved per dimension; majorize→project limit cycle */
```

Use ASCII for ordinary prose punctuation (commas, semicolons between clauses) and for identifiers that are not part of a formula (`EntityIdx->EntityId` join maps, log arrows, protocol names). When a comment is clearly a mapping or formula (`f: A β†’ B`, `scale_c = max(1, R_packing / R_hop-ideal)`), keep `β†’`, `Γ—`, `Β·`, and relation symbols.

**Do not** replace helpful math glyphs with spelled-out words (`intersect`, `union`, `times`, `less than or equal`, `much less than`) unless the line is pure narrative with no formula structure.

## Narration anti-patterns

These phrases are smells. When you catch yourself writing them, rewrite to state the guarantee or contract instead.

| Smell | Problem | Rewrite as |
| ----------------------------------- | ------------------------ | --------------------------------------- |
| "Wraps a `Foo`" / "Backed by `Foo`" | Narrates structure | State what the item IS |
| "Contains the bytes for" | Narrates storage | State what the item provides |
| "Used by X to…" / "Called from Y" | Narrates callers | Describe the provided behavior |
| "Stores the value in a Map" | Narrates implementation | State the performance guarantee, if any |
| "This is a thin wrapper around" | Narrates composition | State the semantic purpose |
| "Helper function for…" | Narrates role, not value | Say what it computes and when to use it |
| "Removed the old…" / "No longer…" | Narrates history | Delete; git remembers |

## File headers

A strong file header reads like a short tour, roughly in this order:

1. One sentence: what this module owns.
2. The mental model β€” primary types/operations and their relationship, stated operationally (what a caller _does_ with them, not a struct listing).
3. Invariants and protocols that span the file (threading, buffer lifecycles, ordering requirements).
4. Honest limits: what this module intentionally does not handle, when that omission is central to correct expectations.

Correctness-critical implementation details belong here β€” the ones that explain why the approach is sound and when it would break. Incidental details (which collection type backs a map) do not.

## Editing pass

After drafting, check at three distances:

1. First screen: can a reader identify what the item/module is and when to use it?
2. Middle: is the mental model clear? Are defaults and failure modes explicit?
3. Details: are invariants, complexity, and unsupported cases stated where a maintainer would look before changing the code?

Then remove generic filler. The style is detailed, but every detail earns its place.

## Review checklist

Before finalizing documentation or a comment pass:

- First sentence says what the item is; no doc merely restates the signature or name.
- Fallible operations document concrete failure conditions.
- Casts, non-null assertions, and index arithmetic carry invariant justifications.
- Config knobs state default + tradeoff.
- Inline comments explain why, are affirmative and present-tense, and sit at the point of surprise.
- No banners, no commented-out code, no history narration, no caller narration, no ALL-CAPS emphasis in prose.
- Comments are self-contained; no pointers to external markdown/spec files for essential context.
- Prose punctuation is ASCII; rewrite Unicode dash/ellipsis prose instead of substituting `---`, `--`, or semicolons for em dashes.
- Concurrency protocols are documented where the coordination happens.
- Every `{@link}` resolves; plain backticks are not used for type references.
27 changes: 27 additions & 0 deletions .claude/skills/skill-rules.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,33 @@
"blockMessage": "Skill is required to proceed",
"skipConditions": {}
},
"documenting-typescript-code": {
"type": "domain",
"enforcement": "suggest",
"priority": "high",
"description": "TypeScript documentation and comment-writing guide for doc comments (TSDoc), file headers, and inline comments. Use when writing or reviewing doc comments, documenting functions/types/modules, writing inline comments, explaining invariants, or auditing comment quality in TypeScript code.",
"promptTriggers": {
"keywords": [
"tsdoc",
"jsdoc",
"doc comment",
"inline comment",
"documentation"
],
"intentPatterns": [
"\\bdocument(ing|ation)?\\b.*?\\b(typescript|function|type|interface|class|module)\\b",
"\\b(write|add|create|review|clean)\\b.*?\\bcomments?\\b"
]
},
"fileTriggers": {
"include": [],
"exclude": [],
"content": [],
"create-only": false
},
"blockMessage": "Skill is required to proceed",
"skipConditions": {}
},
"exploring-rust-crates": {
"type": "domain",
"enforcement": "suggest",
Expand Down
17 changes: 17 additions & 0 deletions .cursor/rules/meaningful-identifiers.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,29 @@ metadata:

Callback parameters and local variables must describe the value they hold.

## Abbreviations

Spell identifiers out unless the abbreviation is genuinely well known.

- Acceptable: `src`, `dst`, `id`, `idx` (index), `min`/`max`, `rng`.
- Not acceptable: `tgt` (write `target`), `hw` (write `highway`), `cnt`, `mgr`,
`deps` (write `dependencies`, e.g. `#dependencies` / `FooDependencies`),
`seg` (write `segment`, e.g. `segmentCount` / `instanceSegmentRange`),
ad-hoc truncations in general.
- Math-heavy code is exempt where the short names mirror the notation of the
algorithm or paper (`x`, `y`, `k1`, `h1`, `wij`); keep a comment or doc link
naming the algorithm so the notation has a referent.

## Rules

- Name array callback params after the element's domain type:
`batches.map((batch) => …)`, `bins.filter((bin) => …)`,
`checkpoints.find((checkpoint) => …)`. Never reuse `right`/`left`/`column`
for values that are not sort operands or table columns.
- Don't suffix parameter-object type names with `Args` (`FooArgs`); name the
noun the object is: `CorridorPlan`, `BubbleCellPack`, or `FooOptions` when
it's genuinely optional knobs. Likewise name the parameter itself after
that noun (`plan`, `pack`, `options`) β€” `args` says nothing.
- Name `reduce` accumulators after what they accumulate: `sum`/`total` for a
running total, not `step`.
- Name percentile/ratio arguments for the quantity they represent
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/codspeed.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ jobs:
with:
scope: ${{ matrix.name }}

- name: Warm up repository
uses: ./.github/actions/warm-up-repo

- name: Build the benchmark target
run: turbo run build:codspeed --filter=${{ matrix.name }}

Expand Down
Loading
Loading