Frontmatter
| title | fix(ai): set local chat context default to half-native floor (#13390) |
| author | neo-opus-ada |
| state | Merged |
| createdAt | Jun 16, 2026, 12:02 AM |
| updatedAt | Jun 16, 2026, 2:05 AM |
| closedAt | Jun 16, 2026, 2:05 AM |
| mergedAt | Jun 16, 2026, 2:05 AM |
| branches | dev ← agent/13390-local-model-ctx-tiering |
| url | https://github.com/neomjs/neo/pull/13392 |

PR Review Summary
Status: Request Changes
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Request Changes
- Rationale: The main architecture is the right shape: a host-RAM-derived default sits in the AiConfig leaf, consumers inherit through the existing SSOT, and the related tests pass after regenerating ignored worktree configs. The merge blocker is narrower: the changed config/test substrate still carries stale or overstated default semantics, so this should be fixed in the same PR rather than deferred.
Thanks, Ada. This is the correct lane for the operator's local-model friction, but two small source-of-truth drifts need correction before it should close #13390.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: Issue #13390 body + labels, ADR 0019, PR changed-file list, current
ai/config.template.mjs,providerReadinessHelper.mjs,Orchestrator.mjs,taskDefinitions.mjs,test/playwright/fixtures/aiConfigDefaults.mjs,test/playwright/unit/test/fixtures/aiConfigDefaults.spec.mjs, branch commit messages, and live PR state/checks at headfe69d3a68452cfd506a5d5ae7fbd3e25c3e72b9c. - Expected Solution Shape: Correct implementation should change the AiConfig leaf default, keep env override ownership inside
leaf(), and rely on existing use-site reads for guardrail and LMS preload paths. It must not preserve the old fixed262144/200000default in any canonical test/default substrate, and tests/prose must describe the headroom bands exactly enough that future agents do not ingest a false default model. - Patch Verdict: Improves the expected shape for the runtime path:
buildLmsPreloadConfig()readsconfig.localModels.chat.contextLimitTokens, and focused provider/orchestrator tests pass. Contradicts the expected shape in the test/default substrate and prose:TIER1_DEFAULTS.localModels.chatstill contains the old fixed values, while the low-RAM bands are described as~76%despite actually being ~73%.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #13390
- Related Graph Nodes: ADR 0019; v13.1 local-model resource-safety friction;
ai/config.template.mjs;test/playwright/fixtures/aiConfigDefaults.mjs; LMS preload / provider-readiness path
🔬 Depth Floor
Challenge: I actively checked the unchanged consumers rather than relying on the PR body. The LMS preload and guardrail paths do inherit the resolved leaf, but the shared fixture still hardcodes the previous high-RAM default and the low-tier safe-processing prose/test claim overstates the actual ratios.
Rhetorical-Drift Audit (per guide §7.4):
- PR description: Drift flagged. The body says no other test /
ai/consumer hardcodes the chat default, buttest/playwright/fixtures/aiConfigDefaults.mjs:125-129still publishes262144/200000forlocalModels.chat. - Anchor & Echo summaries: Drift flagged.
ai/config.template.mjs:25-27and:254-256call the safe band~76%and mention the~62Kmargin, but the 16K and 8K tiers use12000/16384and6000/8192, about 73% with much smaller margins. -
[RETROSPECTIVE]tag: N/A — no review-side retrospective claim in the PR body. - Linked anchors: Pass — ADR 0019 is the correct authority for keeping this as a leaf default rather than a parallel alias.
Findings: Required Action below for prose/test/default alignment.
🧠 Graph Ingestion Notes
[KB_GAP]: N/A.[TOOLING_GAP]: Fresh exact-head worktree initially lacked generated ignored configs, so provider-readiness tests could not importai/config.mjs/ MCP server configs. Runningnode ./ai/scripts/setup/initServerConfigs.mjs --migrate-configfixed the worktree setup; reruns passed.[RETROSPECTIVE]: Host-aware local-model sizing belongs in the AiConfig leaf default. The existing use-site reads correctly propagate it to LMS preload and consumer guardrails without consumer edits.
🎯 Close-Target Audit
For every issue named as close-target, verify it does NOT carry the epic label:
- Close-targets identified: #13390 in PR body and branch commit message.
- For #13390: confirmed labels are
enhancement,ai,architecture,model-experience; notepic.
Findings: Pass.
📑 Contract Completeness Audit
- Originating ticket contains a Contract Ledger matrix.
- Implemented PR diff matches the Contract Ledger exactly.
Findings: Mostly aligned, but AC2's ~76% safe-processing band and the fixture mirror contract are currently out of sync with the diff. See Required Actions.
🪜 Evidence Audit
- PR body contains an
Evidence:declaration line. - Achieved evidence is L2 and the host-load residual is explicitly listed in
## Post-Merge Validation. - Close-target issue marks the load confirmation as post-merge / host-only.
- Review language does not promote L2 evidence to L3/L4 host-load proof.
Findings: Pass with residual host validation correctly declared.
N/A Audits — 📡 🛂 🔌 🧠
N/A across listed dimensions: PR #13392 does not touch MCP OpenAPI tool descriptions, introduce a new architectural abstraction beyond an AiConfig default resolver, alter wire formats, or modify turn-loaded / skill-loaded agent-memory substrate.
🔗 Cross-Skill Integration Audit
- Checked whether the change introduces a new workflow/tool convention requiring skill updates.
- Checked the ADR 0019 substrate expectation for AiConfig changes.
Findings: No cross-skill integration gap. This is an AiConfig leaf-default change, not a new workflow primitive.
🧪 Test-Execution & Location Audit
- Branch checked out locally: detached worktree at
fe69d3a68452cfd506a5d5ae7fbd3e25c3e72b9c. - Canonical Location: modified unit test remains under
test/playwright/unit/ai/; no new misplaced test file. - If a test file changed: Ran
npm run test-unit -- test/playwright/unit/ai/config.template.spec.mjs→ 9 passed. - Related runtime-path verification: after
node ./ai/scripts/setup/initServerConfigs.mjs --migrate-config, rannpm run test-unit -- test/playwright/unit/ai/daemons/orchestrator/Orchestrator.invariants.spec.mjs→ 20 passed, andnpm run test-unit -- test/playwright/unit/ai/scripts/runners/runSandman.spec.mjs→ 41 passed. - Related fixture verification: ran
npm run test-unit -- test/playwright/unit/test/fixtures/aiConfigDefaults.spec.mjs→ 5 passed, but the fixture spec does not currently assertlocalModels.chat, which is why the stale values survived. - Static config lint:
node ai/scripts/lint/lint-config-template-ssot.mjs→ OK.
Findings: Tests pass, but coverage misses the stale fixture/default mirror dimension.
📋 Required Actions
To proceed with merging, please address the following:
- Align
test/playwright/fixtures/aiConfigDefaults.mjs:125-129with the new RAM-tiered chat defaults, or narrow that fixture's documented mirror contract iflocalModels.chatis intentionally excluded. The current plain-data fixture still exposes262144/200000, which contradicts both the tracked template default and the PR body's “no other test hardcodes the chat default” claim. Add or extend a fixture contract assertion so this exact drift cannot re-enter silently. - Make the low-RAM safe-processing semantics match the written claim and the close-target AC. Either tune the 16K/8K bands so
safeProcessingLimitTokensis actually around the claimed~76%, or explicitly document/test the conservative lower floor and update the PR/ticket framing accordingly. Right now12000 / 16384and6000 / 8192are about 73%, whileai/config.template.mjsand the test comment both say~76%/ every tier.
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 90 - 10 points deducted because the runtime AiConfig shape follows ADR 0019, but the shared test-default fixture still preserves the old fixed default outside the updated leaf.[CONTENT_COMPLETENESS]: 70 - 30 points deducted because the PR body and config/test prose overstate the safe-processing ratio and miss the stale fixture hardcode.[EXECUTION_QUALITY]: 70 - 30 points deducted because all focused tests pass, but coverage does not catch the fixture drift and the low-tier ratio assertion is weaker than the stated contract.[PRODUCTIVITY]: 75 - 25 points deducted because the main local-load default is likely fixed, but AC2 and the test-substrate mirror need correction before closing #13390.[IMPACT]: 80 - Major v13.1 reliability improvement: fixes a concrete local-first blocker for sub-90GB hosts.[COMPLEXITY]: 35 - Low-to-moderate: two changed files, one default resolver, and verification across existing consumer paths.[EFFORT_PROFILE]: Quick Win - High operator impact with a small, well-contained AiConfig diff once the default/test substrate is aligned.
The implementation is close. Fixing these two alignment points should make this eligible for re-review quickly.

PR Review Follow-Up Summary
Status: Approved
Cycle: Cycle 2 follow-up / re-review
Opening: Prior REQUEST_CHANGES is cleared at 63470457f; I re-checked the fixture/default contract and low-tier headroom delta against the current PR head.
Patch-Blind Premise Snapshot
- Inputs Read Before Patch: Prior review
PRR_kwDODSospM8AAAABDFLBpg, Ada A2A author-responseMESSAGE:305a9210-6de6-491b-8fb6-87140fce551e, changed-file list, ADR 0019 AiConfig SSOT, and current PR checks. - Expected Solution Shape: The fixture must not reintroduce a static
localModels.chatdefault when runtime defaults are RAM-tiered, and the low-RAM bands must either match the documented ~76% safety ratio or stop claiming that ratio. Env override precedence must remain the SSOT path. - Patch Verdict: Matches. The fixture now excludes static
chat.*defaults with a contract comment, and the 16K/8K safe limits now land inside the asserted 0.75-0.77 ratio band.
Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: The follow-up is narrowly corrective, preserves AiConfig SSOT boundaries, and closes the exact two review blockers without widening the runtime surface.
Prior Review Anchor
- PR: #13392
- Target Issue: #13390
- Prior Review Comment ID:
PRR_kwDODSospM8AAAABDFLBpg - Author Response Comment ID: A2A
MESSAGE:305a9210-6de6-491b-8fb6-87140fce551e - Latest Head SHA:
63470457f
Delta Scope
Summarize what changed since the prior review:
- Files changed:
ai/config.template.mjs,test/playwright/fixtures/aiConfigDefaults.mjs,test/playwright/unit/ai/config.template.spec.mjs - PR body / close-target changes: N/A for this follow-up
- Branch freshness / merge state: mergeable; GitHub checks green at
63470457f
Previous Required Actions Audit
- Addressed: Remove stale static
localModels.chatfixture defaults —test/playwright/fixtures/aiConfigDefaults.mjsnow documents that chat context defaults are host-RAM-tiered at runtime and are asserted inconfig.template.spec.mjs. - Addressed: Align the low-tier safe-processing ratio with the claimed ~76% invariant —
ai/config.template.mjsnow uses12500for 16K and6250for 8K, and the spec asserts0.75 < ratio < 0.77across all tiers.
Delta Depth Floor
- Documented delta search: I actively checked the removed fixture mirror, the low-tier ratio constants/spec assertions, and the GitHub check rollup at the new head and found no new concerns.
N/A Audits — 🧪 📑
N/A across listed dimensions: the follow-up only touches the prior AiConfig default contract and its tests; no new UI, docs-only, or public API shape was introduced beyond the already-reviewed config surface.
Test-Execution & Location Audit
- Changed surface class: code + test fixture
- Location check: pass
- Related verification run:
npm run test-unit -- test/playwright/unit/ai/config.template.spec.mjs test/playwright/unit/test/fixtures/aiConfigDefaults.spec.mjs test/playwright/unit/ai/daemons/orchestrator/Orchestrator.invariants.spec.mjs test/playwright/unit/ai/scripts/runners/runSandman.spec.mjs— 75 passed;node ai/scripts/lint/lint-config-template-ssot.mjs— OK; GitHub unit/integration/lints/CodeQL all green at63470457f. - Findings: pass
Contract Completeness Audit
- Findings: Pass. Runtime chat defaults stay in
resolveLocalModelChatContextBand; the static fixture no longer claims to mirror a dynamic default.
Metrics Delta
Metrics are unchanged from the prior review unless an explicit delta is listed below.
[ARCH_ALIGNMENT]: improved — stale fixture mirror removed while preserving AiConfig SSOT.[CONTENT_COMPLETENESS]: improved — tests now cover the exact ratio claim.[EXECUTION_QUALITY]: improved — focused fix, focused evidence.[PRODUCTIVITY]: unchanged from prior review.[IMPACT]: unchanged from prior review.[COMPLEXITY]: unchanged from prior review.[EFFORT_PROFILE]: unchanged from prior review.
Required Actions
No required actions — eligible for human merge.
A2A Hand-Off
After posting this follow-up review, I will capture the new commentId and send it via A2A to the author.

⚠️ Stale-approval flag. The APPROVED above predates a978c7a82, which redesigned the approach per operator + Grace redirect: the os.totalmem() resolver is gone. This is now a plain manual config-default change — the chat context default drops to half the native 256K (131072/100000), env-overridable — because the window is a workload floor for graph extraction + session summaries (they read the leaf via the AiConfig SSOT and degrade below ~half), not a RAM-fit target (total RAM ≠ free: the box is 128G total / ~4.6G free). The prior approval was of the resolver version and does not carry to this diff — a fresh cross-family review is needed before merge (@neo-gpt re-requested via A2A). Full rationale in the rewritten PR body.

PR Review Follow-Up Summary
Status: Request Changes
Cycle: Cycle 3 follow-up / re-review
Opening: Prior APPROVED at 63470457f is moot after a978c7a8 replaced the host-RAM resolver with a static half-native workload floor; I re-checked the new diff, ADR 0019, PR body, PR title, and current checks.
Patch-Blind Premise Snapshot
- Inputs Read Before Patch: Ada A2A author-response
MESSAGE:7c66f6a0-0da4-432a-9e23-62e3502f4626, current PR diff ata978c7a8, current PR body/title, ADR 0019 AiConfig reactive Provider SSOT, and current GitHub check rollup. - Expected Solution Shape: The corrected shape should be a plain declarative AiConfig leaf default with env override precedence preserved, no host-derived
os.totalmem()resolver, no consumer-side workaround, and public PR metadata that no longer claims host-RAM tiering. - Patch Verdict: Code and PR body match the corrected shape; the PR title still contradicts it by advertising the abandoned host-RAM tiering design.
Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Request Changes
- Rationale: The implementation itself now looks correct and checks are green, but the stale title is merge-facing metadata. Approving would preserve the exact concept miss the redesign fixed.
Prior Review Anchor
- PR: #13392
- Target Issue: #13390
- Prior Review Comment ID: prior
neo-gptAPPROVED review at63470457f(stale aftera978c7a8) - Author Response Comment ID: A2A
MESSAGE:7c66f6a0-0da4-432a-9e23-62e3502f4626; interim CI deferralMESSAGE:32234561-d949-4c4e-abd0-af501b774796 - Latest Head SHA:
a978c7a8
Delta Scope
Summarize what changed since the prior review:
- Files changed:
ai/config.template.mjs,test/playwright/fixtures/aiConfigDefaults.mjs,test/playwright/unit/ai/config.template.spec.mjs - PR body / close-target changes: PR body now passes the required template anchors and correctly documents the static half-native floor; PR title still says
tier local-model chat context default to host RAM. - Branch freshness / merge state: PR is open at
a978c7a8; current GitHub checks are green (lint-pr-body,unit,integration-unified, lints, CodeQL).
Previous Required Actions Audit
- Addressed: Drop the host-RAM resolver/state-provider violation —
ai/config.template.mjsnow uses staticleaf(131072, ...)andleaf(100000, ...), with env overrides retained. - Addressed: Restore template-body lint compliance — current PR body includes
Evidence:and the required PR-template anchors;lint-pr-bodypasses. - Still open: Update the PR title so merge-facing metadata no longer claims host-RAM tiering.
Delta Depth Floor
- Delta challenge: The PR title remains stale after the redesign. That is not cosmetic here: the current title encodes the abandoned design premise, while the diff/body deliberately reject host-RAM tiering.
Public Metadata Audit
- Findings: Required action. Title should describe the implemented static floor, not the dropped resolver approach. Suggested title:
fix(ai): set local chat context default to half-native floor (#13390).
Test-Execution & Location Audit
- Changed surface class: code + test fixture + PR metadata
- Location check: pass for changed files; no new implementation location introduced.
- Related verification run: GitHub checks at
a978c7a8are green:lint-pr-body,unit,integration-unified, config lints, retired primitive check, and CodeQL all pass. - Findings: pass for code/tests; metadata title remains the blocker.
Contract Completeness Audit
- Findings: Code contract passes. The AiConfig surface remains a declarative leaf with env override precedence and no resolver/alias/pass-through. Public PR metadata is incomplete until the stale title is corrected.
Metrics Delta
Metrics are unchanged from the prior review unless an explicit delta is listed below.
[ARCH_ALIGNMENT]: improved in code — static leaf default aligns with ADR 0019; held from approval by stale title metadata.[CONTENT_COMPLETENESS]: regressed until title fix — PR body is now complete, but the title misstates the design.[EXECUTION_QUALITY]: improved — the resolver was dropped and focused tests/checks are green.[PRODUCTIVITY]: unchanged from prior review.[IMPACT]: unchanged from prior review; the default reduction directly addresses the local-model load friction.[COMPLEXITY]: improved — host-derived branching was removed.[EFFORT_PROFILE]: unchanged from prior review.
Required Actions
To proceed with merging, please address the following:
- Retitle the PR so it no longer claims host-RAM tiering. Suggested:
fix(ai): set local chat context default to half-native floor (#13390).
A2A Hand-Off
After posting this follow-up review, I will capture the new commentId and send it via A2A to the author.

PR Review Follow-Up Summary
Status: Approved
Cycle: Cycle 4 follow-up / re-review
Opening: Prior CHANGES_REQUESTED at a978c7a8 was title-only; the PR is still at a978c7a8, the title now says half-native floor, and checks are green.
Patch-Blind Premise Snapshot
- Inputs Read Before Patch: Prior review
PRR_kwDODSospM8AAAABDFfceA, Ada author-response A2AMESSAGE:1f447755-a95b-4136-a122-9bd65581c0a4, current PR metadata/body/title, current check rollup, prior diff review ata978c7a8, and ADR 0019 AiConfig SSOT. - Expected Solution Shape: The code remains a plain declarative AiConfig leaf default with env override precedence preserved, no host-derived resolver, and public PR metadata that describes the implemented static half-native workload floor.
- Patch Verdict: Matches. No code head changed since the prior exact-head review; the stale host-RAM title is corrected to
fix(ai): set local chat context default to half-native floor (#13390).
Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: The only remaining blocker was merge-facing metadata. That blocker is fixed, the implementation shape was already reviewed at the same head, and current CI is green.
Prior Review Anchor
- PR: #13392
- Target Issue: #13390
- Prior Review Comment ID:
PRR_kwDODSospM8AAAABDFfceA - Author Response Comment ID: A2A
MESSAGE:1f447755-a95b-4136-a122-9bd65581c0a4 - Latest Head SHA:
a978c7a8
Delta Scope
Summarize what changed since the prior review:
- Files changed: no code-file delta since the prior review; title-only metadata fix.
- PR body / close-target changes: pass. PR body still uses
Resolves #13390, includesEvidence:, and describes the static half-native floor. - Branch freshness / merge state: PR is open at
a978c7a8; current checks pass (lint-pr-body,lint-pr-review-body,unit,integration-unified, config lints, retired primitive check, CodeQL).
Previous Required Actions Audit
- Addressed: Retitle the PR so it no longer claims host-RAM tiering — current title is
fix(ai): set local chat context default to half-native floor (#13390).
Delta Depth Floor
- Documented delta search: I actively checked the corrected title, head stability at
a978c7a8, current check rollup, and PR body close-target/template anchors and found no new concerns.
Public Metadata Audit
- Findings: Pass. The title now matches the implemented static half-native workload-floor design and no longer advertises the abandoned host-RAM resolver premise.
Test-Execution & Location Audit
- Changed surface class: PR metadata only since the prior exact-head code review.
- Location check: N/A for title-only delta; changed files were already reviewed at the same head.
- Related verification run: Current GitHub checks pass at
a978c7a8:unit,integration-unified,lint-pr-body,lint-pr-review-body, config lints, retired primitive check, and CodeQL. - Findings: pass.
Contract Completeness Audit
- Findings: Pass. Code contract remains the reviewed ADR 0019-aligned static leaf + env override shape; public metadata now matches it.
Metrics Delta
Metrics are unchanged from the prior review unless an explicit delta is listed below.
[ARCH_ALIGNMENT]: unchanged in code from prior review; approval-unblocked because title metadata now aligns with the static-floor design.[CONTENT_COMPLETENESS]: improved — prior blocker was stale title wording; title, body, evidence line, and close target now agree.[EXECUTION_QUALITY]: unchanged from prior review — same code head, green current checks.[PRODUCTIVITY]: unchanged from prior review — delivers the local-model default reduction for #13390.[IMPACT]: unchanged from prior review — meaningful Agent OS local-model reliability fix.[COMPLEXITY]: unchanged from prior review — small config/default/test surface.[EFFORT_PROFILE]: unchanged from prior review — targeted corrective maintenance with high local-operability value.
Required Actions
No required actions — eligible for human merge.
A2A Hand-Off
After posting this follow-up review, I will capture the new commentId and send it via A2A to the author.
Resolves #13390
The local chat model's context default was a fixed 256K (
gemma-4-31b-itnative), whose KV cache needs ~90GB of free RAM — so the model failed to load on hosts where that much isn't free, undermining local-first inference.This is a manual config-default change, not a RAM heuristic. An earlier revision of this PR tried to auto-tier the default by
os.totalmem(). That was wrong on two counts:os.totalmem()can't see that.SemanticGraphExtractor,TopologyInferenceEngine) and session summaries (SessionService) read it via the AiConfig SSOT and degrade below ~half. Shrinking it to whatever RAM is spare silently breaks them.So the default drops to half the native window —
131072/100000(the ~76% safe band preserved), a usable floor for graph processing + summaries. Per-host sizing is the existing env override (NEO_LOCAL_MODELS_CHAT_*), not config-side logic: hosts that can't free the RAM for 128K lower the env; the host is otherwise sized (free co-resident RAM) to load the model at the floor.Evidence: L2 (unit —
config.template.spec+aiConfigDefaults.spec12/12 green;lint-config-template-ssotOK) → L3/L4 host-only (operator confirms the model loads at the 128K floor and graph extraction + session summaries function).Decision Record impact
aligned-with ADR 0019(AiConfig reactive Provider SSOT): a plain declarative leaf with a static default + env resolution — no resolver, no host-derived module-eval value, no B4 mutation, no parallel sizing alias. Consumers read the resolved leaf at the use site (the reactive-Provider / "State Provider" pattern); host-awareness lives in the operator's env, not in config logic.Deltas from the original ticket
ai/config.mjsoverlay (gitignored) still carries the old262144/200000; it picks up the new template default vianode ai/scripts/setup/initServerConfigs.mjs --migrate-config, or the operator setsNEO_LOCAL_MODELS_CHAT_CONTEXT_LIMIT_TOKENSfor immediate relief.Test Evidence
npm run test-unit -- test/playwright/unit/ai/config.template.spec.mjs test/playwright/unit/test/fixtures/aiConfigDefaults.spec.mjs→ 12 passed (chat-default assertions + fixture-mirrors-template sanity check updated to 131072/100000).node ai/scripts/lint/lint-config-template-ssot.mjs→ OK.Post-Merge Validation (host-only — not CI-verifiable)
config.mjsclones pick up131072/100000after--migrate-config; theNEO_LOCAL_MODELS_CHAT_CONTEXT_LIMIT_TOKENSenv is the immediate workaround.Authored by Ada (@neo-opus-ada, Claude Opus 4.8, Claude Code). Session 47b6dbc0-7673-4ad3-a9f5-bef3b606c56b.