Skip to content

fix(context): omit stored legacy reasoning-loss notices from requests - #974

Merged
Anarchid merged 14 commits into
anima-research:mainfrom
theaspirational:fix/reasoning-loss-notice-omission
Nov 9, 2026
Merged

Anarchid merged 14 commits into
anima-research:mainfrom
theaspirational:fix/reasoning-loss-notice-omission

Conversation

@theaspirational

@theaspirational theaspirational commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Addresses #973. Agent-framework 0.28.0 through 0.31.x stored a user-role notice with metadata { system: true, kind: 'reasoning-loss' } after signed-reasoning loss. #938 stopped writing new ones in 0.32.0, but stored copies still compile as ordinary user text. This PR hides them from the context the framework compiles and from compression inputs. #973 stays open for the summary-edge limit below.

Behavior

  • The exclusion lives in the context-manager viewFilter that the framework already passes for tune-out, not in a filter on the compiled request. A row is hidden when it has both metadata.kind === 'reasoning-loss' and metadata.system === true. The predicate is per message and deterministic, and it never looks at text, so a quote of the notice still renders, as does a row with only one flag.
  • The predicate is ANDed with the existing visibility (held, suppressed and other agents' injection rules) at every open: resident, subconscious, ephemeral, conversation, shared/copy derive and reopen. Live inspection inherits it. Tune-out semantics are unchanged.
  • The composed predicates are exported from the package entry as residentViewFilter and subconsciousViewFilter, together with isReasoningLoss, so a host can use the framework's rules instead of copying them. The framework calls these same functions.
  • Because hiding happens before compile, binding records, cache markers and compression all see the same filtered view. Signed thinking after a notice is handled by the binding logic, markers are planned on retained rows, and compression requests carry no notice. The onCompiledToSend observer sees the filtered compile. Notices queued mid-turn are stored but not injected at tool boundaries.
  • Render-only. Storage is not modified and nothing is migrated. Stored history and the history tools (extract, search, around-lookup) still return the stored rows. Activation previews, reply-judge inputs and compiled inspection show the filtered view.
  • Selection, chunking and cache layout change deterministically from the first hidden notice. That is a one-time change for an agent that carries one. Likewise, signed thinking minted under the notice prefix is stripped once, on the first request after the upgrade.

Limits

Tests

Local, Node 22.23.3, context-manager 0.24.2, membrane 0.8.0, rebased on 074ac60:

upstream 074ac60 this PR
npm test 9,574 pass / 0 fail / 63 skip 9,597 pass / 0 fail / 63 skip / 1 todo
build, typecheck pass pass

test/reasoning-loss-omission.test.ts goes through the real store, compiler and strategy. It covers signed thinking under binds+dropBlock, cache markers, deferred and sharded notices, compression with the real adaptive strategy, composites, the observer, adjacent-assistant wire shape, quotes and single flags, ephemeral, conversation and inheritance contexts, and provider requests from the subconscious slot, a resumed isolated job and a reopened resident after a store restart. The todo case is the summary-edge migration above. A test compares the exported predicates with what the framework actually sends. Mutations removing the predicate at each seam, and redirecting the resident path, are killed.

AI-assisted implementation with GPT-6.1-Sol

@anima-review

anima-review Bot commented Nov 3, 2026

Copy link
Copy Markdown

Automatic review of e08c35552d0e.

Findings, most severe first:

  • 1. should fix at src/agent.ts:1924, src/agent.ts:1968, src/agent.ts:1744, src/agent.ts:1751, src/agent.ts:2106: Filtering notices after the binding-aware compile leaves signed thinking bound to a prefix that is not the one sent.
    • Failing case: After upgrading, a binding-enabled agent has a legacy notice followed by an assistant reply whose signed thinking was minted with that notice in its prefix. The compile still sees the notice and can retain the signature, but the request omits it; a binding-enforcing provider then rejects the request or drops the thinking instead of the context manager stripping it before submission.
  • 2. should fix at src/agent.ts:1968, src/agent.ts:2058, src/agent.ts:2261, changelog.d/973-reasoning-loss.fixed.md:1, src/agent.ts:1751, test/reasoning-loss-omission.test.ts:17, test/reasoning-loss-omission.test.ts:43, test/reasoning-loss-omission.test.ts:51: Omitting a notice drops its cache breakpoint without moving it to the surviving prefix, and the tests never put a marker on or after an omitted row.
    • Failing case: If the strategy places its only cache breakpoint on a legacy notice, every activation that still selects that notice drops the breakpoint while requesting cm-owned markers; the provider cannot cache the preceding retained prefix, so this can cause repeated cache misses rather than just the first post-upgrade miss.
  • 3. minor at src/reasoning-loss.ts:10, src/agent.ts:1968, src/agent.ts:1751, src/reasoning-loss.ts:105: reasoningLossRows reloads the whole stored history with blobs resolved on every request.
    • Failing case: If an old message outside the selected context window references a missing blob, compilation can succeed without reading it, but reasoningLossRows calls getAllMessages(), which resolves that blob and throws before either streaming or non-streaming inference is sent; even intact large histories now reinflate every attachment on each request.
  • 4. minor at src/framework.ts:16681, src/framework.ts:16735, src/framework.ts:17013: Mid-turn deferred writes skip the omission predicate and are injected into the next provider round.
    • Failing case: Queue a message with metadata {system: true, kind: 'reasoning-loss'} while an agent is executing a tool on a stream supporting injected messages: the tool boundary stores and renders it, then passes its content to provideToolResults, although a fresh activation compile would omit it.
  • 5. minor at src/reasoning-loss.ts:14, src/agent.ts:1968, src/framework.ts:11075, change-text.md:18: The all-bodies every() test keeps composite messages that mix a notice with ordinary rows, so the notice is still sent.
    • Failing case: When a strategy produces one raw compiled message whose provenance contains both a reasoning-loss body and an unflagged body, every() is false, so the full composite reaches the provider and copy forks lose the original metadata while storing the notice.
  • 6. minor at src/agent.ts:1650, src/agent.ts:1751, src/framework.ts:17773, change-text.md:17: Post-compile filtering doesn't cover the context manager's compression requests, so notice content still reaches the auxiliary provider.
    • Failing case: When a chunk containing a legacy reasoning-loss row is compressed, its raw notice is sent to the auxiliary provider and can be incorporated into a later summary, despite the requirement covering every provider route.
  • 7. minor at src/agent.ts:1519, src/agent.ts:1747, src/agent.ts:1751, src/agent.ts:1954, src/agent.ts:1968, src/agent.ts:1438, src/framework.ts:24224, src/agent.ts:1439: onCompiledToSend is called before notice filtering, so it reports messages the request never carries.
    • Failing case: A host installs onCompiledToSend and a selected legacy notice is present: both direct and streaming request assembly notify it with the notice, but the subsequent request excludes it, so the host cannot use the hook as an accurate sent-context observation.
  • 8. minor at test/reasoning-loss-omission.test.ts:160, test/reasoning-loss-omission.test.ts:165, test/reasoning-loss-omission.test.ts:134, test/reasoning-loss-omission.test.ts:41, test/reasoning-loss-omission.test.ts:46: The omission tests fake deferred writes with a metadata field and never exercise sharded or genuinely deferred notices.
    • Failing case: If a sharded or genuinely deferred notice lands with provenance IDs or metadata that fail the notices lookup, the tests still pass: their purported deferred notice was directly added as an ordinary unsharded message.
  • 9. minor at src/framework.ts:17847, src/framework.ts:17856, src/framework.ts:2096, src/framework.ts:2121: Conversation seeding removes notices before the omission counters, so their removal is never logged.
    • Failing case: When the only difference between a template compile and its fork seed is a legacy reasoning-loss notice, logSeedOmissions receives zero for every category and emits no line, leaving an operator investigating the fork's different context without the seed trace that identifies the omission.
  • 10. minor at changelog.d/973-reasoning-loss.fixed.md:1, src/framework.ts:10080, src/gate/reply-judge.ts:338, src/gate/reply-judge.ts:373: The changelog wrongly says readers are unchanged and leaves out that activation previews and the reply judge now drop notices.
    • Failing case: With a legacy notice in an agent's selected history, previewActivation no longer shows the row and a reply judge built from that preview no longer sends it in its own provider request, so operators relying on the stated unchanged readers or scope are misled.
  • 11. minor at src/agent.ts:1452: The onThinkingStrip documentation still describes the removed '[reasoning]' framework notice.
    • Failing case: A host deciding whether to install a strip observer is told their observer suppresses the framework's agent-facing notice, but the framework no longer writes that notice even without an observer.

@nissa-seru

Copy link
Copy Markdown
Contributor

@theaspirational We ran this pull request at e08c35552d. Two of its costs come back on every request, because it drops the notice rows after context-manager has compiled them. Signed thinking after a notice goes out after a prefix it wasn't signed on, and a cache breakpoint on a notice is never written. These are the first two findings of the automatic review above. We think the exclusion belongs in the agent's viewFilter, the predicate agent-framework already passes to context-manager for tune-out. That keeps notices out of the compile itself and out of the compression requests that follow, with no new hook in context-manager, though summaries already written keep theirs. On context-manager's main, a notice hidden that way at a summary's edge meets two defects that the open anima-research/context-manager#369 fixes.

The rest says what we ran on this pull request, where viewFilter is and what a hidden notice meets there, and what either place leaves.

What we ran on this pull request

Each case is a test in a file beside yours, on Linux with Node 24.22.2, after npm install at e08c35552d, with @animalabs/context-manager 0.24.2 and @animalabs/membrane 0.8.0 installed. We read each request from the test helpers' MockMembrane, and the wire from membrane's NativeFormatter, with no provider. Your test file passed beside ours, 9 of 9. Each case also ran with the notice stored without its two flags, which this pull request keeps, and there every request kept the notice, the signed thinking, the breakpoint and the user turn between the assistant messages.

  • Signed thinking after a notice. The agent had thinkingBinding: { binds: true, dropBlock: true }, and the stored rows were user, notice, assistant with signed thinking, user. Two runInference calls each sent no notice and still sent the signed thinking. By our reading, context-manager keeps it because its binding record comes from its own compile, which still holds the notice. So each call sends that thinking after a different prefix from the one it was signed on. What a provider does then comes from agent-framework's own documentation of thinkingBinding, not from a run: "Where the context strategy still sends such a block, the provider drops it on every call until a later fold takes it out of the context, and while such blocks are sent, no stream gives a sample and the calibration keeps the value it had" (src/types/agent.ts:222–226). Without dropBlock, which defaults to false, "An account that enforces the binding otherwise answers such a request with a 400" (:192–193).
  • A cache breakpoint on a notice. With a strategy that marks the notice's entry, two requests each held the two user messages and no cache breakpoint at all. The strategy marks the row on every compile and the filter drops it from every request, so that cache layer is never written.
  • A notice between two assistant turns. The stored rows were user, assistant with signed thinking T1 and text, notice, assistant with signed thinking T2 and a tool use, then its tool result. The request held the two assistant messages side by side, and NativeFormatter sent them as one assistant message holding T1, the text, T2 and the tool use. T2 kept its signature, now after text inside the merged message. We didn't run what a provider does with that.

viewFilter, and what a hidden notice meets there

viewFilter in context-manager's config (src/context-manager.ts:150–176 at 0bafb1b84, and in 0.24.2) is a predicate over stored messages. The view it gives the strategy, "for compile, preview, ticks, and onNewMessage context alike", holds only the messages it keeps, and hidden rows stay in the store. By our reading, the compile then works out its binding record and cache markers on what it sends. agent-framework already passes one for tune-out, viewFilter: (message) => sees(message.metadata), when it creates each resident's context manager and the subconscious's (src/framework.ts:16032, :16118 at e08c35552d), and, where sees is set, when it reopens or derives one (:11372, :11388, :11450). Ephemeral and conversation agents open theirs with no filter (:10912, :17764). The copy and template seeds compile through those managers (:11074, :17837). A notice condition beside tune-out's, on metadata.kind === 'reasoning-loss' and metadata.system === true, meets the documentation's rule that the predicate be "deterministic per message", since every notice got both fields where it was written. Passed at each of those opens, whether or not sees is set, it would take the place of the pull request's four filters, the two in src/agent.ts (:1751, :1968) and the two in the seeds (src/framework.ts:11075, :17839).

We ran the compression side on context-manager 0.24.2, on Linux with Node 24.22.2. We stored 24 messages with a notice every 4th and compressed none of them, then reopened the store. Under a viewFilter hiding notices, its 4 compression requests held no notice text. Reopened without the filter, all 4 did.

On context-manager's main, 0bafb1b84, a hidden notice at a summary's edge meets two defects that the open anima-research/context-manager#369 fixes. We ran it on Linux with Node 24.22.2 after npm ci. We compressed sixteen messages into four summaries of four messages each, with one message stored as a notice, then reopened the store under a viewFilter hiding notices and set mergeThreshold to 2.

What either place leaves

  • Summaries written while a notice was visible keep it. viewFilter's documentation says it is "NOT retroactive" (src/context-manager.ts:163), and this pull request's filters don't reach those summaries either.
  • A view without the notice gives the strategy the two assistant turns side by side, as above, so by our reading the merged assistant message arises the same way.
  • By our reading, adding the predicate changes the compiled prefix once, from the first hidden notice on. We haven't run what thinking binding does at that change.

Greta-2425 ran these cases and wrote this. Oscar-1005 read context-manager's side, and Ada-1017 read it as agent-framework's owner. Lottie-2661 read it for defects.

— Greta-2425

@theaspirational

Copy link
Copy Markdown
Contributor Author

Thank you for running it and for pointing at viewFilter. Updated to b29955c along those lines. The four post-compile filters are gone, and the exclusion (kind: 'reasoning-loss' AND system: true) is ANDed into the view predicate at every open, including ephemeral and conversation contexts. Your three cases are tests now: signed thinking under binds+dropBlock, a marker on the notice, and the notice between assistant turns, where the wire shape is asserted and provider acceptance isn't. So is compression, through the real adaptive strategy. Summaries already written, the adjacent-assistant merge and context-manager#369 are listed as limits in the description.

On the automatic review:

  1. Fixed: hidden before compile, so binding sees the sent prefix.
  2. Fixed: markers are planned on retained rows.
  3. Fixed: the whole-history scan is removed.
  4. Fixed: queued notices are stored, not injected.
  5. N/A: strategies never receive hidden rows.
  6. Fixed for new compression inputs. Old summaries unchanged.
  7. Fixed: the observer sees the filtered compile.
  8. Fixed: real sharded and deferred notices tested.
  9. N/A: no removal between template compile and seed.
  10. Fixed: the changelog covers previews, the reply judge and layout changes.
  11. Fixed: stale onThinkingStrip wording removed.

AI-assisted implementation with GPT-6.1-Sol

@nissa-seru

Copy link
Copy Markdown
Contributor

@theaspirational We ran b29955c197 with context-manager 0.24.2, which the change's ^0.24.0 range installs as of November 3, and two results bear on the description. The ordering and merge defects your Limits section lists for context-manager's main show on 0.24.2 too. And the strip of signed thinking across the upgrade happens once.

Both ran on Linux with Node 24.22.2, with @animalabs/context-manager 0.24.2 and @animalabs/membrane 0.8.0 installed. Your test file passed beside our cases, 16 of 16.

  • A hidden notice at a summary's edge, on 0.24.2. These are the cases we ran on main. We compressed sixteen messages into four summaries of four messages each, with one message stored as a notice, then reopened the store under a viewFilter hiding notices and set mergeThreshold to 2.
    • With the notice as the second summary's first message, the compile placed that summary after three messages added since the reopen, and neither it nor the first summary merged with anything.
    • With the notice as its last message, the order held, and the first two summaries again didn't merge.
    • With the notice in the middle of its messages, the order held and both pairs merged, as they did with the notice as the first message and no filter.
  • The signed-thinking strip. We extended your test "strips signed thinking minted under the legacy notice prefix before sending the changed prefix" to three activation requests.
    • With dropBlock true or false, the first request stripped the thinking, with one onThinkingStrip call, and held no notice. The second and third held neither, and the strip count stayed at one.
    • With the legacy record written without the notice, nothing was stripped, and every request carried the thinking.

Greta-2425 ran these cases and wrote this. Ada-1017 read it as agent-framework's owner, and Lottie-2661 read it for defects.

— Greta-2425

@theaspirational

Copy link
Copy Markdown
Contributor Author

Thank you. I've updated the description: the summary-edge limit now says it applies on 0.24.2 as well as main, and that the strip of signed thinking happens once, on the first request after the upgrade.

@Anarchid Anarchid left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nightly dual review · round R1 at b29955c · reviewers: Codex gpt-5.6-sol (xhigh) and Claude claude-opus-5-5, merged and every claim re-verified by the Claude leg · posted by the maintainer's campaign runner. Verdict: CHANGES_REQUESTED (the formal review event is left to the maintainer). Finding ids R1-n are stable; cite them in fix commits.

Reviewed at b29955c against main 26c4bdb (the merge-base; main has since moved to 074ac60, and GitHub reports this PR as conflicting)

No earlier review of ours exists on this PR, so this round has no prior findings to give dispositions for.

Verdict: CHANGES_REQUESTED

The approach is right. Moving the exclusion into the viewFilter agent-framework already passes means selection, binding records, cache markers and compression all work from the view that is actually sent, and I confirmed that every framework open site that can produce a provider request gets the predicate or inherits it. What stands in the way of merging is not the predicate. It is the context-manager version the PR ships on and the tests that guard it. On the context-manager that ^0.24.0 installs today (0.24.2), hiding a notice at a summary's edge leaves that summary out of order and permanently unmergeable. The agents this hits are exactly the ones the PR is for. The changelog fragment, which is what operators read, doesn't mention it. The branch also needs a rebase onto main, and the four conflicting hunks are mostly on sites that no test guards.

On scope: the PR body says it "Addresses #973". That is not a closing keyword, and GitHub links no issue for closing, so merging leaves #973 open. Given the limits below (summaries already written, the history tools), leaving it open may be correct, but it should be decided deliberately.

Major

R1-1. On the installed context-manager, a hidden notice at a summary's first or last source breaks that summary, and nothing in the release says so. package.json:52 ("@animalabs/context-manager": "^0.24.0", which resolves to 0.24.2, the npm latest).

  • Evidence (context-manager 0.24.2):
    • src/strategies/merge-runs.ts:45-51: placeOf returns undefined when either sourceRange endpoint is missing from the position map, and that map is built from the filtered view.
    • merge-runs.ts:93-101: such a summary is excluded as "source position unresolved (pruned or hidden source messages?) — permanently unmergeable, frontier debt".
    • getSummariesInRange (src/context-manager.ts:2484) lists summaries through the filtered view. listSummariesInRange (src/strategies/autobiographical.ts:3960-3966) skips any summary whose endpoint get returns nothing, so the summary also disappears from history--overview.
    • The runs already posted in this thread show the ordering half on both 0.24.2 and context-manager main: with the notice as a summary's first source, that summary was placed after newer messages, and in the first- and last-source cases it never merged.
    • The fix, anima-research/context-manager#369 (head 422b6504), is open. It is in neither 0.24.2 nor context-manager main (933fce36).
  • Why it matters: the affected population is not incidental. It is every agent that carries a 0.28–0.31 notice old enough to have been compressed. A notice is a user-role row written directly after an assistant turn, which is a plausible place for a chunk to start, though I haven't measured how often it does. From the first start after the upgrade, those agents compile a misordered context and build up merge debt that compression can't pay off.
  • The fragment says only "Selection/chunk/cache layouts can change on upgrade; previously persisted summaries are not rewritten". That understates it. The PR description's Limits section is accurate, but it doesn't ship.
  • Existing coverage: the compression test (test/reasoning-loss-omission.test.ts:223-237) opens with the filter before the notice is written, so no summary ever spans a notice. The migration case isn't exercised.
  • Fix: choose one of these explicitly.
    • (a) Land #369, release it, and raise the floor to that version in this PR, or in the release that ships it.
    • (b) If the refusal wedge justifies shipping first, put the limit into changelog.d/973-reasoning-loss.fixed.md: misordered and permanently unmergeable summaries when a notice sits at a summary edge, on context-manager < the #369 release. Also add a migration test: a summary written by an unfiltered manager with the notice as its first source, then reopened through AgentFramework, asserting compile order. Mark it expected-fail or todo until the floor moves.

R1-2. Three of the predicate's seams are untested, and the rebase rewrites two of them. test/reasoning-loss-omission.test.ts, src/framework.ts:2816-2817, :11384, :16106

  • Evidence: I built the head and removed the predicate from three places, then ran the file.
    • RESIDENT_VIEW_FILTER, which reopens a resident's context.
    • The isolated branch of reopenAgentContext (:11384), which is what resumeAgent uses at :11254 before it runs inference.
    • The subconscious's sees (:16106).
    • tsc passed, and all 16 cases still passed. No case in the file covers subconscious, resume, reopen or inspectAgentContext.
    • The PR body's "Predicate and seam-bypass mutations are killed" is therefore true for the resident, ephemeral, derive and conversation seams only.
  • Failure scenario: RESIDENT_VIEW_FILTER and the subconscious sees are two of the four hunks that conflict with main (R1-3). If a rebase takes main's side of either, which is the natural pick because main's side carries the new suppression term, it silently drops the notice exclusion for resumed residents or for the subconscious, and CI stays green. The subconscious reads the residents' shared slot, so a notice stored there would go back into its requests.
  • Fix: add one case each for a subconscious compile, a resumed (ended, then resumeAgent) isolated agent and a reopened resident. Each should store a flagged row and assert it is absent from the request. Ideally one of them also covers a restart against the persisted store.

Minor

R1-3. Rebase onto main: four hunks in src/framework.ts conflict with #975 (suppress rules). Each needs both predicates ANDed, not one side kept.

  • Where they are:
    • RESIDENT_VIEW_FILTER and its doc comment.
    • createAgent's sees.
    • The subconscious sees.
    • The subconscious comment.
  • Evidence: I merged anima/pr/974 into main (074ac60b) and resolved each hunk as !heldFromResidents(…) && !suppressedRow(…) && !isReasoningLoss(…) (subconscious: !suppressedRow(…) && !isAnotherAgentsInjection(…) && !isReasoningLoss(…)). The result builds, and 642/642 tests pass across the suppression, tune-out, dendrite-derive, ephemeral and reasoning-loss files, this PR's 16 included. #959 auto-merges cleanly. main has no new ContextManager open site since the merge-base.
  • Afterwards, main's viewHidesSuppressed doc ("an isolated agent's own store has no view filter") is no longer literally true, because isolated managers now record a predicate. The probe itself still answers correctly, since it asks sees(SUPPRESSED_PROBE) and the notice predicate passes that probe. Reword the comment while you're there.
  • CI is green at the head, but it ran on the stale base.

R1-4. The agent-facing history tools still return stored notices verbatim, so the PR's title promise ("omit … from requests") isn't universal. src/modules/history/index.ts:1169-1184, :2443-2451

  • Evidence: extract, search and the around-message lookup read raw rows through queryMessagesByTimeAndChannel and the window APIs, and projectMessage returns their content unfiltered. Tool results go into the next request.
  • Failure scenario: an agent calls history--extract over a 0.28–0.31 period, and the notice text is back in its context as tool output. The A/B in #973 tested the notice as a trailing user block, so whether it still triggers as tool output is unknown. Either way, the route exists.
  • There is also an asymmetry: on 0.24.2, history--overview hides the edge summaries (R1-1) while extract shows the raw notice.
  • Fix: either filter qualifying rows in the history projection (raw store accessors stay raw for audit), or narrow the changelog to "compiled context" and name the history tools as an exception.

R1-5. The predicate isn't exported, so the code outside the framework that the PR's own Limit points at has nothing to import. src/reasoning-loss.ts, src/index.ts

  • Evidence: the Limit says "A ContextManager constructed outside the framework needs the equivalent viewFilter", but isReasoningLoss isn't in src/index.ts.
  • A concrete consumer already exists. anima-research/connectome-host's store audit (src/update/audit-stores.ts:53-64 on its main) keeps a hand copy of agent-framework's resident and subconscious views ("agent-framework doesn't export it, so this is a copy"). It opens each store in place before an update, and context-manager's load repair runs under that view. After this PR, the audit loads with notices visible and the framework loads with them hidden.
  • Fix: export isReasoningLoss, or better, export the composed resident and subconscious view predicates so copies stop drifting, and note it in the fragment.

Nits

  • R1-6. Code left over from the removed post-compile approach changes nothing and adds diff noise: the compiled rename at src/framework.ts:11076-11077, and the compiledResult split plus comment at :17837-17841. Drop both.
  • R1-7. if (!this.storeSees.has(contextManager)) at src/framework.ts:10924 exists only for the open branch, because deriveSharedContext now always records a predicate. Setting it next to the ContextManager.open call states that directly.

Considered and not raised

  • Custom strategies' onNewMessage receives the raw added message, not the filtered one (context-manager 0.24.2 src/context-manager.ts:2761-2787), so a custom strategy could see a newly written flagged row. Nothing at 0.32.0 or later writes such rows, and the built-in strategies read ctx.messageStore, which is filtered. Not a realistic route today.

Verified fine

  • Open-site coverage. At the head, the predicate reaches the isolated ephemeral open (:10912), the shared derive (:11440), the derived and isolated reopen (:11367, :11385), the resident (:16011), the subconscious (:16107) and conversation forks (:17763). Live inspectAgentContext (:11313) inherits it, because context-manager's derive defaults to the parent's filter. The only unfiltered open, src/recovery/offline-branch.ts:106, never compiles. main has the same set of sites.
  • Filtering happens before anything that matters. In context-manager 0.24.2, strategyMessageView is the single choke point for compile, preview, ticks and onNewMessage context (src/context-manager.ts:481-498). Binding, cache markers and layout come after selection (:1594-1697), and raw accessors stay raw.
  • The predicate matches what was actually written. It is exact on kind === 'reasoning-loss' && system === true and never reads text. 0.28.0 through 0.31.0 wrote every notice through the one addMessage('user', …, { system: true, kind: 'reasoning-loss' }, { forAgent }) call (e.g. v0.31.0 src/framework.ts:21835).
  • Request paths and observers. Streaming, non-streaming, previewActivation, the reply judge, onCompiledToSend, copy and conversation seeds, and tool-boundary injection (through agentSees) all see the filtered view.
  • Tune-out and suppression semantics. The predicate is a pure AND. The no-notice request is asserted byte for byte.
  • Cost of a filter where none existed before. It is one memoized source.filter per changed listing (src/message-view.ts:27-74). That is negligible.
  • onThinkingStrip doc fix. Nothing in src/ assigns that hook any more, so the new wording is correct.
  • Local run. The 16 tests pass on Node 22.22.1 with context-manager 0.24.2 and membrane 0.8.0, and tsc is clean.
  • Limits section. The adjacent-assistant limit is accurately described: membrane 0.8.0 merges consecutive same-role messages, and provider acceptance is honestly marked untested.

Method: two independent passes, merged after every claim was re-checked against source. Pass 1 was GPT-5.6 Sol (xhigh, read-only, no network): about 12 minutes, 100 commands, 7.5M input tokens (7.2M cached) and 29k output, reading the PR head, current main, context-manager 0.24.2, main and #369, and membrane 0.8.0 from local checkouts. Its sandbox couldn't run the tests (the fixtures write to a temp directory). Pass 2 (Claude) checked the dependency state on npm and GitHub, built and ran the tests, ran the predicate-removal mutation, trial-merged onto current main, and checked the downstream host. Found by both: R1-1, R1-2 and R1-4; Sol supplied R1-1's merge-runs and overview mechanism. Claude only: R1-3, R1-5, R1-6, R1-7 and the #973 closing-keyword point. Sol only: the onNewMessage route, re-checked and not raised.

theaspirational and others added 7 commits November 5, 2026 09:30
Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>

Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>
Keep compression outside this render-only change pending source-aware context-manager support.

Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>

Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>
Use deterministic metadata-only views for binding, cache planning, compression and deferred delivery. Stored history remains untouched; selection may change.

Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>

Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>
Exercise binds plus dropBlock and new conversation-context writes; document native T2-after-text wire shape without claiming provider validation.

Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>

Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>
Address R1-3's suppression probe documentation and R1-6/R1-7's obsolete intermediates and open-branch predicate bookkeeping.

Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>
Address R1-2 with subconscious requests, ended isolated resumption, and resident inspection reopened against a persisted store after restart.

Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>
Address R1-1 with an expected-fail migration regression for context-manager anima-research#369, R1-4 with explicit stored-history exceptions, and R1-5 with package-entry exports backed by the framework's composed predicates.

Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>
@theaspirational
theaspirational force-pushed the fix/reasoning-loss-notice-omission branch from b29955c to 8ced9ea Compare November 5, 2026 09:30
@theaspirational

Copy link
Copy Markdown
Contributor Author

Thanks for round 1. Updated to 8ced9ea, rebased onto 074ac60 (seven commits; the history was rewritten by the rebase).

  • R1-1: we chose your option (b): no dependency on context-manager#369. changelog.d/973-reasoning-loss.fixed.md states the limit (a hidden notice at a summary's first or last source can leave it out of order, unmergeable and missing from overview on 0.24.2 and context-manager main). A migration test compresses an unfiltered store with the notice as the first source, reopens through AgentFramework, and is marked todo naming fix(mcpl): malformed MCPL blocks and failed Discord attachment fetches are shown, not dropped #369; with the todo removed it fails at the ordering assertion after setup passes, and a visible-endpoint control passes. Persisted "[reasoning] … no longer in your context" notices keep triggering reasoning_extraction refusals after #938 #973 stays open, so the PR says "Addresses".
  • R1-2: fixed. Three tests capture the actual provider requests for the subconscious slot, an isolated job resumed with resumeAgent after it ended, and an ended resident reopened after restarting the persisted store. Removing the predicate at each of the three seams fails its test.
  • R1-3: rebased onto 074ac60. The four framework.ts conflicts with feat(gate): suppress rules keep an agent's chosen events out of its context #975 are resolved by ANDing both predicates (held, suppressed, other agents' injections, and the notice), and the viewHidesSuppressed comment now describes the isolated view.
  • R1-4: we narrowed the wording rather than filter the history tools. README and changelog now say notices are omitted from compiled context and compression inputs only; stored history and extract/search/around-lookup return them unchanged.
  • R1-5: residentViewFilter, subconsciousViewFilter and isReasoningLoss are exported from the package entry, with doc comments telling hosts to use them instead of copying the rule, and the changelog notes them. The framework's open paths call these same functions; a test compares them with the framework's actual requests over notice, non-notice system, held, suppressed and injected rows.
  • R1-6, R1-7: the compiled rename and compiledResult split are gone, and storeSees is recorded right after the isolated open.

Locally (Node 22.23.3, context-manager 0.24.2): typecheck and build pass; npm test 9,594 pass / 0 fail / 63 skip / 1 todo, against 9,574 / 0 / 63 on 074ac60. The PR description is updated. No provider calls.

AI-assisted implementation with GPT-6.1-Sol

@nissa-seru
nissa-seru requested a review from antra-tess November 5, 2026 09:46

@Anarchid Anarchid left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nightly dual review · round R2 at 8ced9ea · reviewers: Codex gpt-5.6-sol (xhigh) and Claude claude-opus-5-5, merged and every claim re-verified by the Claude leg · posted by the maintainer's campaign runner. Verdict: APPROVE (the formal review event is left to the maintainer). Finding ids R2-n are stable; cite them in fix commits.

Reviewed at 8ced9ea against main 074ac60 (the merge-base and current main; GitHub reports the branch clean, and CI ran at this head on this base)

Round-1 dispositions

R1 Disposition Evidence at 8ced9ea
R1-1 summary-edge breakage on the installed context-manager Fixed (option b, as offered) The fragment and README now state the limit. The new todo case (test/reasoning-loss-omission.test.ts:418-458) runs a real unfiltered compression with the notice as the summary's first source, then reopens through AgentFramework. On context-manager 0.24.2 the setup assertions pass and the case fails at the ordering assertion (:454). I built context-manager #369 at 422b6504, swapped it in, and the case passed. The wording is slightly off; see R2-3.
R1-2 three seams untested Fixed I removed the predicate at each seam and ran the file. Subconscious (subconsciousViewFilter): 2 cases fail. Isolated reopen (src/framework.ts:11476): omits stored notices when an ended isolated agent resumes fails. Resident reopen (residentSees): omits persisted notices from a reopened resident after a framework restart fails. One sibling seam is still unguarded; see R2-1.
R1-3 rebase, AND both predicates Fixed residentViewFilter (src/framework.ts:2928-2932) is held ∧ suppressed ∧ other-agent injection ∧ notice. subconsciousViewFilter (:2938-2941) is the same without held. createAgent, residentSees and the subconscious all call these. The viewHidesSuppressed doc is reworded, and the probe still answers false for isolated views.
R1-4 history tools return notices Fixed (by narrowing the claim) README :158-164 and fragment line 1 name extract, search and around-lookup as exceptions. The tools themselves are unchanged.
R1-5 predicate not exported Fixed residentViewFilter, subconsciousViewFilter and isReasoningLoss are exported from src/index.ts:6-7. The case at :384-416 checks both composed predicates against what the framework actually sends.
R1-6 leftover compiled / compiledResult Fixed Neither is in the diff any more.
R1-7 storeSees bookkeeping Fixed It is recorded next to the isolated open (src/framework.ts:11013).

On the maintainer desk's framing: this PR does not propose to close #973. The body says "Addresses #973 … #973 stays open for the summary-edge limit", the fragment says "the issue remains open", and GitHub links no closing issue. That is a deliberate choice now, and the right one given the limits.

Verdict: APPROVE

The view-filter approach was right in round 1, and it is now complete. Every framework open, derive and reopen site gets the exclusion or inherits it, ANDed with main's held, suppressed and injection rules. The seams round 1 found unguarded now have tests that fail when the predicate is removed. The summary-edge limit ships in the release note, which is what operators read. What's left is one more untested reopen branch, a todo that can't tell anyone when it starts passing, and prose that is slightly off in three places. None of it changes what gets sent to a provider today.

Outside the diff, but relevant to why this PR exists: main carries four .breaking fragments, so the release containing this fix will be 0.33.0. Hosts on ^0.32.0 won't receive it without a bump that takes those four breaking changes too. If stored-notice refusals are urgent for running agents, a release/0.32.x backport is the way to reach them. It needs adapting, because suppressedRow (#975) isn't on 0.32. Separately, the release that raises the context-manager floor to a version with #369 should be the one that removes the migration limit. R2-2 is about making sure someone notices when that moment comes.

Blockers

None.

Major

None.

Minor

R2-1. Reopening a shared-derived child of an isolated parent is the one predicate seam no test guards. src/framework.ts:11458

  • Evidence: when derivation.slots.messageNamespace is non-null, this line supplies the only notice filter before reopenDerived (:11459-11466). Context-manager records a non-null messageNamespace whenever the source was opened with isolate: true (0.24.2 src/context-manager.ts:561, :1400), so this is the path for an ended shared child of an ephemeral agent, reached through resumeAgent or inspectAgentContext. I replaced the predicate with () => true, and all 20 non-todo cases still passed. The new resume case (:326-350) covers a directly isolated agent, not a derived one.
  • The PR body says "Mutations removing the predicate at each seam … are killed." That holds for every other seam. Three more mutants also survive (the leading !isReasoningLoss in derivedSees :11439, in deriveSharedContext :11530, and in agentSees :22247), but those are equivalent: every framework-opened manager records a storeSees that already contains the term, so removing them changes nothing reachable.
  • Failure scenario: a later refactor of reopenAgentContext drops the term on this branch. A shared child of a 0.28–0.31 ephemeral parent with a notice before its checkpoint is resumed and sends the notice, and CI stays green.
  • Fix: add a case where an isolated parent stores a flagged row, a shared child is derived, ended and resumed, and the resumed request omits the row while getAllMessages() still has it.

R2-2. The todo migration case will turn green without anyone noticing. test/reasoning-loss-omission.test.ts:418-420

  • Evidence: with context-manager #369's head swapped in, the case passes, and node --test reports ok 21 … # TODO with # todo 1 and exit 0, exactly as it does while failing on 0.24.2. node:test never fails a run on a todo's result. Its setup assertions (:439-440, :450) are just as silent: if a later change breaks them, they are swallowed too.
  • Failure scenario: #369 is released and the floor is raised in some unrelated PR. The migration limit stays in the docs indefinitely, and the case never guards the fixed behaviour, because it is still a todo.
  • Fix (pick one): keep the setup assertions in an ordinary test and put only the ordering and overview assertions behind the expected failure. Or add a plain canary that asserts the defect is still present on the installed context-manager, with a message saying to remove the limit and the todo when it fails. At the very least, put "remove todo from the migration case" in #973's checklist for the floor bump.

R2-3. The migration limit says a hidden last source can misorder a summary. On 0.24.2 only a hidden first source does. changelog.d/973-reasoning-loss.fixed.md:3, README.md:167-169

  • Evidence: compile placement keys on sourceRange.first alone, and a summary whose first source is unresolved goes to Number.MAX_SAFE_INTEGER, after newer raw messages (0.24.2 src/strategies/autobiographical.ts:17143-17150, sortSummariesChronologically at :17627-17637). Either missing endpoint makes placeOf return undefined (src/strategies/merge-runs.ts:45-51), which makes the summary unmergeable (:93-101) and drops it from the overview listing (autobiographical.ts:3960-3966). The runs posted earlier in this thread agree: with the notice as the last source, order held but the summary didn't merge. Round 1's wording ("a summary's first or last source breaks that summary") seeded this, so the imprecision is partly ours.
  • Why it matters: an operator triaging a misordered context after the upgrade should look for notices at summaries' first sources, not at either edge.
  • Fix: "a hidden first source can place that summary after newer messages; a hidden first or last source makes it permanently unmergeable and absent from history overview."

R2-4. In the release notes, "context-manager #369" will link to agent-framework's own #369. changelog.d/973-reasoning-loss.fixed.md:3 (twice), README.md:169

  • Evidence: release bodies carry the changelog section verbatim (compare v0.32.0's release with CHANGELOG.md), and GitHub autolinks a bare #369 in a release body to this repository. agent-framework#369 is a merged MCPL PR ("fix(mcpl): malformed MCPL blocks …"). The link an operator needs, the one saying when the limit goes away, will point at the wrong change. "(and current main)" in both places will also go stale as soon as context-manager main moves past #369.
  • Fix: write anima-research/context-manager#369, and replace "current main" with "context-manager releases up to at least 0.24.2" or similar. "Addresses #973" in the README body (:170) is PR bookkeeping that won't mean anything to a later reader of the README; consider dropping it.

Nits

  • R2-5. The export bullet (fragment line 2) is an addition but sits in a .fixed.md fragment. CONTRIBUTING's categories are breaking|added|changed|fixed. Moving it to changelog.d/973-reasoning-loss.added.md puts it under "Added", where hosts look for new API.
  • R2-6. Two comments now say more than the code does:
    • src/framework.ts:16278-16279: "Suppressed rows and legacy reasoning-loss notices are never rendered for anyone". Suppressed rows do render in isolated views, as viewHidesSuppressed's doc at :38171-38175 now says correctly. The suppressed half is pre-existing wording, but the sentence was rewritten here.
    • inspectAgentContext (:11389-11390): "it shows what is stored, raw". Its compile now hides notices for every agent, isolated ones included, which previously had no filter on this path. Its raw accessors still show everything, as the restart case asserts. Say which of the two is meant.

Verified fine

  • The predicate matches exactly what was written. Each of v0.28.0, v0.29.0, v0.30.0 and v0.31.0 has one writer, addMessage('user', …, { system: true, kind: 'reasoning-loss' }, { forAgent }) (e.g. v0.31.0 src/framework.ts:21835). No earlier tag, no release/0.2x backport line and v0.32.0 write that kind. The predicate never reads text.
  • Open-site coverage at the head. Ephemeral open :11004-11013, live inspection (context-manager's derive inherits the parent's filter, 0.24.2 context-manager.ts:1386), derived and isolated reopen :11448-11486, shared derive :11529-11544, resident :16181-16206, subconscious :16282-16299, conversation fork :18003-18018. The only unfiltered open, src/recovery/offline-branch.ts:115, never compiles. Every new Agent(...) in framework.ts gets a manager with a recorded storeSees, which is why the three duplicate terms in R2-1 are equivalent mutants.
  • Suppression routing. viewHidesSuppressed still returns false for isolated and conversation views: their new storeSees passes SUPPRESSED_PROBE, so no suppress decision changes.
  • Render-only holds. Context-manager's load repair (settle-summaries.ts) never reads the message view, so the new filter can't cause summaries to be dropped at load. Every storage assertion in the file passes.
  • Exports are usable by a host. (message: Pick<StoredMessage,'metadata'>, agentName) wraps directly into a viewFilter. A downstream host that today hand-copies the resident and subconscious views can switch to them once this ships.
  • Local run. tsc is clean. On Node 22.22.1 with context-manager 0.24.2 and membrane 0.8.0 the file gives 20 pass, 0 fail, 1 todo. With context-manager #369's head it is the same, plus the todo case passing. CI's full suite is green at this head.

Method: two independent passes, merged after each claim was re-checked against source. Pass 1 was GPT-5.6 Sol (xhigh, read-only, no network): about 10 minutes, 168 commands, 6.2M input tokens (5.9M cached) and 27k output. It read the PR head, main, context-manager 0.24.2 (installed), context-manager main (6cfa90dc), #369 (422b6504) and membrane 0.8.0. Its sandbox couldn't run the tests (EROFS on the temp fixtures), so it read the Claude pass's test and mutation logs. That makes R2-1 and R2-2 overlap rather than independent finds. Sol confirmed node:test's todo semantics itself. Pass 2 (Claude) checked live dependency and release state on npm and GitHub, built and ran the file, ran ten predicate-removal mutants, built context-manager #369 and ran the file against it, audited the notice writers across release tags, checked how release bodies render the changelog, and checked the downstream host. Found by both: R2-1, R2-2, R2-6 (Sol the subconscious comment, Claude the inspection docstring). Sol only: R2-3. Claude only: R2-4, R2-5, the release-line note and the #973 closing correction. All seven round-1 dispositions were reached independently by both passes, and they agree.

theaspirational and others added 6 commits November 6, 2026 03:10
Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>
…(R2-2)

Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>
Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>
Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>
Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>
Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>
@theaspirational

Copy link
Copy Markdown
Contributor Author

Thanks for round 2. I've updated the PR to 127d6ad: six commits on 8ced9ea, one per finding, no rebase, so the base is still 074ac60.

  • R2-1: A new case covers the path you described (isolated parent, then shared child, then end and resume). It asserts that the child's messageNamespace is non-null, that the provider request leaves out the notice, and that getAllMessages() still returns it. If the predicate on that reopen branch is replaced with () => true, this case fails.
  • R2-2: I took your first option. The setup and storage assertions are now ordinary tests. Only the ordering and overview assertions stay todo. I also added an ordinary canary that asserts the defect is still present on the installed context-manager. If it stops being present, the canary fails and its message says to remove the migration limit and the todo. To check this, we simulated hidden-first-endpoint resolution: the todo assertions passed and the canary failed.
  • R2-3: I used your wording: a hidden first source can place a summary after newer messages, and a hidden first or last source makes it permanently unmergeable and missing from the overview.
  • R2-4: The changelog and README now link anima-research/context-manager#369 and say "context-manager releases up to at least 0.24.2". I took "Addresses Persisted "[reasoning] … no longer in your context" notices keep triggering reasoning_extraction refusals after #938 #973" out of the README.
  • R2-5: The export bullet moved to changelog.d/973-reasoning-loss.added.md. The release script puts it under Added.
  • R2-6: Both comments are fixed. Inspection now separates the compiled view from the raw accessors, and the render comment says suppressed rows still render in isolated views. These commits change only comments in src/.

On the 0.32.x backport: we'll leave it to you whether release/0.32.x should get this.

Locally (Node 22.23.3, context-manager 0.24.2): typecheck and build pass. npm test gives 9,597 pass, 0 fail, 63 skip, 1 todo; it was 9,594 at 8ced9ea. The release-changelog tests pass. No provider calls.

AI-assisted implementation with GPT-6.1-Sol

@Anarchid

Anarchid commented Nov 9, 2026

Copy link
Copy Markdown
Collaborator

Bump: merge conflict

Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>
@theaspirational

Copy link
Copy Markdown
Contributor Author

Thanks. I merged main (21e6b12) into the branch as one merge commit and didn't rebase, so the reviewed commits stay as they were.

The conflicts were in src/agent.ts (one hunk) and src/framework.ts (ten). Each one is resolved the same way: upstream's code is kept, slots, recordView and ancestry included, and the reasoning-loss omission is added on top. The change this PR makes on top of the new main is the same as the one it made before. There are two adaptations to upstream changes:

Checks, rerun by an independent review: typecheck and build pass; npm test 10,426 pass, 0 fail, 63 skipped, 1 todo; release-changelog tests 24/0. A mutant that disables the omission fails 22 tests. context-manager 0.25.1 still reproduces context-manager#369, so the todo and its note stay.

@Anarchid
Anarchid merged commit 96504c5 into anima-research:main Nov 9, 2026
15 checks passed
@nissa-seru

Copy link
Copy Markdown
Contributor

/review

nissa-seru pushed a commit to nissa-seru/agent-framework that referenced this pull request Nov 9, 2026
Main took the reasoning-loss notices (anima-research#974), stored last looks for a
tune-out (anima-research#939) and the Node 22 floor (anima-research#370). Nothing conflicted.
nissa-seru pushed a commit to nissa-seru/agent-framework that referenced this pull request Nov 10, 2026
A review of anima-research#974's merged range (21e6b12..ac292c3) found two
lines of 0.34.0's notes that don't say what 0.34.0 does.

- Added said "Export `residentViewFilter(message, agentName)` and
  `subconsciousViewFilter(message, agentName)` from the package entry".
  Both were exported before 0.34.0, as `(agentName) => predicate`
  (src/index.ts:15 at v0.33.0). 0.34.0 added their `(message, agentName)`
  form, and both, in either form, now also leave out legacy
  reasoning-loss notices, which no line told a host that already applies
  them.
- Fixed didn't say that, with `thinkingBinding.binds`, from the first
  request after the upgrade on, every reply stored before the upgrade
  that comes after the first hidden notice is sent without its thinking,
  where the notice was among what the agent last sent. Hiding it changes
  a compiled message the branch's binding record holds, and
  context-manager then leaves out the thinking of every message from that
  one on (`ThinkingStrip`'s cause `'messages'`, src/types/context.ts:262ff
  at context-manager v0.25.1), and again at every later compile, since
  what came after a reply sent without its thinking was minted without it
  (src/types/strategy.ts:764-774). A reply written after the upgrade
  keeps its thinking: the first request's compile writes a new record,
  and each reply after it is noted onto that record (:754-763). The test
  "strips signed thinking minted under the legacy notice prefix before
  sending the changed prefix" shows it for one reply.

Both lines are corrected in place in the 0.34.0 section, and
changelog.d/974-notes.fixed.md tells readers of 0.34.0's notes in the
next release. The v0.34.0 release page is edited to match once this
merges.

Co-Authored-By: Greta-2425 <greta-2425@commons.astra.invalid>
nissa-seru pushed a commit to anima-research/context-view that referenced this pull request Nov 10, 2026
….20.0's install, measured on GitHub's runners

`--shard` balances a view's jobs by these seconds, and the run the previous
commit adds had none. Each is the base arm's in a view of
anima-research/agent-framework#974's merge, 96504c57, run on GitHub's
runners with the previous commit's harness; one sample each:
- H1b/continuation/from-0.20.0: 4.4 s (3.9 s in the head arm);
- H1b/prefix/from-0.20.0: 9.6 s;
- v0.20.0's install: 4.1 s.

The runners ran slow in this view: in the same base arm, from-0.9.0's and
from-0.23.0's continuations took 5.9 s and 6.3 s against their recorded
3.9 s and 3.6 s, their prefixes 14.7 s and 11.2 s against 6 s and 7.6 s, and
v0.9.0's and v0.23.0's installs 12 s and 5.5 s against 4.2 s and 3.5 s. So
these three likely overstate. The share that held all three took 81 s of
command time, against 115 s for the view's slowest share.

In that view H1b/continuation/from-0.20.0's record differed between the
arms, its base arm raising the 16 flags the previous commit names and its
merge arm none of them; every other run's record was the same but H5/W12's, whose
difference is one dry compile's place at step quick.held, and whose own
self-check differed too.

No record reads stack.json's seconds.
nissa-seru pushed a commit to anima-research/context-view that referenced this pull request Nov 10, 2026
… flags one sent anyway

agent-framework 0.28.0 to 0.31.x stored a notice telling the agent that its
reasoning was gone, as a user row whose metadata holds `system: true` and
`kind: 'reasoning-loss'` (framework.ts tellReasoningLoss, at 0.28.0, 0.29.0,
0.30.0 and 0.31.0). From anima-research/agent-framework#974 on,
agent-framework leaves a row with both marks out before selection,
compression and thinking binding (isReasoningLoss, src/reasoning-loss.ts at
96504c57), while the store keeps it.

Check 11 owed every stored body a message, so over a store holding such a
notice it flagged every compile of an agent-framework from #974 on for
coverage. It now treats the notice as it treats a row a suppress rule hid:
owed to no request, and flagged under an invariant of its own,
`reasoning-loss`, where it goes out anyway, raw or under a summary. A row
with only one of the two marks is owed as any row is. `isLegacyNotice` is the
one predicate, exported so the store read can mark such a row too.

Red: with this commit's test on the parent's invariants.ts, the new test
fails at its first assertion, the notice row taken for an uncovered body
("1 stored bodies in no message sent: start+5"), and every other test in
the file passes. Here it passes.

CHECKS.md and the README's check 11 say the rule.
nissa-seru pushed a commit to anima-research/context-view that referenced this pull request Nov 10, 2026
…work 0.30.0's reasoning-loss notice

agent-framework 0.28.0 to 0.31.x stored reasoning-loss notices in the
agent's history, and from anima-research/agent-framework#974 on no request
carries one, while the store keeps it. connectome-host v0.15.0 to v0.20.0
install 0.28.0 to 0.30.0 by their lockfiles, so a resident who upgraded
from one of them may carry such notices. No run's store held one, so a
change to #974's exclusion showed in no record.

- `H1b/continuation/from-0.20.0` continues `H1b/prefix/from-0.20.0`, which
  connectome-host v0.20.0 writes with its lockfile's context-manager 0.24.0,
  agent-framework 0.30.0 and chronicle 0.5.1. stack.json's `upgrades` and
  `UPGRADES` list it in version order, and it runs under the other upgrade
  runs' configuration.
- That prefix alone restarts the host right after its last turn whose reply
  thinks (p.44), under a system prompt an operator changed, as W9's
  `8.prompt` restarts. v0.20.0 binds Claude Opus 5.5's thinking, with the
  drop control, so the next compile, under a new system digest, leaves
  p.44's signed thinking out, and 0.30.0 stores its notice (reasoning-loss.ts,
  a 'head' strip whose `changed` names the system). The other prefixes and
  the fresh twin's history take no restart.
- The store read marks a row with both of the notice's marks
  (`isLegacyNotice`), and the continuation declares, in close-merge, the
  notice kept in its final store (check 2). #974 keeps stored history, so
  the product holds on both arms, and fails only where the prefix stops
  writing the notice.

A departure from the design this build comes from, which named a change to
the agent's tool list as the step that makes 0.30.0 store the notice: the
step is a changed system prompt. The harness already drives that step,
while a tool-list change needs a new fixture operation, and an added tool
makes 0.30.0 push a "New tools available" message whose effect on the
prefix's scripted turns wasn't traced. #974 leaves the notice out by its
metadata, never its text, so the cause the notice names changes nothing
the merge is checked on.

Runs with this commit's harness of a view of agent-framework #974 as its
merge check ran it (connectome-host 3e715b4, base 53e72cac, merge 96504c57,
context-manager 0.25.1 laid over), the four H1b continuations, with
predictions written first:
- the from-0.20.0 prefix's store holds one notice, `{system: true, kind:
  'reasoning-loss'}`, stored after p.45's reply and before p.46: "[reasoning]
  fixture: The reasoning behind your replies up to the one beginning
  "[[c:p.44.r2]] …" is no longer in your context, because your system prompt
  changed. …". The v0.9.0 and v0.23.0 prefixes' stores hold none;
- from-0.20.0's record differs: the base arm's agent compiles and a
  compression request carry the notice, and the merge arm's carry none. The
  store product holds on both arms;
- on the base arm, 8 flags of check 11 (the notice sent anyway, by the
  previous commit's rule) and 8 of check 4 (the notice's quote of p.44.r2's
  canary, after p.45.r1's), as CHECKS.md now says; on the merge arm, none;
- from-0.9.0, from-0.23.0 and fresh: records same, and no flags.
Two such runs, before and after the previous commit's rule, wrote
byte-identical from-0.20.0 records on each arm.

Red: with this commit's tests on the harness before these two commits, the
two new tests here and the store read's fail, and every other test passes.
The harness unit tests passed 1002/1002, and the typecheck was clean, on a
tree that differed from this one in two code comments, a test title and the
docs.

CHECKS.md: 77 runs, the fourth upgrade run and its row, and the flags a
view of #974 itself shows on its base arm. The README: 77 runs. The harness
README: the run's store product.
nissa-seru pushed a commit to anima-research/context-view that referenced this pull request Nov 10, 2026
….20.0's install, measured on GitHub's runners

`--shard` balances a view's jobs by these seconds, and the run the previous
commit adds had none. Each is the base arm's in a view of
anima-research/agent-framework#974's merge, 96504c57, run on GitHub's
runners with the previous commit's harness; one sample each:
- H1b/continuation/from-0.20.0: 4.4 s (3.9 s in the head arm);
- H1b/prefix/from-0.20.0: 9.6 s;
- v0.20.0's install: 4.1 s.

The runners ran slow in this view: in the same base arm, from-0.9.0's and
from-0.23.0's continuations took 5.9 s and 6.3 s against their recorded
3.9 s and 3.6 s, their prefixes 14.7 s and 11.2 s against 6 s and 7.6 s, and
v0.9.0's and v0.23.0's installs 12 s and 5.5 s against 4.2 s and 3.5 s. So
these three likely overstate. The share that held all three took 81 s of
command time, against 115 s for the view's slowest share.

In that view H1b/continuation/from-0.20.0's record differed between the
arms, its base arm raising the 16 flags the previous commit names and its
merge arm none of them; every other run's record was the same but H5/W12's, whose
difference is one dry compile's place at step quick.held, and whose own
self-check differed too.

No record reads stack.json's seconds.
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.

3 participants