Skip to content

Latest commit

 

History

History
166 lines (134 loc) · 8.5 KB

File metadata and controls

166 lines (134 loc) · 8.5 KB

fuzzy-search Development Guidelines

Stella Context

Stella is an open-source legal workspace and set of legal-data tooling.

International audience: do not assume English language or English typography conventions are universal. Highlight competing standards (date formats, quotation marks, citation styles, legal terminology) when relevant.

Public Repository Context

  • Treat legal data, personal data, and repository secrets as sensitive.
  • Keep project instructions, PRs, commits, and comments limited to public engineering context visible from the repository and diff.
  • Do not publish private user, customer, infrastructure, incident, pricing, roadmap, or competitive context in generated instructions or GitHub artifacts.

Compliance-Aware Engineering

Stella code is intended for use in environments with SOC 2 and ISO 27001 style controls. Treat security, auditability, least privilege, data minimization, and workspace isolation as baseline engineering requirements.

When making changes, prefer designs that preserve clear ownership boundaries, structured audit trails, encryption-aware data handling, and explicit access checks. Keep public PRs and comments focused on the implementation visible in the diff; do not describe private controls, internal security architecture, or certification details unless they are already public in the repository.

GitHub Interactions

  • When commenting on GitHub (PRs, issues), include "CC on behalf of @username" where username is the GitHub handle of the person who requested the comment.
  • This repository (including PRs, commits, comments) is public. Never include marketing language, internal business context, pricing, competitive analysis, user identities, conversation specifics, or security architecture beyond what the diff shows. Write for the reviewing engineer.

Meta Preferences

  • Never manually reformat code you did not semantically change (auto-formatter output from bun run format is fine to include)
  • Vary punctuation: prefer colons, semicolons, commas, and parentheses over em dashes
  • Prefer explicit over implicit; when a backend endpoint accepts a discriminator (e.g., ?type=document|file), thread it through the full stack (URL params, component props) instead of hardcoding a default on the frontend
  • If TypeScript can make a class of bug structurally impossible (branded types, discriminated unions, exhaustive checks), prefer that over runtime validation or manual discipline
  • Conventional Commits: feat:, chore:, fix:, docs:
  • Rebase feature branches onto main (linear history)
  • Fail fast: validate at boundaries, return/throw early
  • Minimize brace nesting: invert conditions, early returns
  • Use named constants, not string literals for domain values
  • No direct document.cookie assignment
  • Avoid spread in loop accumulators (use .push())
  • If you encounter a pre-existing bug or lint error while working on something else, fix it (separate commit)

Design Principles

  • No hidden complexity; code is the docs. Every operation must work for humans, scripts, and AI agents alike.
  • No lock-in: standard formats, self-hosting is first-class.
  • AI is a tool, not a persona. No anthropomorphizing.
  • Performance is non-negotiable. Batch operations, minimize round-trips, lazy-load aggressively.
  • Vertical slices over horizontal layers. Features are independent end-to-end slices (own routes, components, handlers). New capabilities land in their own slice; existing code stays untouched.

Coding Conventions

TypeScript

  • No enums: use as const objects or union types
  • Model mutually exclusive internal states as discriminated unions with a stable type, status, or domain-specific discriminator. Avoid boolean flag sets plus optional payload fields when only some combinations are valid.
  • When the linter blocks an as cast, restructure to narrow properly (type guards, in checks, records instead of arrays). If truly unavoidable, ask before adding and include a // SAFETY: comment explaining why the cast is sound.
  • When a type mismatch appears, trace it to the source (e.g., the handler or query that produces the wrong type) rather than casting at the consumer. Check git to verify you did not introduce the mismatch yourself before blaming the framework.
  • Use .at(0) when the element may not exist (signals possible absence). Use [0] only when existence is already established (length check, or a // SAFETY: comment).
  • Prefer arrow functions over function expressions
  • Destructure in the parameter when the intermediate variable is not reused (e.g., { body: { file, name } } not body then const { file, name } = body)
  • Prefer discriminated union narrowing (obj.type === "x") over "key" in obj checks. Use in only when the type is not a discriminated union and there is no discriminator to check.
  • For function arguments, including helpers: use normal typed parameters for one argument, and also for two arguments when their types are different enough to stay readable. Use a named SomethingOptions, SomethingArgs, or SomethingParams object for 3+ arguments, or when two same-type or otherwise interchangeable positional arguments would be easy to mix up. Reserve Props for React component props.
  • Reuse util types from libraries instead of hand-rolling (e.g., React.PropsWithChildren<P> for props with children, React.ComponentProps<"button"> for HTML element props). Check React, TanStack, and other deps before defining custom equivalents.
  • Keep helper-local types close to the helper they describe: put SomethingOptions, SomethingResult, and similar aliases immediately above the function, not in a file-level type dump far away from the implementation.
  • If a return type is noisy enough to hurt readability, hoist it into a nearby alias such as SomethingResult and use it in the signature (e.g., SomethingResult or Promise<SomethingResult>). If the return type is simple, keep it inline.

Module Side Effects

  • No module-level side effects in shared modules. If a module exports both a side-effecting singleton (DB connection, auth client, pool) and reusable utilities, split them: put utilities in a separate file so consumers can import them without triggering initialization. The side-effecting module re-exports for convenience.
  • Never import test-only types in prod code. If a prod generic needs to accept both prod and test instances, use a structural constraint ({ transaction: ... }) instead of importing a type from a test file.
  • Defer eager initialization with lazy singletons. When a module-level call (betterAuth(), drizzle()) depends on another module's export, wrap it in a getX() getter so it runs at first use, not at import time. This prevents TDZ errors from non-deterministic module evaluation order.

Testing

Only test what can actually go wrong: bugs the type system, framework, or linter would miss. Prefer invariants over examples when the input space is large. Full conventions in /conventions-testing.

Linting

oxlint (ultracite preset) + oxfmt. To suppress a rule: // eslint-disable-next-line rule-name

Repository Specifics

@stll/fuzzy-search is a Node/Bun package backed by a Rust Myers approximate substring engine, with native and WASM package outputs.

Commands

  • bun install
  • bun run lint
  • bun run typecheck
  • bun test
  • bun run test:props
  • bun run test:runtime:bun
  • bun run test:runtime:node
  • bun run build:js
  • bun run version:check

Native Package Rules

  • Keep approximate-match semantics, offsets, returned match text, and replace-safe spans consistent across native, WASM, Bun, and Node runtimes.
  • Use property tests for edit-distance boundaries and regression tests for Unicode and overlapping-match behavior.
  • Avoid changing package artifact layout unless release packaging is the target.

Releases

  • Every pull request that changes published runtime code must add a Changesets entry; use bun run changeset --empty for an intentional no-release change.
  • Changesets owns CHANGELOG.md and the version PR. The version command synchronizes VERSION, every npm package, Cargo manifests and lock metadata, and the generated native loader guard.
  • Keep .github/workflows/release.yml as the trusted-publishing caller. Do not add another changelog generator or publish from the Changesets workflow.