linkedparticles-core 1.187.3__tar.gz → 1.192.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/PKG-INFO +1 -1
  2. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/artifacts/schemas/context.jsonld +2 -0
  3. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/artifacts/schemas/interchange.schema.json +2 -0
  4. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/artifacts/schemas/particle.schema.json +10 -0
  5. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/artifacts/schemas/shacl/ParticleShape.ttl +19 -0
  6. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/config.py +179 -7
  7. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/conformance/contract.py +10 -0
  8. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/conflict_resolution.py +11 -0
  9. linkedparticles_core-1.192.2/particles/core/ladders.py +244 -0
  10. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/probe_verdict.py +20 -0
  11. linkedparticles_core-1.192.2/particles/core/rung_ladder.py +443 -0
  12. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/schema.py +176 -3
  13. linkedparticles_core-1.192.2/particles/core/validity.py +394 -0
  14. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/general.py +309 -19
  15. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/interchange/codec.py +10 -0
  16. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/llm/__init__.py +4 -0
  17. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/llm/registry.py +35 -5
  18. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/pyproject.toml +1 -1
  19. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/_client_fixtures.py +41 -2
  20. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conftest.py +1 -0
  21. linkedparticles_core-1.187.3/tests/test_validity_extraction.py +0 -258
  22. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/LICENSE +0 -0
  23. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/NOTICE +0 -0
  24. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/README.md +0 -0
  25. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/artifacts/conformance/README.md +0 -0
  26. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/artifacts/conformance/profile.yaml +0 -0
  27. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/artifacts/conformance/similarity_vectors.json +0 -0
  28. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/artifacts/schemas/shacl/CorpusSnapshotShape.ttl +0 -0
  29. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/artifacts/schemas/shacl/ProvenanceChainShape.ttl +0 -0
  30. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/artifacts/schemas/shacl/SubjectShape.ttl +0 -0
  31. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/artifacts/schemas/shacl/TrustStatementShape.ttl +0 -0
  32. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/artifacts/schemas/trust_lens.schema.json +0 -0
  33. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/constraints.txt +0 -0
  34. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/__init__.py +0 -0
  35. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/conformance/__init__.py +0 -0
  36. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/conformance/_resources.py +0 -0
  37. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/conformance/fixtures.py +0 -0
  38. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/conformance/jsonschema.py +0 -0
  39. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/conformance/profile.py +0 -0
  40. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/conformance/runner.py +0 -0
  41. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/conformance/shacl.py +0 -0
  42. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/conformance/types.py +0 -0
  43. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/conformance/validator.py +0 -0
  44. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/__init__.py +0 -0
  45. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/_resources.py +0 -0
  46. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/cascade_gate.py +0 -0
  47. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/claims.py +0 -0
  48. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/closure_measure.py +0 -0
  49. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/conflict_review.py +0 -0
  50. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/consolidation_cadence.py +0 -0
  51. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/contradiction_disclosure.py +0 -0
  52. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/duplicate_key.py +0 -0
  53. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/equivalence.py +0 -0
  54. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/fingerprint.py +0 -0
  55. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/generics.py +0 -0
  56. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/granularity.py +0 -0
  57. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/held_release.py +0 -0
  58. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/jsonld_context.py +0 -0
  59. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/modality.py +0 -0
  60. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/observer_scope.py +0 -0
  61. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/past_value.py +0 -0
  62. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/predicate_profile.py +0 -0
  63. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/progress.py +0 -0
  64. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/provenance.py +0 -0
  65. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/reanchor.py +0 -0
  66. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/scoring/__init__.py +0 -0
  67. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/scoring/confidence.py +0 -0
  68. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/scoring/decay.py +0 -0
  69. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/scoring/relevance.py +0 -0
  70. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/scoring/utility.py +0 -0
  71. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/spend_budget.py +0 -0
  72. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/stance.py +0 -0
  73. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/status.py +0 -0
  74. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/vocabulary.py +0 -0
  75. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/vocabulary_jsonld.py +0 -0
  76. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/core/vocabulary_report.py +0 -0
  77. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/egress.py +0 -0
  78. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/embeddings.py +0 -0
  79. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/__init__.py +0 -0
  80. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/agent.py +0 -0
  81. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/append_delta.py +0 -0
  82. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/calibration.py +0 -0
  83. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/components.py +0 -0
  84. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/docstrings.py +0 -0
  85. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/github/__init__.py +0 -0
  86. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/github/_shared.py +0 -0
  87. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/github/gist.py +0 -0
  88. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/github/pages.py +0 -0
  89. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/github/repo.py +0 -0
  90. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/hackernews.py +0 -0
  91. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/incremental.py +0 -0
  92. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/journal.py +0 -0
  93. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/mastodon.py +0 -0
  94. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/mcp_memory.py +0 -0
  95. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/migration_preview.py +0 -0
  96. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/modality.py +0 -0
  97. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/nomisma.py +0 -0
  98. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/numista/__init__.py +0 -0
  99. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/numista/_shared.py +0 -0
  100. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/numista/coin.py +0 -0
  101. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/numista/issuer.py +0 -0
  102. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/numista/listing.py +0 -0
  103. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/polarity.py +0 -0
  104. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/property_keys.py +0 -0
  105. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/rdf.py +0 -0
  106. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/reddit.py +0 -0
  107. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/registry.py +0 -0
  108. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/scope.py +0 -0
  109. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/session_state.py +0 -0
  110. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/structure.py +0 -0
  111. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/subject_gate.py +0 -0
  112. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/subject_scope.py +0 -0
  113. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/taxonomy.py +0 -0
  114. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/tool_turns.py +0 -0
  115. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/trust_lens.py +0 -0
  116. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/vocabulary.py +0 -0
  117. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/extraction/wikidata.py +0 -0
  118. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/http.py +0 -0
  119. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/interchange/__init__.py +0 -0
  120. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/interchange/jsonl.py +0 -0
  121. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/interchange/yaml_ld.py +0 -0
  122. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/llm/adapters/__init__.py +0 -0
  123. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/llm/adapters/anthropic.py +0 -0
  124. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/llm/adapters/local.py +0 -0
  125. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/llm/adapters/openai_compat.py +0 -0
  126. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/llm/batch_budget.py +0 -0
  127. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/llm/breaker.py +0 -0
  128. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/llm/client.py +0 -0
  129. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/llm/errors.py +0 -0
  130. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/llm/fencing.py +0 -0
  131. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/llm/logprobs.py +0 -0
  132. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/llm/pool.py +0 -0
  133. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/llm/replay.py +0 -0
  134. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/llm/spend_budget.py +0 -0
  135. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/llm/usage.py +0 -0
  136. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/py.typed +0 -0
  137. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/render/__init__.py +0 -0
  138. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/render/markdown.py +0 -0
  139. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/secrets.py +0 -0
  140. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/url_canonical.py +0 -0
  141. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/particles/url_safety.py +0 -0
  142. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/__init__.py +0 -0
  143. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/_upstream.py +0 -0
  144. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/MANIFEST.yaml +0 -0
  145. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/hackernews-thread-001/content.bin +0 -0
  146. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/hackernews-thread-001/manifest.yaml +0 -0
  147. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/hackernews-thread-001/snapshot.json +0 -0
  148. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/journal-entry-001/content.bin +0 -0
  149. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/journal-entry-001/manifest.yaml +0 -0
  150. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/journal-entry-001/snapshot.json +0 -0
  151. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/mastodon-thread-001/content.bin +0 -0
  152. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/mastodon-thread-001/manifest.yaml +0 -0
  153. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/mastodon-thread-001/snapshot.json +0 -0
  154. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/mcp-memory-export-001/content.bin +0 -0
  155. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/mcp-memory-export-001/manifest.yaml +0 -0
  156. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/mcp-memory-export-001/snapshot.json +0 -0
  157. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/nomisma-concept-001/content.bin +0 -0
  158. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/nomisma-concept-001/manifest.yaml +0 -0
  159. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/nomisma-concept-001/snapshot.json +0 -0
  160. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/numista-coin-001/content.bin +0 -0
  161. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/numista-coin-001/manifest.yaml +0 -0
  162. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/numista-coin-001/snapshot.json +0 -0
  163. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/numista-issuer-001/content.bin +0 -0
  164. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/numista-issuer-001/manifest.yaml +0 -0
  165. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/numista-issuer-001/snapshot.json +0 -0
  166. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/numista-listing-001/content.bin +0 -0
  167. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/numista-listing-001/manifest.yaml +0 -0
  168. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/numista-listing-001/snapshot.json +0 -0
  169. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/rdf-graph-001/content.bin +0 -0
  170. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/rdf-graph-001/manifest.yaml +0 -0
  171. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/rdf-graph-001/snapshot.json +0 -0
  172. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/reddit-thread-001/content.bin +0 -0
  173. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/reddit-thread-001/manifest.yaml +0 -0
  174. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/reddit-thread-001/snapshot.json +0 -0
  175. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/taxonomy-coins-001/content.bin +0 -0
  176. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/taxonomy-coins-001/manifest.yaml +0 -0
  177. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/taxonomy-coins-001/snapshot.json +0 -0
  178. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/trust-lens-001/content.bin +0 -0
  179. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/trust-lens-001/manifest.yaml +0 -0
  180. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/trust-lens-001/snapshot.json +0 -0
  181. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/web-article-001/content.bin +0 -0
  182. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/web-article-001/manifest.yaml +0 -0
  183. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/web-article-001/snapshot.json +0 -0
  184. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/web-article-002/content.bin +0 -0
  185. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/web-article-002/manifest.yaml +0 -0
  186. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/web-article-002/snapshot.json +0 -0
  187. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/web-essay-001/content.bin +0 -0
  188. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/web-essay-001/manifest.yaml +0 -0
  189. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/web-essay-001/snapshot.json +0 -0
  190. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/web-interview-001/content.bin +0 -0
  191. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/web-interview-001/manifest.yaml +0 -0
  192. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/web-interview-001/snapshot.json +0 -0
  193. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/wikidata-entity-001/content.bin +0 -0
  194. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/wikidata-entity-001/manifest.yaml +0 -0
  195. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/conformance/fixtures/wikidata-entity-001/snapshot.json +0 -0
  196. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/fixtures/scope/normative-rule-file.md +0 -0
  197. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/fixtures/scope/normative-rule-file.recorded.json +0 -0
  198. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/fixtures/scope/rule-file-agents-md.md +0 -0
  199. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/fixtures/scope/rule-file-agents-md.recorded.json +0 -0
  200. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_calibration_isotonic.py +0 -0
  201. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_confidence.py +0 -0
  202. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_config_client_sections.py +0 -0
  203. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_config_sample.py +0 -0
  204. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_conformance_fixture_gen.py +0 -0
  205. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_conformance_similarity_vectors.py +0 -0
  206. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_conformance_validator.py +0 -0
  207. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_core_contradiction_disclosure.py +0 -0
  208. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_core_held_release.py +0 -0
  209. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_core_observer_scope.py +0 -0
  210. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_core_provenance.py +0 -0
  211. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_core_vocabulary.py +0 -0
  212. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_egress_policy.py +0 -0
  213. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_embeddings.py +0 -0
  214. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_extraction_agent.py +0 -0
  215. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_extraction_vision.py +0 -0
  216. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_interchange_schema.py +0 -0
  217. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_llm_batch_budget.py +0 -0
  218. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_llm_logprobs.py +0 -0
  219. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_llm_pool.py +0 -0
  220. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_llm_replay.py +0 -0
  221. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_llm_usage.py +0 -0
  222. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_schema.py +0 -0
  223. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_secrets.py +0 -0
  224. {linkedparticles_core-1.187.3 → linkedparticles_core-1.192.2}/tests/test_url_canonical.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: linkedparticles-core
3
- Version: 1.187.3
3
+ Version: 1.192.2
4
4
  Summary: Store-free client library for Particles: define, validate, serialize, and extract provenance-tracked belief particles
5
5
  Project-URL: Homepage, https://linkedparticles.org
6
6
  Project-URL: Documentation, https://docs.linkedparticles.org
@@ -63,6 +63,8 @@
63
63
  "particleType": { "@id": "particles:particleType" },
64
64
  "assertionModality": { "@id": "particles:assertionModality" },
65
65
  "validUntil": { "@id": "psum:duration", "@type": "xsd:dateTime" },
66
+ "validFrom": { "@id": "particles:validFrom", "@type": "xsd:dateTime" },
67
+ "validKind": { "@id": "particles:validKind" },
66
68
  "supersedes": { "@id": "particles:supersedes", "@type": "@id" },
67
69
  "subjectIds": { "@id": "particles:subject", "@type": "@id", "@container": "@set" },
68
70
  "subjects": { "@id": "particles:subjects", "@container": "@list" },
@@ -85,6 +85,8 @@
85
85
  },
86
86
  "uncertaintyKind": { "type": "string" },
87
87
  "validUntil": { "type": "string", "format": "date-time" },
88
+ "validFrom": { "type": "string", "format": "date-time" },
89
+ "validKind": { "type": "string", "enum": ["EVENT", "STATE"] },
88
90
  "supersedes": { "type": "string" },
89
91
  "basis": {
90
92
  "type": "object",
@@ -100,6 +100,16 @@
100
100
  "format": "date-time",
101
101
  "description": "Core: expiry for time-bounded claims (lazy query-time filter, §9.3)"
102
102
  },
103
+ "valid_from": {
104
+ "type": ["string", "null"],
105
+ "format": "date-time",
106
+ "description": "Core: when the claim begins to hold in the world, the counterpart of valid_until; read by the window route (§9.3), never by reconciliation"
107
+ },
108
+ "valid_kind": {
109
+ "type": ["string", "null"],
110
+ "enum": ["EVENT", "STATE", null],
111
+ "description": "Core: how the world-time pair is read; EVENT is a moment (the point [valid_from, valid_from], never with a valid_until), STATE a span"
112
+ },
103
113
  "supersedes": {
104
114
  "type": ["string", "null"],
105
115
  "format": "uuid",
@@ -112,6 +112,25 @@ particles:ParticleShape
112
112
  sh:message "assertion_modality, when present, must be FALSIFIABLE, EVALUATIVE, EXPERIENTIAL, or CONSTITUTIVE." ;
113
113
  ] ;
114
114
 
115
+ # validKind — optional reading of the world-time pair: EVENT is
116
+ # a moment, STATE a span. An EVENT never carries a validUntil — a
117
+ # cardinality across two properties the shape cannot express without a
118
+ # SPARQL constraint, so the Core model validator enforces it.
119
+ sh:property [
120
+ sh:path particles:validKind ;
121
+ sh:maxCount 1 ;
122
+ sh:datatype xsd:string ;
123
+ sh:in ( "EVENT" "STATE" ) ;
124
+ sh:message "valid_kind, when present, must be EVENT or STATE." ;
125
+ ] ;
126
+
127
+ sh:property [
128
+ sh:path particles:validFrom ;
129
+ sh:maxCount 1 ;
130
+ sh:datatype xsd:dateTime ;
131
+ sh:message "valid_from, when present, must be a single xsd:dateTime." ;
132
+ ] ;
133
+
115
134
  # canonicalForm — optional marker of which of the prose/structured pair is
116
135
  # the assertion; PROSE default. STRUCTURED additionally requires
117
136
  # a structuredClaim to be present — a cardinality the shape cannot express
@@ -409,7 +409,9 @@ class ProviderSelection(BaseModel):
409
409
  """
410
410
 
411
411
  provider: str = "anthropic"
412
- model: str = "claude-sonnet-4-6"
412
+ # The compiled default since 1.189.0, when it moved from claude-sonnet-4-6
413
+ # behind measurements registered before the runs.
414
+ model: str = "claude-sonnet-5-5"
413
415
 
414
416
 
415
417
  class OpenAICompatProviderConfig(BaseModel):
@@ -572,6 +574,27 @@ _LIST_PRICES_PER_MTOK: dict[str, tuple[float, float]] = {
572
574
  }
573
575
 
574
576
 
577
+ # Measured estimate factors that ship for the compiled default and the model it
578
+ # replaced, keyed like ``llm.price_per_mtok``. Characters per input
579
+ # token follow the shipped convention: the old tokenizer's 4.0 rule of thumb
580
+ # divided by the measured token ratio against claude-sonnet-4-6 (1.3437 on one
581
+ # run's byte-identical extraction prompts, token-counting endpoint, 2026-10-13).
582
+ # The output scale is relative to claude-sonnet-5, which the audit's per-call
583
+ # figures were fitted on: claude-sonnet-5-5 wrote 59,760 output tokens on the
584
+ # 2026-10 provider survey's 18 calls against claude-sonnet-5's 111,950 on the same
585
+ # calls (0.534). The extraction figure is the memory benchmark's 6,700 scaled the
586
+ # same way. The claude-sonnet-4-6 entries come from paired run
587
+ # (docs/benchmarks/default-model-adr0317-2026-10-13.md).
588
+ _SHIPPED_CHARS_PER_TOKEN: dict[str, float] = {"claude-sonnet-5-5": 2.98}
589
+ _SHIPPED_OUTPUT_SCALE: dict[str, float] = {
590
+ "claude-sonnet-5-5": 0.534,
591
+ "claude-sonnet-4-6": 0.800,
592
+ }
593
+ _SHIPPED_EXTRACTION_OUTPUT_TOKENS: dict[str, int] = {
594
+ "claude-sonnet-5-5": 3_578,
595
+ "claude-sonnet-4-6": 5_363,
596
+ }
597
+
575
598
  _T = TypeVar("_T")
576
599
 
577
600
 
@@ -591,6 +614,23 @@ def lookup_by_model(
591
614
  return None, None
592
615
 
593
616
 
617
+ #: Every completion purpose, in the order the operator-facing lines print them.
618
+ #: A literal here because config cannot import ``particles.llm``;
619
+ #: tests/test_config.py pins it equal to ``particles.llm.LLMPurpose``.
620
+ LLM_PURPOSES: tuple[str, ...] = (
621
+ "extraction",
622
+ "semantic_lint",
623
+ "verification",
624
+ "subject_resolution",
625
+ "query_response",
626
+ "synthesis",
627
+ "abstraction",
628
+ "benchmark",
629
+ "benchmark_answer",
630
+ "use_judge",
631
+ )
632
+
633
+
594
634
  def _default_prices() -> dict[str, TokenPrice]:
595
635
  return {
596
636
  model: TokenPrice(input=inp, output=out)
@@ -603,9 +643,11 @@ class LLMConfig(BaseModel):
603
643
 
604
644
  ``default`` is the fallback pairing; each purpose may override it. The
605
645
  operator can thus route high-volume ``extraction`` to a cheap model while
606
- keeping low-volume ``synthesis`` on a hosted one. All compiled defaults are
607
- ``claude-sonnet-4-6`` so the out-of-the-box behaviour is unchanged from
608
- before the port existed.
646
+ keeping low-volume ``synthesis`` on a hosted one. Every purpose falls back
647
+ to the compiled default, ``claude-sonnet-5-5`` since 1.189.0 (
648
+ ``claude-sonnet-4-6`` before), except ``use_judge``, which carries its own
649
+ compiled selection. ``particles config validate`` names the
650
+ default in force and where it came from.
609
651
 
610
652
  The legacy ``extraction.model`` / ``wiki.model`` keys are migrated into
611
653
  this section by ``_migrate_legacy_keys`` (``extraction.model`` →
@@ -712,6 +754,30 @@ class LLMConfig(BaseModel):
712
754
  override = getattr(self, purpose, None)
713
755
  return override if isinstance(override, ProviderSelection) else self.default
714
756
 
757
+ def selection_source(self, purpose: str) -> str:
758
+ """Where ``purpose``'s selection comes from, as an operator reads it.
759
+
760
+ ``"llm.<purpose>"`` when the configuration sets that purpose,
761
+ ``"compiled llm.<purpose>"`` for a purpose with its own compiled
762
+ selection that the configuration leaves alone (``use_judge``),
763
+ ``"llm.default"`` when the purpose falls back to a configured default,
764
+ and ``"compiled default"`` when nothing set it. ``"default"`` itself
765
+ reads as either of the last two.
766
+ """
767
+ if purpose != "default" and getattr(self, purpose, None) is not None:
768
+ if purpose in self.model_fields_set:
769
+ return f"llm.{purpose}"
770
+ return f"compiled llm.{purpose}"
771
+ return "llm.default" if "default" in self.model_fields_set else "compiled default"
772
+
773
+ def routed_elsewhere(self) -> dict[str, ProviderSelection]:
774
+ """The purposes whose selection differs from ``default``, in purpose order."""
775
+ return {
776
+ purpose: sel
777
+ for purpose in LLM_PURPOSES
778
+ if (sel := self.for_purpose(purpose)) != self.default
779
+ }
780
+
715
781
  @model_validator(mode="after")
716
782
  def _validate_provider_wiring(self) -> LLMConfig:
717
783
  """Fail dangling provider names / adapter kinds at config load.
@@ -976,6 +1042,16 @@ class ModalityRegenerationConfig(BaseModel):
976
1042
  commit_interval: int = Field(default=25, ge=1)
977
1043
 
978
1044
 
1045
+ class ValidityBackfillConfig(BaseModel):
1046
+ """Defaults for ``particles validity``, the prose-date default for ``valid_from``.
1047
+
1048
+ The pass makes no model call, so it has no rate limit; ``commit_interval``
1049
+ is how often it commits, so an interrupt costs seconds of work.
1050
+ """
1051
+
1052
+ commit_interval: int = Field(default=200, ge=1)
1053
+
1054
+
979
1055
  class ExtractionPolarityConfig(BaseModel):
980
1056
  """LLM-semantic claim-polarity classification of candidates (cap. 1).
981
1057
 
@@ -1020,10 +1096,18 @@ class ExtractionValidityConfig(BaseModel):
1020
1096
  a structural decision (does a boundary exist?), never the stored
1021
1097
  ``confidence.value``. ``enabled: false`` reproduces the pre-0197
1022
1098
  behaviour exactly (no candidate ever carries ``valid_until`` from extraction).
1099
+
1100
+ ``session_source_types`` names the source types a harness deposits as a
1101
+ session transcript. For those, the extractor may anchor a
1102
+ past-tense claim reporting an act performed *in the session* at the
1103
+ reference date as an ``EVENT`` under the ``session`` basis, so a window
1104
+ read finds what a session did; for every other source a past-tense claim
1105
+ with no date gets no start. Empty disables the rule.
1023
1106
  """
1024
1107
 
1025
1108
  enabled: bool = True
1026
1109
  min_boundary_confidence: float = 0.75
1110
+ session_source_types: list[str] = Field(default_factory=lambda: ["CONVERSATION"])
1027
1111
 
1028
1112
 
1029
1113
  class StructuredClaimConfig(BaseModel):
@@ -1777,6 +1861,10 @@ class SubjectsConfig(BaseModel):
1777
1861
  # claude-sonnet-4-6; on an ordinary-prose gold set, 0.898 to 0.918 against
1778
1862
  # 0.735, 45 of 49 names judged at about US$0.20 per 100 names, no correct
1779
1863
  # link lost on either (docs/benchmarks/subject-resolution-judge-2026-10-01.md).
1864
+ # Re-measured 2026-10-13 on claude-sonnet-5-5, the compiled default since
1865
+ # 1.189.0, at 7 hits: 1.000 on the suite and 0.939 on the ordinary-prose
1866
+ # set, no correct link lost, at about US$0.09 and US$0.20 per 100 names
1867
+ # (docs/benchmarks/default-model-adr0317-2026-10-13.md).
1780
1868
  # With no LLM key, an open breaker, or an unusable reply it takes the top
1781
1869
  # hit, so `top_hit` is also what an offline store gets. Set `top_hit` to
1782
1870
  # resolve with no model call at all.
@@ -3001,6 +3089,15 @@ class AuditConfig(BaseModel):
3001
3089
  # 0 probes nothing (disclosed the same way). `particles lint` is not
3002
3090
  # affected: cost gating is the audit's concern, lint stays exhaustive.
3003
3091
  max_contradiction_probes: int = Field(default=50, ge=0)
3092
+ # (the ruling, order, do not drop): under a probe
3093
+ # cap the census probes the pairs some single reader sees first (the
3094
+ # observer precondition reconciles or reviews them) and
3095
+ # reserves this share of the cap for cross-scope pairs, two projects'
3096
+ # claims the precondition declines, so a contradiction between projects
3097
+ # is still discovered and recorded as OBSERVER_DIVERGENCE. A share neither
3098
+ # side fills goes to the other. An ordering, never a filter; a store that
3099
+ # was never rescoped, and uncapped `particles lint`, are not reordered.
3100
+ cross_scope_probe_share: float = Field(default=0.2, ge=0.0, le=1.0)
3004
3101
  # read each pair the probe flagged a second time, on
3005
3102
  # ``llm.verification``, with each claim's source passage, note name and
3006
3103
  # note date, and count only the confirmed pairs in the headline. The report
@@ -3061,7 +3158,12 @@ class AuditConfig(BaseModel):
3061
3158
  # measured ~3,600 output tokens per memory-note call on claude-haiku-4-5
3062
3159
  # against ~6,700 on claude-sonnet-5, so routing ``llm.extraction`` to haiku
3063
3160
  # warrants an entry of about 0.55. A model with no entry is scaled by 1.
3064
- estimate_output_scale_by_model: dict[str, float] = Field(default_factory=dict)
3161
+ # Ships with measured entries for the compiled default and the model it
3162
+ # replaced (``_SHIPPED_OUTPUT_SCALE``); operator entries merge
3163
+ # over them key by key.
3164
+ estimate_output_scale_by_model: dict[str, float] = Field(
3165
+ default_factory=lambda: dict(_SHIPPED_OUTPUT_SCALE)
3166
+ )
3065
3167
  # Each call's output is taken to fall anywhere within this fraction of its
3066
3168
  # expected figure. The expected range runs from every call at (1 - spread)
3067
3169
  # to every call at (1 + spread), and a call whose output would pass
@@ -3108,6 +3210,14 @@ class AuditConfig(BaseModel):
3108
3210
  # Wall time per second reading: the measured runs read 22 flags in ~41 s.
3109
3211
  estimate_seconds_per_verification: float = Field(default=2.0, ge=0.0)
3110
3212
 
3213
+ @field_validator("estimate_output_scale_by_model", mode="before")
3214
+ @classmethod
3215
+ def _merge_over_shipped_scales(cls, value: Any) -> Any:
3216
+ """Operator entries replace the shipped ones key by key; the rest stay."""
3217
+ if isinstance(value, dict):
3218
+ return {**_SHIPPED_OUTPUT_SCALE, **value}
3219
+ return value
3220
+
3111
3221
  @field_validator("estimate_output_scale_by_model")
3112
3222
  @classmethod
3113
3223
  def _non_negative_output_scale(cls, value: dict[str, float]) -> dict[str, float]:
@@ -3524,8 +3634,10 @@ class MemoryBenchmarkConfig(BaseModel):
3524
3634
  # on claude-sonnet-5 but ~3.6k on claude-haiku-4-5 — so an arm routing
3525
3635
  # ``llm.extraction`` elsewhere is mis-estimated ~2x on the write side
3526
3636
  # without an entry here. The rendered estimate says which source it used.
3637
+ # Ships with measured entries for the compiled default and the model it
3638
+ # replaced; operator entries merge over them key by key.
3527
3639
  estimate_output_tokens_per_extraction_call_by_model: dict[str, int] = Field(
3528
- default_factory=dict
3640
+ default_factory=lambda: dict(_SHIPPED_EXTRACTION_OUTPUT_TOKENS)
3529
3641
  )
3530
3642
  # Characters per input token — the factor the estimate and the pre-flight
3531
3643
  # context-window check divide prompt bytes by. The scalar is the classic
@@ -3536,8 +3648,30 @@ class MemoryBenchmarkConfig(BaseModel):
3536
3648
  # lookup as ``llm.price_per_mtok`` — is what keeps their input projection and
3537
3649
  # their window verdict honest. The write side is keyed on the extraction
3538
3650
  # model, the answer side and the window check on the answer model.
3651
+ # The map ships one entry, for the compiled default, and the
3652
+ # scalar stays the old tokenizer's 4.0, so a model with no entry (a local
3653
+ # or OpenAI-compatible one included) keeps the factor it always had.
3654
+ # Operator entries merge over the shipped one key by key.
3539
3655
  chars_per_token: float = Field(default=4.0, gt=0.0)
3540
- chars_per_token_by_model: dict[str, float] = Field(default_factory=dict)
3656
+ chars_per_token_by_model: dict[str, float] = Field(
3657
+ default_factory=lambda: dict(_SHIPPED_CHARS_PER_TOKEN)
3658
+ )
3659
+
3660
+ @field_validator("estimate_output_tokens_per_extraction_call_by_model", mode="before")
3661
+ @classmethod
3662
+ def _merge_over_shipped_output_tokens(cls, value: Any) -> Any:
3663
+ """Operator entries replace the shipped ones key by key; the rest stay."""
3664
+ if isinstance(value, dict):
3665
+ return {**_SHIPPED_EXTRACTION_OUTPUT_TOKENS, **value}
3666
+ return value
3667
+
3668
+ @field_validator("chars_per_token_by_model", mode="before")
3669
+ @classmethod
3670
+ def _merge_over_shipped_chars_per_token(cls, value: Any) -> Any:
3671
+ """Operator entries replace the shipped ones key by key; the rest stay."""
3672
+ if isinstance(value, dict):
3673
+ return {**_SHIPPED_CHARS_PER_TOKEN, **value}
3674
+ return value
3541
3675
 
3542
3676
  @field_validator("estimate_output_tokens_per_extraction_call_by_model")
3543
3677
  @classmethod
@@ -3735,6 +3869,31 @@ class LeakageBenchmarkConfig(BaseModel):
3735
3869
  confirm_call_threshold: int = Field(default=50, ge=0)
3736
3870
 
3737
3871
 
3872
+ class UpdateGateBenchmarkConfig(BaseModel):
3873
+ """The trip-versus-move case and the update-gate pair sets.
3874
+
3875
+ Run counts and safety margins only. The pipeline under test runs the
3876
+ compiled defaults with every purpose pinned to the chosen model: nothing
3877
+ here re-tunes extraction, reconciliation or consolidation. There is no
3878
+ confirm threshold: every live run asks before its first call, because
3879
+ neither suite has a free live path.
3880
+ """
3881
+
3882
+ # The record's protocol (item 5): the bar is stated only when a
3883
+ # run uses these counts.
3884
+ move_runs: int = Field(default=3, ge=0)
3885
+ trip_alone_runs: int = Field(default=2, ge=0)
3886
+ # Samples per pair in the update-gate replay; the sets were registered at 3.
3887
+ samples: int = Field(default=3, ge=1)
3888
+ # The per-run ceiling --max-usd defaults to, as a multiple of a measured
3889
+ # estimate (a profile or the 2026-10-12 record). An upper-bound estimate is
3890
+ # already a ceiling and is used as is.
3891
+ max_usd_multiplier: float = Field(default=4.0, ge=1.0)
3892
+ # How long one run's child may take before it is stopped and reported
3893
+ # incomplete. A live run took a few minutes on 2026-10-12.
3894
+ run_timeout_seconds: float = Field(default=1800.0, gt=0.0)
3895
+
3896
+
3738
3897
  class BenchmarkConfig(BaseModel):
3739
3898
  """Benchmark-harness run persistence (family).
3740
3899
 
@@ -3903,6 +4062,7 @@ class ParticlesConfig(BaseModel):
3903
4062
  extraction_stance: ExtractionStanceConfig = Field(default_factory=ExtractionStanceConfig)
3904
4063
  extraction_polarity: ExtractionPolarityConfig = Field(default_factory=ExtractionPolarityConfig)
3905
4064
  extraction_validity: ExtractionValidityConfig = Field(default_factory=ExtractionValidityConfig)
4065
+ validity_backfill: ValidityBackfillConfig = Field(default_factory=ValidityBackfillConfig)
3906
4066
  extraction_vision: ExtractionVisionConfig = Field(default_factory=ExtractionVisionConfig)
3907
4067
  structured_claim: StructuredClaimConfig = Field(default_factory=StructuredClaimConfig)
3908
4068
  rdf: RdfConfig = Field(default_factory=RdfConfig)
@@ -3956,6 +4116,9 @@ class ParticlesConfig(BaseModel):
3956
4116
  default_factory=RelevanceFloorBenchmarkConfig
3957
4117
  )
3958
4118
  benchmark_leakage: LeakageBenchmarkConfig = Field(default_factory=LeakageBenchmarkConfig)
4119
+ benchmark_update_gate: UpdateGateBenchmarkConfig = Field(
4120
+ default_factory=UpdateGateBenchmarkConfig
4121
+ )
3959
4122
  benchmark: BenchmarkConfig = Field(default_factory=BenchmarkConfig)
3960
4123
  refetch_floors: dict[str, int] = Field(default_factory=lambda: dict(_DEFAULT_REFETCH_FLOORS))
3961
4124
  local_refresh: LocalRefreshConfig = Field(default_factory=LocalRefreshConfig)
@@ -4130,6 +4293,15 @@ _ENV_OVERRIDES: list[tuple[str, str, str]] = [
4130
4293
  ]
4131
4294
 
4132
4295
 
4296
+ def env_override_names() -> frozenset[str]:
4297
+ """Every environment variable that overrides a config field.
4298
+
4299
+ A benchmark that runs the SDK in a child process with a private environment
4300
+ removes these, so no override of the operator's reaches the run.
4301
+ """
4302
+ return frozenset(name for name, _section, _field in _ENV_OVERRIDES)
4303
+
4304
+
4133
4305
  # ---------------------------------------------------------------------------
4134
4306
  # Loader
4135
4307
  # ---------------------------------------------------------------------------
@@ -103,6 +103,16 @@ CONTRACT: list[FieldContract] = [
103
103
  ),
104
104
  FieldContract("uncertainty_kind", FieldTier.OPTIONAL, "Extension A free-text label"),
105
105
  FieldContract("valid_until", FieldTier.OPTIONAL, "Time-bounded claims only"),
106
+ FieldContract(
107
+ "valid_from",
108
+ FieldTier.OPTIONAL,
109
+ "Claims with a stated world-time start; the window route's input",
110
+ ),
111
+ FieldContract(
112
+ "valid_kind",
113
+ FieldTier.OPTIONAL,
114
+ "EVENT (a moment) or STATE (a span); how valid_from and valid_until are read",
115
+ ),
106
116
  FieldContract("supersedes", FieldTier.OPTIONAL, "Set by reindex, not by extractors"),
107
117
  FieldContract(
108
118
  "tags",
@@ -699,6 +699,10 @@ def decide_ladder(
699
699
  # written and no cascade runs.
700
700
  RETIRED_VALUE_KEY = "conflict:retired_value"
701
701
 
702
+ #: The ``properties`` key naming the ladder rung whose verdict opened an
703
+ #: INCONSISTENCY record, ``name@version``.
704
+ DECIDED_BY_KEY = "conflict:decided_by"
705
+
702
706
 
703
707
  def build_inconsistency_particle(
704
708
  existing: Particle,
@@ -709,6 +713,7 @@ def build_inconsistency_particle(
709
713
  asserted_by: str = "extract-pipeline",
710
714
  trigger_ref_type: ProvenanceRefType = ProvenanceRefType.SOURCE,
711
715
  retired_twin: bool = False,
716
+ decided_by: str | None = None,
712
717
  ) -> Particle:
713
718
  """Construct the INCONSISTENCY ``Particle`` for an unresolvable pair.
714
719
 
@@ -752,6 +757,10 @@ def build_inconsistency_particle(
752
757
  headline says so, and :data:`RETIRED_VALUE_KEY` carries the twin's
753
758
  ``status_reason`` in ``properties`` so Review can tell the two kinds
754
759
  of record apart.
760
+ - ``decided_by``: the stamp of the ladder rung whose
761
+ verdict opened the record, carried in ``properties`` under
762
+ :data:`DECIDED_BY_KEY`; ``None`` leaves it unstamped (a fail-closed
763
+ record no rung decided, or a retired-value hold).
755
764
  """
756
765
  # Inherit subject_ids from the existing particle (Particle A). Fall back
757
766
  # to the new particle's set if existing has none.
@@ -773,6 +782,8 @@ def build_inconsistency_particle(
773
782
  f"Particle A: {existing.id} — {existing.content[:120]}\n"
774
783
  f"Particle B (new): {new.content[:120]}"
775
784
  )
785
+ if decided_by is not None:
786
+ properties = {**(properties or {}), DECIDED_BY_KEY: decided_by}
776
787
 
777
788
  return Particle(
778
789
  content=inc_content,