Substantive-Rationale Exception — Ungraduated-Discussion Cross-Check
Per ticket-create-workflow §1c: this ticket cites Discussion #12062 which has NOT yet graduated. The substantive-rationale 3-part exception applies:
- Substantive-rationale declaration: @neo-gpt's
[GRADUATION_DEFERRED] STEP_BACK comment on #12062 (discussion-comment 17069393) explicitly identified OQ11 cap-raise as a standalone hot-fix that should be split out of the SSOT Epic graduation path. Operator (@tobiu) corroborated the 256K cap value (gemma-4-31b native context).
- Inline divergence-matrix substance: see §"Avoided Traps / Divergence Matrix" below — 3 alternatives enumerated (status-quo cap / proposed raise / chunking-only) with falsifying sources per option.
- Downstream amendment acknowledgment: this ticket is narrow config-only scope; sections that may need refresh post-Discussion #12062 graduation are flagged inline ("Out of Scope / Future-Refresh" section below).
Context
ai/config.template.mjs:125 + ai/config.mjs:125 set openAiCompatible.contextLimitTokens = 32768 with safeProcessingLimitTokens: undefined (defaults to Math.floor(32768 × 0.75) = 24,576 via DEFAULT_SAFE_FRACTION = 0.75 in ai/services/memory-core/helpers/ConsumerFrictionHelper.mjs:110). The default was sized for an earlier model-context era. gemma-4-31b-it (operator's current model per ai/config.mjs:120 model: 'gemma-4-31b-it') supports 256K (262,144) tokens natively. The cap is 8× smaller than the model's actual capacity.
Operator-surfaced empirical signal: "when the local gemma4 processing worked, my machine fans glew for 10 minutes. and this did not happen for a week or more." The disappearance maps to a combination of failure surfaces (full V-B-A in Discussion #12062 §2.4); this ticket addresses ONE of those surfaces — the invokeWithGuardrail size-cap pre-check in ai/services/graph/SemanticGraphExtractor.mjs:133-147.
The Problem
When invokeWithGuardrail runs estimatedTokens > safeProcessingLimitTokens check (24,576 tokens current), it aborts the LLM call BEFORE provider dispatch and returns null payload. SemanticGraphExtractor returns null, DreamService sees success = null, does NOT mark graphDigested: true, session is re-fetched next REM cycle → infinite silent-failure loop. No fans-glow because no LLM call ever happens for over-cap sessions.
Live distribution of recent session-payload sizes (sandman log, 2026-05-27):
| Session |
Chars |
Est. Tokens (~÷4) |
Vs current safe (24,576) |
Vs current cap (32,768) |
fcd8fe25 |
280,364 |
~70,091 |
2.85× over |
2.14× over |
c9173ca5 |
308,051 |
~77,012 |
3.13× over |
2.35× over |
14821142 |
116,908 |
~29,227 |
1.19× over |
under |
10857550 |
18,472 |
~4,618 |
under |
under |
8fbfd919 |
123,574 |
~30,893 |
1.26× over |
under |
0a203336 |
54,214 |
~13,553 |
under |
under |
2c4aa4df |
20,924 |
~5,231 |
under |
under |
4cd1588c |
43,426 |
~10,856 |
under |
under |
da7e69d0 |
486,542 |
~121,635 |
★ 4.95× over |
★ 3.71× over |
388c4d72 |
130,106 |
~32,526 |
1.32× over |
at cap |
Tally vs current cap: 5/10 over safe-band (guardrail abort); 4/10 over hard cap.
The Architectural Reality
ai/config.template.mjs:118-127 — canonical openAiCompatible config block; defines contextLimitTokens + safeProcessingLimitTokens
ai/config.mjs:107-116 — operator-overlay (currently in-sync with template per overlay-sync executed earlier this session)
ai/config.template.mjs:521-523 + ai/config.mjs:478-480 — env-var bindings NEO_OPENAI_COMPATIBLE_CONTEXT_LIMIT_TOKENS + NEO_OPENAI_COMPATIBLE_SAFE_PROCESSING_LIMIT_TOKENS (operator-override path preserved)
ai/services/memory-core/helpers/ConsumerFrictionHelper.mjs:110 — DEFAULT_SAFE_FRACTION = 0.75 (75% safe-band default)
ai/services/memory-core/helpers/ConsumerFrictionHelper.mjs:329-377 — invokeWithGuardrail consumer; emits friction record + null result on size-cap exceed
ai/services/graph/SemanticGraphExtractor.mjs:120-150 — consumer of the guardrail; computes consumerContextTokens + consumerSafeTokens from the openAiCompatible config block
ai/services/graph/SemanticGraphExtractor.mjs:183-187 — if (!payload) return null on guardrail abort
gemma-4-31b-it published context: 256K tokens (262,144) (operator-confirmed; also applies to gemma-4-26B MoE per operator statement). Industry-standard 4 chars/token English avg → 262K tokens ≈ 1,048,576 chars; safe-band at 76% (200,000 tokens) ≈ 800,000 chars headroom.
The Fix
4-line config change in BOTH ai/config.template.mjs AND ai/config.mjs (now in-sync):
openAiCompatible: {
host : 'http://127.0.0.1:11434',
model : 'gemma-4-31b-it',
embeddingModel : 'text-embedding-qwen3-embedding-8b',
apiKey : '',
unloadRetryCount : 3,
unloadRetryDelayMs : 500,
- contextLimitTokens : 32768,
+ contextLimitTokens : 262144, // gemma-4-31b native 256K context
- safeProcessingLimitTokens: undefined // = 0.75 × 32768 = 24,576 (current default)
+ safeProcessingLimitTokens: 200000 // explicit; ~76% of cap; ~62K tokens headroom for system-prompt + response
}Files touched:
ai/config.template.mjs (canonical default — committed)
ai/config.mjs (operator overlay — gitignored; commit MUST include this to satisfy MUST be in sync invariant per operator directive 2026-05-27 ~00:14Z)
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
aiConfig.openAiCompatible.contextLimitTokens |
ai/config.template.mjs:125 (canonical default); NEO_OPENAI_COMPATIBLE_CONTEXT_LIMIT_TOKENS (env override) |
Raised 32768 → 262144 |
env override unchanged; operators can re-pin to 32768 explicitly if needed |
inline comment cites "gemma-4-31b native 256K context" |
gemma-4-31b/-26B MoE published 256K context per operator V-B-A; SemanticGraphExtractor.mjs:126 reads this value at every Tri-Vector invocation |
aiConfig.openAiCompatible.safeProcessingLimitTokens |
ai/config.template.mjs:126 (canonical default; was undefined); NEO_OPENAI_COMPATIBLE_SAFE_PROCESSING_LIMIT_TOKENS (env override) |
Set explicitly to 200000 (was undefined → defaulted to Math.floor(262144 × 0.75) = 196,608 post-cap-raise) |
env override unchanged |
inline comment cites "~76% of cap; ~62K tokens headroom" |
ConsumerFrictionHelper.mjs:110 DEFAULT_SAFE_FRACTION = 0.75; explicit value avoids implicit-math drift if future cap-raise lands |
ConsumerFrictionHelper.invokeWithGuardrail size-cap pre-check behavior |
ai/services/memory-core/helpers/ConsumerFrictionHelper.mjs:329-377 (unchanged in this PR) |
Existing pre-check semantics preserved; new cap shifts what counts as "over-safe-band" |
no fallback needed — same code path, larger band |
unchanged |
Sandman-log payload distribution (10 sessions tallied above) shows 0/10 over new safe-band vs 5/10 today |
Decision Record impact
aligned-with ADR 0014 (cloud-deployment-topology) — uses the same configurable model substrate ADR 0014 established; no conflict
none with any other ADRs
Acceptance Criteria
Out of Scope / Future-Refresh
- OUT OF SCOPE — this ticket: structural chunking (OQ12 hierarchical-summarization in Discussion #12062 — Sub 7 of the SSOT Epic when it graduates); orchestrator-as-SSOT shape (Discussion #12062 graduation); silent-failure root-cause investigation across all 13 hypotheses (Sub 1 of the SSOT Epic); 5-axis observability primitive (Sub 2 of the SSOT Epic).
- REFRESH POST-DISCUSSION-#12062-GRADUATION: if the SSOT Epic graduates with a different config-substrate placement (e.g., per-consumer cap overrides instead of openAiCompatible-block defaults), this ticket's AC1/AC2 may need re-pointing. The cap value (262144) is operator-anchored and survives any substrate-placement reshape.
Avoided Traps / Divergence Matrix
| Option |
When this would be right |
Falsifier |
Rejection rationale |
| A. Status-quo cap (32768) |
If gemma-4 actually had a 32K context window OR if oversized sessions were rare |
Falsifier: operator V-B-A confirms gemma-4-31b native context = 256K; sandman-log shows 5/10 sessions over current safe-band |
Empirically falsified |
| B. Raise cap to 262144 + explicit safeProcessing=200000 (RECOMMENDED) |
When the cap is provably 4-8× too small AND chunking is out-of-scope for this ticket |
Empirical: 0/10 recent sessions exceed new safe-band; heaviest at 61% of safe-band; matches gemma-4 native context |
Adopted |
| C. Chunking-only fix (skip cap raise, implement hierarchical summarization) |
If the structural fix to unbounded session size could land in the same hot-fix window AND if all current sessions could wait |
Falsifier: chunking is OQ12 in Discussion #12062 — multi-file substrate work, NOT a config-only hot-fix; estimated several days of design+implementation |
Wrong scope for hot-fix path; chunking complements but doesn't replace cap-raise |
Related
- Discussion #12062 — Orchestrator-as-SSOT for the REM (Sandman) Pipeline (parent ideation; OQ11 split this out per @neo-gpt STEP_BACK)
- #12059 — Fix Sandman graph provider routing (companion regression; @neo-gpt-owned; PR #12061)
- PR #11966 — original introduction of
buildGraphProvider dispatch (the regression-introducing PR per Discussion #12062 §2.4 hypothesis #8)
- ADR 0014 cloud-deployment-topology (aligned-with)
Handoff Retrieval Hints
query_raw_memories(query='contextLimitTokens safeProcessingLimitTokens gemma-4 256K context window cap')
query_summaries(query='Sandman size-cap silent-failure invokeWithGuardrail')
- File anchors:
ai/config.template.mjs:118-127 + ai/config.mjs:107-116 (config block); ai/services/memory-core/helpers/ConsumerFrictionHelper.mjs:110 (DEFAULT_SAFE_FRACTION); ai/services/graph/SemanticGraphExtractor.mjs:120-150 (consumer)
- Discussion #12062 §2.4.1 (the smoking-gun analysis section)
🤖 Generated with Claude Code
Substantive-Rationale Exception — Ungraduated-Discussion Cross-Check
Per
ticket-create-workflow §1c: this ticket cites Discussion #12062 which has NOT yet graduated. The substantive-rationale 3-part exception applies:[GRADUATION_DEFERRED]STEP_BACK comment on #12062 (discussion-comment 17069393) explicitly identified OQ11 cap-raise as a standalone hot-fix that should be split out of the SSOT Epic graduation path. Operator (@tobiu) corroborated the 256K cap value (gemma-4-31b native context).Context
ai/config.template.mjs:125+ai/config.mjs:125setopenAiCompatible.contextLimitTokens = 32768withsafeProcessingLimitTokens: undefined(defaults toMath.floor(32768 × 0.75) = 24,576viaDEFAULT_SAFE_FRACTION = 0.75inai/services/memory-core/helpers/ConsumerFrictionHelper.mjs:110). The default was sized for an earlier model-context era. gemma-4-31b-it (operator's current model perai/config.mjs:120 model: 'gemma-4-31b-it') supports 256K (262,144) tokens natively. The cap is 8× smaller than the model's actual capacity.Operator-surfaced empirical signal: "when the local gemma4 processing worked, my machine fans glew for 10 minutes. and this did not happen for a week or more." The disappearance maps to a combination of failure surfaces (full V-B-A in Discussion #12062 §2.4); this ticket addresses ONE of those surfaces — the
invokeWithGuardrailsize-cap pre-check inai/services/graph/SemanticGraphExtractor.mjs:133-147.The Problem
When
invokeWithGuardrailrunsestimatedTokens > safeProcessingLimitTokenscheck (24,576 tokens current), it aborts the LLM call BEFORE provider dispatch and returnsnullpayload. SemanticGraphExtractor returnsnull, DreamService seessuccess = null, does NOT markgraphDigested: true, session is re-fetched next REM cycle → infinite silent-failure loop. No fans-glow because no LLM call ever happens for over-cap sessions.Live distribution of recent session-payload sizes (sandman log, 2026-05-27):
fcd8fe25c9173ca514821142108575508fbfd9190a2033362c4aa4df4cd1588cda7e69d0388c4d72Tally vs current cap: 5/10 over safe-band (guardrail abort); 4/10 over hard cap.
The Architectural Reality
ai/config.template.mjs:118-127— canonicalopenAiCompatibleconfig block; definescontextLimitTokens+safeProcessingLimitTokensai/config.mjs:107-116— operator-overlay (currently in-sync with template per overlay-sync executed earlier this session)ai/config.template.mjs:521-523+ai/config.mjs:478-480— env-var bindingsNEO_OPENAI_COMPATIBLE_CONTEXT_LIMIT_TOKENS+NEO_OPENAI_COMPATIBLE_SAFE_PROCESSING_LIMIT_TOKENS(operator-override path preserved)ai/services/memory-core/helpers/ConsumerFrictionHelper.mjs:110—DEFAULT_SAFE_FRACTION = 0.75(75% safe-band default)ai/services/memory-core/helpers/ConsumerFrictionHelper.mjs:329-377—invokeWithGuardrailconsumer; emits friction record + null result on size-cap exceedai/services/graph/SemanticGraphExtractor.mjs:120-150— consumer of the guardrail; computesconsumerContextTokens+consumerSafeTokensfrom the openAiCompatible config blockai/services/graph/SemanticGraphExtractor.mjs:183-187—if (!payload) return nullon guardrail abortgemma-4-31b-it published context: 256K tokens (262,144) (operator-confirmed; also applies to gemma-4-26B MoE per operator statement). Industry-standard 4 chars/token English avg → 262K tokens ≈ 1,048,576 chars; safe-band at 76% (200,000 tokens) ≈ 800,000 chars headroom.
The Fix
4-line config change in BOTH
ai/config.template.mjsANDai/config.mjs(now in-sync):openAiCompatible: { host : 'http://127.0.0.1:11434', model : 'gemma-4-31b-it', embeddingModel : 'text-embedding-qwen3-embedding-8b', apiKey : '', unloadRetryCount : 3, unloadRetryDelayMs : 500, - contextLimitTokens : 32768, + contextLimitTokens : 262144, // gemma-4-31b native 256K context - safeProcessingLimitTokens: undefined // = 0.75 × 32768 = 24,576 (current default) + safeProcessingLimitTokens: 200000 // explicit; ~76% of cap; ~62K tokens headroom for system-prompt + response }Files touched:
ai/config.template.mjs(canonical default — committed)ai/config.mjs(operator overlay — gitignored; commit MUST include this to satisfyMUST be in syncinvariant per operator directive 2026-05-27 ~00:14Z)Contract Ledger Matrix
aiConfig.openAiCompatible.contextLimitTokensai/config.template.mjs:125(canonical default);NEO_OPENAI_COMPATIBLE_CONTEXT_LIMIT_TOKENS(env override)aiConfig.openAiCompatible.safeProcessingLimitTokensai/config.template.mjs:126(canonical default; wasundefined);NEO_OPENAI_COMPATIBLE_SAFE_PROCESSING_LIMIT_TOKENS(env override)undefined→ defaulted toMath.floor(262144 × 0.75) = 196,608post-cap-raise)ConsumerFrictionHelper.invokeWithGuardrailsize-cap pre-check behaviorai/services/memory-core/helpers/ConsumerFrictionHelper.mjs:329-377(unchanged in this PR)Decision Record impact
aligned-withADR 0014 (cloud-deployment-topology) — uses the same configurable model substrate ADR 0014 established; no conflictnonewith any other ADRsAcceptance Criteria
ai/config.template.mjsupdated —contextLimitTokens: 262144+safeProcessingLimitTokens: 200000with inline comment citing gemma-4 native contextai/config.mjs(operator overlay) updated to match —MUST be in syncinvariant preserved per operator 2026-05-27 ~00:14Z directiveaiConfig.openAiCompatible.contextLimitTokens === 262144post-overlay-merge (Node REPL vianode --checkis insufficient; need runtime import check)ai:run-sandmaninvocation produces fans-glow signal on at least ONE undigested session (depends on companion #12059 routing fix landed first; AC4 deferred until #12061 merges)Out of Scope / Future-Refresh
Avoided Traps / Divergence Matrix
Related
buildGraphProviderdispatch (the regression-introducing PR per Discussion #12062 §2.4 hypothesis #8)Handoff Retrieval Hints
query_raw_memories(query='contextLimitTokens safeProcessingLimitTokens gemma-4 256K context window cap')query_summaries(query='Sandman size-cap silent-failure invokeWithGuardrail')ai/config.template.mjs:118-127+ai/config.mjs:107-116(config block);ai/services/memory-core/helpers/ConsumerFrictionHelper.mjs:110(DEFAULT_SAFE_FRACTION);ai/services/graph/SemanticGraphExtractor.mjs:120-150(consumer)🤖 Generated with Claude Code