Skip to content

feat(context): ship the adaptive-context lifecycle on by default#746

Merged
macanderson merged 1 commit into
mainfrom
feat/lifecycle-on-by-default
Jul 26, 2026
Merged

feat(context): ship the adaptive-context lifecycle on by default#746
macanderson merged 1 commit into
mainfrom
feat/lifecycle-on-by-default

Conversation

@macanderson

Copy link
Copy Markdown
Owner

context.lifecycle.enabled now defaults to true. The whole lifecycle — decomposed recall, frame identity, recall telemetry, selection reasons, the typed learning loop, the ledger and its review surface — is what a workspace gets without configuring anything.

Stacked on #745, which repairs a main that does not currently compile. Review that first.

Why this is safe to default on

The behavior-compatibility suite asserts every spec §8 guarantee on both the typed path and the opted-out one, from the same assertions: tombstone suppression across re-learning on every surface, the per-session creation cap, never clobbering a hand-edited file, deterministic candidate identity, and failure isolation.

Phase 3 deliberately kept the lexical loop reachable rather than deleting it, so "behavior-compatible" stays a checkable claim rather than a promise. Defaulting on is the point of having built that evidence — a lifecycle nobody runs cannot be evaluated.

The flip is two changes, not one

This is the part worth reviewing closely. Flipping LifecycleSettings::default() alone would have shipped nothing.

The reader asked:

.and_then(|s| s.context).is_some_and(|c| c.lifecycle.enabled)

A workspace with no settings.json — the common case, and every new user — answered false regardless of the struct's default, because the context block was absent rather than present-and-false. An absent block now means "the defaults", which is what it always should have meant.

There are tests for the no-settings-file case and the empty-block case specifically, because that is exactly the gap that would have shipped this as a silent no-op.

What still fails closed

An unreadable or malformed settings file stays OFF. That file may be the one in which someone turned the lifecycle off, and silently overriding an opt-out we failed to parse is worse than leaving a default unapplied. An explicit "enabled": false is honored and restores the previous behavior wholesale.

Notes for the reviewer

  • The test fixtures that used to get the lexical loop by writing nothing now opt out explicitly, since "write nothing and get the old path" is no longer true. That is a change to what the fixtures say, not to what they assert — no assertion was relaxed.
  • DriverConfig::lifecycle_enabled still defaults false on purpose: a programmatically built config should opt in deliberately rather than inherit a product default it never read. The CLI passes the real setting.
  • learning.mode and governance.mode remain inert — they have no consumers outside settings tests. lifecycle.enabled is the only real switch.

Gate

make gate green: exit 0, 3805 tests, check-file-size: OK — 475 Rust files, none over 1500 lines except 25 grandfathered (none grew).

@vercel

vercel Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
stella-cli-docs Ignored Ignored Preview Jul 26, 2026 11:36pm

@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 @macanderson, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

`context.lifecycle.enabled` now defaults to `true`. The whole lifecycle —
decomposed recall, frame identity, recall telemetry, selection reasons, the
typed learning loop, the ledger and its review surface — is what a workspace
gets without configuring anything.

WHY THIS IS SAFE TO DEFAULT ON
The behavior-compatibility suite asserts every spec §8 guarantee on BOTH the
typed path and the opted-out one, from the same assertions: tombstone
suppression across re-learning on every surface, the per-session creation cap,
never clobbering a hand-edited file, deterministic candidate identity, and
failure isolation. The migration deliberately kept the lexical loop reachable
rather than deleting it, so "behavior-compatible" stays a checkable claim
instead of a promise. Turning the default on is the point of having built that
evidence — a lifecycle nobody runs cannot be evaluated.

THE FLIP IS TWO CHANGES, NOT ONE
`LifecycleSettings::default()` alone would have shipped nothing. The reader
asked `.and_then(|s| s.context).is_some_and(|c| c.lifecycle.enabled)`, so a
workspace with no `settings.json` — the common case, and every new user —
answered `false` regardless of the struct's default, because the `context`
block was absent rather than present-and-false. An absent block now means "the
defaults", which is what it always should have meant. There are tests for the
no-settings-file case and the empty-block case specifically, because that is
the gap that would have shipped this as a no-op.

WHAT STILL FAILS CLOSED
An unreadable or malformed settings file stays OFF. That file may be the one in
which someone turned the lifecycle off, and silently overriding an opt-out we
failed to parse is worse than leaving a default unapplied. An explicit
`"enabled": false` is honored, and restores the previous behavior wholesale.

The test fixtures that used to get the lexical loop by writing nothing now opt
out explicitly, because "write nothing and get the old path" is no longer true.
That is a change to what the fixtures say, not to what they assert.

`DriverConfig::lifecycle_enabled` still defaults `false`: a programmatically
built config should opt in deliberately rather than inherit a product default
it never read. The CLI passes the real setting.

`make gate` green: exit 0, 3805 tests, check-file-size OK.
@macanderson
macanderson force-pushed the feat/lifecycle-on-by-default branch from fda3cac to f591ebe Compare July 26, 2026 23:36
@macanderson
macanderson enabled auto-merge (squash) July 26, 2026 23:42
@macanderson
macanderson merged commit cdb38b5 into main Jul 26, 2026
9 checks passed
@macanderson
macanderson deleted the feat/lifecycle-on-by-default branch July 26, 2026 23:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant