fix: index decisions/ as entities so decision records reach the bot prompt

Root cause: decision records have type: decision, but the entity indexer
only accepted type: entity and only scanned entities/. The claim indexer
scanned decisions/ but filtered out non-claim types. Result: decision
records fell through both indexes entirely — invisible to the bot.

Fix: add decisions/ to entity indexer scan paths, accept type: decision
alongside type: entity, include summary/proposer in search aliases.
Remove decisions/ from claim indexer (was silently dropping them anyway).

Pentagon-Agent: Epimetheus <3D35839A-7722-4740-B93D-51157F7D5E70>
This commit is contained in:
m3taversal 2026-03-23 17:28:30 +00:00
parent c7c71ec9d1
commit 425e7a1bac

View file

@ -106,15 +106,23 @@ class KBIndex:
time.time() - start, len(self._entities), len(self._claims), len(self._positions)) time.time() - start, len(self._entities), len(self._claims), len(self._positions))
def _index_entities(self): def _index_entities(self):
"""Scan entities/ for all entity files.""" """Scan entities/ and decisions/ for entity and decision files."""
entities_dir = self.repo_dir / "entities" entity_dirs = [
self.repo_dir / "entities",
self.repo_dir / "decisions",
]
for entities_dir in entity_dirs:
if not entities_dir.exists(): if not entities_dir.exists():
return continue
for md_file in entities_dir.rglob("*.md"): for md_file in entities_dir.rglob("*.md"):
self._index_single_entity(md_file)
def _index_single_entity(self, md_file: Path):
"""Index a single entity or decision file."""
try: try:
fm, body = _parse_frontmatter(md_file) fm, body = _parse_frontmatter(md_file)
if not fm or fm.get("type") != "entity": if not fm or fm.get("type") not in ("entity", "decision"):
continue return
name = fm.get("name", md_file.stem) name = fm.get("name", md_file.stem)
handles = fm.get("handles", []) or [] handles = fm.get("handles", []) or []
@ -122,6 +130,10 @@ class KBIndex:
entity_type = fm.get("entity_type", "unknown") entity_type = fm.get("entity_type", "unknown")
domain = fm.get("domain", "unknown") domain = fm.get("domain", "unknown")
# For decision records, also index summary and proposer as searchable text
summary = fm.get("summary", "")
proposer = fm.get("proposer", "")
# Build aliases from multiple sources # Build aliases from multiple sources
aliases = set() aliases = set()
aliases.add(name.lower()) aliases.add(name.lower())
@ -130,6 +142,9 @@ class KBIndex:
aliases.add(h.lower().lstrip("@")) aliases.add(h.lower().lstrip("@"))
for t in tags: for t in tags:
aliases.add(t.lower()) aliases.add(t.lower())
# Add proposer name as alias for decision records
if proposer:
aliases.add(proposer.lower())
# Mine body for ticker mentions ($XXXX and standalone ALL-CAPS tokens) # Mine body for ticker mentions ($XXXX and standalone ALL-CAPS tokens)
dollar_tickers = re.findall(r"\$([A-Z]{2,10})", body[:2000]) dollar_tickers = re.findall(r"\$([A-Z]{2,10})", body[:2000])
@ -155,7 +170,14 @@ class KBIndex:
# Extract wiki-linked claim references from body # Extract wiki-linked claim references from body
related_claims = re.findall(r"\[\[([^\]]+)\]\]", body) related_claims = re.findall(r"\[\[([^\]]+)\]\]", body)
# Body excerpt for context # Body excerpt — for decisions, lead with summary for better prompt context
if summary:
overview = f"{summary} "
body_lines = [l for l in body.split("\n") if l.strip() and not l.startswith("#")]
remaining = 500 - len(overview)
if remaining > 0:
overview += " ".join(body_lines[:10])[:remaining]
else:
body_lines = [l for l in body.split("\n") if l.strip() and not l.startswith("#")] body_lines = [l for l in body.split("\n") if l.strip() and not l.startswith("#")]
overview = " ".join(body_lines[:10])[:500] overview = " ".join(body_lines[:10])[:500]
@ -185,7 +207,6 @@ class KBIndex:
self.repo_dir / "domains", self.repo_dir / "domains",
self.repo_dir / "core", self.repo_dir / "core",
self.repo_dir / "foundations", self.repo_dir / "foundations",
self.repo_dir / "decisions",
] ]
for claim_dir in claim_dirs: for claim_dir in claim_dirs:
if not claim_dir.exists(): if not claim_dir.exists():
@ -447,7 +468,7 @@ def _domain_from_path(path: Path, repo_dir: Path) -> str:
"""Infer domain from file path.""" """Infer domain from file path."""
rel = path.relative_to(repo_dir) rel = path.relative_to(repo_dir)
parts = rel.parts parts = rel.parts
if len(parts) >= 2 and parts[0] in ("domains", "entities"): if len(parts) >= 2 and parts[0] in ("domains", "entities", "decisions"):
return parts[1] return parts[1]
if len(parts) >= 1 and parts[0] == "core": if len(parts) >= 1 and parts[0] == "core":
return "core" return "core"