Skip to content

docs(config): document the fan-effect and utterance-prior flags - #1237

Merged
github-actions[bot] merged 1 commit into
mainfrom
docs/config-new-lane-flags
Jul 31, 2026
Merged

docs(config): document the fan-effect and utterance-prior flags#1237
github-actions[bot] merged 1 commit into
mainfrom
docs/config-new-lane-flags

Conversation

@robotrocketscience

@robotrocketscience robotrocketscience commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Both lanes merged today — AELFRICE_FAN_EFFECT (#1234, #1176) and AELFRICE_UTTERANCE_PRIOR_WEIGHT (#1231, #1174) — and neither appeared anywhere in docs/ or README.md. Every comparable lane flag has a docs/user/CONFIG.md section:

flag in CONFIG.md before this PR
AELFRICE_ENTITY_PERSIST_DEMOTE yes
AELFRICE_ORIGIN_TIEBREAK yes
AELFRICE_SUPERSESSION_DEMOTE yes
AELFRICE_TEMPORAL_SPINE yes
AELFRICE_BM25F_PER_FIELD yes
AELFRICE_FAN_EFFECT no
AELFRICE_UTTERANCE_PRIOR_WEIGHT no

So these two were the exception, not a change of convention.

What the sections say

Both follow the existing shape — what the lane does, why the default sits where it does, the determinism argument per #605, and the precedence chain. Each records that it has no TOML tier yet (accurate: both resolvers are env → kwarg → default) and that the default flip is a separate operator call gated on a measurement that has not run.

Two facts are included because they are easy to get wrong and expensive to rediscover:

  • The fan lane is only at cost parity because the active-belief count is memoised on store_generation(). Recomputing it per query costs 1.315 ms against 0.045 ms for the whole shipped lane, which is a ~35x regression that reads as "the lane is slow" rather than "one call is slow". That was caught in review of feat(retrieval): ACT-R fan-effect ranking for the entity lane, default off (#1176) #1234, not by a test.
  • The utterance-prior W-sweep has to be scored below the locked block. L0 locks are injected ahead of the ranked candidates and never trimmed, so on a real store the top-k is locks and is constant in this weight — a top-k metric returns a guaranteed null that looks like a result.

Verified, not asserted

Every claim in the new prose was checked against the code rather than copied from the PR bodies:

  • use_fan_effect / utterance_prior_weight kwarg names exist on retrieve_v2 (retrieval.py:4243 and the resolver bank).
  • Neither has a TOML tier — no hits in the config surface.
  • "At 0.0 nothing reads the ingest log" is true at both sites: the build is gated if utterance_prior_weight != 0.0 else None at retrieval.py:3531 and :3629, and utterance_prior.py:212 short-circuits independently.
  • score() sums stems in sorted order (the feat(retrieval): utterance-vs-knowledge document prior, inert at W=0 (#1174) #1231 determinism fix), so the mean is order-stable.
  • Version label v4.2+ matches pyproject.toml (4.2.0).

Insert-only: 24 added lines, 0 deletions against main.

Not fixed here, but measured while checking

29 of the 74 AELFRICE_* environment variables read by src/ appear nowhere in docs/ or README.md — 39%. The largest clusters are the cadence knobs (9), the meta-belief overrides (4) and the implicit-feedback knobs (3); the rest are singletons like AELFRICE_BM25_K3, AELFRICE_AUTO_RELATIONSHIPS and AELFRICE_TEMPORAL_HALF_LIFE_SECONDS.

That is a pre-existing gap, not one these two lanes created, and it is too big to fold in here. Nothing gates it — I checked, and no test asserts that a documented env var exists or that a shipped one is documented, which is why the gap opens silently each time a lane lands. A parse-src/-and-assert test of the kind #1207 already uses would close it, but it would fail on 29 names today and so needs a decision about which of those are deliberately internal (AELFRICE_FORCE_EXPANSION, AELFRICE_TRANSCRIPTS_DIR and similar look like test seams rather than user knobs). Happy to file that separately if it is wanted.

Summary by Sourcery

Document configuration flags for the fan-effect entity ranking lane and the utterance-vs-knowledge prior weight in the retrieval pipeline.

Documentation:

  • Add CONFIG.md section describing the use_fan_effect flag, its behavior, defaults, and precedence.
  • Add CONFIG.md section documenting utterance_prior_weight, its semantics, safety constraints, and configuration precedence.

Both lanes merged today (#1234, #1231) and neither appeared anywhere in
docs/ or README. Every comparable lane flag —
AELFRICE_ENTITY_PERSIST_DEMOTE, AELFRICE_ORIGIN_TIEBREAK,
AELFRICE_SUPERSESSION_DEMOTE, AELFRICE_TEMPORAL_SPINE,
AELFRICE_BM25F_PER_FIELD — has a CONFIG.md section, so these two were the
odd ones out rather than a new convention.

Follows the existing section shape: what it does, why the default is
where it is, the determinism argument per #605, and the precedence
chain. Each records that it has no TOML tier yet and that its default
flip is a separate operator call gated on a measurement.

Two facts included because they are easy to get wrong and expensive to
rediscover: the fan lane's cost is at parity only because the
active-belief count is memoised (recomputing it per query costs 1.315 ms
and dominates), and the utterance-prior W-sweep has to be scored below
the locked block, since L0 locks are injected ahead of the ranked
candidates and a top-k metric is constant in that weight.

Insert-only: 24 added lines, no deletions.

Refs #1176, #1174
@robotrocketscience robotrocketscience added the author-Setr PR coordination mutex label Jul 31, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @robotrocketscience, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@robotrocketscience robotrocketscience added the attn:review Needs review (PR open, awaiting reviewer) label Jul 31, 2026
@github-actions github-actions Bot added the docs label Jul 31, 2026
@sourcery-ai

sourcery-ai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Reviewer's Guide

Documents two previously-undocumented retrieval configuration flags (use_fan_effect / AELFRICE_FAN_EFFECT and utterance_prior_weight / AELFRICE_UTTERANCE_PRIOR_WEIGHT) in docs/user/CONFIG.md, describing their behavior, performance characteristics, determinism guarantees, and precedence hierarchy without changing any code behavior.

Flow diagram for config flag precedence resolution

flowchart LR
    subgraph use_fan_effect_resolution
        env_fan[AELFRICE_FAN_EFFECT env var]
        kwarg_fan[use_fan_effect kwarg]
        default_fan[default false]
        resolver_fan[fan_effect_resolver]

        env_fan -->|set| resolver_fan
        kwarg_fan -->|set if env unset| resolver_fan
        default_fan -->|fallback| resolver_fan
        resolver_fan --> retrieve[retrieve_v2]
    end

    subgraph utterance_prior_weight_resolution
        env_prior[AELFRICE_UTTERANCE_PRIOR_WEIGHT env var]
        kwarg_prior[utterance_prior_weight kwarg]
        default_prior[default 0.0]
        resolver_prior[utterance_prior_weight_resolver]

        env_prior -->|set| resolver_prior
        kwarg_prior -->|set if env unset| resolver_prior
        default_prior -->|fallback| resolver_prior
        resolver_prior --> rerank[L1 rerank]
    end
Loading

File-Level Changes

Change Details Files
Add documentation for the fan-effect lane configuration flag, including semantics, scoring formula, performance notes, determinism guarantees, and configuration precedence.
  • Introduce a use_fan_effect section describing how L2.5 entity-tier ranking switches from a raw distinct-entity count to an ACT-R style fan-weighted activation score
  • Explain the scoring formula using log-IDF-like fan weights derived from active belief counts and how it degenerates to the previous overlap-count ordering when fans are equal
  • Call out implementation constraints such as computing the logarithm in Python instead of SQL, memoising the active-belief count to keep the lane cost-neutral, and maintaining the returned tuple shape
  • Document determinism guarantees by specifying that entities are iterated in sorted order for activation summation
  • Define configuration precedence for enabling the lane (environment variable, Python kwarg, then default), note the absence of a TOML tier, list the affected retrieval APIs, and clarify that the feature is shipped default-off pending an A/B measurement
docs/user/CONFIG.md
Add documentation for the utterance-vs-knowledge prior weight configuration flag, including its role in reranking, numerical behavior, determinism, and configuration precedence.
  • Introduce an utterance_prior_weight section describing it as a log-odds prior that demotes utterance-like content versus knowledge-like content in the L1 rerank
  • Describe how the prior is estimated from ingest-log provenance (transcript vs filesystem/git rows) without supervised labels or embeddings and the retrieval failure mode it addresses
  • Clarify numerical behavior: log-additive but clamped at zero, using a mean over stems to avoid length bias, with deterministic scoring via sorted-order accumulation
  • Explain short-circuit behavior at weight 0.0 (no ingest-log reads), handling of malformed or negative values by falling back to 0.0, and caching of the prior per store
  • Define configuration precedence (environment variable, Python kwarg, then default), note the absence of a TOML tier, explain that the feature is default-off pending a weight sweep, and highlight the evaluation caveat that the sweep must be scored below the locked block due to L0 locks dominating top-k metrics
docs/user/CONFIG.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@robotrocketscience, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 22 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 4f6c3b67-e64f-4aa6-a01c-acf24fe71da8

📥 Commits

Reviewing files that changed from the base of the PR and between 1a3dc5e and bcfd8cf.

📒 Files selected for processing (1)
  • docs/user/CONFIG.md

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@robotrocketscience

Copy link
Copy Markdown
Owner Author

[claim:review:Toug:2026-07-31T13:41:53Z]

@robotrocketscience

Copy link
Copy Markdown
Owner Author

Checked every technical claim in both sections against the code rather than
reading for plausibility, since I built one of the two lanes. Accurate
throughout.
One omission worth closing, one nit, and one caution about a
number it cites.

Verified against the source

utterance_prior_weight:

  • classes read from ingest_log, transcript vs filesystem/git — correct, and
    the pinned constants are CLASS_Q_SOURCE_KINDS / CLASS_K_SOURCE_KINDS
  • log-additive and clamped at 0 — correct, and the stated reason (the rerank
    score is log-domain and routinely negative, so an unclamped term would
    reorder documents the lane has no opinion about) is exactly right
  • score() returns a mean, not a sum — correct, and the length-normalisation
    rationale matches the docstring
  • sorted-stem summation for determinism — correct
  • at 0.0 the lane short-circuits and nothing reads the ingest log
    correct, and both byte-identical short-circuits carry the clause
  • malformed/negative fall through to 0.0 — correct
  • built once per store and cached — correct
  • precedence env > kwarg > default — correct

use_fan_effect:

  • A_i = Σ_j ln((N + 1) / (fan_j + 1)) — matches
    activation += source_activation - math.log(fan[ent] + 1.0) with
    source_activation = ln(N + 1)
  • every term non-negative — holds, and it holds because
    count_active_beliefs() counts exactly the population the fan query filters
    to (valid_to IS NULL on both sides); worth knowing that is what the
    guarantee rests on
  • degenerates to the overlap count when fans are equal — correct
  • no table, no migration, log in Python because SQL LN() needs
    SQLITE_ENABLE_MATH_FUNCTIONS — correct
  • memoised on store_generation() — correct, and I verified separately that the
    memo stays exact across soft_delete_belief / restore_belief /
    delete_belief, which is the property that claim rests on

The one thing I would change

The use_fan_effect section says "Honoured on both retrieve() and
retrieve_v2()". The utterance_prior_weight section says nothing — and it is
equally honoured.
By contrast with its neighbour, the silence reads as "not
on the production path", which is the #1107 failure mode the fan section is
explicitly guarding against.

Verified empirically rather than by inspection: on a seeded store,
AELFRICE_UTTERANCE_PRIOR_WEIGHT=8 changes the ordering returned by
retrieve() — not retrieve_v2() — because resolve_utterance_prior_weight
is env-first and fires even though retrieve() passes no kwarg.

Worth stating the asymmetry precisely, because it is not symmetric in one
respect: for both lanes the env var reaches retrieve(), but neither
exposes a Python kwarg on retrieve() itself. Suggest the same sentence in
both sections, phrased so the env-var route is what "honoured" means.

Nit

The absolute latencies (0.039 ms vs 0.045 ms) are machine-specific — on the
same live store I measured 0.066 vs 0.060, same conclusion, different
numbers. Both say parity; neither is wrong. In user-facing docs I would say "at
parity with the lane it replaces" and keep the absolute figures on the issue,
where the hardware is recorded. Not blocking.

Caution on a cited statistic

The fan section cites "86% of entities appear in exactly one" — that is my
figure from #1233, and it is used correctly here, as evidence that fan
varies enough for the weighting to bite.

Flagging only because I refuted the other inference from that same statistic
earlier today: it does not mean those keys are dead weight. Pruning
single-belief keys blanks the L2.5 lane entirely on 26.7% of real queries, since
such a key still contributes to its own belief and is the most discriminative
signal available. The doc does not make that error — but the number now appears
in a user-facing document, so I would rather the next reader meet it with the
right reading attached. See
#1233's correction.

Ship it

Insert-only (24 added, 0 deleted, verified). CI clean, no unresolved threads,
discretion grep clean. Filling a real gap — both lanes merged today with no
docs/ presence while every comparable flag has a section.

Approving; adding ready-to-merge. The reachability sentence is worth a
follow-up commit but I would not hold a docs-only PR for it.

@robotrocketscience robotrocketscience added ready-to-merge Trigger merge-train: FF main to this PR's head and removed attn:review Needs review (PR open, awaiting reviewer) labels Jul 31, 2026
@robotrocketscience

Copy link
Copy Markdown
Owner Author

[release:review:Toug:2026-07-31T14:00:23Z]

@github-actions
github-actions Bot merged commit bcfd8cf into main Jul 31, 2026
27 of 37 checks passed
@github-actions github-actions Bot removed the ready-to-merge Trigger merge-train: FF main to this PR's head label Jul 31, 2026
@github-actions

Copy link
Copy Markdown

merge-train: merged bcfd8cfmain via FF push.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author-Setr PR coordination mutex docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant