Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
e1e1924
feat: checkpoint
indietyp Jun 30, 2026
225efd6
feat: performance + code review
indietyp Jul 1, 2026
cdf538e
feat: performance + code review
indietyp Jul 1, 2026
95b8767
feat: code review
indietyp Jul 1, 2026
c51e148
feat: code review
indietyp Jul 1, 2026
dfacec6
feat: code review
indietyp Jul 1, 2026
384bfcd
feat: code review
indietyp Jul 1, 2026
8b694ff
feat: code review
indietyp Jul 1, 2026
d0a4eae
feat: code review
indietyp Jul 1, 2026
86ea8ca
feat: checkpoint
indietyp Jul 2, 2026
d259a05
feat: checkpoint
indietyp Jul 2, 2026
25542d3
feat: checkpoint
indietyp Jul 2, 2026
1885b69
chore: docs
indietyp Jul 2, 2026
3be2eab
feat: checkpoint
indietyp Jul 2, 2026
73b2de3
feat: checkpoint
indietyp Jul 2, 2026
05be361
feat: checkpoint
indietyp Jul 2, 2026
a7b7beb
feat: checkpoint
indietyp Jul 2, 2026
2956c63
feat: explode components
indietyp Jul 2, 2026
aab8e2c
feat: checkpoint
indietyp Jul 2, 2026
62453c5
feat: v2 -> v1
indietyp Jul 2, 2026
59e21b9
feat: docs + atlas
indietyp Jul 2, 2026
94cf64d
feat: make everything configurable!
indietyp Jul 2, 2026
31aa6a4
feat: remove the old
indietyp Jul 2, 2026
4e1ea57
temp: snapshot
indietyp Jul 2, 2026
45d6f3f
temp: snapshot II
indietyp Jul 2, 2026
87d9547
feat: majorization improvements + UI
indietyp Jul 3, 2026
71dc96e
Split worker into entity lifecycle: EntityGraphWorker under worker/en…
indietyp Jul 3, 2026
8010534
Add type-graph worker lifecycle (INIT_TYPE): TypeGraphWorker, shared …
indietyp Jul 3, 2026
55948d9
Split worker connection into FrameConnection base + entity/type subcl…
indietyp Jul 3, 2026
1689b56
Parameterize the scene pipeline over node identity via SceneHandle
indietyp Jul 3, 2026
2b1b436
Restructure React bridges: entity bridge under entity-graph/, scene i…
indietyp Jul 3, 2026
b912b6d
Add the type-graph bridge: types page Graph view on the new visualizer
indietyp Jul 3, 2026
77664c8
Migrate the flow outputs graph to the new EntityGraphVisualizer
indietyp Jul 3, 2026
8a0dbed
Remove the sigma-based visualizers and their dependencies
indietyp Jul 3, 2026
05c35da
fix: double mount
indietyp Jul 3, 2026
dc7ae0f
feat: do not loosely type
indietyp Jul 3, 2026
e313dac
chore: remove fixture
indietyp Jul 3, 2026
4fdc4ba
chore: remove straggler
indietyp Jul 3, 2026
ba2b35e
chore: remove straggler
indietyp Jul 3, 2026
f4af41d
chore: remove straggler
indietyp Jul 3, 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
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
11 changes: 11 additions & 0 deletions .cursor/hooks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": 1,
"hooks": {
"preToolUse": [
{
"command": "node \"/Users/bmahmoud/.cursor/skills/impeccable/scripts/hook-before-edit.mjs\"",
"timeout": 5
}
]
}
}
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
Loading
Loading