zettelkasten.synapse.synthesis¶
zettelkasten.synapse.synthesis ¶
Claim-aligned cross-store synthesis: the WS4 layer over the synapse overlay.
The generic note-note overlay (:mod:zettelkasten.synapse.overlay, kind
generic) stays as-is — a useful, register-agnostic substrate. This module
adds a CLAIM-ALIGNED overlay + a grounded per-cell synthesis on top of it:
-
:func:
build_claim_connections— a thin wrapper over :func:overlay.build_connectionsthat restricts the two registers (canon =claim/findingZK notes, preferring_crosssynthesis claims; practice =decision/experiment/checkpointmemory entries), overfetches to offset the cross-register recall loss, persists to a SEPARATE file (.synapse/links/claim_links.json, kindclaim), and ANNOTATES each surviving edge withclaim_strengthand a blended synthesispriority. The typer confidence stays the ONLY gate;claim_strengthonly weights the priority/synthesis order — it never drops an edge. -
:func:
synthesize_matrix/ :func:synthesize_cell— a GROUNDED per-cell brief for an aligned (practice, canon-claim) pair. The brief says what the practice did, what the canon claim asserts, and the agreement/tension, CITING the memory entry id and the claim's RETRIEVED verbatim quotes and inventing nothing. Quotes are retrieved (never generated);synthis injectable (mirrors :func:zettelkasten.synapse.matrix._llm_synth) so it builds/tests with no LLM; an optional verifier checks the brief traces to the material. Only HIGH-VALUE cells (a strong claim met by a high-confidence relation, or ANY contradiction) are synthesized, to bound LLM cost. -
:func:
cross_store_contradictions— extract practice→canoncontradictsedges from the claim overlay as real-world counter-evidence to feed :func:zettelkasten.claims.debate_map(so a claim's contested status can reflect practice, not just the literature).
Read-only w.r.t. .memory/ and .zettelkasten/; the only write is synapse's
own .synapse/ overlay, exactly as the generic build.
priority_weight ¶
Map a claim strength to a priority weight in [0.5, 1.0].
A weak (or unknown) claim keeps a positive FLOOR so its edge's blended
priority is never zero — claim_strength only reorders synthesis, it must
NEVER silently drop an edge. Unknown strength (claim not in the index) maps to
a neutral 0.75.
Source code in zettelkasten/synapse/synthesis.py
claim_strength_lookup ¶
claim_strength_lookup(get_graph: GetGraph, projects: list[str] | None, graphs_dir: 'Any | None' = None) -> 'Callable[[str, str], float | None]'
A (zk_source, zk_id) -> claim_strength|None lookup over one claim context.
Builds the deterministic :mod:zettelkasten.claims context ONCE (lazily, on
first lookup) over the whole scope, then resolves each canon endpoint's
:func:zettelkasten.claims.claim_strength. Returns None for an endpoint
that is not a scored claim (e.g. a finding with no evidence, or a note the
index does not hold) — the caller treats that as neutral priority.
Source code in zettelkasten/synapse/synthesis.py
build_claim_connections ¶
build_claim_connections(zk_get_graph: GetGraph, projects: list[str] | None = None, graphs_dir: 'Any | None' = None, typer: Any = None, per_node_k: int = CLAIM_PER_NODE_K, sim_threshold: float = 0.45, min_confidence: float = 0.55, max_pairs: int = 200, limit: int | None = None, overfetch: int = CLAIM_OVERFETCH, strength_fn: 'Callable[[str, str], float | None] | None' = None, stance_classify_fn: 'Any | None' = None) -> dict[str, Any]
Build (and persist) the CLAIM-ALIGNED overlay (kind claim).
Restricts candidates to canon claim/finding × practice decision/experiment/
checkpoint (preferring _cross synthesis claims), overfetches to offset the
cross-register recall loss, types each pair with the injectable typer
(LLM by default), keeps edges clearing min_confidence (the ONLY gate), and
annotates each with claim_strength + a blended priority. Persists to
.synapse/links/claim_links.json and returns the overlay dict.
PRECISION-FIRST CONTRADICTIONS. On the DEFAULT path (no injected typer) the
LLM relation typer is wrapped by :func:_stance_gated_typer so any
contradicts verdict must additionally clear the SHARED symmetric stance gate
(:func:zettelkasten.stance.classify_contradiction, forward+reverse at
:data:CONTRADICTION_CONFIDENCE_FLOOR) — the same precision bar WS3's
intra-corpus discovery uses — before it can survive as a cross-store
contradicts edge feeding the debate map. Because that gate is UNCONDITIONAL
on this debate-feeding path, an injected typer (tests, the eval harness) MUST
also supply a stance_classify_fn so its contradicts verdicts route
through the same symmetric gate without an LLM; omitting it raises
ValueError rather than shipping ungated contradictions into the debate map.
Source code in zettelkasten/synapse/synthesis.py
is_high_value ¶
Whether a cell is worth an (LLM) grounded brief.
ANY contradiction qualifies (it is candidate real-world counter-evidence); otherwise the canon claim must be strong AND the relation high-confidence.
Source code in zettelkasten/synapse/synthesis.py
verify_brief ¶
Deterministic TRACEABILITY check: does the brief trace to the material?
A True result is a traceability signal — every numeric token and quoted
span in the brief traces to the provided material AND the memory id is cited —
NOT a semantic-entailment guarantee. It answers "did the brief invent specifics
absent from the material?", never "is the brief's meaning correct?". Two whole
classes of error are therefore explicitly OUT OF SCOPE and pass this check (the
brief is FLAGGED downstream, never rewritten):
- lexical MEANING-INVERSION — asserting the opposite with in-vocabulary words ("momentum DECREASES returns" when the material says it increases them);
- UNIT-VARIANT restatement — an equivalent figure in different units (a brief
saying
2.5%when the material says250bps); - spelled MULTIPLIER / FRACTION / ORDINAL magnitudes — the spelled-number check only covers cardinals combined with a magnitude word or a statistic unit (see (b)); it does NOT recognise multipliers ("double", "tenfold"), fractions ("a quarter", "half", "a third") or ordinals used as magnitudes ("a fourth"), so a fabricated figure phrased that way is not traced by the numeric gate.
Requirements, all conservative and LLM-free:
- (a) the brief CITES the memory entry id verbatim;
- (b) NUMERIC faithfulness — every numeric/statistic token in the brief
(percentages, basis points, p-values, plain numbers) also appears in the
material. SPELLED-out numbers are traced ONLY when they carry a magnitude word
or a statistic unit ("four hundred basis points", "twenty percent"): such a
span must trace to the material as its digit equivalent or the same spelled
phrase. A STANDALONE bare cardinal ("one of our decisions", "the first
experiment") is ordinary prose, not a figure, and is deliberately NOT required
to trace — so this catches spelled fabricated magnitudes, but does not treat
every number-word as a statistic.
The cited memory id is handled SEPARATELY: its literal string must appear in
the brief (a), but its own digits are neither required to trace nor counted as
"material numbers" — a hex id like
deci-a7688a22must never lend its hash digits ({'22', '7688'}) to a fabricated brief integer; - (c) any explicitly quoted span in the brief is a verbatim substring of a provided quote body;
- (d) at least
_TRACE_FLOORof the brief's content words appear in the material's vocabulary (memory summary/title + claim text + retrieved quotes + relation).
Source code in zettelkasten/synapse/synthesis.py
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 | |
synthesize_cell ¶
synthesize_cell(material: dict[str, Any], synth: 'CellSynthesizer | None' = None, *, verify: bool = True, verify_fn: 'BriefVerifier | None' = None) -> dict[str, Any]
Produce (and optionally verify) a grounded brief for one cell's material.
Returns {brief, verified, quote_ids}. synth is injectable (default is
a tool-free LLM pass that degrades to ""); verify_fn defaults to the
deterministic :func:verify_brief. A brief that fails verification is kept
but flagged verified=False (surfaced, never silently dropped).
Source code in zettelkasten/synapse/synthesis.py
synthesize_matrix ¶
synthesize_matrix(lens: dict[str, Any], material_fn: CellMaterialFn, synth: 'CellSynthesizer | None' = None, *, verify: bool = True, verify_fn: 'BriefVerifier | None' = None) -> dict[str, Any]
Add grounded per-cell briefs to a claim-overlay matrix lens (HIGH-VALUE only).
For each high-value cell (:func:is_high_value), material_fn(cell) returns
the grounded material (memory summary + claim + retrieved verbatim quotes) or
None to skip; :func:synthesize_cell then produces the brief. Purely
additive: returns a lens copy with a cell_synthesis list. material_fn
and synth are injectable so this builds/tests with no claim index or LLM.
Source code in zettelkasten/synapse/synthesis.py
claim_material_provider ¶
claim_material_provider(zk_get_graph: GetGraph, projects: list[str] | None = None, graphs_dir: 'Any | None' = None) -> CellMaterialFn
Default material_fn: assemble a cell's grounded material from the stores.
Builds the claim context + memory source ONCE (lazily) and, per cell, resolves
the memory entry's summary and the canon claim's top RETRIEVED verbatim quotes
(from :attr:ResolvedClaim.supporting_quotes, strongest first). Returns
None when the canon endpoint is not a scored claim in scope.
Source code in zettelkasten/synapse/synthesis.py
cross_store_contradictions ¶
cross_store_contradictions(overlay: dict[str, Any] | None = None, *, min_confidence: float = 0.55) -> list[dict[str, Any]]
Practice→canon contradicts edges from the claim overlay (counter-evidence).
Returns the claim-overlay edges typed contradicts clearing min_confidence,
shaped for :func:zettelkasten.claims.debate_map's cross_store_contradictions
parameter: {memory_id, zk_id, zk_source, confidence, rationale, claim_strength}.
A practice node contradicting a strong canon claim is real-world counter-evidence,
so feeding these lets a claim's contested status reflect practice, not just the
literature.
On the default build path these contradicts edges were already vetted by the
SHARED symmetric stance gate (:func:build_claim_connections wraps the LLM typer
with :func:_stance_gated_typer), so they clear the same precision bar as WS3's
intra-corpus discovery before they reach the debate map. This function only
re-applies the min_confidence floor as a final selection cut.