feat(kb): CRM association proof via oo, fix ssh-tunnel self-ref + oo creds

- bin/facts/crm: prove person<->company/company<->project against ooCRM
  x corpus SoT (knowledge-mesh-seed.yaml), write 78 facts (root=facts)
- tools/crmfacts.py + test_crm_facts.py: parser under unit tests (26 pass)
- docs/crm-associations-proof.md: provable graph, mistakes, fixes
- oo merge 759->763 resolves duplicate GoldenRatio.Exchange legal entity
- bin/db/ssh-tunnel: "$0" self-check + accept-new/BatchMode ssh flags
- AGENTS.md: document bin/facts/crm
This commit is contained in:
2026-08-10 23:22:34 +01:00
parent 6f766226f6
commit d6b17e8819
7 changed files with 234 additions and 1 deletions
+29
View File
@@ -0,0 +1,29 @@
"""crmfacts - pure helpers for bin/facts/crm (association proofing).
Shared with tools/ unit tests so the corpus-org parser is covered in CI.
"""
import re
def corpus_orgs(raw: str) -> dict[str, dict]:
"""Parse the orgs block of the CV knowledge-mesh YAML into id -> fields.
Fields kept: label, kind, period, website. Stops at the first sibling
top-level key (clients, timeline, ...).
"""
m = re.search(r"^orgs:\n(.*?)\n^(?:clients|timeline|tech_weights|nodes|edges):", raw, re.S | re.M)
if not m:
return {}
orgs: dict[str, dict] = {}
cur = None
for line in m.group(1).splitlines():
lm = re.match(r"^\s*- id:\s*(\S+)", line)
if lm:
cur = lm.group(1)
orgs[cur] = {}
continue
fm = re.match(r"^\s+(\w+):\s*(.*)$", line)
if fm and cur and fm.group(1) in ("label", "kind", "period", "website"):
orgs[cur][fm.group(1)] = fm.group(2).strip()
return orgs