Grain

Description

The level of resolution at which an entity is individuated — its identity-grain. Every named entity has a grain: a session has session-grain, a user has user-grain, a field has field-grain, a program has program-grain. Grain matters because decisions that look like single choices are often two entangled decisions — “what rule applies?” and “at what grain does it apply?” Confusing grains produces bugs with a characteristic signature: behavior that seems correct locally but breaks at the wrong level of aggregation or disaggregation.

The grain-coupling move is the key diagnostic: when a decision behaves differently depending on the grain at which you inspect it, you’ve found grain-coupling. The move is to decouple the grains — identify that what looked like one decision was actually two, each operating at a different level of resolution. This is structurally analogous to separating orthogonal axes of variation in matrix decomposition: what appeared as a single blob has identifiable components.

Encounters

  • Identity-grain in agent frameworks — a “session” in Claude Code has session-grain for some properties (conversation history) and program-grain for others (working directory). Confusing them produces context-management bugs.
  • Field-grain vs. record-grain in databases — a policy that should apply per-field is incorrectly applied per-record, or vice versa; the bug appears as incorrect aggregation.
  • Program-grain in program-identity work — what constitutes “a program” varies by grain: file-level, module-level, repository-level. The level at which identity is asserted determines which operations are valid.
  • Session-grain in KCC — KCC’s camp-session concept has grain mismatches: some properties are per-season, some per-session, some per-week. Grain-coupling bugs appeared as incorrect rollups.
  • Cadence-grain — “daily” vs. “weekly” vs. “per-event” cadences are grain choices. A process whose grain mismatches its data source accumulates systematic error.
  • “What is the unit of X?” — whenever this question produces disagreement, grain-coupling is present.

When it applies / triggers on

User-initiated: User is asking about granularity, resolution, or the “unit” of something. Also when a bug is described as “correct in some cases but wrong in aggregate” or “works for one X but breaks for multiple Xs.”

Agent-initiated: Engine notices a rule or design decision that appears to operate at multiple levels simultaneously without explicit handling for the level mismatch. Candidate inference: “this decision is grain-coupled — what are the two (or more) distinct grains entangled here, and which grain is load-bearing for each sub-decision?”

Vocabulary cues: “per-session,” “per-user,” “per-field,” “per-item,” “per-request,” “granularity,” “resolution,” “unit of X,” “what counts as one X,” “level of detail,” “aggregate,” “disaggregate.”

Situation-shape signals: A rule that feels right at one level of inspection but wrong at another. A design decision where reasonable people disagree because they’re implicitly using different grains.

Composes with

  • stack-layer (composition relationship) — grain and stack-layer often co-occur: layers in a stack operate at different grains, and grain mismatches across layers produce characteristic bugs. The grain diagnostic complements the load-bearing-layer diagnostic.
  • load-bearing (composition relationship) — “what is the grain of this decision?” is a load-bearing question: it determines which operations are valid at which level. A decision at the wrong grain is not load-bearing in the right place.
  • uniformity-dividend (composition relationship) — a uniformity dividend requires all instances to share the same grain. If grains differ, uniformity is illusory (the invariant doesn’t hold across the dimension being standardized).
  • cadence (composition relationship) — cadence choices are implicitly grain choices: “daily cadence” is day-grain; “per-event cadence” is event-grain. Cadence mismatches (process grain ≠ data grain) are a common source of accumulation error.
  • doctrine (composition relationship) — a doctrine applied at the wrong grain is ineffective or harmful. Doctrine entries should specify their grain explicitly: “when [condition] at [grain], apply [rule].”

When it doesn’t apply

  • Uniformly single-grained systems — a system where all decisions operate at a single, unambiguous grain has no grain-coupling to diagnose. The form earns its keep when multiple grains are in play simultaneously.
  • When “granularity” is just a detail choice — adjusting resolution along a dimension that doesn’t affect correctness (e.g., choosing how many decimal places to display) doesn’t require the grain frame. Grain matters when the resolution choice affects what rules apply or what counts as the same entity.
  • Pure aggregation — when explicitly summing over a dimension (total users, total events), the grain is the aggregate itself and usually isn’t ambiguous.

Sources

  • The term “grain” is used in relational databases (grain of a fact table in dimensional modeling — Kimball) and in photography/film (resolution of detail).
  • Program-identity work in James’s corpus; session-grain mismatches in KCC; cadence-grain in agent frameworks.
  • 21 hits in full corpus with consistent semantic shape across identity-grain, field-grain, session-grain, program-grain.
  • The “grain-coupling move” — identifying that one apparent decision is two grain-entangled decisions — appears to be novel framing relative to standard granularity discourse.

Canonical exemplars from corpus (T2 2026-05-17)

Mined via scripts/mine_new_form_exemplars.py from data/backfilled-insights.jsonl. 111 backfill-only matches at score ≥ 2 — much higher than the 21-hit catalog count because the new heuristic catches per-session/per-user/per-X granularity phrasings. Top co-occurrences: doctrine (17), cadence (10), active-gate-vs-passive-audit (4).

  • Program-grain truth vs session-grain truth at the same surface (cwd: campconnect, 2026-05-03): “This is the same shape as the search bug: program-grain truth (an aggregate already computed in match.aggregates) and session-grain truth (a single record) are both available, but the rendering layer reaches for the wrong one… the deeper invariant: when…” — grain-coupling diagnostic at its sharpest: same UI surface reaching for two grains of truth and choosing wrong.
  • Program-grain URL making session-grain claims (cwd: campconnect, 2026-05-03): “This whole arc lived inside one architectural insight: the program-grain URL was making session-grain claims, and the page surfaces had no honest way to reason about that mismatch. PR #639 fixed the search-side incarnation (haystack joined across grains). PR #645 fixes the detail-page incarnation.” — grain-coupling resolved by naming the two grains and aligning them per-surface.
  • Recursive question on a “fix the cosmetic branch” diagnosis (cwd: campconnect, 2026-05-05): “When a fix has the shape ‘make the cosmetic branch less buggy,’ that’s worth one recursive question: do we need the cosmetic branch at all? … PR #707 is a real fix to a real bug, but it’s also evidence that the structure causing the bug was a candidate for removal.” — the diagnostic surfaces a grain question (is the branch needed at this level of resolution, or has its load-bearing role expired?).
  • Display-shape control grain choice (toggle placement) (cwd: campconnect, 2026-05-11): “Toggle placement = adjacent to Sort. Sort and grouping are both display-shape controls; keeping them visually paired makes the relationship discoverable… Persistence = kcc.programsGrouping.{desktop,mobile} localStorage.” — grain choices propagating from control-grain to persistence-grain to UI-pairing.

Trigger pattern (T2): Grain surfaces when the user asks “what’s the unit of X?”, reports a bug that’s “correct in some cases but wrong in aggregate,” or proposes a decision at one level when the agent recognizes a second entangled grain. The 17 co-occurrences with doctrine show that doctrines often specify their grain explicitly (“at [grain], apply [rule]”).