Skip to content

Fixing the Broken#

Rebuilding Jac's TopologyIndex: from O(N) scans to type-keyed buckets

Jac runs a lot of graph queries. They show up everywhere in Object-Spatial code, from [root --> [?:User]] to multi-hop walks like [r ->:Authored:-> [?:Post] ->:Tagged:-> [?:Topic]]. The naïve way to answer them is to walk every edge from the origin, load the targets, and check the filters. The TopologyIndex was added in PR #5205 to skip that work for type-filtered queries -- store enough metadata on the root node to resolve the survivors without ever touching the database.

The original implementation worked, but it had two problems we couldn't ignore. It scanned a flat adjacency list on every query, so cost was independent of selectivity (a query that matched 1% of the graph cost the same as one that matched 99%). And it had a quiet correctness bug for inheritance hierarchies: parent-type queries silently returned the empty set instead of all subtype instances.

PR #5784 rebuilds the index around a type-keyed lookup map with MRO-aware fan-out. Same canonical wire format. Same API surface. But typed reads now scale with match count, parent-type queries do the right thing, and the planner knows when to skip the index entirely. This post walks through what changed, why, and what the measured numbers look like.

Sometimes, Meta-Packages Need to Go. Here's Why.

If you've used jac create --use client to scaffold a Jac full-stack project, you've seen jac-client-node and @jac-client/dev-deps in your jac.toml. They're npm meta-packages — packages that exist solely to declare a list of other packages as dependencies. The idea: one line in your config gives you React, Vite, TypeScript, and everything else you need.

Sounds clean. In practice, it's a trap. I think we should replace both meta-packages with direct dependency injection, and I want to make the case for why.

Dataclasses: Python's Admission That Classes Are Broken (And How Jac Fixes It Properly)

Python's traditional class syntax has a problem: defining any class with fields requires excessive boilerplate. After decades of developers writing the same __init__, __repr__, and __eq__ methods, Python 3.7 introduced dataclasses (PEP 557) as a decorator-based solution. But dataclasses are a retrofit—what if dataclass semantics were built into the language from the start?