What happened?
Compartments are being flagged as legacy despite the current Historian V2 producing <p1>/<p2>/<p3>/<p4> tier tags in the output. The "Historian V2 is released — upgrade your compartments" message appears for sessions where the historian ran successfully with legacy=0 on the run itself.
Root cause: The tier extraction parser (extractTier / TIER_REGEXES) fails silently when the historian model produces malformed closing tags. The model closes <p1> with </p2> instead of </p1>, so the regex /<p1\s*>(.*?)<\/p1>/s doesn't match. When p1 extraction fails, the compartment falls through to the legacy code path and is marked legacy=1.
Evidence:
1. DB stats (1,042 compartments total):
- 73 compartments with
legacy=1 (all have p1=NULL)
- 969 compartments with
legacy=0 (all have p1 populated)
- Zero non-legacy compartments have NULL p1
2. All 73 legacy compartments contain tier tags in content but NOT in the p1 column:
| Check |
Legacy (73) |
Non-legacy (969) |
<p1> opening tag in content |
✅ YES |
N/A (tags extracted, content is clean text) |
</p1> closing tag in content |
❌ NO |
N/A |
</p2> closing tag in content |
✅ YES |
N/A |
p1 column |
NULL |
Populated |
3. The model output looks like this:
<compartment start="1" end="50" title="...">
<p1>
...content...
</p2> ← wrong closing tag — should be </p1>
<p2>
...content...
</p2>
<p3>...</p3>
<p4>...</p4>
</compartment>
4. historian_runs.legacy = 0 for ALL runs that produced legacy compartments:
This is the disconnect — the run is NOT marked legacy, but the compartments it produced ARE. The legacy flag on compartments is derived from whether p1 was extracted, not from the run itself.
Code reference:
extractTier and TIER_REGEXES (in compartment-parser.ts / dist index.js):
function makeTierRegex(n) {
return new RegExp(`<p${n}\\s*/>|<p${n}\\s*>(.*?)</p${n}>`, "s");
}
function extractTier(inner, index) {
const m = inner.match(TIER_REGEXES[index]);
if (!m) return; // undefined — regex didn't match
return unescapeXml2((m[1] ?? "").trim());
}
The regex /<p1\s*>(.*?)<\/p1>/s requires an exact </p1> closing tag. When the model produces </p2> as the closing tag for <p1>, the regex doesn't match → extractTier returns undefined → p1 is not set.
insertCompartmentRows (in compartment-storage.ts):
function insertCompartmentRows(db, sessionId, compartments, now) {
for (const compartment of compartments) {
const hasTiers = typeof compartment.p1 === "string" && compartment.p1.length > 0;
stmt.run(..., hasTiers ? 0 : 1, ...); // legacy = hasTiers ? 0 : 1
}
}
When p1 is undefined (extraction failed), hasTiers is false → legacy = 1.
The chain:
Model outputs <p1>...</p2> (mismatched closing tag)
→ extractTier regex /<p1>(.*?)<\/p1>/s doesn't match
→ p1 = undefined
→ parseCompartmentOutput falls through to fallback (no p1/p2/p3/p4 fields)
→ insertCompartmentRows: hasTiers = false
→ legacy = 1
→ Dashboard shows "legacy" tag
→ "Historian V2 upgrade" message appears (false positive)
Model context:
Historian model: opencode/deepseek-v4-flash-free. The model consistently produces <p1>...</p2> instead of <p1>...</p1>. This has been observed across 73 compartments spanning from April 28 to July 23, 2026 — including compartments created today.
Possible fixes:
- Parser-side: Make the tier regex more lenient — e.g.,
/<p${n}\s*>(.*?)<\/p[1-4]>/s to accept any </pN> closing tag, then validate the closing tag number matches
- Parser-side: Add a fallback that tries
/<p1\s*>(.*?)<\/p\d+>/s when the exact match fails
- Prompt-side: Add explicit instruction in the historian prompt to verify closing tags match opening tags
Environment:
- Magic Context: v0.32.4
- Historian model:
opencode/deepseek-v4-flash-free
- Historian
disallowed_tools: ["*"] (though legacy compartments existed before this was set)
- DB:
~/.local/share/cortexkit/magic-context/context.db
What happened?
Compartments are being flagged as
legacydespite the current Historian V2 producing<p1>/<p2>/<p3>/<p4>tier tags in the output. The "Historian V2 is released — upgrade your compartments" message appears for sessions where the historian ran successfully withlegacy=0on the run itself.Root cause: The tier extraction parser (
extractTier/TIER_REGEXES) fails silently when the historian model produces malformed closing tags. The model closes<p1>with</p2>instead of</p1>, so the regex/<p1\s*>(.*?)<\/p1>/sdoesn't match. When p1 extraction fails, the compartment falls through to the legacy code path and is markedlegacy=1.Evidence:
1. DB stats (1,042 compartments total):
legacy=1(all havep1=NULL)legacy=0(all havep1populated)2. All 73 legacy compartments contain tier tags in
contentbut NOT in thep1column:<p1>opening tag in content</p1>closing tag in content</p2>closing tag in contentp1column3. The model output looks like this:
4.
historian_runs.legacy= 0 for ALL runs that produced legacy compartments:This is the disconnect — the run is NOT marked legacy, but the compartments it produced ARE. The
legacyflag oncompartmentsis derived from whetherp1was extracted, not from the run itself.Code reference:
extractTierandTIER_REGEXES(incompartment-parser.ts/ distindex.js):The regex
/<p1\s*>(.*?)<\/p1>/srequires an exact</p1>closing tag. When the model produces</p2>as the closing tag for<p1>, the regex doesn't match →extractTierreturnsundefined→ p1 is not set.insertCompartmentRows(incompartment-storage.ts):When p1 is
undefined(extraction failed),hasTiersis false →legacy = 1.The chain:
Model context:
Historian model:
opencode/deepseek-v4-flash-free. The model consistently produces<p1>...</p2>instead of<p1>...</p1>. This has been observed across 73 compartments spanning from April 28 to July 23, 2026 — including compartments created today.Possible fixes:
/<p${n}\s*>(.*?)<\/p[1-4]>/sto accept any</pN>closing tag, then validate the closing tag number matches/<p1\s*>(.*?)<\/p\d+>/swhen the exact match failsEnvironment:
opencode/deepseek-v4-flash-freedisallowed_tools:["*"](though legacy compartments existed before this was set)~/.local/share/cortexkit/magic-context/context.db