Skip to content

docs: say which decay ships, and which is designed but unwired (#1218) - #1221

Merged
github-actions[bot] merged 3 commits into
mainfrom
docs/issue-1218-posterior-decay
Jul 30, 2026
Merged

docs: say which decay ships, and which is designed but unwired (#1218)#1221
github-actions[bot] merged 3 commits into
mainfrom
docs/issue-1218-posterior-decay

Conversation

@robotrocketscience

@robotrocketscience robotrocketscience commented Jul 30, 2026

Copy link
Copy Markdown
Owner

Closes #1218.

Verified the premise before editing anything

scoring.decay, type_half_life and TYPE_HALF_LIFE_SECONDS have no caller
under src/. retrieval.py imports posterior_mean,
partial_bayesian_score, gamma_posterior_score, zeta_posterior_score and
the zeta constants — and nothing else from scoring. The only other importers
in src/ are context_rebuilder (posterior_mean) and wonder/strategies
(uncertainty_score). So nothing ever moves a stored (α, β) toward the
Jeffreys prior
, and PHILOSOPHY's lock story rested on the lock short-circuit
inside that function — an exemption from a mechanism that does not run.

One correction to the issue's own replacement text

The issue says to describe retrieval-time _apply_temporal_decay as live:

retrieval-time _apply_temporal_decay (retrieval.py:1757-1803) is live
and is a decay mechanism

That is too generous, and writing it would have replaced one inaccuracy with
another. Traced:

  • _apply_temporal_decay is called at retrieval.py:4139, inside
    retrieve_v2 — not retrieve().
  • It is guarded by temporal_sort, which is bool = False at
    retrieval.py:3915.
  • temporal_sort=True appears nowhere in src/ outside that signature.
  • Production hooks call retrieve().

So it is not on the default path either. The honest "what ships" list is
shorter than the issue's:

mechanism acts on on the default path?
scoring.decay (posterior → prior) posterior no caller at all
_apply_temporal_decay (#473) ranking no — retrieve_v2 + temporal_sort=False
marker-edge demotion (#1207) ranking opt-in, as its producer is
entity-persistence demotion (#1096) ranking yes, resolver default-ON

Entity-persistence is the one that ships by default — verified reachable from
retrieve(), which passes use_entity_persist_demote=None (resolver-driven)
rather than hard-off, landing at _entity_persist_penalty in the L1 rerank.
Every live mechanism acts on ranking position, never on the posterior,
which is the distinction the docs were collapsing.

A fourth statement, not in the issue

PHILOSOPHY.md:145 — "Beliefs are still mutated for decay and feedback" —
carries the same error and is corrected alongside. Feedback mutates beliefs;
decay does not.

AC3 is enforced, not written down

The third criterion asks that these statements be revisited if #1162 later
wires or deletes scoring.decay. A cross-link alone is a hope. So
tests/test_docs_posterior_decay_1218.py pins the code fact the prose rests
on, and fails in both directions of that disposition — verified by
performing each:

change result
add decay to a from aelfrice.scoring import in src/ test_posterior_decay_still_has_no_production_caller fails
rename scoring.decay away test_the_decay_surface_is_still_there_to_be_unwired fails

Both failure messages name ARCHITECTURE.md and PHILOSOPHY.md as the files to
update.

It parses src/ rather than grepping: decay exists as a local variable
for the ranking factor inside _apply_temporal_decay, so a text search
reports exactly the conflation this issue exists to undo. A first version using
ast.Name had the same bug and failed on retrieval.py — only ImportFrom aelfrice.scoring and scoring.<name> attribute access count.

It deliberately does not assert the docs' wording. Prose gets rephrased,
and a text match says nothing about whether the claim is true. It also would
have cost more than it is worth: my first draft read docs/, and
test_ci_path_filter correctly failed —

['docs'] are used by tests/ but absent from the `code` filter in ci.yml.
A PR touching only those paths takes the `echo` branch and reports a passing
pytest matrix without running the tests that cover them.

The fix it suggests is docs/** in the filter, which would run the full pytest
matrix on every docs-only PR. For a test asserting that an issue number appears
in a markdown file, that is a bad trade, so the test was dropped instead. The
enforcement that matters is the code-fact assertion, which needs no docs read.

Acceptance criteria

  • The three statements describe shipped behaviour, distinguishing
    ranking-time decay from posterior decay.
  • The PHILOSOPHY lock story no longer rests on a function with no caller —
    restated in terms of the lock floor and aelf lock overwrite semantics,
    with the decay short-circuit explicitly marked as design intent not wired.
  • Cross-linked to [Umbrella] Inert, unreachable, and decorative mechanisms — graph substrate and the delete list #1162, and enforced by a test that fails either way the
    disposition goes.

Verification

  • Full suite: 6473 passed, 69 skipped, 71 xfailed.
  • Docs-only change plus one new test; no src/ change.

Note for sequencing

The marker-edge row above is described as opt-in rather than default, which is
true on main today and stays true after #1220 (#1207) lands — that PR wires
the pass but its producer, aelf doctor --detect-stale, remains opt-in. No
merge-order dependency either way.

Summary by Sourcery

Clarify documentation around decay mechanisms to distinguish designed-but-unwired posterior decay from the ranking-time decay that actually ships, and add a test to enforce that the docs track the code’s wiring status.

Documentation:

  • Update PHILOSOPHY.md to explain that posterior decay is implemented but unused, describe which ranking-based decay mechanisms are live and default-on, and correct statements about belief mutation.
  • Revise ARCHITECTURE.md’s description of scoring.py to list the functions retrieval actually uses and explicitly mark posterior decay helpers as designed but not wired.
  • Record the posterior-decay documentation correction and its enforcement test in the v4 changelog.

Tests:

  • Add a docs-focused test that parses src/aelfrice to assert that posterior decay helpers have no production caller and still exist, ensuring future wiring or deletion triggers a documentation update.

@robotrocketscience robotrocketscience added the author-garsecg PR coordination mutex label Jul 30, 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

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Important

Review skipped

Ignore keyword(s) in the title.

⛔ Ignored keywords (2)
  • docs:
  • release:

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 23710ae7-42e1-4897-81ad-932c074c0f5b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actions

Copy link
Copy Markdown

PR-size soft cap

This PR is over the advisory size threshold:

  • 111 changed lines (limit: 200)
  • 4 changed files (limit: 3)

Bigger PRs collide with more open work, which under the parallel-session workflow tends to produce repeated attn:merge-conflict cycles (see #602). When practical, split into smaller PRs that each touch a focused surface.

This is advisory only — nothing is blocked. If the size is intentional (large refactor, module removal, generated code), apply the size:override label and this comment will be removed on the next push.

@robotrocketscience robotrocketscience added the attn:review Needs review (PR open, awaiting reviewer) label Jul 30, 2026
@sourcery-ai

sourcery-ai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Reviewer's Guide

Docs were corrected to accurately describe which decay mechanisms are actually wired in production (ranking vs posterior), PHILOSOPHY/ARCHITECTURE/CHANGELOG were updated to clarify lock behaviour and unwired posterior decay, and a new test was added to assert the code fact that posterior decay remains unwired or is explicitly removed, ensuring future wiring/removal forces doc updates.

Flow diagram for posterior-decay enforcement test

flowchart TD
    A[Run pytest] --> B[tests/test_docs_posterior_decay_1218.py]
    B --> C[test_posterior_decay_still_has_no_production_caller]
    B --> D[test_the_decay_surface_is_still_there_to_be_unwired]

    C --> E{any ImportFrom aelfrice.scoring includes decay}
    E -->|yes| F[Fail: update ARCHITECTURE.md and PHILOSOPHY.md for wired posterior decay]
    E -->|no| G[Pass: posterior decay still has no production caller]

    D --> H{scoring.decay / type_half_life / TYPE_HALF_LIFE_SECONDS still defined}
    H -->|no| I[Fail: update ARCHITECTURE.md and PHILOSOPHY.md for removed posterior decay]
    H -->|yes| J[Pass: decay surface still present but unwired]
Loading

File-Level Changes

Change Details Files
Clarify PHILOSOPHY around decay, locks, and what mechanisms actually ship.
  • Explain that posterior decay via scoring.decay is implemented but unwired, and that its lock short-circuit is design intent rather than shipped behaviour.
  • Describe the three ranking-time mechanisms (entity-persistence demotion, temporal decay in retrieve_v2, marker-edge demotion), noting which are default-on vs opt-in and that all act on ranking position, not the posterior.
  • Reframe lock durability in terms of lock-floor in rerank and aelf lock overwrite semantics, and correct claims about beliefs mutating for decay to state they mutate via feedback and lifecycle operations.
docs/concepts/PHILOSOPHY.md
Update ARCHITECTURE docs to reflect actual scoring surface used in production and mark posterior decay as designed-but-unwired. docs/concepts/ARCHITECTURE.md
Document the posterior-decay correction and enforcement in the v4 changelog.
  • Add a changelog entry explaining that ARCHITECTURE and PHILOSOPHY previously asserted shipped posterior decay, clarifying the distinction between unwired posterior decay and live ranking-time mechanisms.
  • Describe the new test-based enforcement that fails if scoring.decay gets a production caller or is removed, and note that the test parses src/ to avoid conflating ranking decay with posterior decay.
CHANGELOG/v4.md
Add a test that asserts posterior decay remains unwired while the decay surface still exists, forcing doc updates if #1162 wires or deletes it.
  • Implement AST-based scanning of src/aelfrice to find references to decay, type_half_life, and TYPE_HALF_LIFE_SECONDS via imports from aelfrice.scoring or scoring. attribute access, explicitly excluding local variables named decay in retrieval’s ranking-time temporal decay.
  • Add a test asserting that no src module other than scoring.py references the posterior-decay surface (no production caller), and a negative-control test asserting that scoring still defines the decay-related names and producing targeted failure messaging pointing to ARCHITECTURE.md and PHILOSOPHY.md when the surface is removed.
tests/test_docs_posterior_decay_1218.py

Assessment against linked issues

Issue Objective Addressed Explanation
#1218 Update ARCHITECTURE and PHILOSOPHY documentation so the three identified statements describe shipped behaviour, correctly distinguishing ranking-time decay mechanisms from absent posterior decay.
#1218 Revise the PHILOSOPHY lock story so it no longer rests on the unwired scoring.decay lock short-circuit, instead grounding it in actual shipped protections (lock floor, aelf lock semantics) or explicitly marking decay behaviour as design intent only.
#1218 Ensure that if #1162 later wires or deletes scoring.decay, the decay-related documentation statements are revisited, via explicit linkage or automated enforcement.

Possibly linked issues


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

@robotrocketscience

Copy link
Copy Markdown
Owner Author

[claim:review:Setr:2026-07-30T22:27:56Z]

@robotrocketscience

Copy link
Copy Markdown
Owner Author

Review: approved. The code facts the prose rests on all check out.

A docs PR is only as good as the claims underneath it, so I re-derived each
one against github/main rather than reading the body.

No posterior decay ships. retrieval.py imports exactly
DEFAULT_POSTERIOR_WEIGHT, ZETA_ALPHA_DEFAULT, ZETA_BETA_DEFAULT,
ZETA_SCALE_DEFAULT, gamma_posterior_score, partial_bayesian_score,
posterior_mean, zeta_posterior_score from scoring — no decay, no
type_half_life. The only other src/ importers are context_rebuilder
(posterior_mean) and wonder/strategies (uncertainty_score). Nothing
moves a stored (α, β) toward the prior. ✅

The correction to the issue's own replacement text is right, and load-bearing.
_apply_temporal_decay has exactly one call site, inside retrieve_v2,
guarded by temporal_sort — which defaults False and is never assigned
True anywhere in src/. Writing the issue's suggested "is live" text would
have swapped one false statement for another, in the file whose whole purpose
is being accurate about what ships. ✅

Entity-persistence is genuinely the one that ships.
is_entity_persist_demote_enabled defaults True, and retrieve() passes
use_entity_persist_demote=None — resolver-driven, not hard-off — so it is
reachable on the production path rather than only through retrieve_v2. ✅

AC3 is enforced, and I confirmed the enforcement is real

The claim that matters here is that the test fails in both directions of a
future #1162 disposition, because a test that only fails one way would let the
docs rot in the other. Performed both against the shipped source:

mutation result
add decay to retrieval.py's from aelfrice.scoring import test_posterior_decay_still_has_no_production_caller
rename scoring.decay away test_the_decay_surface_is_still_there_to_be_unwired

Baseline 2 passed. Each mutation fails exactly one test and leaves the other
green, which is the shape you want — the two are independent, not one assert
wearing two names. This is the right answer to "a cross-link alone is a hope."

Two notes, neither blocking

  • The PR body cites retrieval.py:1757-1803, :4139 and :3915; the actual
    positions on main are 2189, 4306 and 4082. I checked whether those
    drifted refs shipped — they did not, no retrieval.py:NNN appears in the
    docs diff, so this is confined to the PR description and rots nowhere. Worth
    knowing given how often line refs in this repo's issue bodies have drifted.
  • The body says retrieval.py imports "posterior_mean,
    partial_bayesian_score, gamma_posterior_score, zeta_posterior_score and
    the zeta constants"; it also imports DEFAULT_POSTERIOR_WEIGHT. Does not
    touch the argument — nothing in that list is a decay function.

Adding the fourth statement (PHILOSOPHY.md "mutated for decay and feedback")
was the right call: it carried the same error and fixing three of four would
have left the file self-contradicting.

CI green, CLEAN, discretion grep on added lines clean. Adding ready-to-merge.

@robotrocketscience robotrocketscience added the ready-to-merge Trigger merge-train: FF main to this PR's head label Jul 30, 2026
@github-actions

Copy link
Copy Markdown

merge-train: blocked

branch is not fast-forward on main (branch base 1f86537d720a3b21c1b2e463bbe76c00d2ec2b0d, current main d514499f59f2ff1091c1a76ecd74fbecc9dd1429). Rebase locally (git rebase github/main), force-push, and re-add the label.

The ready-to-merge label has been removed. Address the issue above and re-add the label when you're ready for another attempt.

@github-actions github-actions Bot removed the ready-to-merge Trigger merge-train: FF main to this PR's head label Jul 30, 2026
@robotrocketscience

Copy link
Copy Markdown
Owner Author

[claim:review:Toug:2026-07-30T22:31:58Z]

@robotrocketscience

Copy link
Copy Markdown
Owner Author

[release:review:Toug:2026-07-30T22:32:05Z]

scoring.decay, type_half_life and TYPE_HALF_LIFE_SECONDS have no caller
under src/, so nothing moves a stored (alpha, beta) toward the Jeffreys
prior. Three statements described posterior decay as shipped, and
PHILOSOPHY's lock story rested on the lock short-circuit inside that
function — an exemption from a mechanism that does not run.

Corrects the filed issue's own replacement text, which describes
retrieval-time _apply_temporal_decay as live: it is reachable only via
retrieve_v2 behind temporal_sort, which defaults False and is set
nowhere in src/, while the production hooks call retrieve(). The live,
default-on demotion is entity-persistence (#1096), which acts on ranking
position — and it is ranking, not the posterior, in every case.

A fourth statement not listed in the issue carried the same error and is
corrected alongside.
Fails in both directions of #1162's pending disposition: wiring
scoring.decay trips the no-caller assertion, deleting it trips a
negative control. The failure messages name the two files to update, so
the cross-link the issue asked for is enforced rather than written down.

Parses src/ rather than grepping it — `decay` is a local variable for
the ranking factor inside _apply_temporal_decay, which is exactly the
conflation being undone. Deliberately does not assert the docs' wording:
a text match on prose breaks on rephrasing, and reading docs/ would
require adding docs/** to CI's code path filter, taxing every docs-only
PR with the full matrix.
@robotrocketscience

Copy link
Copy Markdown
Owner Author

Rebased onto current main and force-pushed — the train bounced this only because #1220 and #1224 landed underneath while it was in review, nothing in the diff.

Verified the rebase is reviewably inert: the src/ + tests/ + docs/ diff against the merge-base is byte-identical before and after (same md5), the CHANGELOG resolution is insert-only, and the two docs-fact tests still pass. My review above stands, including both mutation directions.

Re-adding ready-to-merge once CI is green.

@robotrocketscience
robotrocketscience force-pushed the docs/issue-1218-posterior-decay branch from eb028fb to 64f698e Compare July 30, 2026 22:36
@robotrocketscience robotrocketscience added the ready-to-merge Trigger merge-train: FF main to this PR's head label Jul 30, 2026
@github-actions
github-actions Bot merged commit 64f698e into main Jul 30, 2026
28 checks passed
@github-actions github-actions Bot removed the ready-to-merge Trigger merge-train: FF main to this PR's head label Jul 30, 2026
@github-actions

Copy link
Copy Markdown

merge-train: merged 64f698emain via FF push.

@robotrocketscience

Copy link
Copy Markdown
Owner Author

[release:review:Setr:2026-07-30T22:40:44Z]

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

Labels

attn:review Needs review (PR open, awaiting reviewer) author-garsecg PR coordination mutex

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs: ARCHITECTURE and PHILOSOPHY assert posterior decay that has no production caller

1 participant