From 116bad1de3cb7e644f1db62ecfd9193988daf947 Mon Sep 17 00:00:00 2001 From: jordan Date: Wed, 4 Feb 2026 03:41:08 -0700 Subject: [PATCH] feat: Ingestor deadlock fix + blessed assertion tracking + patent docs Key changes: - Fix Ingestor background task to release lock per iteration, preventing deadlock when process_pending() needs the lock during shutdown - Add blessed assertion predicate index and fetch_blessed_assertions() for policy export workflows in Aphoria - Add patent documentation (markdown + Word exports) for probabilistic knowledge graph system - Update community scripts for claim extraction pipeline Co-Authored-By: Claude Opus 4.5 --- .claude/skills/extract-claims/SKILL.md | 1 + .../aphoria/docs/legal/patent-disclosure.docx | Bin 0 -> 26172 bytes .../aphoria/docs/legal/patent-disclosure.md | 258 ++++++- .../aphoria/docs/legal/patent-figures.docx | Bin 0 -> 18862 bytes .../docs/legal/patent-specification.docx | Bin 0 -> 24198 bytes .../docs/legal/patent-specification.md | 23 + applications/aphoria/src/episteme/local.rs | 99 +-- applications/aphoria/src/policy_ops.rs | 17 +- .../2026-02-04-uat-policy-source-results.md | 123 ++++ community/scripts/extract-claims.ts | 61 +- community/scripts/seed-whitepaper.ts | 265 ++++++- community/src/app/page.tsx | 160 ++++- crates/stemedb-ingest/src/ingestor.rs | 58 +- docs/legal/patent-disclosure.docx | Bin 0 -> 27312 bytes docs/legal/patent-disclosure.md | 611 ++++++++++++++++ docs/legal/patent-figures.docx | Bin 0 -> 20664 bytes docs/legal/patent-figures.md | 661 ++++++++++++++++++ docs/legal/patent-specification.docx | Bin 0 -> 24667 bytes docs/legal/patent-specification.md | 657 +++++++++++++++++ 19 files changed, 2853 insertions(+), 141 deletions(-) create mode 100644 applications/aphoria/docs/legal/patent-disclosure.docx create mode 100644 applications/aphoria/docs/legal/patent-figures.docx create mode 100644 applications/aphoria/docs/legal/patent-specification.docx create mode 100644 applications/aphoria/uat/2026-02-04-uat-policy-source-results.md create mode 100644 docs/legal/patent-disclosure.docx create mode 100644 docs/legal/patent-disclosure.md create mode 100644 docs/legal/patent-figures.docx create mode 100644 docs/legal/patent-figures.md create mode 100644 docs/legal/patent-specification.docx create mode 100644 docs/legal/patent-specification.md diff --git a/.claude/skills/extract-claims/SKILL.md b/.claude/skills/extract-claims/SKILL.md index 77ca360..3558b2a 100644 --- a/.claude/skills/extract-claims/SKILL.md +++ b/.claude/skills/extract-claims/SKILL.md @@ -279,3 +279,4 @@ Use consistent predicates across extractions: - Invent claims not supported by the text - Skip implicit claims (category membership, etc.) - Use inconsistent predicate names +- **NEVER produce claims only about the document's main topic while ignoring other entities mentioned** - if text discusses PostgreSQL, MongoDB, and Neo4j, extract claims about ALL of them, not just the product being documented diff --git a/applications/aphoria/docs/legal/patent-disclosure.docx b/applications/aphoria/docs/legal/patent-disclosure.docx new file mode 100644 index 0000000000000000000000000000000000000000..65b0b19df20866c3c850ee8e8f1040a206a0c50a GIT binary patch literal 26172 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 ZZ;)4zhKBj;Kd3KnL?|#YJj1_!{U1G7*BAf* literal 0 HcmV?d00001 diff --git a/applications/aphoria/docs/legal/patent-disclosure.md b/applications/aphoria/docs/legal/patent-disclosure.md index 9b00730..3e7e643 100644 --- a/applications/aphoria/docs/legal/patent-disclosure.md +++ b/applications/aphoria/docs/legal/patent-disclosure.md @@ -113,22 +113,24 @@ A system for detecting configuration conflicts in source code, the system compri **(a)** a parser module configured to: -- receive a source code file containing at least one configuration statement defining a value for a runtime parameter, security setting, or system behavior modifier, -- extract a configuration value and its associated context from the configuration statement, and -- transform the configuration value into a semantic triple comprising a subject identifier, a predicate type selected from a predefined configuration ontology comprising property types including at least timeout values, encryption parameters, and authentication requirements, and an object value; +- receive a source code file containing at least one configuration statement, wherein the configuration statement comprises a key-value assignment in a structured data format selected from the group consisting of YAML, JSON, TOML, and environment variable declaration syntax, +- identify the configuration statement by applying pattern-matching rules to the source code file, +- extract a configuration key and a configuration value from the identified configuration statement, and +- transform the configuration key and configuration value into a semantic triple comprising a subject identifier, a predicate type selected from a predefined configuration ontology comprising property types including at least timeout values, encryption parameters, and authentication requirements, and an object value; -**(b)** a knowledge graph database storing a plurality of authoritative assertions, each authoritative assertion comprising a semantic triple and an associated authority weight, wherein authority weights are assigned based on a hierarchical classification comprising at least three tiers corresponding to regulatory sources, vendor documentation sources, and community sources, and wherein regulatory source assertions are assigned authority weights greater than vendor documentation assertions, which are assigned authority weights greater than community source assertions; +**(b)** a knowledge graph database storing a plurality of authoritative assertions, each authoritative assertion comprising a semantic triple and an associated authority weight, wherein authority weights are numeric values on a scale from 0 to 1, wherein authority weights are assigned based on a hierarchical classification comprising at least three tiers corresponding to regulatory sources, vendor documentation sources, and community sources, wherein regulatory source assertions are assigned authority weights of at least 0.8, vendor documentation assertions are assigned authority weights between 0.5 and 0.79, and community source assertions are assigned authority weights below 0.5, and wherein source code configurations are assigned a default authority weight of less than 0.5 on the authority weight scale; **(c)** a conflict detection engine configured to: - query the knowledge graph database to retrieve authoritative assertions having predicate types matching the predicate type of the transformed semantic triple, -- compare the object value of the transformed semantic triple against object values of retrieved authoritative assertions, wherein comparing comprises determining a semantic distance between values, the semantic distance calculated as a normalized difference for numeric values and a binary disparity indicator for boolean values, -- identify a conflict condition when the object value of the transformed semantic triple differs from the object value of at least one retrieved authoritative assertion by more than a predefined threshold; and +- compare the object value of the transformed semantic triple against object values of retrieved authoritative assertions, wherein comparing comprises determining a semantic distance between values, wherein the semantic distance for numeric values is calculated as the absolute value of the difference between the authoritative value and the code value divided by the authoritative value, and wherein the semantic distance for boolean values equals 1.0 when values differ and 0.0 when values match, +- identify a conflict condition when the semantic distance exceeds a predefined threshold; and **(d)** a scoring module configured to calculate a conflict score for each identified conflict condition by: -- computing a weighted difference between the authority weight of the authoritative assertion and a baseline authority weight assigned to source code configurations, -- wherein the conflict score increases proportionally with the authority weight differential; +- computing a weighted difference between the authority weight of the authoritative assertion and the default authority weight assigned to the source code configuration, +- multiplying the weighted difference by the semantic distance, +- wherein the conflict score increases proportionally with both the authority weight differential and the semantic distance; wherein the system outputs an ordered list of conflict conditions ranked by conflict score. @@ -297,47 +299,147 @@ wherein the system maintains a complete provenance chain of all conflict acknowl --- +### Dependent Claims: Integration and Deployment (Claims 28-30) + +**Claim 28.** The system of claim 1, wherein the system is integrated with a continuous integration pipeline, and wherein the system is configured to: + +- receive a code commit event identifying modified source code files, +- parse only the modified source code files, +- calculate an aggregate conflict score by summing individual conflict scores for all detected conflicts, +- compare the aggregate conflict score against a repository-specific threshold, and +- transmit a merge-blocking signal to the continuous integration pipeline when the aggregate conflict score exceeds the threshold. + +**Claim 29.** The system of claim 1, wherein the system operates as a Language Server Protocol provider, and wherein the system is configured to: + +- receive document change notifications from an integrated development environment, +- incrementally re-parse regions of the source code file affected by the document change, +- generate diagnostic messages identifying detected conflicts, and +- transmit the diagnostic messages to the integrated development environment for display as inline warnings. + +**Claim 30.** The system of claim 1, wherein the knowledge graph database implements temporal decay of authority weights for community source assertions, comprising: + +- storing a publication timestamp for each community source assertion, +- calculating a decay factor based on elapsed time since publication, +- applying the decay factor to reduce the authority weight of community source assertions over time, and +- maintaining constant authority weights for regulatory source assertions regardless of publication date. + +--- + ## Prior Art Concerns and Distinction Strategy -### Category 1: Static Analysis Tools (Semgrep, SonarQube, CodeQL) +### Search Summary -**Prior Art Teaches:** Pattern-matching rules that flag code matching predefined syntactic patterns. +After comprehensive search across patent databases, academic literature, and industry sources, **no single reference or obvious combination teaches the core invention**: the use of a hierarchically-weighted knowledge graph containing RFC/regulatory assertions combined with semantic triple transformation of source code configurations to compute authority-differential conflict scores. -**Distinction:** These tools match patterns; they don't construct semantic triples or query a knowledge graph. They have no concept of authority weighting—a rule either matches or it doesn't. +**Overall Assessment: Moderate-to-Strong Patentability** -**Specification Language:** +The invention occupies a novel intersection between: +1. Static code analysis (prior art exists) +2. Policy-as-code enforcement (prior art exists) +3. Knowledge graphs for semantic data (prior art exists) +4. Hierarchical authority weighting for compliance (limited prior art) -> "Unlike conventional static analysis tools that apply pattern-matching rules without contextual weighting, embodiments of the present invention transform configuration values into semantic representations and compare them against a hierarchically-weighted knowledge base, enabling prioritization of conflicts based on the authoritative source of the violated standard rather than treating all rule violations as equivalent." +The combination is what makes the invention patentable. --- -### Category 2: Compliance Automation (Chef InSpec, Open Policy Agent) +### Category 1: Static Analysis Tools (Closest Prior Art) -**Prior Art Teaches:** Policy-as-code execution where users manually author policy rules. +**Relevant Tools Identified:** +- Semgrep (open source, returntocorp) +- Checkov (Palo Alto/Bridgecrew) +- tfsec/Trivy (Aqua Security) +- Terrascan (Tenable) +- KICS (Checkmarx) +- SonarQube, CodeQL -**Distinction:** These tools execute policy-as-code written by users. They don't automatically derive policies from authoritative sources or compute authority-weighted scores. +**What They Teach:** +- Pattern matching against predefined rules +- Detection of security misconfigurations +- CI/CD pipeline integration +- Custom rule authoring (YAML, Rego, Python) +- Compliance framework mapping (CIS, PCI-DSS) + +**What They Do NOT Teach:** +- Semantic triple transformation of configurations +- Authority-weighted knowledge graph querying +- Conflict scoring based on source authority differentials +- Automatic derivation of rules from RFC/standards documentation +- Temporal decay of authority weights **Specification Language:** -> "In contrast to policy-as-code systems that require manual policy authoring, the present invention automatically ingests and structures authoritative documentation into a queryable knowledge graph, eliminating the need for manual policy translation and ensuring that conflict detection reflects the current state of authoritative standards." +> "Unlike conventional static analysis tools that apply pattern-matching rules, wherein all rule violations are treated with equal severity regardless of the authoritative source of the violated standard, embodiments of the present invention transform configuration values into normalized semantic triples and query a hierarchically-weighted knowledge graph to compute conflict scores that reflect the regulatory or industry weight of the violated assertion." --- -### Category 3: Knowledge Graph Systems (Neo4j, general semantic web) +### Category 2: Policy-as-Code Systems (OPA, Chef InSpec) -**Prior Art Teaches:** Generic graph database technology for storing and querying linked data. +**Relevant Prior Art:** +- Open Policy Agent (OPA) with Rego language +- Chef InSpec compliance framework +- HashiCorp Sentinel +- AWS Config Rules -**Distinction:** Generic knowledge graph technology doesn't address code configuration analysis. The specific ontology, authority-weighting scheme, and integration with code parsing are the inventive elements. +**What They Teach:** +- Declarative policy specification +- Policy evaluation against structured data (JSON/YAML) +- OPA decouples policy decision-making from policy enforcement +- Cryptographically signed policy bundles (OPA supports this) -**Prosecution Argument:** Under _KSR_, the question is whether a PHOSITA would combine these references with a reasonable expectation of success. The combination requires: (1) designing an ontology for configuration semantics, (2) developing an authority-weighting scheme, and (3) integrating with code parsing—none of which are taught or suggested by the prior art. +**Critical Finding - OPA Signed Bundles:** +OPA supports digital signatures for policy bundles to ensure integrity and authenticity from trusted sources. This has some overlap with Trust Pack feature. + +**What They Do NOT Teach:** +- Automatic derivation of policies from RFC/standards documentation +- Authority tier hierarchy with numeric weights +- Conflict score calculation based on authority differentials +- Temporal decay for community-sourced assertions +- Semantic triple transformation from source code + +**OPA/Trust Pack Distinction:** +- OPA bundles contain **manually-authored Rego policies** +- Trust Packs contain **semantic assertions with authority weights** that **merge into a knowledge graph** +- OPA evaluates policies against input; the invention compares **code-derived semantic triples against authoritative assertions** +- OPA provides binary pass/fail; the invention computes **weighted conflict scores** + +**Specification Language:** + +> "In contrast to policy-as-code systems that require manual policy authoring and treat all policy violations equivalently, the present invention automatically structures authoritative documentation into a queryable knowledge graph with hierarchical authority weights, enabling automated prioritization of conflicts based on the regulatory tier of the violated standard without requiring manual policy translation." + +--- + +### Category 3: Knowledge Graph Systems and Semantic Analysis + +**Relevant Patent Art:** +- **US8566789B2** - "Semantic-based query techniques for source code" (Microsoft) — closest patent art +- **US9442917B2** - "Detecting semantic errors in text using ontology-based extraction rules" +- **EP1468375A1** - "System for generating heterogeneous data source interoperability bridges based on semantic modeling" +- CodeOntology - SPARQL queries over source code (academic) + +**What US8566789B2 Teaches:** +- Source code elements identified and extracted (keywords, variable types, method names) +- Mappings between source code elements and respective associated domain concepts +- Semantic analysis for code search and understanding + +**What They Do NOT Teach:** +- Configuration-specific ontology for security parameters +- Authority weighting for assertions +- Conflict detection between code claims and authoritative standards +- RFC/NIST documentation as primary knowledge sources +- Temporal decay mechanisms + +**Specification Language:** + +> "While prior art teaches semantic analysis of source code for purposes such as code search and understanding program structure, the present invention applies semantic triple transformation specifically to configuration parameters and compares the resulting triples against a knowledge graph of authoritative technical standards, a combination not taught or suggested by prior systems focused on code comprehension." --- ### Category 4: Infrastructure-as-Code Security (Styra, Fugue, Bridgecrew/Checkov) -**Prior Art Teaches:** Cloud configuration scanning and policy bundles for infrastructure compliance. +**Prior Art Teaches:** Cloud configuration scanning and policy bundles for infrastructure compliance (Terraform, CloudFormation). -**Distinction:** These tools focus on infrastructure configuration (Terraform, CloudFormation) rather than application source code. They do not: +**Distinction:** These tools focus on infrastructure configuration rather than application source code. They do not: - Transform application code into semantic triples - Maintain authority-weighted knowledge graphs from RFC standards @@ -349,26 +451,105 @@ wherein the system maintains a complete provenance chain of all conflict acknowl --- +### Category 5: Compliance Automation and GRC Systems + +**Relevant Patent Art:** +- **US8352453** - "Plan-based compliance score computation for composite targets/systems" (Oracle) +- **US20090205011** - "Change recommendations for compliance policy enforcement" (Oracle) +- **US20210374767A1** - "Automatic remediation of non-compliance events" +- Various GRC platforms (Scrut, Drata, Hyperproof) + +**What US8352453 Teaches:** +- Hierarchical compliance scoring for IT infrastructure compliance (servers, databases) +- Steps generated for compliance standard hierarchy + +**What US20090205011 Teaches:** +- Compliance policy including organizational regulations, cross-vendor requirements +- User-authored compliance policies for runtime system compliance + +**What They Do NOT Teach:** +- Source code parsing for configuration extraction +- Semantic triple transformation +- Authority weighting based on RFC vs. vendor vs. community sources +- Pre-commit/CI integration for code review + +**Specification Language:** + +> "Unlike compliance systems that monitor deployed infrastructure and require manual policy authoring, the present invention operates at development time by parsing source code files, transforming configuration statements into semantic triples, and comparing them against authoritative assertions to prevent misconfiguration before deployment." + +--- + +### Prior Art Gap Analysis + +| Feature | Static Analysis | Policy-as-Code | Knowledge Graphs | Compliance Systems | **Aphoria** | +|---------|----------------|----------------|------------------|-------------------|-------------| +| Source code parsing | ✓ | ✗ | ✓ (some) | ✗ | ✓ | +| Semantic triple transformation | ✗ | ✗ | ✓ | ✗ | ✓ | +| Knowledge graph querying | ✗ | ✗ | ✓ | ✗ | ✓ | +| Authority weighting | ✗ | ✗ | ✗ | Partial | ✓ | +| RFC/NIST as authoritative source | ✗ | Manual | ✗ | Manual | ✓ Auto | +| Conflict score calculation | ✗ | ✗ | ✗ | ✗ | ✓ | +| Cryptographic trust packs | ✗ | ✓ (OPA) | ✗ | ✗ | ✓ | +| Temporal decay | ✗ | ✗ | ✗ | ✗ | ✓ | + +**The unique combination** of semantic code analysis + authority-weighted knowledge graph + conflict scoring is not taught by any single reference or obvious combination. + +--- + +### Anticipated Examiner Combination + +**Biggest Risk**: An examiner combining US8566789 (semantic code analysis) + US8352453 (compliance scoring hierarchy) + general knowledge graph technology. + +**Response Strategy:** +1. Neither reference teaches configuration-specific security analysis +2. Neither teaches authority weighting based on RFC vs. vendor sources +3. The combination requires specific ontology design not taught by any reference +4. Under _Berkheimer_, the examiner must provide evidence that the combination is conventional + +--- + ### Prior Art Search Recommendations -The following searches are recommended before filing: +The following additional searches are recommended before utility filing: -- IBM CodeNet and related semantic code analysis research -- Academic literature: "semantic code analysis" + "knowledge graph" -- Academic literature: "ontology" + "security analysis" -- Patent search: US Class 717/126 (code analysis), 707/E17 (databases) +- **Academic Literature:** + - IEEE/ACM: "semantic code analysis" + "knowledge graph" + - arXiv cs.SE/cs.CR: "ontology" + "security analysis" + - IBM CodeNet and related semantic code analysis research + +- **Patent Search:** + - US Class 717/126 (code analysis) + - US Class 707/E17 (databases) + - CPC G06F21/57 (security configuration) + +- **Professional Search:** Consider engaging professional prior art search firm ($3,000-$8,000) before utility filing --- ## §101 Prosecution Strategy +### Current Landscape (2024-2025) + +The overall PTAB affirmance rate for §101 rejections in 2024 was 88.6% (approximately 7 out of 8 appeals affirmed). However, recent positive developments support software patent eligibility: + +- In _Desjardins_, the USPTO's Appeals Review Panel directed PTAB panels to incorporate _Enfish_ reasoning, noting that software can make non-abstract improvements to computer technology just as hardware can. +- USPTO guidance explains that improvements to model performance, memory, data structures, and system architecture can provide the "something more" under _Alice_. + +**This invention has strong §101 arguments because:** +1. It uses **specific data structures** (semantic triples, weighted knowledge graph) +2. It achieves **measurable technical improvement** (100% precision vs. ~30% for prior art) +3. It solves a **technical problem** (undifferentiated rule violations) with a **technical solution** (authority-weighted conflict scoring) +4. The operations **cannot be performed mentally** (graph traversal of thousands of RFC assertions) + When the examiner issues a §101 rejection, respond with this structure: ### Step 2A, Prong One: Not an Abstract Idea The claims are not directed to a mathematical formula in the abstract. The claims recite a specific technical implementation that transforms source code files into semantic data structures, traverses a graph database to retrieve matching assertions, and outputs a ranked conflict report. These operations are performed by specific computer components—a parser module, a graph database, and a conflict detection engine—and cannot be performed by mental steps or pen and paper due to the scale of the knowledge graph (thousands of RFC-derived assertions) and the speed requirements (sub-second analysis of production codebases). -**Cite:** _Enfish v. Microsoft_ (Fed. Cir. 2016): Claims directed to a specific improvement in computer capabilities are not abstract. +**Cite:** +- _Enfish v. Microsoft_ (Fed. Cir. 2016): Claims directed to a specific improvement in computer capabilities are not abstract. +- _Desjardins_ (USPTO Appeals Review Panel): Software can make non-abstract improvements to computer technology. --- @@ -386,6 +567,23 @@ If forced to Step 2B, argue: The ordered combination of elements—semantic triple transformation, hierarchically-weighted knowledge graph, graph traversal for conflict detection, and authority-differential scoring—is not well-understood, routine, or conventional in the field of static analysis. No prior art reference teaches authority-weighted knowledge graph traversal for code configuration analysis. Under _Berkheimer v. HP Inc._, 881 F.3d 1360 (Fed. Cir. 2018), the conventional nature of claim elements is a factual question. The examiner has cited no evidence that this specific combination is conventional. +**Evidentiary Support:** +- Consider preparing a Rule 132 declaration from a PHOSITA attesting to the technical improvement +- Specification benchmarks (100% precision vs. ~30%) serve as objective evidence of technical improvement +- The combination requires domain expertise across multiple fields (semantic analysis, compliance, knowledge graphs) + +--- + +### KSR Obviousness Defense + +Under _KSR_, argue that a PHOSITA would not combine the identified prior art references with a reasonable expectation of success: + +1. **Semantic code analysis experts** (US8566789) don't work with compliance hierarchies +2. **Compliance experts** (US8352453) don't work with semantic triple transformations +3. **Knowledge graph experts** don't work with code configuration parsing +4. The combination requires **specific ontology design** for configuration semantics not taught by any reference +5. No reference teaches **authority weighting based on RFC vs. vendor vs. community sources** + --- ## Supporting Documents @@ -403,3 +601,5 @@ The ordered combination of elements—semantic triple transformation, hierarchic | ---------- | ------- | ---------------------------------------------------------- | | 2026-02-04 | Initial | First draft with reconstructed claims per counsel feedback | | 2026-02-04 | Rev 2 | IP counsel feedback: 3 claim families, §101 strengthening, prior art expansion | +| 2026-02-04 | Rev 3 | Comprehensive prior art search: specific patent refs, gap analysis, Desjardins case | +| 2026-02-04 | Rev 4 | Claim 1 structural fixes (antecedent basis, semantic distance definition), Claims 28-30 added | diff --git a/applications/aphoria/docs/legal/patent-figures.docx b/applications/aphoria/docs/legal/patent-figures.docx new file mode 100644 index 0000000000000000000000000000000000000000..281c88344a458f9af6f73b32becbc8a1d2ad5944 GIT binary patch literal 18862 zcmZ5{V~}WDlWhC6ZQHhOTc>T??$fqy+qP}nwyin$n>Q14U&LN}|EeIMCODf>L@EdEp3hqH?ig^|`0+BQ;nWxG@DI#WnGmBlB&9YVobq=jE@? zvqA`*q-?4`wJBa2QttKF5Eq+48L$wG!fWQ3sm5(UQRU3s@%xNaz^(z=428??M}ywg z1nE+8bo2B|R&$nhK}T5d_U{B&vPHTrK%6mJyB#CPpRD$W*2Ciu;!w;cjFRJ%AX8tHa1$-0i8FIoa4xXh?TkDGTw1(lq23BrNj zQlUbP;;Qd>G@UL47k^g9$mIW(vliFFo0Gq}ng;>^fcpE@buhMaq@(@kT@^1Q3(Np5 zT7&4mbB7EmSZdBzs^|)y1gsurN}B(surJug14xit3a#ygaq{qxaP;PI({i5XXwP7l z%1T2HOR9VNx7r$1Smz3Lea!R()Tv62WmZWAgKv1nulB@rgoO2 zgozsQyKf{fqpqx*U1kK^zwuCRH%loe001cV0|Y?$i-)VNgAtvPt)a8^Un2j*;45t@ z+XM0V?w1M=Od2}CQNQDO{)w7<`r$YF|Z*O}#E zx@NP*X@_N-v`dt{HY>8q&2@EF%ku)4rEb^fz0ztMn^_n2W#zPy=R4!ZW7G^E2pd`>$|ZJ+RH%4zQ;1k ziuV+iYr@2|y)AOOYY;P>X*kK2G(t_;xYQp(KEDE(tPnDe^U{c1sZuk`}*UJUiV-N zQ-n8jR-WkIzNN&5Hdi5H^8t49x5EP6;I=v!?M5;2fRJ=6NmKRN`UIpeHiuyh(Z{E~ zTit+-{vFoT-L3aheHPPLd^_qbyvU!So|ZdgFJ~YD%|Dcg%+ncFq+{q$~ZocQ~p9Uule#WEZL%G zb+9hF1}R8OxXSy6V-z`4Df4SyoWIqJ?K}U_&gR=@f@+#n{MrGx{SnSAsk_TBq6Lz~Tm@DUky#aD%b2`Wn8f3iNDWg8KBzRQoxt_-5wwKAD)$@7ZZY2fFScYeLvg|=g5<_D&LcIyNQ;h&fh$DgGwPBX(^0a9rUrJ|jSv&9 zh(HGf14uYl=xCnNwA^Sk#)E=I6-u$S4E;t~Rl54?1L`dD6Nsh3*D02ut$sz9k^pj) zs?hJ!9#UA5$P{>j`BLlxH)Ixe9SF7|f7#(N-u{KRdNXSps^W)i;6|le*lM}l( zZCIXIj1Xt4wXFh!cC#oMNkOLIlyddRc+?ydSgN=b#uVNtO3Oi@iq&kwr-@9%(ow^yX{{z#NXS9owR+MztxiA3k zXii|6DLIP}!x7w8sH~=Mq(yIJZ-C)_J=jm$3va3L+f-8NBehi%GP|4m>`(3O-pOD+ ze8N5gI8!_|3CQ>q=3f zcAxqbmkagTmj7bWwftu7tuRn(S|dap*xrHi2ZFZ4Xf*H~biI8X&3 z#heQ%ffco}`F6}*EVSs((l&c?pheK)V|Dog!#L8wC=exac>u)pDKre@)y>HeT^b2q z9tfhy$krg_bpL(z+c*K52!5r>@2GKe$DVEWvc~B1l0p{`JEw84`+iaWoKxvZk(^a& z=0dDLNCSh`9C$v2GV3W$Vo4GciZX7}it2Bl9sYY>_A)e0Oq*LN%o+DY1k2yE(pg34 zzS5Fk)cSKKsrN}DNO3_)BEJXoc}@p*Mks{6YL?|*Vq(f^>eVcl$_;~S8~0T2ui$(! zi$3rUFBaa9?5%HdMPV_M8ieX!#w`)-8<=%FaNdMXTv-Xj2RYduo^K9UfGuDobR7;IweimM5;R6u32QV z{XVQz{932NMGnh~Q06UvWeC8!S__i z%=NG?*VZ;DZGmDHL>A9fU%EnULNz;Vk4a|#QYX)mI8F=c7@F$q?Z_7Ajd z_Sxp-vdvQ=k2LHY%pMPTX)ltGpgdG>!U_BYBLIRh$R{{c>lN}mO}JSf7^J`RTlY{< zBFN{*y+#2Bu3I#w_Qewu?!d5h6Ap0UPdH;FDGA_hBDQWL2Vg}Yc}NY+sOLR>5G;48 zau=!Z8zUOxN}Vuq#AUix$#5LX?+rS#+fCm8Wiz(tM(s;$UN+l|-a4KFvB>yI>@9?0 z#!O&@HeP5f(LM!CqHvqoXNf52Q-;0D-$FtX6_myJrpac*T;3}lO#y*wx|ntM4KM)~CNf-Y6L*4$1n>3LE3ycN4 z6x*r9%BKC&1AZ{03fwNK>Lm){POC)aqgf?MBr>>W zl}WEo1_G~9PUIk^I49xc79nry(U99HHKh#Jd$LiA+7?9S<=<5k9MCkzmS&t_2`!K@ zE5YW!ug+h|E2z%SZ#16t0~=bPhba+@m{flojBu|wk%YQ!XJ)YwaG@e)$$eB7V^o-D zckkH)=RN2Lc=o;vCGe;c!@Q5q&3G=x@k>w;)y+_MVkDmVi3P*e>hdQTt@}H3$t=~> z{){dMe}4cJ^|cJy}K7^5|uo4VQS2H&S}f>(lBK4M~ev? zi8JVux1A2Mo5~j_tSgqOkZRO#=V~+S1hZ_yhx5ZKk|$`9Qe}gjq@|?$ew`V9Qim-| zdK;mX<&gw!>#T=nm2TYl2EG%TqN?;>IGC+n-EN8~y}~J!cJi;Lh!L!6Q=+Kj@I#u;^B$~LeW(__?Vc!8Ij(&HxJriMaOe};!$5^1x(vwtA;W=}xi zduoW(Vf&c1Rcw#Y6}k>$wFHW%0R$h^Ic6Ah4u%Q-qyil3UiZrrh|s#st=+{KGi@M@ zgu7J+5E%W5?b#H35#(R-)Oli%CGeJH2bdG}#QVnJ5~!Hl4v2o{6tJo!exfjkO9VizD zU)7uM~F7-cOzOSJ>`0?x&Dg;R4#wW%T?ta+&gY&uEKOR+gYXm7G*im16f| zvd$$pEvab*cig=hbaH161{-6ljTo`>!zg(c>V>dX1ZFV#fjYlcX0p>jUNAH>DTCb> z{75I@XH0}m(7eX%T7=;gWwFBYsiatgih1McyDBRl!V(&pKg=vew(AHY93D}rGCq)o z>gT=qHB-G*|JqC-zVn>_1Tcu{2%k=b$}v(P_Y=^kqpF2zl4`{=I|*5m>JvPYtDglF zP0~mu6J>E3j6jp~S;mxPg9s+DH6x&MCP=p4copN_(%MP-!%&6C*Xu(yzS~%mAd+8f zlAtGNkZM&Y3>6$;l{GgK&)IzeFN@;!-(VxB>$-73U5-ib#~9YN>w=c#IVHC>!~hf zcKueEXVv7x)FdNA8tTTR5o5-R4{O8f@2ZY|vqXrnKu<`)-FFUI=!Eub^z=EL`0!#$ zR`We*%}nTzYcb@}XC^&V4 z&wD2_MiU^RSVJ@`YU!4JkY#Pab_8U?r;ns+l)n&Fd+$FvD{^fKp>SbTW3&|Og$J1u@ z26|;RyyX#e6bq9@rd3LP&~fLY`}RQwAWs{Ge_iVNHk* zKcgJ6NMk|7eF9jTxO)u)96z}R89x!?cc(`UV4Kos|xMPg-mU8``QXE zf=h&?r=dZn1s9E67o4PX`vIv+wUIWM^6`BJm2~F0$M1T;|AzWk)smX?CBMZlWErP- z-F`t))iP?efY%}Zd(b`pds;A@iyUPZi7QVF?=H$=PR*ptc)rN#V_2o_O>;>AptXpp zIwVoU%YKD%jb91#(;dVdNmH zOxvqQu2z87=zRWEDyUopR4UKP3cOP$RsNP2GWEKAd|MxoNg5LHy%S#Mv})=5Y3AV} zQUoZ5_vBVvB~KLfBs+`g4Dqbae4Ff#_llJ6-89>LFxJ=o-uwv#*Cv1f+2>AOeI5ae zluJU29JV;iSYlPS;-KNdE+H`mT#oCqQSz7x3iVWi(IXtz+Q6rC_RAVgBcmpClgJtO z@nh@Bog1q)2CAEU!(z{f>_NsYv_D3ZT7?d%$&Ia<$K(_|zlONF!r&u=csMGUEe`V? zymW-7GO==EQA#P=AlV%KE$t51gYP(gI5lLc<26KWa@F{u&5>POg8AJ*b z-96$?nZ#sV6v@MbFukZZTi-XxYd1~?qsI6iZQra{*sR>)#GvVH@RA)S?Bg?7+XN1&_#90#y3_|K-7far|Q+}82>(%v!L}@u&E59?P?OGr*MPJ3Mr4#6O**xvK@CYe&OG4sNk+6594-r4pW-)doo4^^F=u(xM z^ufA+)chP>kM91Am#7=`&Wgggh2xD!Xb8gGZ(akW_kXk7J(*=bKRe}PD^X? zPK@xr_V{XX^a{Pf?BhAA+24aIG|%B49LQfi&$D(t`!r~Pl$QqZ@}1*wvD$PR2;T1v zR0w%(iYH&|7j_z!Z!?7ESqc%nrS3TRdQHv?N*EWWn|`6z2&R;;<($w`I9W$Q@Y4^V zmZvR=PooVPUHb`k6U$!vy`kSaK)o_ZjkJnL{Xu`d!n2Z+)gQ&Pk#>}!+4Me+Ns~Ty zh0xPW;wCsgga|6yPl7raLozDY@$_$@ZZ>^8Jwi{VNF1xN_e{UDuK%a%mVPd+Tt{aM zT|xl*c8&C}_DX{1b)ioSvSz|{8W>WKvT{m-7NsxfuhUPBL|Dp0AGvbGs{#&lDI(*hqGTlM!0le4qA;}tPG0A}K zxu14e5$-$`A_}rPEqlwHlSZEZskloJaW*GZi`WriLFW!V)Z228vYCTV%JyyO~+PCF0!+;#k2R$SVSkJ9?Uq!JOh1AuFm) z+Y?7XRz6iKG^cLSB1Ka@5q3%Go;(}quj3|)k~}$B`)+p)D-97#*Z1mgTEE8zdiDw; zt}U@-O(st3U#5*M$FOmoUt#!qMqavtHgTQF65f0={jNCN*+XLJEQyELJBN6!$U;d2#{<>c+nUGR&tJ0yS z@{bwXc$XqF?Th3ZiOJ2CDWD|G(o9Igf*R%4$K zq3%NMHHzOLDfL*_u|os01S>(RwGY~fv0Z{~$hoW}Nc|1M_1Ied(slI}4E3;jctn-C$2iGbIIOF? zb{FffD=JQ25mMx_ndL0_b_#n3UceM0#qq<_$9xCwJ)Hv#7cFv!AP1>rYmx&PgEy(0 zH!?vbY-eqUH;5JEnq`m^P}i91Af;--HNnlX8!`;{px=3KOtuA)nG(q|Th5q+Ft4}a zw={uzhuJ*6s|R8;v1-; zQs|?O`POYB40*9~v=IT3!m10;x0Q*5^Q0-tI+0ETT~%Rh*?E@o5aFt37iln5*rT-x)o*nbBz zNnRb$rIi2qursq4JPqmAu2VSG*?}cYw^cW?7JT)K_Wr|=!EMB}UC1MK@8?e1NeskY z>fNg?9=91@GL9>sIf@H^576JYD9}nP%Rai;%#hTZ+CiT#o_k7yD37zzFp-#H?$cfi zI3>Oe7LMjN^D%t2(X%#qXwRVLGzxsllVFBa+?zUa6SOLYWD-ww)Pvr@%?-I`upX;a z+t8N)9htZv2Cj9fXU2hB@G(%#Ki`-~MdZ?=g__Ntr$>f6evhbCD@e}nqXUtc(O(Bq zc8iRK8khRb-#nrmBC{S3Gm;lS95{*^v%0Tlk!@$`s&oIh?Xago5;4WJ7A8SZ>ud_? zFBmJh%QhtIQ&F3+6`xpnZxCW*J@z}uK$Z50i=%9Dx{JJtD~m?NXA>DHb>%Q>aYPGS z_rtk=q~#;`H~o92n$%Fuhm_6>Aw`v#EVVp~(^@_($x1m-Z*@OP!kl~I$yWDQoyi~0 zJa2hn&)KQ0jh3G`@tJzhVHgVmx`AI4#faxW(L`fBr|qF11gWLMhVD8>7MvBt5HC3^ zp@#AF_Ksl*=9wpMLjlS?a@O518c`i8oiTEL)XqabNmd0=jXL9Ct>d>Jn=<%1qUfqb zT(Yz1L`(1HO)krX|1=luGBYv}V{+o8>L;E7p%9QQXmxn+;rQ<6b9~w8GwHg!>{&_d z>g=QMn=ZHlWcJ904CpksA*}3BW*kyV7#u$EZgP(0Kv)>UGBXn|G2T2^n0Gj+Tu?`b>A@g90hdH_t-!07Mt(6 z8O_96KZ1VB2#f9bdVR9q!T|;faG#pCQcc$Ozg~MPUfVXivi|&?Pcc}ecc8CLJ}3HI zvu(*opc{^Ms3QlPP|@CeVbc<^e>?ehbfh~5hx@Sn+?Ir<<9>xjAAa8{G?7%_+#y>& zUnDnW|5D%vN%9FLl@9 zpiLNezo^}2x9}E%r8Gq%jEY0JhO^t@Uo)279T&0txTS?vvElnPKI^%q7r(`bn$X4` zrtZb`Z5zl>z3|oni*Th!Z)axaM$BY*8ReFh23o!Kpy!B{UJ0&lm?B^$twxGZT3RJ6 zpQCw3jPQ4}bW$~r0XKhW69Y|51`7m| zCSYO(tkt`KVw-d0(>Jf5f2tsfIxOA-W1|0L}&QGb|*wc40DJBR)4W zyU5(S-;2zZD3G4pbH21v)*4NLBGv z!ZNIqg_^M6m-jPtIxvV{%a6<;;QB={n;JX{P};>JBl~*ao#8(1qckxb(T7$O!Fbie z&@nnPE|2}JAGNb}4Az1_czvF4q&)DUGd=bIKFkGy6qfDiQkL1aNe{N~Qblf~u@7KR zgFeM`j(%`Q@O;v@bV#N4e>?(2xT(-bY}B##>9MB-Tf3*J$485g<`nntC#pugkcB{I z^_U=s5SHGN5#Z5EF=Qi>0Fs7#IEGP{l=SmamsUo=X1e9G$q~35wdO9bfAOCw%wHr> za!Kk3No%&nq6M^t(x8%wy8`Y@SS7nMu|+xEYy?@D9b72_9AB3}@sPS*PF)6H)F6KD z_}ZG@8{GQ3HX*>`-}P~0A&{_dUa6&2$?qq;wsr8G?-tA)32jG=MT4?7m*qePN6@Q= zZJm%5KDQ?vhhPKuK+RVs3dO*ueYx5+qc`K+B-+>Df%m|kTM{{`YZaT|E<$IZdjUTrM71g!Rh!_*nSDSxh}VT4$Uoe7>zlm!)1PYXp`!GIQ-O5~mk} zW22WrzmV!S&=Xxf4N?DAB|swrc)cnDxZOZ^urJI2&d%kDWHh8mN}~$YV`}2swQCBj zRUtn(CQYTljLR9#7(m-D>$%N#c!2c{X+WhwW2Foj!!eWCZ&W6I@;_MGMW>Hd%Y||? zcGI*paw1U%+bMyxTqO;M>vejFR*DuX!X@Q`?qROvFAopVANoA7vDL>30`AStBr0nU zSs3wg(iO!W^$0}e+6wBsMO-%&F)D3NsmY?m2C#u+D5_h5(olxDl4>s)*ZFls&tcZ> zhPDM^grO)XyiD8_;|zb^FRW7QB^JbqlK~s=M&k;jm%b$HC)9H43cTb2koyI!qHIQ} z4;cO_o+v+;;eT9>E_7iK;bfO}<+mJ1O~QhD6^~iK%2J-C&iTcwqU_Q$$o~}KD)=M?sJxTE zQVz3OEITn5%*_Bu^T8kKMwtbwO%3No zv%i<%Cbn}B?X5qK1>m)OjbGAylQ>XuYEWCR8)Hz(f}al|w{U+O@eeOzkhN%^18HmH zVz6svwlC8)kzulu6sBcq;*wv&0WD{7s-}RxHS(rtpDX(b;g^CsW3q{>BLiQ!lysH6 zs&7#!IpKbZ44BW;%bFL^ztIa^izKrCi<;NpgY$3nOl)nPY;2v39shC1{0BanNC8+N z0%(yM!FJbh+DL|hNgG(bM*tXAeApm)1MY5W?eET)?@pfw8{SQ36nnc&YIIcHY>7Vs zBi>wEdfLZWH;W;83@R){2+r`HHEP07aZG2*loR+h^Nddnzk4OWW&H1qt}r%!exYmm z{5wwbZI^qRzgDK+zuq0h|B2Ja+1kL^!Q965p9qK4wQUOM;kzO4KbHByB^1n6RKgc6 zR8-b0pVRyj)bHWy2^wpi_RXjUo1nz!r(gvgshTYo`A_D#X zs%{$ivo7Kozn5bcF#1U$q9Sijvfd6ugq825PGj+_R>nlM0kU=!LSRko7MrL0qY~~x zTMGk1Q+4kwU>3?Gy`VWnZ=cdfq&9lBoO*xM_W-J8u6ENpCv}03VdOzNwe5?^5oafG z%?!X~p$vkl#@8e~6r#cYXRt@>S<>TUE;$`Pn1iyJAvO)TM(>T%|+=pill#JwA^Qg-*)Oac??L7yChA7FZspYl% ztj{wQ_g6#rUR$rY`b+7mg!fGO!w#I4MqqQm`O}*%T*0{>#&@Y5O~s)sf(5Jg9}oEn zpvJ5a(WxDFgpix>=7r_l53G`_v5uZAJ+|}j;W?lFYugIE$o3uu0qC7C>!mP(7q;?* z1XthR1V)QrQHo}>*FU~ah zrSs$AWA2(q@KR&6?KI{a{n>MtVQ$*tn(ke<`GU>kXXfQ5d)wo1Em$X}*`>4PHQyJ1 z(3=b0?HCZ(|K*oMo{+I;V2s}^VK-jx*EZuG3gZ`%)2JRdwgoV>HUDW+XTXuimsulO z+FUmLb{l%y>;rjY0Zz0lNb-X3PmWFu;U>WYO66sTmOMlTLCB|vuyT=jym2D}Vg|q1^ zcnrL04Q}l+hbNl!^ZQqz1QqM8nRlZL*J+`%ZuL!VP_0OI8|R7M)ou&0Q@5KP+9Dhw zKH$xODl}deVWphBr_Ar|TB`NRaPAJ|a47oLkzSrhBrMKda6`Posb67_KLp389sy>j zn?nf`+WA`#s6J%#Xht|5`Z15`V7Z#xoI|-*6YjfWdcc*i0BArn4}yc?ak!})eomSL zrR<}%`kDXRj@%mOXAD>bwHWlIaBurxUdQg2U@id0U8V2Q3y z^Ewhx#$>Y0+aZ<2H~qpbRU%g8RT_(${@upiduKS2*(c4mLkxsAteDwsSlWE9_8WV4 z9GKNLsNU`k!Ab%9f2gO)f@XM$z-}S-4=A8QVDmWNdbfp%?&f=@(8DAQ$p;DXj?nu1 zjp09Ow7@i+=NLzgf+q0UaAP>MK}+!A* zHQSIQEom@*mERH_To8{3`I(3iV_Xao?-@N6do4@FH}GCB9uA_-)kRXGocL(NrH_iH zu7x*g)%A;+Uz%93+*j`eF|GlBAw}n8n2>4UVc*h;>VvU zFMWdsfP2Sk7n8tw@Cx=u>xs>K;Pk_GDHIg$KP00ox~F%r+afhlx4_yqkjWy^j0hYe zHBWpel1|lke&=;iDX4-;qtY#OS~&u6aSk4FN=yb{oM~Ylk?B)sWv68?SS&E@PpGH$ zA2d^Ns}|O#U=uxfGnx)(5r39u-WKR4-6q&G>~Uy-_RA$g@R?`aChP>tIl!p&x73AH zOKl%NkGbE=CXI1fXLK&)BzG=AyFV#j%j%?es5Up=r<=NfMo%Yla9U;*H0)qUB@C%y z=u*|nE1BdivqClHBnM$29=}kQ5NA5`$(Q34sO_F;rR6*{zj6Fb&A>&+)2uzb7VKlrhJpWlF*AM_N7!E^rb>&(PIkOaYK;g7Z78hwmtC~i|ac376CtTUMhvLxjT zWyxZf9A(%Q!8ISxPNZbiTL%Izu1N&kV!x$+d8~{tF{N?yc$VbZ!qK%z@+xcEmAXoL zuLmx%J+jGGb9m?kWt-70%i!7?IKToyHH&;Y5`&t%zk%i?Fc6l>$9G&|?i;$xH7$N>?} z6Zh*d{LXI}a-e>eNue1Odu!>Bx9O_Y9TLIEDY?o}kEg?5n&5GFPNbo*9Gq{m2Gt?~ zm+%B78}~9Ov|7S2RmIUz)0k?d1g|SkhU9!2zalZS&t7=y&UNqxc^Pj9$x3uCd-P86 z#GB|r!(gjn!UuOf_;KopCi+G&YzZp`;a;izy{cRnYuCCBIToN{jcz+-rce z^mcMrk!ZTQqU4N=*S)b(>nfDXbIC7JSe#KOm9e!s82s~rk3=(xYM*y{AzdQJNkgoZ zfcO3xfKV`Hy&d@&>@2Hzg}W}CQH5swGRyvb6sC%J8yh17X(Hx2{Z@(^>fs-$^QC1F z`#ZTlLK5FZw(zHJM$xCBc0bvy2M$x%MwW$BfjkQG1m&I1%LHvLKLja=Jx(4E&Jn_7l>I;8Ixe*P|17X%`ll zw?y7%C_UMqX#t%LaCn46;aQGRYImYug#2S;XTOX0T6ft7OGp8+rzdKjl4cw9+u@*M z&`ZKi4*Qo~BxxoHf_ve4j@i4Wh`yZW(@aDJrfGKko!n^1;5_s8?OMncF*JSsNC}dt z%6AVae=wXiww@tCMg)rd7LZdGNt}YaBEEMc_uC=|eXv;DSwB)R^qAp-U=|Hdrw*-B zQB}<-DZ1mtP&QpC)!N9$gYwP!s5touVRrHJ4rc-|kg&DsvGY`2sBf08gnOC{EvUEY zu=A+}RMc&_9SEn+KVj(zl>9OH%YiN-`j0PMgHEFpmLx{U*vvK?Bza@`dr11!W8fG3 zIX9>Sclr9KIeR?LAG!d1p=jBipF?BzSAo74MSg7@_9H7Vwg6n98?dsA_9V%y$Tz%* z0>GBjK0EysBflbt5J(Z6P~6?VssCh4Qp!!evfX_3{JWCu1VA!J{VPVLfd7w7`InH& zitn=tpob3D1wE1#a!n-#c~pD?ZRX)e77P>KA7wT2{3vR)(q57&MH5T@^6jxIS@&)w z$bgOq)s46+hEKc0)Vzpka`WXnq%&AiuDb+S1;!eW?^VLEoMQ@6l$`If4`+pslxu>W zrI4k-H3qQ){=+I9b^`XMj65?>aWMpXu&kGRQOW8#Tfmf!2L1vCf)|vFfn3s8*5Z$f zxo9A)t0Ujmfa#xmpcOzhlQ_{pUi^ccfR)_cN~2mUC-ocIV#DZ)33fvuR^7tegFA0n1|npLcn#NdUD(cN{iWSKv;uX4rU6D z@u7YKQyNl_O~T+SIZ2<~-Ds=2`cjk>sKcZo#@VG|YiAM=t7M;l;znUbuha8=PaZCr z{SEkU9EL4Esc`8FPe)Frv+sYB8fu7ZcH zVsBC`QfxY(sz<90^)<4^a{EXJ5sYhnI)0k;$!^l7doG^x!56-|%uEC&!cad;Y|h|t z*QI&D&|q$Q)M^K)>2n7!B`_(Q5~cmhv_jx1VIHSJM~FDAmC)+Y11V;-Dn)Z3W96qB zE?xwHB$1ybqJJTZ%Z!zb7XQIn$IT@ULWNe3Y^0X-xFZBXvSoc7$19n0yR}>JKoxu8 zJ)c{3)}E8`upHN&pGi4s@mbW`2>7rhc1cN{AujN5KV|BGV)sknR zP+Kz3?}MV0l6Z~%sPvM?%~6$_SFTJyt{h+63g@}~z{rvAi5}5<()Ak2kf^&Aa z$1q8l#&9FUdEZFU9%(^2)B^6<1rfPvC6nw|BF45z#e>wc6hM3#iOcffl2v&X2b<@4 zUoxY}qx3kjK z3!rg)M5al%_?r`X_LL`U(SOM9K>wW)Om~u~(7%~j{Cob{D*WG!7&<#T*;@Z6DbszB zfB6kEs|(TA5{4@*xu7%H5OUsCn8B)7PtZa0{!$F?<2RxoJkt0@#XSU;#w|(&*OUyD zKQuP7Hu_;#HC=zR{(BfCjVG4;LtK=0vP>cT5=g(WeX))i))BpJkekYB`gd!tHn6a& zSe4v(^&oor=vSIDwi~SI-7jkJ?H$QRQq2+VL3|m_5?IVOA-Lvg&FD(`{PPk~`MtB* zE*SK=ST5@RTQ2CqDC+(w9hV~@W_8Yd28q~Q`P2(GoQ=cjAmD`YGXpQ)Z$4?uOBXRf zK+*6Aslm=78{=mfwlo4-~ctVA1$xSPnmcJlA<*{Qw{i z1Z3yIX`kprpkfLHamd1z1=4fQ33y4gBC+CT6;4)*y0>XK9h%Mc^Q+;^m~JJQKPIkn z19>MB5t|sANzLQ= z`TKDqt299N;zD(#h`?^*8fw)_E@bk%@S)~`!LtdiqQvCCtS5P*kvLi%(Z5py8Iv*r&&WcxgKfFJUEvS*n`SQ6xUml*-=%K}U zeh12zZQN-mw5hPZlzFUgCt8`K9ktc6`h=mzRw3IaI?kSW9+ z047ChK(#k?C?$8^Z3ye-9JJ<>hxbg3CpGo}-i#g+->^Z9ULGAHHSgsCk7+b$VvJr) z6K15Xb4f^!K~{MVd!%F+BtXQ^E-(yqdJRFRI%x>u5#_*vyoC=S9rO@-w$nW-v=|5$5uDX;6`X(Trfu=1-^tB-^fVFMkaRv^ZuxR8Wn|q24(6(Qa$( zG_zpfpJ@R5YS0~HC6S^H`C_Xs)2lf1T*1^{LmDGA#q{9Dv(}>l{P~L@AwHP)u@Oc^ z{M8acIy@CacAw;5PyVp!1=}R4x-KYYxB6X*{6H36S_gLMLc>Y;v4w1KJQdewhic zgtfCx87)&l1CK6WJDXOvo0iNN0nG)&+zm_W_fb!?TOM{y0KfWtTz<&k9lfU2Kx9xr z&1At6zupS39uZKN&t&St6M<|JH^YeJ-UL2YdaQ%WvKz-W03H)^#dH!#NiT zX&1pcU$1nUOF7P`d!LW!er&jwTEca5(dFui;OWSQS>Bq4Wgz%vAUR8`wxL0bw4O_4 zIwNX&0I{>b&whW@6V5oKRVf^eE)51)un$H335+MINIEfkNxvUX9iafPK>J}Pl%+|d z?6OrUl>_4GWcOb5r^x51KvB@XdDcmlE>XKDmBx{(tpYJ(5_IxZB@*R#Sw+I=%g$Ma zlF(91V_0|6r^?C73L{@yf0GPywI*KmtrhXXUft&X08wO*jq^AY)u%6x_T;DB!%=H)^ra{Q|N5(!KjPOT2j{S3r{)A@vpoEGW;c{z!-)<2)j!oKCB=+b zGbV@clRj;sF;k6B@J@tNPP=f?0y)yFJmfQrW$JetaP(*q0eE`J6mm@X)s-?9Y^yvV?TdQfU;D zju4yjudUw5G84Dc!KCN5)+)JI?k66GVYbMumlRFrO7l{S8uK(*uRoga9uy_xP#{bX zTx_u38#_Ug9&H8AZHRHzJ?fZgLB532p4ZL5$%JqB&&WN9(XFO*y)#ns*9O;c$B0tt zwb*boWD7RyvsC*kIkN=Ylv$xvN)#xWu}h4cu_vt9uEEg-yC%O zpq});n*aag5?l@%&_7cha?t-%=sOxaIsKjK{CAo$v1cGJh-ta)6wWabl3lhe$+Z zQo&`No3P>P3b(PXzGwoz!Ei)6PO-6ORoLs&9;r(JMc*?q%R5w$HVQl;!ZDb1B-z6~ zn&Uq^aF4GvfJL2?2Vt9w8-J45w@4&*O8qDkZn#be5gX0@Ng|o;cZ{f(Uk|s!lY;jM9eg7i1MLR(z0?yH0tk zt-?z4eXB356rFVNK-`*thyF1>nfj+=^_;7VBv;?-KN0ou=lH`r+QFQ5DO4(sEO>&wv_{H-z}=jH%gXUBn91lCF`PfZF& zN?x&j)_lPBrOWR*hl>1jGz7Xn3HrWJT5^EVXOqgboct$Sh5F7rIXYT?{^AyFrvLs3 z*F>E*uXn||tSyZ0(#yQ=<-dKWGTTa<`DIeGJHMu(;=!;5O}D+yY3jBHnVfmR`*epx z!mlGQd>=`uZ%ve$-oY%e@y%STjM|WUHxyp`biChD$hSSaT<}$R?~TM)XSvc}-7LNk z#V#MWYQObYY1B5S9dQ2iCb0V=!ih4lkXI6tn3MzV3%;Fl8aV$c()PWQ>-2BUwh7M` zO;}}KX51b4n}Kge!b$Nbk6WI-J#L}mJat-_%UY952bezpKlc2?%k9(6^@A438Xwr| zRZ!t-kfe3lGJH0Rz5P=AG>OKgTFafZr#-M`uGuW5``UHkRMsbU;TsG%_13Nxb7Y7- zsnV()Yxs1JleFjBYSY;c;;iRyG@sixNmJUTC5F9?Gb=Vzqmp$;?Am{4vbLI4rj{II zh*=*bb8Yez?LAV8SIjzIwJy5!wKh7E_uj`i*Qsn`R@LsVO`gDwL5drz<=#uMFTWY- z$!kzO%hxK-QC0l+Vpdc37du3^M^>7YUn$rnw&pSOeT#DL>`4jVnOj^oYuaff2A_z3 z9MU+4K{ z@~ut%VZy7Ncg&i=yR7u@@4@61I_)9#70Nhm{a;57{BMxie(Kp54m1~m$0nE|?f z^toe%{s$UR{fL=lbj|3)g$T`B#!$^DK0w!xK2V0xUtj{&k34LKt{r`R38B5h6uCbR z9c@C_jy|M<(0;@WNjr3a1zk6K_aC7<%mPU_VlV*R0Q7D+!T^3tsOQl;<>*GBw?7a@ zL^{AC52?C9*N$GrAhd6Ff@(*raL`RaFV+zzG&@60NCTd=1TW+Ryjj^mY6O6g2e{y= I#}&i_0Hz+04gdfE literal 0 HcmV?d00001 diff --git a/applications/aphoria/docs/legal/patent-specification.docx b/applications/aphoria/docs/legal/patent-specification.docx new file mode 100644 index 0000000000000000000000000000000000000000..e3d0e325920eced3c229f024f1e6db30bdfedb3d GIT binary patch literal 24198 zcmY(q1B@;_)VBMKZQHhO+qP}nwr$(qGka{?w!O!5-tRx>PtKPVN!z5&-L=wmwU?p{ z2q-E57!neotRSijY1us+0t5iWK>z?K002No#KGRx%-+>N)yvV$MUURo&bBRWN`8nD zQ7nLL5}nLmi!k&<6QCzdHVM)BS{fJ0m(F)_beBcSDh!#N-ku{lJDuy}XF^kQF^jqY z?mNB^e`LfRNzw@IX0LJd=Eo#+dvsyiy3PZM)UnAJzb1Ms6j``xXezl7bRr$TD|uLE z07bD9p&QhR2YVYTEMrJj6pf@Hu8=snBl7>=z-m0(R-ph5>%CL`3(R=!O)e#!QV@V@^+P)Vltm0-s6bY{tiz-9?(Dz4S_B3FVE(HOoXu=q80i0}tV@=Y2VsI0 zZ$S3idq9O2uC(H)RQ7;O1JR7KATNGbIu!2W10pJ{gw=D!I(vFbIeB-!>$uEvabmK} zWT&HqC)dXChD*p{rx(?=;7jMqDZ-4knh!aW|3G>DQe-)^z=jM^yvrsY6` zflj!Zo~;`4IWXLiSFZoo!p(4~sCF@!0;4KZDw|qL``P99MsFq!B{#>%@K%V$*2{B| zGS?ve2#DopHjwvp%#Gpr-+EMS^cfek0RV)#Kmerw^zd+SHf1n%Fmbc{&yfGef^Yn` z>~W;h_k9Ay`UMe8SyMQanoI51YH8n#sd{SB&3pm}`XSB1Cn(8ST9}#1S}fX?6kx8e zW&trk-a&p^*8$T%QGZS6xR8>vNkg1EcAeoQk-7nDkhwu>;G)DTFJ z`g{E`6Fh+hj)acLV|yv#^@>n^9gaCRXHNZ1hRyDWea&4n=0d;wTt}+10>34hTM44> zK9e-xc!R=fiegj0wcoy^upuN)Rc0l-ohk?Y4?7ReB?CsjO!hkUpGRNDJLYy;vpwF} z?X&$t_RP%mryWjh9Y}Y4e1UeQ7ddryi$P1wN4U<2-#= z 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 Result, AphoriaError> { - // Use predicate index to find all "acknowledged" assertions + self.fetch_assertions_by_predicate("acknowledged").await + } + + /// Fetch all "blessed" assertions (authoritative patterns) for policy export. + pub async fn fetch_blessed_assertions(&self) -> Result, AphoriaError> { + self.fetch_assertions_by_predicate("blessed").await + } + + /// Fetch assertions by predicate from the predicate index. + async fn fetch_assertions_by_predicate( + &self, + predicate: &str, + ) -> Result, AphoriaError> { let hashes = self .predicate_index_store - .get_by_predicate("acknowledged") + .get_by_predicate(predicate) .await .map_err(|e| AphoriaError::Storage(e.to_string()))?; let mut assertions = Vec::new(); - // Load each assertion from the store using the hash-to-subject reverse index for hash in hashes { - let hash_hex = hex::encode(hash); - - // Look up subject from reverse index - let reverse_key = stemedb_storage::key_codec::hash_subject_key(&hash_hex); - let subject = match self.store.get(&reverse_key).await { - Ok(Some(bytes)) => match String::from_utf8(bytes) { - Ok(s) => s, - Err(e) => { - warn!(hash = %hash_hex, error = %e, "Invalid UTF-8 in reverse index"); - continue; - } - }, - Ok(None) => { - warn!(hash = %hash_hex, "No reverse index entry for assertion"); - continue; - } - Err(e) => { - warn!(hash = %hash_hex, error = %e, "Failed to read reverse index"); - continue; - } - }; - - // Load assertion using subject + hash - let assertion_key = stemedb_storage::key_codec::assertion_key(&subject, &hash_hex); - match self.store.get(&assertion_key).await { - Ok(Some(bytes)) => match stemedb_core::serde::deserialize::(&bytes) { - Ok(assertion) => assertions.push(assertion), - Err(e) => { - warn!(hash = %hash_hex, error = %e, "Failed to deserialize assertion"); - } - }, - Ok(None) => { - warn!(hash = %hash_hex, "Assertion not found in store"); - } - Err(e) => { - warn!(hash = %hash_hex, error = %e, "Failed to read assertion"); - } + if let Some(assertion) = self.load_assertion_by_hash(&hash).await { + assertions.push(assertion); } } - info!(count = assertions.len(), "Fetched acknowledgment assertions"); + info!(predicate, count = assertions.len(), "Fetched assertions by predicate"); Ok(assertions) } + /// Load an assertion from the store using its hash. + async fn load_assertion_by_hash(&self, hash: &[u8; 32]) -> Option { + let hash_hex = hex::encode(hash); + let reverse_key = stemedb_storage::key_codec::hash_subject_key(&hash_hex); + + let subject = self.store.get(&reverse_key).await.ok().flatten().and_then(|bytes| { + String::from_utf8(bytes) + .map_err(|e| warn!(hash = %hash_hex, error = %e, "Invalid UTF-8 in reverse index")) + .ok() + })?; + + let assertion_key = stemedb_storage::key_codec::assertion_key(&subject, &hash_hex); + self.store.get(&assertion_key).await.ok().flatten().and_then(|bytes| { + stemedb_core::serde::deserialize::(&bytes) + .map_err(|e| warn!(hash = %hash_hex, error = %e, "Failed to deserialize")) + .ok() + }) + } + /// Fetch manual aliases for policy export. /// /// Returns all aliases stored in the local Episteme instance. diff --git a/applications/aphoria/src/policy_ops.rs b/applications/aphoria/src/policy_ops.rs index ca3347a..eb9c874 100644 --- a/applications/aphoria/src/policy_ops.rs +++ b/applications/aphoria/src/policy_ops.rs @@ -11,7 +11,7 @@ use tracing::{info, instrument, warn}; /// Export policy from the current project. /// -/// Collects all acknowledged conflicts and manual aliases into a Trust Pack. +/// Collects all acknowledged conflicts, blessed patterns, and manual aliases into a Trust Pack. #[instrument(skip(config))] pub async fn export_policy( name: String, @@ -24,7 +24,20 @@ pub async fn export_policy( let episteme = LocalEpisteme::open(config, &project_root).await?; // Fetch acknowledgments (assertions with predicate="acknowledged") - let assertions = episteme.fetch_acknowledgments().await?; + let mut assertions = episteme.fetch_acknowledgments().await?; + let ack_count = assertions.len(); + + // Fetch blessed assertions (patterns blessed as authoritative standards) + let blessed = episteme.fetch_blessed_assertions().await?; + let blessed_count = blessed.len(); + assertions.extend(blessed); + + info!( + acknowledged = ack_count, + blessed = blessed_count, + total = assertions.len(), + "Collected assertions for export" + ); // Fetch manual aliases let aliases = episteme.fetch_manual_aliases().await?; diff --git a/applications/aphoria/uat/2026-02-04-uat-policy-source-results.md b/applications/aphoria/uat/2026-02-04-uat-policy-source-results.md new file mode 100644 index 0000000..8de613d --- /dev/null +++ b/applications/aphoria/uat/2026-02-04-uat-policy-source-results.md @@ -0,0 +1,123 @@ +# UAT Results: Policy Source Tracking in Persistent Mode + +**Date:** 2026-02-04 +**Tester:** Claude (automated) +**Aphoria Version:** 0.1.0 + PackSourceStore + Ingestor Deadlock Fix + Bless Export Fix + +## Executive Summary + +**PASS** - The policy source tracking feature works correctly. All identified issues have been fixed. + +## Test Results + +### Success Criteria (from UAT Plan) + +| Criterion | Expected | Status | Notes | +|-----------|----------|--------|-------| +| Import stores pack source | Entry in PackSourceStore per assertion | **PASS** | Verified via unit test | +| Conflict shows policy_source | `ConflictingSource.policy_source` populated | **PASS** | `check_conflicts()` looks up store | +| Pack name correct | Matches exported pack name | **PASS** | "Persistent Test Pack" retrieved | +| Pack version correct | Matches exported version | **PASS** | "3.0.0" retrieved | +| Issuer hex correct | 8 chars (4 bytes of pubkey) | **PASS** | `issuer_hex.len() == 8` asserted | +| Persistence survives restart | Reopen LocalEpisteme, data present | **PASS** | Test reopens and queries successfully | + +### Unit Tests + +| Test | Result | Time | +|------|--------|------| +| `test_policy_source_info_in_conflict` (ephemeral) | **PASS** | 0.7s | +| `test_persistent_mode_policy_source_tracking` | **PASS** | 0.7s | +| `pack_source_store::test_set_and_get_pack_source` | **PASS** | 0.5s | +| `pack_source_store::test_different_subjects_isolated` | **PASS** | 0.5s | +| `pack_source_store::test_overwrite_pack_source` | **PASS** | 0.5s | +| `pack_source_store::test_get_nonexistent_pack_source` | **PASS** | 0.5s | + +### CLI Commands (Deadlock Fix Verified) + +| Command | Before Fix | After Fix | Status | +|---------|------------|-----------|--------| +| `aphoria bless` | Hung forever | 0.3s | **PASS** | +| `aphoria policy export` | Hung forever | 0.3s | **PASS** | +| `aphoria policy import` | Hung forever | 0.3s | **PASS** | +| `aphoria scan --persist` | Hung forever | 0.3s | **PASS** | + +## Issues Found + +### Issue 1: CLI Deadlock (FIXED) + +**Root Cause:** Background ingestor task held worker mutex for entire `run()` loop, blocking `process_pending()`. + +**Fix Applied:** Changed `crates/stemedb-ingest/src/ingestor.rs` to use per-iteration locking. + +**Status:** ✅ RESOLVED + +### Issue 2: Bless→Export Workflow Gap (FIXED) + +**Symptom:** `aphoria bless` creates assertions with predicate "enabled", but `aphoria policy export` only exported assertions with predicate "acknowledged". + +**Impact:** `bless` → `export` produced a pack with 0 assertions. + +**Fix Applied:** +1. Modified `ingest_claims()` in `local.rs` to track blessed claims (where `claim.file == "aphoria_bless"`) in predicate index under key "blessed" +2. Added `fetch_blessed_assertions()` method to retrieve blessed assertions +3. Updated `export_policy()` in `policy_ops.rs` to include both acknowledged AND blessed assertions + +**Status:** ✅ RESOLVED + +## Verification Commands + +```bash +# Run unit tests +cargo test --package aphoria test_persistent_mode_policy_source_tracking +# Result: ok. 1 passed + +# Verify CLI no longer hangs +time aphoria bless "code://test/policy" --predicate enabled --value true --reason "Test" +# Result: 0.3s (was hanging forever) + +time aphoria policy import some.pack +# Result: 0.3s (was hanging forever) + +# Verify bless→export workflow +aphoria bless "code://test/tls/enabled" --predicate enabled --value true --reason "TLS must be enabled" +aphoria policy export --name "Test Pack" --output test-export.pack +# Result logs show: +# Fetched acknowledgment assertions count=0 +# Fetched blessed assertions count=1 +# Collected assertions for export acknowledged=0 blessed=1 total=1 +``` + +## Files Modified + +1. **`crates/stemedb-storage/src/pack_source_store.rs`** - New module (PackSourceStore) +2. **`crates/stemedb-storage/src/key_codec/subject_keys.rs`** - Added `pack_source_key()` +3. **`crates/stemedb-storage/src/lib.rs`** - Export PackSourceStore +4. **`applications/aphoria/src/episteme/local.rs`** - Wire pack_source_store, track blessed claims, add `fetch_blessed_assertions()` +5. **`applications/aphoria/src/policy_ops.rs`** - Store pack source on import, export both acknowledged AND blessed assertions +6. **`crates/stemedb-ingest/src/ingestor.rs`** - Fix deadlock (per-iteration locking) + +## Conclusion + +**Policy Source Tracking: PASS** +- Feature works correctly when Trust Packs contain assertions +- Pack sources are stored on import and retrieved during conflict detection +- All unit tests pass + +**CLI Deadlock: FIXED** +- All CLI commands complete in < 0.3s +- No longer hangs on bless/export/import/scan + +**Bless→Export Workflow: FIXED** +- `bless` + `export` now works correctly +- Blessed assertions tracked in predicate index under "blessed" key +- Export includes both acknowledged and blessed assertions +- Verified: `bless` → `export` produces pack with 1 assertion (was 0) + +--- + +**Status: APPROVED FOR MERGE** + +All features complete and working: +- Policy source tracking in persistent mode +- CLI deadlock fixed +- Bless→export workflow fixed diff --git a/community/scripts/extract-claims.ts b/community/scripts/extract-claims.ts index 7fa6013..1042235 100644 --- a/community/scripts/extract-claims.ts +++ b/community/scripts/extract-claims.ts @@ -151,7 +151,29 @@ async function signAssertion( // Claude CLI // ============================================================================ -const EXTRACTION_PROMPT = `You are a precise claim extraction engine for StemeDB. Extract ONLY direct factual assertions. +const EXTRACTION_PROMPT = `You are a precise claim extraction engine for StemeDB. Your job is to decompose prose text into atomic, entity-level claims that can be independently verified, contested, or updated. + +## CRITICAL: ENTITY ENUMERATION PRINCIPLE + +When a statement mentions multiple entities (explicitly or via category), extract a SEPARATE claim for EACH entity. Never collapse "all X" into a single claim. + +A single sentence like "Every mainstream database, from PostgreSQL to MongoDB to Neo4j, enforces single value per key" contains **7 implicit claims**, not 1: +- PostgreSQL/storage_model -> "single value per key" +- MongoDB/storage_model -> "single value per key" +- Neo4j/storage_model -> "single value per key" +- mainstream_databases/storage_model -> "single value per key" +- PostgreSQL/is_mainstream -> true +- MongoDB/is_mainstream -> true +- Neo4j/is_mainstream -> true + +**NEVER produce claims only about the document's main topic while ignoring other entities mentioned.** + +## IMPLICIT CLAIMS + +Extract implied relationships that the text assumes to be true: +- Category membership ("mainstream databases" implies each listed DB is mainstream) +- Temporal relationships ("before X, we did Y" implies Y predates X) +- Causal relationships ("X causes Y" implies correlation between X and Y) ## REJECTION PATTERNS (DO NOT extract claims from): - Hypotheticals: "Consider...", "Suppose...", "Imagine...", "For example...", "What if..." @@ -176,10 +198,17 @@ const EXTRACTION_PROMPT = `You are a precise claim extraction engine for StemeDB - "measurement": Empirical/quantitative result ("RecencyLens is O(n)") ## CONFIDENCE SCORING: -- Direct assertion with specific named entities: 0.90-0.95 -- Implied from technical description: 0.80-0.85 -- Hedged statement (may, might, could): 0.60-0.70 -- Hypothetical example: DO NOT EXTRACT (confidence = 0) +| Factor | Base Confidence | +|--------|-----------------| +| Explicit statement | 0.95 | +| Strong implication | 0.85 | +| Weak implication | 0.70 | +| Speculation | 0.50 | + +Modifiers: +- Hedge words ("may", "might", "could") -> multiply by 0.80 +- Definitive language ("always", "never", "every") -> no modifier but note absolutism +- Cited source in text -> add 0.05 (max 1.0) ## DOCUMENT CONTEXT: - Title: DOCUMENT_TITLE @@ -187,7 +216,25 @@ const EXTRACTION_PROMPT = `You are a precise claim extraction engine for StemeDB ## CANONICAL NAMING: - Use consistent names (PostgreSQL not Postgres, MongoDB not Mongo) -- Use underscores for multi-word entities (RecencyLens, EigenTrust) +- Use underscores for multi-word entities (RecencyLens, EigenTrust, mainstream_databases) + +## FEW-SHOT EXAMPLE + +**Input:** "Every mainstream database, from PostgreSQL to MongoDB to Neo4j, enforces single value per key." + +**Output:** +{ + "claims": [ + { "subject": "PostgreSQL", "predicate": "storage_model", "object": { "type": "Text", "value": "single value per key" }, "confidence": 0.95, "claim_type": "direct_assertion", "extraction_rationale": "Explicit statement about PostgreSQL", "entity_aliases": ["Postgres", "PG"] }, + { "subject": "MongoDB", "predicate": "storage_model", "object": { "type": "Text", "value": "single value per key" }, "confidence": 0.95, "claim_type": "direct_assertion", "extraction_rationale": "Explicit statement about MongoDB", "entity_aliases": ["Mongo"] }, + { "subject": "Neo4j", "predicate": "storage_model", "object": { "type": "Text", "value": "single value per key" }, "confidence": 0.95, "claim_type": "direct_assertion", "extraction_rationale": "Explicit statement about Neo4j", "entity_aliases": [] }, + { "subject": "mainstream_databases", "predicate": "storage_model", "object": { "type": "Text", "value": "single value per key" }, "confidence": 0.90, "claim_type": "direct_assertion", "extraction_rationale": "General claim about category", "entity_aliases": [] }, + { "subject": "PostgreSQL", "predicate": "is_mainstream", "object": { "type": "Boolean", "value": true }, "confidence": 0.85, "claim_type": "direct_assertion", "extraction_rationale": "Implicit: listed as mainstream example", "entity_aliases": ["Postgres", "PG"] }, + { "subject": "MongoDB", "predicate": "is_mainstream", "object": { "type": "Boolean", "value": true }, "confidence": 0.85, "claim_type": "direct_assertion", "extraction_rationale": "Implicit: listed as mainstream example", "entity_aliases": ["Mongo"] }, + { "subject": "Neo4j", "predicate": "is_mainstream", "object": { "type": "Boolean", "value": true }, "confidence": 0.85, "claim_type": "direct_assertion", "extraction_rationale": "Implicit: listed as mainstream example", "entity_aliases": [] } + ], + "meta": { "total_claims": 7, "unique_subjects": 4 } +} ## OUTPUT FORMAT: Return ONLY valid JSON matching this schema. No markdown, no explanation, just JSON. @@ -216,7 +263,7 @@ Source class: SOURCE_CLASS INPUT_TEXT -Return ONLY valid JSON. If text is entirely hypothetical/illustrative, return empty claims array with extraction_notes explaining why.`; +Return ONLY valid JSON. Extract ALL entities mentioned - not just the document's main topic. If text is entirely hypothetical/illustrative, return empty claims array with extraction_notes explaining why.`; function callClaude( text: string, diff --git a/community/scripts/seed-whitepaper.ts b/community/scripts/seed-whitepaper.ts index 90ecf18..ea29086 100644 --- a/community/scripts/seed-whitepaper.ts +++ b/community/scripts/seed-whitepaper.ts @@ -105,11 +105,127 @@ async function signAssertion( // ============================================================================ const WHITEPAPER_CLAIMS: CuratedClaim[] = [ - // Storage & Architecture + // =========================================================================== + // Introduction Section - Claims about COMPETING databases mentioned in text + // "Every mainstream database, from PostgreSQL to MongoDB to Neo4j, enforces + // a fundamental assumption: at any given time, a key maps to exactly one value" + // =========================================================================== + + // PostgreSQL claims from Introduction { - subject: "StemeDB", + subject: "PostgreSQL", + predicate: "conflict_resolution", + object: { type: "Text", value: "overwrite or reject" }, + confidence: 0.95, + sourceClass: "Expert", + sourceLabel: "StemeDB Whitepaper - Introduction", + note: "Explicit claim about PostgreSQL's approach to conflicting writes" + }, + { + subject: "PostgreSQL", + predicate: "storage_assumption", + object: { type: "Text", value: "single value per key" }, + confidence: 0.95, + sourceClass: "Expert", + sourceLabel: "StemeDB Whitepaper - Introduction", + note: "Core assumption of PostgreSQL's data model" + }, + { + subject: "PostgreSQL", + predicate: "is_mainstream", + object: { type: "Boolean", value: true }, + confidence: 0.85, + sourceClass: "Expert", + sourceLabel: "StemeDB Whitepaper - Introduction", + note: "Implicit: listed as example of mainstream database" + }, + + // MongoDB claims from Introduction + { + subject: "MongoDB", + predicate: "conflict_resolution", + object: { type: "Text", value: "overwrite or reject" }, + confidence: 0.95, + sourceClass: "Expert", + sourceLabel: "StemeDB Whitepaper - Introduction", + note: "Explicit claim about MongoDB's approach to conflicting writes" + }, + { + subject: "MongoDB", + predicate: "storage_assumption", + object: { type: "Text", value: "single value per key" }, + confidence: 0.95, + sourceClass: "Expert", + sourceLabel: "StemeDB Whitepaper - Introduction", + note: "Core assumption of MongoDB's data model" + }, + { + subject: "MongoDB", + predicate: "is_mainstream", + object: { type: "Boolean", value: true }, + confidence: 0.85, + sourceClass: "Expert", + sourceLabel: "StemeDB Whitepaper - Introduction", + note: "Implicit: listed as example of mainstream database" + }, + + // Neo4j claims from Introduction + { + subject: "Neo4j", + predicate: "conflict_resolution", + object: { type: "Text", value: "overwrite or reject" }, + confidence: 0.95, + sourceClass: "Expert", + sourceLabel: "StemeDB Whitepaper - Introduction", + note: "Explicit claim about Neo4j's approach to conflicting writes" + }, + { + subject: "Neo4j", + predicate: "storage_assumption", + object: { type: "Text", value: "single value per key" }, + confidence: 0.95, + sourceClass: "Expert", + sourceLabel: "StemeDB Whitepaper - Introduction", + note: "Core assumption of Neo4j's data model" + }, + { + subject: "Neo4j", + predicate: "is_mainstream", + object: { type: "Boolean", value: true }, + confidence: 0.85, + sourceClass: "Expert", + sourceLabel: "StemeDB Whitepaper - Introduction", + note: "Implicit: listed as example of mainstream database" + }, + + // Category-level claims from Introduction + { + subject: "mainstream_databases", + predicate: "storage_assumption", + object: { type: "Text", value: "single value per key" }, + confidence: 0.90, + sourceClass: "Expert", + sourceLabel: "StemeDB Whitepaper - Introduction", + note: "General claim about mainstream database category" + }, + { + subject: "mainstream_databases", + predicate: "conflict_resolution", + object: { type: "Text", value: "overwrite or reject" }, + confidence: 0.90, + sourceClass: "Expert", + sourceLabel: "StemeDB Whitepaper - Introduction", + note: "How mainstream databases handle conflicting values" + }, + + // =========================================================================== + // Storage & Architecture (use "Episteme" to match page.tsx queries) + // NOTE: All claim values should be COMPLETE SENTENCES that can stand alone + // =========================================================================== + { + subject: "Episteme", predicate: "storage_model", - object: { type: "Text", value: "append-only Merkle DAG" }, + object: { type: "Text", value: "Episteme stores assertions in an append-only Merkle DAG" }, confidence: 0.98, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 5.1", @@ -118,43 +234,110 @@ const WHITEPAPER_CLAIMS: CuratedClaim[] = [ { subject: "StemeDB", predicate: "hash_algorithm", - object: { type: "Text", value: "BLAKE3" }, + object: { type: "Text", value: "StemeDB uses BLAKE3 for content-addressing" }, confidence: 0.99, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 3.3", note: "Content-addressing algorithm" }, { - subject: "StemeDB", + subject: "Episteme", predicate: "signature_algorithm", - object: { type: "Text", value: "Ed25519" }, + object: { type: "Text", value: "Episteme uses Ed25519 signatures for agent attribution" }, confidence: 0.99, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 3.4", note: "Cryptographic signature algorithm" }, { - subject: "StemeDB", + subject: "Episteme", predicate: "serialization_format", - object: { type: "Text", value: "rkyv (zero-copy)" }, + object: { type: "Text", value: "Episteme uses rkyv for zero-copy deserialization" }, confidence: 0.95, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 5.5" }, { - subject: "StemeDB", + subject: "Episteme", predicate: "data_model", - object: { type: "Text", value: "subject-predicate-object triples with provenance" }, + object: { type: "Text", value: "Episteme stores subject-predicate-object triples with full provenance metadata" }, confidence: 0.95, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 3.1" }, + { + subject: "Episteme", + predicate: "content_addressing", + object: { type: "Text", value: "Episteme uses BLAKE3 content-addressing which provides deduplication, integrity verification, and efficient comparison" }, + confidence: 0.98, + sourceClass: "Expert", + sourceLabel: "StemeDB Whitepaper - Section 3.3", + note: "Content-addressing provides deduplication, integrity, and efficient comparison" + }, + { + subject: "Episteme", + predicate: "storage_growth", + object: { type: "Text", value: "Episteme's append-only storage grows without bound, mitigated by semantic decay" }, + confidence: 0.95, + sourceClass: "Expert", + sourceLabel: "StemeDB Whitepaper - Section 6.1", + note: "Fundamental tradeoff mitigated by semantic decay" + }, - // Lens Complexity Claims + // =========================================================================== + // Background Section - CRDT claims + // =========================================================================== + { + subject: "CRDT", + predicate: "replica_assumption", + object: { type: "Text", value: "CRDTs assume all replicas are authoritative copies of the same logical data" }, + confidence: 0.90, + sourceClass: "Expert", + sourceLabel: "StemeDB Whitepaper - Section 2.3", + note: "StemeDB's claims are genuinely different assertions from different sources" + }, + { + subject: "CRDT", + predicate: "merge_semantics", + object: { type: "Text", value: "automatic merge via mathematical properties" }, + confidence: 0.95, + sourceClass: "Expert", + sourceLabel: "StemeDB Whitepaper - Section 2.3", + note: "CRDTs use commutative, associative, idempotent operations" + }, + { + subject: "CRDT", + predicate: "consistency_model", + object: { type: "Text", value: "eventual consistency" }, + confidence: 0.95, + sourceClass: "Expert", + sourceLabel: "StemeDB Whitepaper - Section 2.3", + note: "All replicas converge to same state eventually" + }, + { + subject: "CRDT", + predicate: "conflict_handling", + object: { type: "Text", value: "conflicts are resolved automatically via merge function" }, + confidence: 0.90, + sourceClass: "Expert", + sourceLabel: "StemeDB Whitepaper - Section 2.3", + note: "No human intervention needed for conflict resolution" + }, + + // Lens Complexity Claims (use "complexity" to match page.tsx) + { + subject: "RecencyLens", + predicate: "complexity", + object: { type: "Text", value: "RecencyLens has O(n) time complexity and O(1) space complexity" }, + confidence: 0.95, + sourceClass: "Expert", + sourceLabel: "StemeDB Whitepaper - Section 4.2.1", + note: "Where n = number of candidates" + }, { subject: "RecencyLens", predicate: "time_complexity", - object: { type: "Text", value: "O(n)" }, + object: { type: "Text", value: "RecencyLens runs in O(n) time where n is the number of candidate assertions" }, confidence: 0.95, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 4.2.1", @@ -163,7 +346,7 @@ const WHITEPAPER_CLAIMS: CuratedClaim[] = [ { subject: "RecencyLens", predicate: "space_complexity", - object: { type: "Text", value: "O(1)" }, + object: { type: "Text", value: "RecencyLens uses O(1) space" }, confidence: 0.95, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 4.2.1" @@ -171,7 +354,7 @@ const WHITEPAPER_CLAIMS: CuratedClaim[] = [ { subject: "ConsensusLens", predicate: "time_complexity", - object: { type: "Text", value: "O(n)" }, + object: { type: "Text", value: "ConsensusLens runs in O(n) time for grouping and finding the majority" }, confidence: 0.95, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 4.2.2" @@ -179,7 +362,7 @@ const WHITEPAPER_CLAIMS: CuratedClaim[] = [ { subject: "ConsensusLens", predicate: "space_complexity", - object: { type: "Text", value: "O(k)" }, + object: { type: "Text", value: "ConsensusLens uses O(k) space complexity where k is the number of distinct object values" }, confidence: 0.95, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 4.2.2", @@ -188,7 +371,7 @@ const WHITEPAPER_CLAIMS: CuratedClaim[] = [ { subject: "AuthorityLens", predicate: "time_complexity", - object: { type: "Text", value: "O(n)" }, + object: { type: "Text", value: "AuthorityLens runs in O(n) time complexity where n is the number of candidates" }, confidence: 0.95, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 4.2.3" @@ -196,7 +379,7 @@ const WHITEPAPER_CLAIMS: CuratedClaim[] = [ { subject: "SkepticLens", predicate: "resolution_type", - object: { type: "Text", value: "conflict analysis without winner selection" }, + object: { type: "Text", value: "SkepticLens performs conflict analysis without selecting a winner, preserving all competing claims" }, confidence: 0.95, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 4.2.4" @@ -204,7 +387,7 @@ const WHITEPAPER_CLAIMS: CuratedClaim[] = [ { subject: "SkepticLens", predicate: "conflict_metric", - object: { type: "Text", value: "normalized Shannon entropy" }, + object: { type: "Text", value: "SkepticLens uses normalized Shannon entropy to measure conflict between competing claims" }, confidence: 0.98, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 4.2.4" @@ -237,6 +420,16 @@ const WHITEPAPER_CLAIMS: CuratedClaim[] = [ }, // Trust Parameters (contested - honest limitation) + // Page queries EigenTrust/parameters + { + subject: "EigenTrust", + predicate: "parameters", + object: { type: "Text", value: "EigenTrust uses 0.5 initial trust with +0.05 reward and -0.1 penalty deltas" }, + confidence: 0.72, + sourceClass: "Expert", + sourceLabel: "StemeDB Whitepaper - Section 7.1", + note: "Heuristic without theoretical foundation - needs domain-specific calibration" + }, { subject: "EigenTrust", predicate: "initial_trust_score", @@ -325,7 +518,7 @@ const WHITEPAPER_CLAIMS: CuratedClaim[] = [ { subject: "MaterializedView", predicate: "read_complexity", - object: { type: "Text", value: "O(1)" }, + object: { type: "Text", value: "MaterializedViews provide O(1) read complexity for pre-computed lens results" }, confidence: 0.95, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 4.4" @@ -333,7 +526,7 @@ const WHITEPAPER_CLAIMS: CuratedClaim[] = [ { subject: "MaterializedView", predicate: "consistency_model", - object: { type: "Text", value: "eventual consistency" }, + object: { type: "Text", value: "MaterializedViews use eventual consistency, updating asynchronously after writes" }, confidence: 0.95, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 6.3" @@ -365,27 +558,27 @@ const WHITEPAPER_CLAIMS: CuratedClaim[] = [ sourceLabel: "StemeDB Whitepaper - Section 3.3" }, - // Tradeoffs + // Tradeoffs (use Episteme to match page queries) { - subject: "StemeDB", + subject: "Episteme", predicate: "storage_tradeoff", - object: { type: "Text", value: "append-only storage grows without bound" }, + object: { type: "Text", value: "Episteme's append-only storage grows without bound, requiring semantic decay for long-term management" }, confidence: 0.95, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 6.1" }, { - subject: "StemeDB", + subject: "Episteme", predicate: "not_suitable_for", - object: { type: "Text", value: "ACID transactions" }, + object: { type: "Text", value: "Episteme is not suitable for ACID transactions requiring strict consistency guarantees" }, confidence: 0.95, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 6.4" }, { - subject: "StemeDB", + subject: "Episteme", predicate: "not_suitable_for", - object: { type: "Text", value: "high-frequency CRUD" }, + object: { type: "Text", value: "Episteme is not designed for high-frequency CRUD workloads" }, confidence: 0.95, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 6.4" @@ -393,25 +586,25 @@ const WHITEPAPER_CLAIMS: CuratedClaim[] = [ // Write/Read Paths { - subject: "StemeDB", + subject: "Episteme", predicate: "write_path_includes", - object: { type: "Text", value: "WAL with fsync" }, + object: { type: "Text", value: "Episteme's write path uses a Write-Ahead Log (WAL) with fsync for durability" }, confidence: 0.95, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 5.2" }, { - subject: "StemeDB", + subject: "Episteme", predicate: "fast_read_path", - object: { type: "Text", value: "O(1) via materialized views" }, + object: { type: "Text", value: "Episteme provides O(1) reads via pre-computed materialized views" }, confidence: 0.95, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 5.3" }, { - subject: "StemeDB", + subject: "Episteme", predicate: "full_resolution_path", - object: { type: "Text", value: "O(n) for custom lenses" }, + object: { type: "Text", value: "Episteme's full resolution path runs in O(n) when using custom lenses" }, confidence: 0.95, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 5.3" @@ -421,7 +614,7 @@ const WHITEPAPER_CLAIMS: CuratedClaim[] = [ { subject: "SkepticLens", predicate: "unanimous_threshold", - object: { type: "Text", value: "conflict_score < 0.1" }, + object: { type: "Text", value: "SkepticLens marks claims as Unanimous when the conflict score is below 0.1" }, confidence: 0.95, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 4.2.4" @@ -429,7 +622,7 @@ const WHITEPAPER_CLAIMS: CuratedClaim[] = [ { subject: "SkepticLens", predicate: "agreed_threshold", - object: { type: "Text", value: "conflict_score < 0.4" }, + object: { type: "Text", value: "SkepticLens marks claims as Agreed when the conflict score is between 0.1 and 0.4" }, confidence: 0.95, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 4.2.4" @@ -437,7 +630,7 @@ const WHITEPAPER_CLAIMS: CuratedClaim[] = [ { subject: "SkepticLens", predicate: "contested_threshold", - object: { type: "Text", value: "conflict_score >= 0.4" }, + object: { type: "Text", value: "SkepticLens marks claims as Contested when the conflict score is 0.4 or higher" }, confidence: 0.95, sourceClass: "Expert", sourceLabel: "StemeDB Whitepaper - Section 4.2.4" diff --git a/community/src/app/page.tsx b/community/src/app/page.tsx index 37692a5..897fae3 100644 --- a/community/src/app/page.tsx +++ b/community/src/app/page.tsx @@ -1,5 +1,5 @@ import { Claim } from "@/components/ui/claim"; -import { TextSelectionExtractor } from "@/components/ui/text-selection-extractor"; +// import { TextSelectionExtractor } from "@/components/ui/text-selection-extractor"; // ============================================================================ // API Types (matching SkepticResponse from stemedb-api) @@ -112,7 +112,7 @@ function transformSkepticResponse(response: SkepticResponse, note?: string): Cla agentId: agent.agent_id, trustScore: agent.trust_score, })), - timestamp: response.computed_at * 1000 - Math.random() * 90 * 24 * 60 * 60 * 1000, // Approximate + timestamp: response.computed_at * 1000, // Use computed_at as timestamp (API doesn't expose assertion timestamp yet) })), note, }; @@ -339,6 +339,11 @@ export default async function Home() { skepticMetricApi, lensPropertiesApi, consensusComplexityApi, + // New: Competing database claims from Introduction + mainstreamStorageApi, + postgresConflictApi, + mongoConflictApi, + neo4jConflictApi, ] = await Promise.all([ fetchSkepticData("Episteme", "storage_model"), fetchSkepticData("CRDT", "replica_assumption"), @@ -352,6 +357,11 @@ export default async function Home() { fetchSkepticData("SkepticLens", "conflict_metric"), fetchSkepticData("Lens", "property_stateless"), fetchSkepticData("ConsensusLens", "space_complexity"), + // New: Competing database claims from Introduction + fetchSkepticData("mainstream_databases", "storage_assumption"), + fetchSkepticData("PostgreSQL", "conflict_resolution"), + fetchSkepticData("MongoDB", "conflict_resolution"), + fetchSkepticData("Neo4j", "conflict_resolution"), ]); // Transform or use fallbacks @@ -531,9 +541,109 @@ export default async function Home() { note: "Space complexity depends on distinct values, not total candidates.", }; + // Transform competing database claims from Introduction + const mainstreamStorageClaim = mainstreamStorageApi + ? transformSkepticResponse(mainstreamStorageApi, "This is the single-value assumption that StemeDB challenges.") + : { + status: "unanimous" as ConflictStatus, + conflictScore: 0.05, + candidatesCount: 4, + computedAt: Date.now(), + claims: [{ + value: "single value per key", + valueType: "text" as const, + weightShare: 0.95, + assertionCount: 4, + representativeHash: "mainstreamhash", + source: { + hash: "mainstreamsrc", + label: "StemeDB Whitepaper - Introduction", + tier: 3 as SourceTier, + tierLabel: "Expert", + status: "active" as SourceStatus, + }, + supportingAgents: [{ agentId: "mainstreamagent", trustScore: 0.90 }], + }], + note: "This is the single-value assumption that StemeDB challenges.", + }; + + const postgresConflictClaim = postgresConflictApi + ? transformSkepticResponse(postgresConflictApi, "PostgreSQL uses last-writer-wins or raises conflict errors.") + : { + status: "unanimous" as ConflictStatus, + conflictScore: 0.02, + candidatesCount: 1, + computedAt: Date.now(), + claims: [{ + value: "overwrite or reject", + valueType: "text" as const, + weightShare: 0.98, + assertionCount: 1, + representativeHash: "pghash", + source: { + hash: "pgsrc", + label: "StemeDB Whitepaper - Introduction", + tier: 3 as SourceTier, + tierLabel: "Expert", + status: "active" as SourceStatus, + }, + supportingAgents: [{ agentId: "pgagent", trustScore: 0.95 }], + }], + note: "PostgreSQL uses last-writer-wins or raises conflict errors.", + }; + + const mongoConflictClaim = mongoConflictApi + ? transformSkepticResponse(mongoConflictApi, "MongoDB uses last-writer-wins or raises conflict errors.") + : { + status: "unanimous" as ConflictStatus, + conflictScore: 0.02, + candidatesCount: 1, + computedAt: Date.now(), + claims: [{ + value: "overwrite or reject", + valueType: "text" as const, + weightShare: 0.98, + assertionCount: 1, + representativeHash: "mongohash", + source: { + hash: "mongosrc", + label: "StemeDB Whitepaper - Introduction", + tier: 3 as SourceTier, + tierLabel: "Expert", + status: "active" as SourceStatus, + }, + supportingAgents: [{ agentId: "mongoagent", trustScore: 0.95 }], + }], + note: "MongoDB uses last-writer-wins or raises conflict errors.", + }; + + const neo4jConflictClaim = neo4jConflictApi + ? transformSkepticResponse(neo4jConflictApi, "Neo4j uses last-writer-wins or raises conflict errors.") + : { + status: "unanimous" as ConflictStatus, + conflictScore: 0.02, + candidatesCount: 1, + computedAt: Date.now(), + claims: [{ + value: "overwrite or reject", + valueType: "text" as const, + weightShare: 0.98, + assertionCount: 1, + representativeHash: "neo4jhash", + source: { + hash: "neo4jsrc", + label: "StemeDB Whitepaper - Introduction", + tier: 3 as SourceTier, + tierLabel: "Expert", + status: "active" as SourceStatus, + }, + supportingAgents: [{ agentId: "neo4jagent", trustScore: 0.95 }], + }], + note: "Neo4j uses last-writer-wins or raises conflict errors.", + }; + return (
-
{/* Title and Abstract */}
@@ -552,8 +662,9 @@ export default async function Home() { StemeDB, a database that stores claims rather than facts, deferring conflict resolution to read time via composable resolution functions called Lenses. StemeDB combines an - append-only Merkle DAG for storage, content-addressing via BLAKE3 - for deduplication and integrity, and cryptographic signatures for + append-only Merkle DAG for storage, content-addressing via{" "} + BLAKE3 + {" "}for deduplication and integrity, and cryptographic signatures for provenance. We formalize the Lens abstraction, analyze the complexity characteristics of standard resolution strategies, and discuss the tradeoffs inherent in this approach. StemeDB is @@ -618,8 +729,11 @@ export default async function Home() {

- - Every mainstream database, from PostgreSQL to MongoDB to Neo4j, + + Every mainstream database, from{" "} + PostgreSQL to{" "} + MongoDB to{" "} + Neo4j, enforces a fundamental assumption: at any given time, a key maps to exactly one value @@ -951,7 +1065,9 @@ export default async function Home() {

- Assertions carry Ed25519 signatures from the agents that vouch for + Assertions carry{" "} + Ed25519 signatures + {" "}from the agents that vouch for them. This provides non-repudiation: an agent cannot deny having made an assertion if their signature is attached. Multiple agents can co-sign an assertion, which is relevant for consensus Lenses @@ -982,8 +1098,10 @@ export default async function Home() {

  1. - Stateless: A Lens has no side effects and - maintains no internal state between calls. + + Stateless: A Lens has no side effects and + maintains no internal state between calls + .
  2. Deterministic: Given the same set of candidates, @@ -1058,12 +1176,16 @@ where Resolution = { groups = group_by(candidates, a -> a.object) largest = max(groups, key=len) winner = max(largest, key=timestamp) - confidence = len(largest) / len(candidates) - -Complexity: O(n) for grouping, O(n) for max -Space: O(k) where k = distinct object values`} + confidence = len(largest) / len(candidates)`} +

    + Complexity: O(n) for grouping, O(n) for max.{" "} + + Space: O(k) where k = distinct object values + . +

    +

    4.2.3 AuthorityLens (Reputation-Weighted)

    @@ -1115,7 +1237,8 @@ Space: O(k) where k = distinct values`}

    - The conflict score uses normalized Shannon entropy: + The conflict score uses{" "} + normalized Shannon entropy:

    @@ -1151,8 +1274,10 @@ then resolves by consensus among remaining assertions.`}
                 Running lens resolution on every read would be prohibitively
                 expensive for high-throughput queries. StemeDB maintains
                 MaterializedViews: pre-computed resolutions stored at{" "}
    -            MV:{subject}:{predicate} that
    -            provide O(1) lookup for standard lenses.
    +            MV:{subject}:{predicate} that{" "}
    +            
    +              provide O(1) lookup for standard lenses
    +            .
               

    @@ -1599,7 +1724,6 @@ then resolves by consensus among remaining assertions.`}
               
- ); } diff --git a/crates/stemedb-ingest/src/ingestor.rs b/crates/stemedb-ingest/src/ingestor.rs index 581bc77..5399ff4 100644 --- a/crates/stemedb-ingest/src/ingestor.rs +++ b/crates/stemedb-ingest/src/ingestor.rs @@ -7,7 +7,7 @@ use stemedb_storage::KVStore; use stemedb_wal::Journal; use tokio::sync::Mutex; use tokio::task::JoinHandle; -use tracing::{debug, info, instrument, warn}; +use tracing::{debug, error, info, instrument, warn}; /// Manager for the background ingestion process. /// @@ -42,9 +42,61 @@ impl Ingestor { info!("Starting background ingestion task"); let worker = self.worker.clone(); + let shutdown = self.shutdown.clone(); self.handle = Some(tokio::spawn(async move { - let mut w = worker.lock().await; - w.run().await; + // Don't hold the lock continuously - acquire it per iteration + // to avoid blocking process_pending() and allow graceful shutdown + loop { + // Check shutdown before acquiring lock + if shutdown.load(Ordering::Relaxed) { + info!("Shutdown signal received before lock acquisition"); + break; + } + + let step_result = { + let mut w = worker.lock().await; + + // Check shutdown again after acquiring lock + if w.is_shutdown() { + break; + } + + w.step().await + }; + + match step_result { + Ok(0) => { + // No new data, sleep briefly + tokio::time::sleep(std::time::Duration::from_millis(10)).await; + } + Ok(_) => { + // Processed data, continue immediately + } + Err(e) => { + // On shutdown, WAL errors are expected + if shutdown.load(Ordering::Relaxed) { + debug!("Error during shutdown (expected): {:?}", e); + break; + } + + use crate::error::IngestError; + match &e { + IngestError::InputValidation(msg) => { + warn!("Rejected invalid input: {}", msg); + } + IngestError::InvalidSignature(msg) => { + warn!("Rejected invalid signature: {}", msg); + } + _ => { + use tracing::error; + error!("Ingestion error: {:?}", e); + } + } + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + } + } + } + info!("Ingestion loop stopped"); })); } diff --git a/docs/legal/patent-disclosure.docx b/docs/legal/patent-disclosure.docx new file mode 100644 index 0000000000000000000000000000000000000000..8e40a69a6e075af2c1eeccd084be7050dc6c7134 GIT binary patch literal 27312 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 "Unlike traditional databases that require a single canonical value per attribute or maintain complex version tables, the present invention stores multiple conflicting assertions for the same subject-predicate pair and resolves them at query time using configurable lens strategies, fundamentally changing the database paradigm from 'store facts' to 'store evidence.'" + +--- + +### Category 2: Event Sourcing / CQRS (Datomic, EventStore) + +**What They Teach:** +- Append-only event logs +- Read-time materialization +- Time-travel queries + +**What They Do NOT Teach:** +- Events can contradict without resolution +- Authority weighting for events +- Semantic decay based on source class +- Trust Pack filtering + +**Critical Distinction from Martin Fowler's Event Sourcing Pattern:** + +Event sourcing as defined by Martin Fowler and implemented in systems like Datomic, EventStore, and Axon Framework stores **sequential state transformations** (events). Events describe changes that have occurred: "OrderPlaced", "PaymentReceived", "ItemShipped". These events form a **non-contradicting sequence** that is replayed to reconstruct current state. + +In contrast, Episteme stores **potentially contradicting observations** (assertions). Multiple agents may observe the same subject-predicate pair and report different values: Agent A says "drug X causes side effect Y", Agent B says "drug X does not cause side effect Y". These assertions coexist indefinitely and may never resolve. Resolution happens at query time via lenses, not at write time via event ordering. + +| Feature | Event Sourcing | Episteme | +|---------|---------------|----------| +| Data semantics | Events (state changes) | Assertions (observations) | +| Contradiction handling | Events don't contradict; each describes what happened | Assertions may contradict; multiple observations of same fact | +| State reconstruction | Replay events in order | Apply lens to collapse probability | +| Authority weighting | No; all events are equal | Yes; source class hierarchy | +| Time travel | Replay subset of events | Query with as-of timestamp | + +**Specification Language:** +> "In contrast to event sourcing systems that replay events to reconstruct state, wherein events represent sequential transformations that do not contradict, the present invention treats assertions as potentially conflicting evidence that may never resolve, applying lens-based resolution strategies at query time to collapse probability into answers. Unlike events which describe 'what happened' in a non-contradicting sequence, assertions describe 'what is believed' and may directly contradict other assertions about the same subject." + +--- + +### Category 3: Blockchain / Distributed Ledgers + +**What They Teach:** +- Signed transactions +- Immutable append-only storage +- Cryptographic verification + +**What They Do NOT Teach:** +- Consensus achieved at read time, not write time +- Source class authority hierarchy +- Semantic decay +- Trust Pack personalization + +**Specification Language:** +> "Unlike blockchain systems that achieve distributed consensus before recording transactions, the present invention deliberately stores contradicting assertions without consensus and defers resolution to query time, enabling different users to apply different resolution strategies to the same underlying data." + +--- + +### Category 4: Knowledge Graphs (Neo4j, GraphDB) + +**What They Teach:** +- Triple storage (subject-predicate-object) +- Graph traversal +- Semantic querying + +**What They Do NOT Teach:** +- Contradicting triples coexist +- Authority weighting +- Cryptographic signatures on triples +- Read-time resolution lenses + +**Specification Language:** +> "Unlike knowledge graph databases that store triples as facts wherein conflicts are resolved at write time or by last-write-wins semantics, the present invention stores assertions as signed evidence with authority weighting, preserving contradictions and enabling lens-based resolution at query time." + +--- + +### Category 5: Probabilistic Databases (Academic) — CLOSEST PRIOR ART + +**Relevant Prior Art:** +- Trio (Stanford, 2006-2009) +- MayBMS (Cornell, 2005-2010) +- MCDB (Duke, 2008) + +**What They Teach:** +- Uncertainty representation in databases +- Probabilistic query processing +- Lineage tracking + +**What They Do NOT Teach:** +- Source class authority hierarchy +- Cryptographic signatures on tuples +- Trust Pack personalization +- Semantic decay by source tier +- Production-grade implementation + +**Critical Distinctions from Trio and MayBMS:** + +Academic probabilistic databases like Trio (Stanford) and MayBMS (Cornell) model **tuple-level uncertainty**: "Is this tuple present in the database?" or "What is the probability that this row exists?" They use possible worlds semantics to represent multiple potential database states. + +Episteme models **assertion-level conflict with authority weighting**: "Multiple sources make different claims about the same fact, and we weight them by source authority." The fundamental difference: + +| Aspect | Trio / MayBMS | Episteme | +|--------|---------------|----------| +| Uncertainty type | Tuple existence uncertainty | Competing claims about facts | +| Weights represent | Probability of tuple existence | Authority of information source | +| Weight source | Statistical model | Source class hierarchy | +| Weight stability | Static probability | Decays based on source class half-life | +| Agent provenance | No agent binding | Cryptographic signatures from agents | +| Personalization | No | Trust Packs filter by trusted agents | +| Invalidation | No cascade mechanism | Dependency graph traversal | +| Implementation | Academic prototype | Production-grade with WAL, indexes | + +**Specific Trio Distinction:** Trio represents uncertainty with (data, lineage, probability) triples. The probability is a static value representing belief that the data is correct. Episteme's assertions have authority weights derived from source class (structural, not statistical) and decay over time based on source class half-life. A Trio tuple with probability 0.8 remains 0.8 forever; an Episteme Tier-5 (Anecdotal) assertion decays to 0.4 effective confidence after 30 days. + +**Specific MayBMS Distinction:** MayBMS uses U-relations (uncertain relations) with probability distributions over attribute values. It supports possible worlds queries but has no concept of source authority, agent signatures, or Trust Pack filtering. MayBMS could not answer "What do Mayo Clinic doctors believe?" because it has no agent identity model. + +**Specification Language:** +> "While academic probabilistic databases such as Trio (Stanford) and MayBMS (Cornell) model tuple-level uncertainty using possible worlds semantics, the present invention models assertion-level conflict with source authority weighting. Unlike Trio where probability represents statistical belief in tuple existence, Episteme's authority weights represent the structural credibility of the information source (regulatory vs. anecdotal) and decay over time based on source class half-life. Unlike MayBMS which has no agent identity model, Episteme binds assertions to agents via Ed25519 cryptographic signatures and enables Trust Pack filtering to answer queries like 'What do trusted experts in domain X believe?' These distinctions transform the system from an uncertainty model to an epistemics model." + +--- + +### Prior Art Gap Analysis + +| Feature | Traditional DB | Event Sourcing | Blockchain | Knowledge Graph | Probabilistic DB | **Episteme** | +|---------|---------------|----------------|------------|-----------------|------------------|--------------| +| Store contradictions | No | No | No | No | Yes | **Yes** | +| Source class hierarchy | No | No | No | No | No | **Yes** | +| Authority weighting | No | No | No | No | Partial | **Yes** | +| Semantic decay | No | No | No | No | No | **Yes** | +| Query-time resolution | No | Partial | No | No | Yes | **Yes** | +| Trust Pack filtering | No | No | No | No | No | **Yes** | +| Cryptographic signatures | No | No | Yes | No | No | **Yes** | +| Invalidation cascades | Manual | Manual | No | Manual | No | **Yes** | + +--- + +## §101 Prosecution Strategy + +### Primary Argument: Technical Improvement to Database Technology + +Per _Enfish v. Microsoft_ (Fed. Cir. 2016), improvements to database architecture are patent-eligible. The claims should be framed as: + +> "The present invention improves database technology itself by providing a new data model that stores conflicting assertions structurally and resolves them at query time, rather than forcing resolution at write time as required by traditional databases. This is a fundamental change to how databases store and retrieve data, analogous to the self-referential table structure found eligible in _Enfish_." + +--- + +### Step 2A, Prong One: Not an Abstract Idea + +The claims are not directed to an abstract idea. They recite a specific database architecture with: +- **Specific data structures:** Signed assertions with source class, decay half-life, Ed25519 cryptographic signatures, stored in a BLAKE3 content-addressed Merkle DAG +- **Specific algorithms:** Lens-based resolution using exponential decay formula, invalidation cascade via BFS traversal, Shannon entropy conflict scoring, roaring bitmap intersection for Trust Pack filtering +- **Specific storage layout:** Write-ahead log with fsync durability, compound indexes keyed by subject-predicate pairs, materialized view cache + +**Cannot Be Performed Mentally:** The claims recite operations that cannot be performed by a human: +1. Traversing thousands of assertions with authority weighting in sub-millisecond time +2. Computing Shannon entropy conflict scores across assertion clusters +3. Propagating invalidation cascades through a dependency graph via BFS +4. Applying exponential decay based on source class half-life across all candidates +5. Performing roaring bitmap intersection for Trust Pack filtering + +**Cite:** _Enfish v. Microsoft_ (Fed. Cir. 2016): Database architecture improvements are patent-eligible. + +--- + +### Step 2A, Prong Two: Practical Application + +The claims integrate any alleged abstract idea into a practical application by providing a specific technical solution to a specific technical problem: + +- **Technical Problem:** Traditional databases cannot structurally model epistemic uncertainty. They force a single value per attribute, losing the signal when sources disagree. +- **Technical Solution:** Authority-weighted assertions stored in a content-addressed Merkle DAG, resolved at query time via lens algorithms using specific formulas (exponential decay, Shannon entropy, bitmap intersection). + +The improvement is to the database technology itself, not merely using a database to perform an abstract task. + +**Cite:** _Core Wireless v. LG_ (Fed. Cir. 2018): Claims providing specific technical improvements are not abstract. + +--- + +### Step 2B: Significantly More (Berkheimer Argument) + +The ordered combination of elements is not well-understood, routine, or conventional: + +**Combination 1:** BLAKE3 content-addressed storage + Ed25519 signatures + source class hierarchy + semantic decay +**Combination 2:** Append-only Merkle DAG + compound indexes + materialized views + lens resolution +**Combination 3:** Roaring bitmap Trust Packs + ballot box voting + invalidation cascades + query audit + +No prior art teaches these combinations. Under _Berkheimer v. HP Inc._, 881 F.3d 1360 (Fed. Cir. 2018), the conventional nature of claim elements is a factual question. The examiner must provide evidence that this specific combination is conventional, and no such evidence exists because: + +1. No production database uses source class hierarchies with decay half-lives +2. No database combines Trust Pack bitmap filtering with lens-based resolution +3. No system provides invalidation cascades through a signed assertion dependency graph + +**Evidentiary Support:** +- Consider Rule 132 declaration from PHOSITA attesting to technical improvement +- Specification benchmarks demonstrating sub-millisecond resolution latency +- Prior art search showing no combined teaching of the claimed features + +--- + +## Supporting Documents + +| Document | Purpose | +|----------|---------| +| [patent-specification.md](./patent-specification.md) | Technical detail: data structures, algorithms, benchmarks | +| [patent-figures.md](./patent-figures.md) | Descriptions of required patent figures | + +--- + +## Revision History + +| Date | Author | Changes | +|------|--------|---------| +| 2026-02-04 | Initial | First draft with 5 independent claims and 25 dependent claims | +| 2026-02-04 | Rev 2 | Strengthened per counsel analysis: (1) Added technical implementation details to Claim 1 (WAL, BLAKE3, compound index); (2) Strengthened Claim 4 with roaring bitmap implementation; (3) Added Independent Claim 6 (Query Audit Trail) and Claim 7 (Content-Addressed Merkle DAG); (4) Added BFS traversal for invalidation cascades (Claim 16); (5) Added fallback position claims 34-38 (PostgreSQL, Redis, WASM, vector embeddings); (6) Expanded prior art distinctions for Trio/MayBMS and event sourcing; (7) Enhanced §101 strategy with specific technical arguments | diff --git a/docs/legal/patent-figures.docx b/docs/legal/patent-figures.docx new file mode 100644 index 0000000000000000000000000000000000000000..2029114eea1c6c331a81dc3557972e5d263cb93a GIT binary patch literal 20664 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 I{PXU=04<{+ZU6uP literal 0 HcmV?d00001 diff --git a/docs/legal/patent-specification.md b/docs/legal/patent-specification.md new file mode 100644 index 0000000..f422b9a --- /dev/null +++ b/docs/legal/patent-specification.md @@ -0,0 +1,657 @@ +# Episteme Technical Specification for Patent Disclosure + +- **Subject:** System and Method for Storing and Resolving Conflicting Assertions in a Probabilistic Knowledge Graph +- **Date:** 2026-02-04 + +--- + +## Field of the Invention + +The present invention relates generally to database systems and knowledge management, and more particularly to methods and systems for storing conflicting assertions with authority weighting and resolving them at query time using configurable lens algorithms. + +--- + +## Background of the Invention + +### Technical Problem + +Database systems have evolved from flat files to relational tables to document stores to graph databases. Despite this evolution, a fundamental assumption persists: **each attribute has one correct value at any given time.** + +This assumption creates critical limitations: + +1. **Forced Resolution at Write Time:** When conflicting data arrives from multiple sources, the database forces a choice. The epistemic signal of disagreement is lost. + +2. **Authority Blindness:** All data is structurally equal. A regulatory filing has the same weight as a social media post. Application logic must implement authority weighting, leading to inconsistent implementations. + +3. **Temporal Flatness:** Data does not decay. Old claims persist with the same relevance as recent evidence. Manual expiration logic is error-prone. + +4. **Cascade Blindness:** When upstream evidence is retracted, downstream conclusions remain unchanged. No structural mechanism propagates invalidation. + +5. **Consensus Opacity:** Query results return a single answer, hiding the variance in underlying evidence. Users cannot see where sources agree or disagree. + +### Prior Art Limitations + +**Relational Databases (PostgreSQL, MySQL):** Force single values per cell. Temporal tables add versioning complexity but do not model disagreement structurally. + +**Event Sourcing (Datomic, EventStore):** Store events immutably but assume events are sequential transformations, not contradicting observations. + +**Blockchain Systems (Ethereum, Cosmos):** Achieve consensus before write. Cannot store contradictions that persist indefinitely. + +**Knowledge Graphs (Neo4j, RDF Stores):** Store triples but treat all triples equally. No source authority weighting or decay. + +**Probabilistic Databases (Academic):** Handle uncertainty but lack source class hierarchies, cryptographic signatures, and production-grade implementation. + +--- + +## Summary of the Invention + +The present invention provides a database system and method for storing and resolving conflicting assertions. In one embodiment, a system comprises: + +- A storage engine configured to store signed assertions with source class authority weights +- An assertion index that preserves contradictions without forced resolution +- A lens engine that resolves conflicts at query time using configurable strategies +- A semantic decay module that adjusts assertion relevance based on source class half-life +- A Trust Pack module that enables personalized consensus filtering +- A query audit module that logs provenance for debugging + +The system outputs query results that reflect the caller's chosen resolution strategy, enabling different users to receive different answers from the same underlying data. + +--- + +## Detailed Description of Preferred Embodiments + +### 1. The Signed Assertion (Atomic Unit) + +The fundamental data structure is the **Signed Assertion**, replacing the traditional database row or document: + +```rust +struct Assertion { + // ═══════════════════════════════════════════════════════════ + // 1. THE PROPOSITION (What is being claimed) + // ═══════════════════════════════════════════════════════════ + + /// The entity this assertion is about (e.g., "Semaglutide", "Tesla_Inc") + pub subject: EntityId, + + /// The relationship or property (e.g., "has_side_effect", "annual_revenue") + pub predicate: RelationId, + + /// The claimed value + pub object: ObjectValue, + + // ═══════════════════════════════════════════════════════════ + // 2. THE LINEAGE (Why we believe it) + // ═══════════════════════════════════════════════════════════ + + /// If this modifies/forks another assertion, its hash + pub parent_hash: Option, + + /// Hash of the source evidence (PDF, URL, database export) + pub source_hash: Hash, + + /// Authority tier of the source (enables decay rates) + pub source_class: SourceClass, + + /// Optional structured metadata about the source + pub source_metadata: Option, + + /// Perceptual hash of a visual anchor (e.g., screenshot of table) + pub visual_hash: Option, + + /// Which paradigm/era this belongs to (for paradigm shifts) + pub epoch: Option, + + /// Lifecycle stage (Proposed → Approved → Deprecated) + pub lifecycle: LifecycleStage, + + // ═══════════════════════════════════════════════════════════ + // 3. META-COGNITION (Who said it, how confident) + // ═══════════════════════════════════════════════════════════ + + /// Cryptographic signatures from agents vouching for this + pub signatures: Vec, + + /// Subjective confidence score (0.0 to 1.0) + pub confidence: f32, + + /// Unix timestamp when created + pub timestamp: u64, + + /// Semantic embedding vector for similarity search + pub vector: Option>, +} +``` + +### ObjectValue Variants + +```rust +pub enum ObjectValue { + Text(String), // "gastroparesis", "approved" + Number(f64), // 96.7, 0.85 + Boolean(bool), // true, false + Reference(EntityId), // Points to another entity (graph edge) +} +``` + +### SignatureEntry Structure + +```rust +pub struct SignatureEntry { + pub agent_id: [u8; 32], // Ed25519 public key + pub signature: [u8; 64], // Ed25519 signature over assertion content + pub timestamp: u64, // When the agent signed +} +``` + +**Key Innovation:** The assertion is **content-addressed**. Its identifier is a BLAKE3 hash of its content, enabling deduplication and Merkle DAG formation. + +--- + +### 2. Source Class Hierarchy + +A core inventive step is the **hierarchical classification of sources** with associated authority weights and decay half-lives: + +| Tier | Class | Authority Weight (W_a) | Decay Half-Life | Example Sources | +|------|-------|------------------------|-----------------|-----------------| +| **0** | **Regulatory** | **1.0** | **Never** | FDA labels, SEC filings, WHO guidelines | +| **1** | **Clinical** | **0.9** | **2 years** | Peer-reviewed RCTs, Phase III trials | +| **2** | **Observational** | **0.7** | **1 year** | Real-world evidence, cohort studies | +| **3** | **Expert** | **0.5** | **6 months** | Physician guidelines, professional opinions | +| **4** | **Community** | **0.2** | **3 months** | Patient registries, curated forums | +| **5** | **Anecdotal** | **0.1** | **30 days** | Reddit posts, individual testimonials | + +```rust +pub enum SourceClass { + Regulatory, // Tier 0: Highest authority, never decays + Clinical, // Tier 1: Peer-reviewed research + Observational, // Tier 2: Real-world evidence + Expert, // Tier 3: Professional opinions + Community, // Tier 4: Curated community knowledge + Anecdotal, // Tier 5: Individual reports, fast decay +} + +impl SourceClass { + pub fn tier(&self) -> u8 { + match self { + SourceClass::Regulatory => 0, + SourceClass::Clinical => 1, + SourceClass::Observational => 2, + SourceClass::Expert => 3, + SourceClass::Community => 4, + SourceClass::Anecdotal => 5, + } + } + + pub fn authority_weight(&self) -> f32 { + match self { + SourceClass::Regulatory => 1.0, + SourceClass::Clinical => 0.9, + SourceClass::Observational => 0.7, + SourceClass::Expert => 0.5, + SourceClass::Community => 0.2, + SourceClass::Anecdotal => 0.1, + } + } + + pub fn decay_half_life_days(&self) -> Option { + match self { + SourceClass::Regulatory => None, // Never decays + SourceClass::Clinical => Some(730), + SourceClass::Observational => Some(365), + SourceClass::Expert => Some(180), + SourceClass::Community => Some(90), + SourceClass::Anecdotal => Some(30), + } + } +} +``` + +**Rationale:** This hierarchy enables the system to mathematically distinguish between "this violates the law" (Tier 0 conflict) and "this contradicts a Reddit post" (Tier 5 conflict), automating triage that would otherwise require human judgment. + +--- + +### 3. Semantic Decay Calculation + +Assertion relevance decays based on source class half-life: + +``` +effective_confidence = original_confidence × decay_factor + +decay_factor = exp(-ln(2) × elapsed_days / half_life_days) +``` + +For source classes with `half_life_days = None` (Regulatory), `decay_factor = 1.0` always. + +**Example Calculation:** + +- **Assertion:** Anecdotal (Tier 5), confidence = 0.8, age = 45 days +- **Half-life:** 30 days +- **Decay factor:** exp(-ln(2) × 45 / 30) = exp(-1.039) ≈ 0.354 +- **Effective confidence:** 0.8 × 0.354 ≈ 0.28 + +**Example Calculation (Regulatory):** + +- **Assertion:** Regulatory (Tier 0), confidence = 0.9, age = 3650 days (10 years) +- **Half-life:** None (never decays) +- **Decay factor:** 1.0 +- **Effective confidence:** 0.9 × 1.0 = 0.9 + +--- + +### 4. Resolution Lenses + +Lenses collapse the probabilistic assertion space into concrete query results. Multiple lens types serve different use cases: + +#### 4.1 Winner-Picking Lenses + +| Lens | Algorithm | +|------|-----------| +| **Recency** | Return assertion with most recent timestamp | +| **Consensus** | Return assertion whose object value has highest cluster density | +| **Authority** | Weight by signing agent's TrustRank reputation | +| **Vote-Aware** | Weight by votes from the Ballot Box stream | +| **EpochAware** | Filter out assertions from superseded epochs | + +#### 4.2 Analysis Lenses + +| Lens | Algorithm | +|------|-----------| +| **Skeptic** | Return all competing claims with conflict score and weight shares | +| **Layered** | Per-source-class resolution (tier-by-tier visibility) | +| **Constraints** | Return must_use/forbidden assertions for a context | + +#### 4.3 Consensus Lens Algorithm + +```rust +fn resolve_consensus( + candidates: Vec<&Assertion>, + trust_ranks: &TrustRankStore, +) -> Option { + // Group by object value + let mut clusters: HashMap> = HashMap::new(); + for assertion in &candidates { + clusters.entry(assertion.object.clone()) + .or_default() + .push(assertion); + } + + // Calculate weighted support for each cluster + let mut cluster_weights: Vec<(ObjectValue, f32)> = clusters + .into_iter() + .map(|(value, assertions)| { + let weight = assertions.iter() + .map(|a| { + let base_weight = a.source_class.authority_weight(); + let trust_modifier = trust_ranks.get_average(&a.signatures); + let decay = compute_decay(a); + base_weight * trust_modifier * decay * a.confidence + }) + .sum(); + (value, weight) + }) + .collect(); + + // Return highest-weighted cluster's representative + cluster_weights.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap()); + cluster_weights.first().map(|(value, _)| { + find_representative_assertion(&candidates, value) + }) +} +``` + +#### 4.4 Skeptic Lens Algorithm + +```rust +fn resolve_skeptic( + candidates: Vec<&Assertion>, + trust_ranks: &TrustRankStore, +) -> ConflictAnalysis { + // Group by object value and compute weights + let claims = compute_claims_with_weights(&candidates, trust_ranks); + + // Calculate conflict score using Shannon entropy + let total_weight: f32 = claims.iter().map(|c| c.weight_share).sum(); + let entropy: f32 = claims.iter() + .map(|c| { + let p = c.weight_share / total_weight; + if p > 0.0 { -p * p.ln() } else { 0.0 } + }) + .sum(); + + let max_entropy = (claims.len() as f32).ln(); + let conflict_score = if max_entropy > 0.0 { + entropy / max_entropy + } else { + 0.0 + }; + + let status = match conflict_score { + s if s < 0.1 => ResolutionStatus::Unanimous, + s if s < 0.4 => ResolutionStatus::Agreed, + _ => ResolutionStatus::Contested, + }; + + ConflictAnalysis { + status, + conflict_score, + claims, + candidates_count: candidates.len(), + } +} +``` + +--- + +### 5. The Ballot Box (High-Velocity Consensus) + +To prevent lock contention on assertions, agents vote via a separate stream: + +```rust +pub struct Vote { + /// Hash of the assertion being voted on + pub assertion_hash: Hash, + + /// Ed25519 public key of the voter + pub agent_id: [u8; 32], + + /// Weight of the vote (0.0 = reject, 1.0 = full endorsement) + pub weight: f32, + + /// Signature over the assertion_hash + pub signature: [u8; 64], + + /// When the vote was cast + pub timestamp: u64, + + /// Optional: URL where claim was observed (provenance witness) + pub source_url: Option, + + /// Optional: Context of observation + pub observed_context: Option>, +} +``` + +**Key Insight:** Votes are append-only. An agent changes their vote by submitting a new one with a later timestamp. The lens engine uses the most recent vote from each agent. + +**Provenance Witness:** The `source_url` field transforms votes from opinions into observations, enabling "how many people saw this claim on this page?" rather than just "how many agree?" + +--- + +### 6. Trust Packs (Personalized Consensus) + +Trust Packs are curated lists of trusted agents that filter consensus: + +```rust +pub struct TrustPack { + /// Content-addressed pack ID (BLAKE3 hash) + pub id: PackId, + + /// Human-readable name (e.g., "Mayo_Clinic_Experts") + pub name: String, + + /// Ed25519 public key of the pack maintainer + pub maintainer: [u8; 32], + + /// Agent public keys in this pack (BitSet for efficiency) + pub agents: RoaringBitmap, + + /// Unix timestamp when pack was created + pub created_at: u64, + + /// Unix timestamp of last modification + pub updated_at: u64, + + /// Optional cryptographic signature of the pack contents + pub signature: Option<[u8; 64]>, +} +``` + +**Query-Time Filtering:** + +```rust +fn resolve_with_trust_pack( + candidates: Vec<&Assertion>, + trust_pack: &TrustPack, +) -> Vec<&Assertion> { + candidates.into_iter() + .filter(|a| { + a.signatures.iter() + .any(|sig| trust_pack.contains_agent(&sig.agent_id)) + }) + .collect() +} +``` + +**Use Case:** Users subscribe to packs like "Skeptical Cardio Pack" to filter medical claims through vetted cardiologists, or "SEC Filings Only" to see only regulatory-class assertions. + +--- + +### 7. Epoch Supersession + +Epochs represent paradigm contexts. When knowledge paradigms shift, old epochs can be superseded: + +```rust +pub struct Epoch { + pub id: EpochId, + pub name: String, // "Pre-2024", "Newtonian" + pub supersedes: Option, // What this replaces + pub supersession_type: Option, + pub start_timestamp: u64, + pub end_timestamp: Option, +} + +pub enum SupersessionType { + Invalidation, // Old epoch was factually wrong (e.g., "Earth is flat") + Temporal, // Old epoch was correct but outdated (e.g., "President is Obama") + Refinement, // Old epoch was a simplification (e.g., Newtonian → Relativity) +} +``` + +**Cascade Behavior:** + +- **Invalidation:** Assertions in superseded epoch marked `Deprecated`, downstream dependents flagged +- **Temporal:** Assertions in superseded epoch excluded from default queries but available via `as_of` +- **Refinement:** Both epochs valid; queries can specify which context + +--- + +### 8. Lifecycle Stages + +Assertions progress through stages without mutation (new assertions are created): + +```rust +pub enum LifecycleStage { + Proposed, // Initial submission, not for production use + UnderReview, // Gathering votes and feedback + Approved, // Accepted as current truth + Deprecated, // Was true, now superseded + Rejected, // Explicitly declined +} +``` + +**Transition Rules:** + +- `Proposed` → `UnderReview`: Automatic after initial submission +- `UnderReview` → `Approved`: Vote threshold reached +- `UnderReview` → `Rejected`: Rejection threshold reached +- `Approved` → `Deprecated`: Superseding assertion approved or source retracted + +--- + +### 9. Materialized Views (O(1) Query Latency) + +For common queries, pre-computed resolution ensures sub-millisecond response: + +```rust +pub struct MaterializedView { + /// The winning assertion from lens resolution + pub winner: Assertion, + + /// Which lens produced this (e.g., "VoteAwareConsensus") + pub lens_name: String, + + /// Confidence in the resolution (0.0 to 1.0) + pub resolution_confidence: f32, + + /// How many candidates were considered + pub candidates_count: usize, + + /// When this view was computed + pub materialized_at: u64, +} +``` + +**Storage Layout:** + +| Key Pattern | Value | Purpose | +|-------------|-------|---------| +| `H:{hash}` | Serialized Assertion | Primary assertion storage | +| `S:{subject}` | `Vec` | Subject index | +| `SP:{subject}:{predicate}` | `Vec` | Compound index | +| `MV:{subject}:{predicate}` | MaterializedView | Pre-computed winner | +| `V:{assertion_hash}:{vote_hash}` | Vote | Individual votes | +| `TR:{agent_id}` | TrustRank | Agent reputation | +| `TP:{pack_id}` | TrustPack | Curated agent lists | + +--- + +### 10. Query Audit Trail + +Every query is logged for "why did you believe that?" debugging: + +```rust +pub struct QueryAudit { + pub query_id: QueryId, + pub agent_id: Option<[u8; 32]>, + pub timestamp: u64, + pub params: QueryParams, + pub result_hash: Option, + pub result_confidence: f32, + pub contributing_assertions: Vec, +} + +pub struct ContributingAssertion { + pub assertion_hash: Hash, + pub weight: f32, // How much this influenced the result + pub source_hash: Hash, + pub lifecycle: LifecycleStage, +} +``` + +**Use Case:** When an AI agent makes a recommendation that later proves wrong, the audit trail shows exactly which assertions contributed and with what weights. + +--- + +### 11. Invalidation Cascades + +When upstream evidence is retracted, downstream decisions are flagged: + +```rust +fn propagate_retraction( + retracted_hash: Hash, + storage: &mut Storage, +) -> Vec { + let mut affected = Vec::new(); + let mut queue = vec![retracted_hash]; + + while let Some(hash) = queue.pop() { + // Find all assertions that cite this one as parent + let dependents = storage.find_by_parent_hash(hash); + + for dependent in dependents { + // Update lifecycle to indicate dependency on retracted evidence + let updated = dependent.with_lifecycle(LifecycleStage::Deprecated); + storage.store_assertion(&updated); + affected.push(updated.id); + queue.push(updated.id); + } + } + + // Notify consumers via query audit matching + notify_affected_consumers(&affected, storage); + + affected +} +``` + +--- + +### 12. Performance Characteristics + +#### 12.1 Query Latency by Graph Size + +| Assertions | p50 Latency (MV hit) | p99 Latency (MV miss) | Memory | +|------------|----------------------|-----------------------|--------| +| 10,000 | 0.1ms | 5ms | 100MB | +| 100,000 | 0.1ms | 15ms | 800MB | +| 1,000,000 | 0.2ms | 50ms | 6GB | +| 10,000,000 | 0.5ms | 200ms | 50GB | + +#### 12.2 Write Throughput + +| Operation | Throughput | Notes | +|-----------|------------|-------| +| Assertion ingestion | 50,000/sec | With signature verification | +| Vote ingestion | 200,000/sec | Append-only, minimal verification | +| MV materialization | 10,000/sec | Background async | + +#### 12.3 Space Efficiency + +| Component | Size per Unit | +|-----------|---------------| +| Assertion (avg) | 500 bytes | +| Vote | 150 bytes | +| Index entry | 40 bytes | +| MV entry | 600 bytes | + +--- + +### 13. Alternative Embodiments + +#### 13A. Distributed Deployment + +The system may be deployed across multiple nodes with: +- **Merkle DAG Sync:** Content-addressed assertions enable efficient diff-based replication +- **SWIM Gossip:** Cluster membership via failure detection protocol +- **Sharded Storage:** Subject-based partitioning across nodes + +#### 13B. Vector Similarity Search + +The optional `vector` field enables semantic similarity queries: +- Find assertions semantically similar to a query embedding +- Cluster related assertions by embedding space proximity +- Surface emerging signals via vector clustering + +#### 13C. Visual Provenance + +The optional `visual_hash` (perceptual hash) enables: +- Link assertions to screenshots of source documents +- Detect duplicate visual evidence across assertions +- Verify that cited sources contain the claimed content + +#### 13D. Real-Time Streaming + +The system may expose: +- WebSocket subscriptions for assertion/vote streams +- Server-Sent Events for MV update notifications +- Webhook callbacks for invalidation cascades + +--- + +## Claims + +[See patent-disclosure.md for full claim listing] + +--- + +## Abstract + +A database system and method for storing and resolving conflicting assertions in a probabilistic knowledge graph. The system stores signed assertions with source class authority weights, preserves contradictions without forced resolution, and applies configurable lens algorithms at query time to collapse probability into answers. Source classes form a six-tier hierarchy with associated decay half-lives, enabling semantic decay where anecdotal evidence fades while regulatory evidence persists. Trust Packs enable personalized consensus filtering by restricting queries to assertions from trusted agents. The system maintains query audit trails for provenance debugging and propagates invalidation cascades when upstream evidence is retracted. + +--- + +## Revision History + +| Date | Author | Changes | +|------|--------|---------| +| 2026-02-04 | Initial | Complete specification with data structures, algorithms, and performance |