shellbrain 0.1.24__tar.gz → 0.1.26__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 (225) hide show
  1. {shellbrain-0.1.24 → shellbrain-0.1.26}/PKG-INFO +1 -1
  2. shellbrain-0.1.26/app/core/contracts/concepts.py +212 -0
  3. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/contracts/requests.py +40 -1
  4. shellbrain-0.1.26/app/core/entities/concepts.py +302 -0
  5. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/entities/telemetry.py +4 -0
  6. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/interfaces/repos.py +75 -0
  7. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/interfaces/unit_of_work.py +2 -0
  8. shellbrain-0.1.26/app/core/use_cases/manage_concepts.py +460 -0
  9. shellbrain-0.1.26/app/core/use_cases/read_concepts.py +435 -0
  10. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/use_cases/read_memory.py +7 -0
  11. shellbrain-0.1.26/app/migrations/versions/20260421_0013_concept_context_graph.py +220 -0
  12. shellbrain-0.1.26/app/migrations/versions/20260422_0014_concept_read_telemetry.py +36 -0
  13. shellbrain-0.1.26/app/migrations/versions/20260422_0015_problem_runs.py +101 -0
  14. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/cli/handlers.py +52 -0
  15. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/cli/hydration.py +8 -0
  16. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/cli/main.py +72 -51
  17. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/cli/schema_validation.py +18 -0
  18. shellbrain-0.1.26/app/periphery/db/models/concepts.py +247 -0
  19. shellbrain-0.1.26/app/periphery/db/models/problem_runs.py +60 -0
  20. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/models/registry.py +3 -1
  21. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/models/telemetry.py +4 -0
  22. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/models/views.py +212 -0
  23. shellbrain-0.1.26/app/periphery/db/repos/relational/concepts_repo.py +774 -0
  24. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/uow.py +2 -0
  25. shellbrain-0.1.26/app/periphery/metrics/pager.py +250 -0
  26. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/metrics/queries.py +23 -0
  27. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/metrics/service.py +8 -0
  28. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/telemetry/operation_summary.py +47 -1
  29. {shellbrain-0.1.24 → shellbrain-0.1.26}/pyproject.toml +1 -1
  30. {shellbrain-0.1.24 → shellbrain-0.1.26}/shellbrain.egg-info/PKG-INFO +1 -1
  31. {shellbrain-0.1.24 → shellbrain-0.1.26}/shellbrain.egg-info/SOURCES.txt +11 -0
  32. {shellbrain-0.1.24 → shellbrain-0.1.26}/README.md +0 -0
  33. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/__init__.py +0 -0
  34. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/__main__.py +0 -0
  35. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/boot/__init__.py +0 -0
  36. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/boot/_dsn_resolution.py +0 -0
  37. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/boot/admin_db.py +0 -0
  38. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/boot/config.py +0 -0
  39. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/boot/create_policy.py +0 -0
  40. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/boot/db.py +0 -0
  41. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/boot/embeddings.py +0 -0
  42. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/boot/home.py +0 -0
  43. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/boot/migrations.py +0 -0
  44. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/boot/read_policy.py +0 -0
  45. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/boot/repos.py +0 -0
  46. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/boot/retrieval.py +0 -0
  47. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/boot/thresholds.py +0 -0
  48. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/boot/update_policy.py +0 -0
  49. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/boot/use_cases.py +0 -0
  50. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/config/__init__.py +0 -0
  51. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/config/defaults/create_policy.yaml +0 -0
  52. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/config/defaults/read_policy.yaml +0 -0
  53. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/config/defaults/runtime.yaml +0 -0
  54. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/config/defaults/thresholds.yaml +0 -0
  55. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/config/defaults/update_policy.yaml +0 -0
  56. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/config/loader.py +0 -0
  57. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/__init__.py +0 -0
  58. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/contracts/__init__.py +0 -0
  59. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/contracts/errors.py +0 -0
  60. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/contracts/responses.py +0 -0
  61. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/entities/__init__.py +0 -0
  62. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/entities/associations.py +0 -0
  63. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/entities/episodes.py +0 -0
  64. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/entities/evidence.py +0 -0
  65. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/entities/facts.py +0 -0
  66. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/entities/guidance.py +0 -0
  67. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/entities/identity.py +0 -0
  68. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/entities/memory.py +0 -0
  69. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/entities/runtime_context.py +0 -0
  70. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/entities/session_state.py +0 -0
  71. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/entities/utility.py +0 -0
  72. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/interfaces/__init__.py +0 -0
  73. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/interfaces/clock.py +0 -0
  74. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/interfaces/config.py +0 -0
  75. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/interfaces/embeddings.py +0 -0
  76. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/interfaces/idgen.py +0 -0
  77. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/interfaces/retrieval.py +0 -0
  78. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/interfaces/session_state_store.py +0 -0
  79. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/policies/__init__.py +0 -0
  80. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/policies/_shared/__init__.py +0 -0
  81. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/policies/_shared/executor.py +0 -0
  82. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/policies/_shared/side_effects.py +0 -0
  83. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/policies/create_policy/__init__.py +0 -0
  84. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/policies/create_policy/pipeline.py +0 -0
  85. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/policies/read_policy/__init__.py +0 -0
  86. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/policies/read_policy/bm25.py +0 -0
  87. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/policies/read_policy/context_pack_builder.py +0 -0
  88. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/policies/read_policy/expansion.py +0 -0
  89. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/policies/read_policy/fusion_rrf.py +0 -0
  90. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/policies/read_policy/lexical_query.py +0 -0
  91. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/policies/read_policy/pipeline.py +0 -0
  92. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/policies/read_policy/scoring.py +0 -0
  93. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/policies/read_policy/seed_retrieval.py +0 -0
  94. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/policies/update_policy/__init__.py +0 -0
  95. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/policies/update_policy/pipeline.py +0 -0
  96. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/use_cases/__init__.py +0 -0
  97. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/use_cases/build_guidance.py +0 -0
  98. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/use_cases/create_memory.py +0 -0
  99. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/use_cases/manage_session_state.py +0 -0
  100. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/use_cases/record_episode_sync_telemetry.py +0 -0
  101. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/use_cases/record_model_usage_telemetry.py +0 -0
  102. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/use_cases/record_operation_telemetry.py +0 -0
  103. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/use_cases/sync_episode.py +0 -0
  104. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/core/use_cases/update_memory.py +0 -0
  105. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/migrations/__init__.py +0 -0
  106. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/migrations/env.py +0 -0
  107. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/migrations/versions/20260226_0001_initial_schema.py +0 -0
  108. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/migrations/versions/20260312_0002_add_hard_invariants.py +0 -0
  109. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/migrations/versions/20260312_0003_drop_create_confidence.py +0 -0
  110. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/migrations/versions/20260313_0004_episode_sync_hardening.py +0 -0
  111. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/migrations/versions/20260313_0005_evidence_episode_event_refs.py +0 -0
  112. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/migrations/versions/20260318_0006_usage_telemetry_schema.py +0 -0
  113. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/migrations/versions/20260319_0007_identity_session_guidance.py +0 -0
  114. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/migrations/versions/20260320_0008_instance_metadata_and_backup_safety.py +0 -0
  115. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/migrations/versions/20260410_0009_frontier_memory_family.py +0 -0
  116. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/migrations/versions/20260414_0010_model_usage_telemetry.py +0 -0
  117. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/migrations/versions/20260414_0011_usage_problem_tokens_multi_solution_metrics.py +0 -0
  118. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/migrations/versions/20260415_0012_read_pack_cost_and_read_roi.py +0 -0
  119. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/migrations/versions/__init__.py +0 -0
  120. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/onboarding_assets/__init__.py +0 -0
  121. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/onboarding_assets/claude/CLAUDE.md +0 -0
  122. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/onboarding_assets/claude/skills/shellbrain-session-start/SKILL.md +0 -0
  123. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/onboarding_assets/claude/skills/shellbrain-usage-review/SKILL.md +0 -0
  124. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/onboarding_assets/codex/AGENTS.md +0 -0
  125. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/onboarding_assets/codex/shellbrain-session-start/SKILL.md +0 -0
  126. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/onboarding_assets/codex/shellbrain-session-start/agents/openai.yaml +0 -0
  127. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/onboarding_assets/codex/shellbrain-session-start/assets/shellbrain-large.svg +0 -0
  128. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/onboarding_assets/codex/shellbrain-session-start/assets/shellbrain-small.svg +0 -0
  129. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/onboarding_assets/codex/shellbrain-session-start/assets/shellbrain_logo.png +0 -0
  130. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/onboarding_assets/codex/shellbrain-session-start/references/request-shapes.md +0 -0
  131. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/onboarding_assets/codex/shellbrain-session-start/references/session-workflow.md +0 -0
  132. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/onboarding_assets/codex/shellbrain-usage-review/SKILL.md +0 -0
  133. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/onboarding_assets/codex/shellbrain-usage-review/agents/openai.yaml +0 -0
  134. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/onboarding_assets/codex/shellbrain-usage-review/assets/shellbrain-small.svg +0 -0
  135. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/onboarding_assets/codex/shellbrain-usage-review/assets/shellbrain_logo.png +0 -0
  136. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/onboarding_assets/cursor/skills/shellbrain-session-start/SKILL.md +0 -0
  137. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/onboarding_assets/cursor/skills/shellbrain-usage-review/SKILL.md +0 -0
  138. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/__init__.py +0 -0
  139. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/admin/__init__.py +0 -0
  140. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/admin/agent_behavior_analysis.py +0 -0
  141. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/admin/analytics.py +0 -0
  142. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/admin/analytics_diagnostics.py +0 -0
  143. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/admin/analytics_queries.py +0 -0
  144. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/admin/backup.py +0 -0
  145. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/admin/destructive_guard.py +0 -0
  146. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/admin/doctor.py +0 -0
  147. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/admin/external_runtime.py +0 -0
  148. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/admin/init.py +0 -0
  149. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/admin/init_errors.py +0 -0
  150. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/admin/instance_guard.py +0 -0
  151. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/admin/machine_state.py +0 -0
  152. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/admin/managed_runtime.py +0 -0
  153. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/admin/model_usage_backfill.py +0 -0
  154. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/admin/privileges.py +0 -0
  155. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/admin/repo_state.py +0 -0
  156. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/admin/restore.py +0 -0
  157. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/admin/storage_setup.py +0 -0
  158. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/admin/upgrade.py +0 -0
  159. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/cli/__init__.py +0 -0
  160. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/cli/presenter_json.py +0 -0
  161. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/__init__.py +0 -0
  162. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/engine.py +0 -0
  163. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/models/__init__.py +0 -0
  164. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/models/associations.py +0 -0
  165. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/models/episodes.py +0 -0
  166. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/models/evidence.py +0 -0
  167. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/models/experiences.py +0 -0
  168. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/models/instance_metadata.py +0 -0
  169. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/models/memories.py +0 -0
  170. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/models/metadata.py +0 -0
  171. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/models/utility.py +0 -0
  172. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/repos/__init__.py +0 -0
  173. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/repos/relational/__init__.py +0 -0
  174. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/repos/relational/associations_repo.py +0 -0
  175. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/repos/relational/episodes_repo.py +0 -0
  176. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/repos/relational/evidence_repo.py +0 -0
  177. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/repos/relational/experiences_repo.py +0 -0
  178. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/repos/relational/memories_repo.py +0 -0
  179. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/repos/relational/read_policy_repo.py +0 -0
  180. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/repos/relational/telemetry_repo.py +0 -0
  181. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/repos/relational/utility_repo.py +0 -0
  182. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/repos/semantic/__init__.py +0 -0
  183. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/repos/semantic/keyword_retrieval_repo.py +0 -0
  184. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/repos/semantic/semantic_retrieval_repo.py +0 -0
  185. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/db/session.py +0 -0
  186. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/embeddings/__init__.py +0 -0
  187. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/embeddings/local_provider.py +0 -0
  188. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/embeddings/query_vector_search.py +0 -0
  189. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/episodes/__init__.py +0 -0
  190. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/episodes/claude_code.py +0 -0
  191. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/episodes/codex.py +0 -0
  192. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/episodes/cursor.py +0 -0
  193. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/episodes/launcher.py +0 -0
  194. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/episodes/model_usage.py +0 -0
  195. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/episodes/normalization.py +0 -0
  196. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/episodes/poller.py +0 -0
  197. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/episodes/poller_lock.py +0 -0
  198. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/episodes/source_discovery.py +0 -0
  199. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/episodes/tool_filter.py +0 -0
  200. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/identity/__init__.py +0 -0
  201. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/identity/claude_hook_install.py +0 -0
  202. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/identity/claude_runtime.py +0 -0
  203. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/identity/codex_runtime.py +0 -0
  204. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/identity/compatibility.py +0 -0
  205. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/identity/cursor_statusline.py +0 -0
  206. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/identity/resolver.py +0 -0
  207. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/metrics/__init__.py +0 -0
  208. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/metrics/artifacts.py +0 -0
  209. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/metrics/browser.py +0 -0
  210. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/metrics/render_html.py +0 -0
  211. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/onboarding/__init__.py +0 -0
  212. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/onboarding/host_assets.py +0 -0
  213. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/session_state/__init__.py +0 -0
  214. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/session_state/file_store.py +0 -0
  215. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/telemetry/__init__.py +0 -0
  216. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/telemetry/session_selection.py +0 -0
  217. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/telemetry/sync_summary.py +0 -0
  218. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/validation/__init__.py +0 -0
  219. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/validation/integrity_validation.py +0 -0
  220. {shellbrain-0.1.24 → shellbrain-0.1.26}/app/periphery/validation/semantic_validation.py +0 -0
  221. {shellbrain-0.1.24 → shellbrain-0.1.26}/setup.cfg +0 -0
  222. {shellbrain-0.1.24 → shellbrain-0.1.26}/shellbrain.egg-info/dependency_links.txt +0 -0
  223. {shellbrain-0.1.24 → shellbrain-0.1.26}/shellbrain.egg-info/entry_points.txt +0 -0
  224. {shellbrain-0.1.24 → shellbrain-0.1.26}/shellbrain.egg-info/requires.txt +0 -0
  225. {shellbrain-0.1.24 → shellbrain-0.1.26}/shellbrain.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shellbrain
3
- Version: 0.1.24
3
+ Version: 0.1.26
4
4
  Summary: Repo-scoped Shellbrain CLI with explicit evidence-backed writes.
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -0,0 +1,212 @@
1
+ """Strict request contracts for the concept-context graph endpoint."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import datetime
6
+ from typing import Annotated, Any, Literal
7
+
8
+ from pydantic import Field, model_validator
9
+
10
+ from app.core.contracts.requests import StrictBaseModel
11
+
12
+
13
+ ConceptKindValue = Literal["domain", "capability", "process", "entity", "rule", "component"]
14
+ ConceptStatusValue = Literal["active", "deprecated", "archived"]
15
+ ConceptRelationPredicateValue = Literal["contains", "involves", "precedes", "constrains", "depends_on"]
16
+ ConceptClaimTypeValue = Literal["definition", "behavior", "invariant", "failure_mode", "usage_note", "open_question"]
17
+ AnchorKindValue = Literal[
18
+ "file",
19
+ "symbol",
20
+ "line_range",
21
+ "api_route",
22
+ "db_table",
23
+ "schema",
24
+ "config_key",
25
+ "test",
26
+ "metric",
27
+ "log",
28
+ "doc",
29
+ "commit",
30
+ "memory",
31
+ ]
32
+ ConceptGroundingRoleValue = Literal[
33
+ "implementation",
34
+ "entrypoint",
35
+ "storage",
36
+ "configuration",
37
+ "test",
38
+ "observability",
39
+ "documentation",
40
+ ]
41
+ ConceptMemoryLinkRoleValue = Literal[
42
+ "example_of",
43
+ "solution_for",
44
+ "failed_tactic_for",
45
+ "changed",
46
+ "validated",
47
+ "contradicted",
48
+ "warned_about",
49
+ ]
50
+ ConceptEvidenceKindValue = Literal["anchor", "memory", "commit", "transcript", "test", "manual"]
51
+ ConceptSourceKindValue = Literal[
52
+ "commit",
53
+ "file_hash",
54
+ "symbol_hash",
55
+ "memory",
56
+ "transcript_event",
57
+ "manual",
58
+ "doc",
59
+ "runtime_trace",
60
+ ]
61
+ ConceptCreatedByValue = Literal["worker", "librarian", "manual", "import"]
62
+ ConceptShowIncludeValue = Literal["claims", "relations", "groundings", "memory_links", "preview_concept"]
63
+
64
+
65
+ class ConceptEvidencePayload(StrictBaseModel):
66
+ """Evidence supplied inline with one truth-bearing concept action."""
67
+
68
+ kind: ConceptEvidenceKindValue
69
+ anchor_id: str | None = None
70
+ memory_id: str | None = None
71
+ commit_ref: str | None = None
72
+ transcript_ref: str | None = None
73
+ note: str | None = None
74
+
75
+ @model_validator(mode="after")
76
+ def _validate_required_reference(self) -> "ConceptEvidencePayload":
77
+ """Require the reference field implied by the evidence kind."""
78
+
79
+ if self.kind == "anchor" and not self.anchor_id:
80
+ raise ValueError("anchor evidence requires anchor_id")
81
+ if self.kind == "memory" and not self.memory_id:
82
+ raise ValueError("memory evidence requires memory_id")
83
+ if self.kind == "commit" and not self.commit_ref:
84
+ raise ValueError("commit evidence requires commit_ref")
85
+ if self.kind == "transcript" and not self.transcript_ref:
86
+ raise ValueError("transcript evidence requires transcript_ref")
87
+ if self.kind in {"manual", "test"} and not self.note:
88
+ raise ValueError(f"{self.kind} evidence requires note")
89
+ return self
90
+
91
+
92
+ class ConceptLifecycleActionFields(StrictBaseModel):
93
+ """Shared optional lifecycle fields on concept write actions."""
94
+
95
+ confidence: float = Field(default=0.5, ge=0.0, le=1.0)
96
+ observed_at: datetime | None = None
97
+ validated_at: datetime | None = None
98
+ source_kind: ConceptSourceKindValue | None = None
99
+ source_ref: str | None = None
100
+ created_by: ConceptCreatedByValue = "manual"
101
+
102
+
103
+ class UpsertConceptAction(StrictBaseModel):
104
+ """Create or update a concept container and aliases."""
105
+
106
+ type: Literal["upsert_concept"]
107
+ slug: str = Field(min_length=1)
108
+ name: str = Field(min_length=1)
109
+ kind: ConceptKindValue
110
+ status: ConceptStatusValue = "active"
111
+ scope_note: str | None = None
112
+ aliases: list[str] = Field(default_factory=list)
113
+
114
+
115
+ class AddRelationAction(ConceptLifecycleActionFields):
116
+ """Create an evidence-backed concept relation."""
117
+
118
+ type: Literal["add_relation"]
119
+ subject: str = Field(min_length=1)
120
+ predicate: ConceptRelationPredicateValue
121
+ object: str = Field(min_length=1)
122
+ evidence: list[ConceptEvidencePayload] = Field(min_length=1)
123
+
124
+
125
+ class AddClaimAction(ConceptLifecycleActionFields):
126
+ """Create an evidence-backed concept claim."""
127
+
128
+ type: Literal["add_claim"]
129
+ concept: str = Field(min_length=1)
130
+ claim_type: ConceptClaimTypeValue
131
+ text: str = Field(min_length=1)
132
+ evidence: list[ConceptEvidencePayload] = Field(min_length=1)
133
+
134
+
135
+ class UpsertAnchorAction(StrictBaseModel):
136
+ """Create or fetch a real-world anchor by canonical locator."""
137
+
138
+ type: Literal["upsert_anchor"]
139
+ kind: AnchorKindValue
140
+ locator: dict[str, Any] = Field(default_factory=dict)
141
+
142
+
143
+ class AnchorSelector(StrictBaseModel):
144
+ """Reference an existing anchor or define an inline anchor to upsert."""
145
+
146
+ id: str | None = None
147
+ kind: AnchorKindValue | None = None
148
+ locator: dict[str, Any] | None = None
149
+
150
+ @model_validator(mode="after")
151
+ def _validate_selector(self) -> "AnchorSelector":
152
+ """Require either an id or a complete inline anchor."""
153
+
154
+ has_inline = self.kind is not None and self.locator is not None
155
+ if not self.id and not has_inline:
156
+ raise ValueError("anchor requires id or kind+locator")
157
+ if self.id and (self.kind is not None or self.locator is not None):
158
+ raise ValueError("anchor selector cannot mix id with kind/locator")
159
+ return self
160
+
161
+
162
+ class AddGroundingAction(ConceptLifecycleActionFields):
163
+ """Create an evidence-backed concept grounding."""
164
+
165
+ type: Literal["add_grounding"]
166
+ concept: str = Field(min_length=1)
167
+ role: ConceptGroundingRoleValue
168
+ anchor: AnchorSelector
169
+ evidence: list[ConceptEvidencePayload] = Field(min_length=1)
170
+
171
+
172
+ class LinkMemoryAction(ConceptLifecycleActionFields):
173
+ """Create an evidence-backed concept-memory link."""
174
+
175
+ type: Literal["link_memory"]
176
+ concept: str = Field(min_length=1)
177
+ role: ConceptMemoryLinkRoleValue
178
+ memory_id: str = Field(min_length=1)
179
+ evidence: list[ConceptEvidencePayload] = Field(min_length=1)
180
+
181
+
182
+ ConceptAction = Annotated[
183
+ UpsertConceptAction | AddRelationAction | AddClaimAction | UpsertAnchorAction | AddGroundingAction | LinkMemoryAction,
184
+ Field(discriminator="type"),
185
+ ]
186
+
187
+
188
+ class ConceptCommandRequest(StrictBaseModel):
189
+ """Canonical concept endpoint request."""
190
+
191
+ schema_version: Literal["concept.v1"]
192
+ mode: Literal["apply", "show"]
193
+ repo_id: str
194
+ actions: list[ConceptAction] | None = None
195
+ concept: str | None = None
196
+ include: list[ConceptShowIncludeValue] = Field(default_factory=list)
197
+
198
+ @model_validator(mode="after")
199
+ def _validate_mode_fields(self) -> "ConceptCommandRequest":
200
+ """Enforce mode-specific request fields."""
201
+
202
+ if self.mode == "apply":
203
+ if not self.actions:
204
+ raise ValueError("mode=apply requires actions")
205
+ if self.concept is not None:
206
+ raise ValueError("mode=apply does not accept concept")
207
+ if self.mode == "show":
208
+ if not self.concept:
209
+ raise ValueError("mode=show requires concept")
210
+ if self.actions is not None:
211
+ raise ValueError("mode=show does not accept actions")
212
+ return self
@@ -2,11 +2,12 @@
2
2
 
3
3
  from typing import Annotated, Literal
4
4
 
5
- from pydantic import BaseModel, ConfigDict, Field, field_validator
5
+ from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
6
6
 
7
7
 
8
8
  MemoryKindValue = Literal["problem", "solution", "failed_tactic", "fact", "preference", "change", "frontier"]
9
9
  AssociationRelationValue = Literal["depends_on", "associated_with", "matures_into"]
10
+ ConceptReadFacetValue = Literal["claims", "relations", "groundings", "memory_links", "evidence"]
10
11
 
11
12
 
12
13
  class StrictBaseModel(BaseModel):
@@ -15,6 +16,43 @@ class StrictBaseModel(BaseModel):
15
16
  model_config = ConfigDict(extra="forbid")
16
17
 
17
18
 
19
+ class ReadConceptsExpandRequest(StrictBaseModel):
20
+ """This model defines concept-context read expansion controls."""
21
+
22
+ mode: Literal["auto", "none", "explicit"] = "auto"
23
+ refs: list[str] = Field(default_factory=list, max_length=5)
24
+ facets: list[ConceptReadFacetValue] = Field(default_factory=list, max_length=5)
25
+ max_auto: int = Field(default=2, ge=1, le=5)
26
+
27
+ @field_validator("refs")
28
+ @classmethod
29
+ def _validate_refs_unique(cls, value: list[str]) -> list[str]:
30
+ """This validator enforces unique concept refs."""
31
+
32
+ if any(not ref.strip() for ref in value):
33
+ raise ValueError("concept refs must be non-empty")
34
+ if len(value) != len(set(value)):
35
+ raise ValueError("concept refs must be unique")
36
+ return value
37
+
38
+ @field_validator("facets")
39
+ @classmethod
40
+ def _validate_facets_unique(cls, value: list[ConceptReadFacetValue]) -> list[ConceptReadFacetValue]:
41
+ """This validator enforces unique concept facets."""
42
+
43
+ if len(value) != len(set(value)):
44
+ raise ValueError("concept facets must be unique")
45
+ return value
46
+
47
+ @model_validator(mode="after")
48
+ def _validate_explicit_refs(self) -> "ReadConceptsExpandRequest":
49
+ """Require explicit concept refs when explicit mode is requested."""
50
+
51
+ if self.mode == "explicit" and not self.refs:
52
+ raise ValueError("expand.concepts.mode=explicit requires refs")
53
+ return self
54
+
55
+
18
56
  class ReadExpandRequest(StrictBaseModel):
19
57
  """This model defines expansion knobs for read requests."""
20
58
 
@@ -24,6 +62,7 @@ class ReadExpandRequest(StrictBaseModel):
24
62
  include_association_links: bool | None = None
25
63
  max_association_depth: int | None = Field(default=None, ge=1, le=4)
26
64
  min_association_strength: float | None = Field(default=None, ge=0.0, le=1.0)
65
+ concepts: ReadConceptsExpandRequest = Field(default_factory=ReadConceptsExpandRequest)
27
66
 
28
67
 
29
68
  class MemoryReadRequest(StrictBaseModel):
@@ -0,0 +1,302 @@
1
+ """Core entities and enums for the typed concept-context graph."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from datetime import datetime
7
+ from enum import Enum
8
+ from typing import Any
9
+
10
+
11
+ class ConceptKind(str, Enum):
12
+ """Allowed high-level concept kinds."""
13
+
14
+ DOMAIN = "domain"
15
+ CAPABILITY = "capability"
16
+ PROCESS = "process"
17
+ ENTITY = "entity"
18
+ RULE = "rule"
19
+ COMPONENT = "component"
20
+
21
+
22
+ class ConceptStatus(str, Enum):
23
+ """Lifecycle state for concept containers."""
24
+
25
+ ACTIVE = "active"
26
+ DEPRECATED = "deprecated"
27
+ ARCHIVED = "archived"
28
+
29
+
30
+ class ConceptLifecycleStatus(str, Enum):
31
+ """Lifecycle state for truth-bearing concept records."""
32
+
33
+ ACTIVE = "active"
34
+ MAYBE_STALE = "maybe_stale"
35
+ STALE = "stale"
36
+ SUPERSEDED = "superseded"
37
+ WRONG = "wrong"
38
+
39
+
40
+ class ConceptRelationPredicate(str, Enum):
41
+ """Allowed concept-to-concept predicates."""
42
+
43
+ CONTAINS = "contains"
44
+ INVOLVES = "involves"
45
+ PRECEDES = "precedes"
46
+ CONSTRAINS = "constrains"
47
+ DEPENDS_ON = "depends_on"
48
+
49
+
50
+ class ConceptClaimType(str, Enum):
51
+ """Allowed concept claim types."""
52
+
53
+ DEFINITION = "definition"
54
+ BEHAVIOR = "behavior"
55
+ INVARIANT = "invariant"
56
+ FAILURE_MODE = "failure_mode"
57
+ USAGE_NOTE = "usage_note"
58
+ OPEN_QUESTION = "open_question"
59
+
60
+
61
+ class AnchorKind(str, Enum):
62
+ """Allowed real-world locator kinds."""
63
+
64
+ FILE = "file"
65
+ SYMBOL = "symbol"
66
+ LINE_RANGE = "line_range"
67
+ API_ROUTE = "api_route"
68
+ DB_TABLE = "db_table"
69
+ SCHEMA = "schema"
70
+ CONFIG_KEY = "config_key"
71
+ TEST = "test"
72
+ METRIC = "metric"
73
+ LOG = "log"
74
+ DOC = "doc"
75
+ COMMIT = "commit"
76
+ MEMORY = "memory"
77
+
78
+
79
+ class AnchorStatus(str, Enum):
80
+ """Lifecycle state for real-world locators."""
81
+
82
+ ACTIVE = "active"
83
+ MAYBE_STALE = "maybe_stale"
84
+ STALE = "stale"
85
+ DEPRECATED = "deprecated"
86
+
87
+
88
+ class ConceptGroundingRole(str, Enum):
89
+ """Allowed concept-to-anchor grounding roles."""
90
+
91
+ IMPLEMENTATION = "implementation"
92
+ ENTRYPOINT = "entrypoint"
93
+ STORAGE = "storage"
94
+ CONFIGURATION = "configuration"
95
+ TEST = "test"
96
+ OBSERVABILITY = "observability"
97
+ DOCUMENTATION = "documentation"
98
+
99
+
100
+ class ConceptMemoryLinkRole(str, Enum):
101
+ """Allowed concept-to-memory link roles."""
102
+
103
+ EXAMPLE_OF = "example_of"
104
+ SOLUTION_FOR = "solution_for"
105
+ FAILED_TACTIC_FOR = "failed_tactic_for"
106
+ CHANGED = "changed"
107
+ VALIDATED = "validated"
108
+ CONTRADICTED = "contradicted"
109
+ WARNED_ABOUT = "warned_about"
110
+
111
+
112
+ class ConceptEvidenceTargetType(str, Enum):
113
+ """Truth-bearing concept record types that evidence may target."""
114
+
115
+ RELATION = "relation"
116
+ CLAIM = "claim"
117
+ GROUNDING = "grounding"
118
+ MEMORY_LINK = "memory_link"
119
+
120
+
121
+ class ConceptEvidenceKind(str, Enum):
122
+ """Allowed evidence source kinds for concept records."""
123
+
124
+ ANCHOR = "anchor"
125
+ MEMORY = "memory"
126
+ COMMIT = "commit"
127
+ TRANSCRIPT = "transcript"
128
+ TEST = "test"
129
+ MANUAL = "manual"
130
+
131
+
132
+ class ConceptSourceKind(str, Enum):
133
+ """Allowed source refs on concept lifecycle records."""
134
+
135
+ COMMIT = "commit"
136
+ FILE_HASH = "file_hash"
137
+ SYMBOL_HASH = "symbol_hash"
138
+ MEMORY = "memory"
139
+ TRANSCRIPT_EVENT = "transcript_event"
140
+ MANUAL = "manual"
141
+ DOC = "doc"
142
+ RUNTIME_TRACE = "runtime_trace"
143
+
144
+
145
+ class ConceptCreatedBy(str, Enum):
146
+ """Allowed authorship channels for concept records."""
147
+
148
+ WORKER = "worker"
149
+ LIBRARIAN = "librarian"
150
+ MANUAL = "manual"
151
+ IMPORT = "import"
152
+
153
+
154
+ class GraphPatchStatus(str, Enum):
155
+ """Allowed graph patch lifecycle states."""
156
+
157
+ PENDING = "pending"
158
+ APPLIED = "applied"
159
+ REJECTED = "rejected"
160
+
161
+
162
+ @dataclass(frozen=True, kw_only=True)
163
+ class Concept:
164
+ """One durable concept container."""
165
+
166
+ id: str
167
+ repo_id: str
168
+ slug: str
169
+ name: str
170
+ kind: ConceptKind
171
+ status: ConceptStatus = ConceptStatus.ACTIVE
172
+ scope_note: str | None = None
173
+ created_at: datetime | None = None
174
+ updated_at: datetime | None = None
175
+
176
+
177
+ @dataclass(frozen=True, kw_only=True)
178
+ class ConceptAlias:
179
+ """One alternate label for a concept."""
180
+
181
+ concept_id: str
182
+ repo_id: str
183
+ alias: str
184
+ normalized_alias: str
185
+ created_at: datetime | None = None
186
+
187
+
188
+ @dataclass(frozen=True, kw_only=True)
189
+ class ConceptLifecycle:
190
+ """Shared lifecycle fields for truth-bearing concept records."""
191
+
192
+ status: ConceptLifecycleStatus = ConceptLifecycleStatus.ACTIVE
193
+ confidence: float = 0.5
194
+ observed_at: datetime | None = None
195
+ validated_at: datetime | None = None
196
+ source_kind: ConceptSourceKind | None = None
197
+ source_ref: str | None = None
198
+ superseded_by_id: str | None = None
199
+ created_by: ConceptCreatedBy = ConceptCreatedBy.MANUAL
200
+
201
+
202
+ @dataclass(frozen=True, kw_only=True)
203
+ class ConceptRelation:
204
+ """One typed concept-to-concept relation."""
205
+
206
+ id: str
207
+ repo_id: str
208
+ subject_concept_id: str
209
+ predicate: ConceptRelationPredicate
210
+ object_concept_id: str
211
+ lifecycle: ConceptLifecycle = field(default_factory=ConceptLifecycle)
212
+ created_at: datetime | None = None
213
+ updated_at: datetime | None = None
214
+
215
+
216
+ @dataclass(frozen=True, kw_only=True)
217
+ class ConceptClaim:
218
+ """One typed statement Shellbrain believes about a concept."""
219
+
220
+ id: str
221
+ repo_id: str
222
+ concept_id: str
223
+ claim_type: ConceptClaimType
224
+ text: str
225
+ normalized_text: str
226
+ lifecycle: ConceptLifecycle = field(default_factory=ConceptLifecycle)
227
+ created_at: datetime | None = None
228
+ updated_at: datetime | None = None
229
+
230
+
231
+ @dataclass(frozen=True, kw_only=True)
232
+ class Anchor:
233
+ """One real-world locator that grounds a concept."""
234
+
235
+ id: str
236
+ repo_id: str
237
+ kind: AnchorKind
238
+ locator_json: dict[str, Any]
239
+ canonical_locator_hash: str
240
+ status: AnchorStatus = AnchorStatus.ACTIVE
241
+ created_at: datetime | None = None
242
+ updated_at: datetime | None = None
243
+
244
+
245
+ @dataclass(frozen=True, kw_only=True)
246
+ class ConceptGrounding:
247
+ """One typed link from concept space to a real-world anchor."""
248
+
249
+ id: str
250
+ repo_id: str
251
+ concept_id: str
252
+ role: ConceptGroundingRole
253
+ anchor_id: str
254
+ lifecycle: ConceptLifecycle = field(default_factory=ConceptLifecycle)
255
+ created_at: datetime | None = None
256
+ updated_at: datetime | None = None
257
+
258
+
259
+ @dataclass(frozen=True, kw_only=True)
260
+ class ConceptMemoryLink:
261
+ """One typed link from an existing Shellbrain memory to a concept."""
262
+
263
+ id: str
264
+ repo_id: str
265
+ concept_id: str
266
+ role: ConceptMemoryLinkRole
267
+ memory_id: str
268
+ lifecycle: ConceptLifecycle = field(default_factory=ConceptLifecycle)
269
+ created_at: datetime | None = None
270
+ updated_at: datetime | None = None
271
+
272
+
273
+ @dataclass(frozen=True, kw_only=True)
274
+ class ConceptEvidence:
275
+ """One evidence pointer attached to a truth-bearing concept record."""
276
+
277
+ id: str
278
+ repo_id: str
279
+ target_type: ConceptEvidenceTargetType
280
+ target_id: str
281
+ evidence_kind: ConceptEvidenceKind
282
+ anchor_id: str | None = None
283
+ memory_id: str | None = None
284
+ commit_ref: str | None = None
285
+ transcript_ref: str | None = None
286
+ note: str | None = None
287
+ created_at: datetime | None = None
288
+
289
+
290
+ @dataclass(frozen=True, kw_only=True)
291
+ class GraphPatch:
292
+ """Minimal reserved future graph-patch proposal record."""
293
+
294
+ id: str
295
+ repo_id: str
296
+ schema_version: str
297
+ status: GraphPatchStatus
298
+ proposed_by: ConceptCreatedBy
299
+ operations_json: list[dict[str, Any]]
300
+ evidence_summary: str | None = None
301
+ created_at: datetime | None = None
302
+ applied_at: datetime | None = None
@@ -72,6 +72,10 @@ class ReadSummaryRecord:
72
72
  direct_token_estimate: int | None
73
73
  explicit_related_token_estimate: int | None
74
74
  implicit_related_token_estimate: int | None
75
+ concept_count: int | None
76
+ concept_token_estimate: int | None
77
+ concept_refs_returned: list[str] | None
78
+ concept_facets_returned: list[str] | None
75
79
  created_at: datetime
76
80
 
77
81
 
@@ -5,6 +5,17 @@ from datetime import datetime
5
5
  from typing import Any, Sequence
6
6
 
7
7
  from app.core.entities.associations import AssociationEdge, AssociationObservation
8
+ from app.core.entities.concepts import (
9
+ Anchor,
10
+ Concept,
11
+ ConceptAlias,
12
+ ConceptClaim,
13
+ ConceptEvidence,
14
+ ConceptGrounding,
15
+ ConceptMemoryLink,
16
+ ConceptRelation,
17
+ GraphPatch,
18
+ )
8
19
  from app.core.entities.evidence import EvidenceRef
9
20
  from app.core.entities.episodes import Episode, EpisodeEvent, SessionTransfer
10
21
  from app.core.entities.facts import FactUpdate, ProblemAttempt
@@ -79,6 +90,70 @@ class IUtilityRepo(ABC):
79
90
  """This method appends a utility observation entry."""
80
91
 
81
92
 
93
+ class IConceptsRepo(ABC):
94
+ """This interface defines persistence operations for the concept-context graph."""
95
+
96
+ @abstractmethod
97
+ def upsert_concept(self, concept: Concept, aliases: Sequence[str]) -> Concept:
98
+ """This method inserts or updates a concept and its aliases."""
99
+
100
+ @abstractmethod
101
+ def get_concept_by_ref(self, *, repo_id: str, concept_ref: str) -> Concept | None:
102
+ """This method resolves a concept by id or slug."""
103
+
104
+ @abstractmethod
105
+ def list_concepts_by_ids(self, *, repo_id: str, concept_ids: Sequence[str]) -> Sequence[Concept]:
106
+ """This method returns concepts for the provided ids."""
107
+
108
+ @abstractmethod
109
+ def list_contains_edges(self, *, repo_id: str) -> Sequence[ConceptRelation]:
110
+ """This method returns active contains edges for cycle validation."""
111
+
112
+ @abstractmethod
113
+ def add_relation(self, relation: ConceptRelation) -> ConceptRelation:
114
+ """This method inserts or returns an active concept relation."""
115
+
116
+ @abstractmethod
117
+ def add_claim(self, claim: ConceptClaim) -> ConceptClaim:
118
+ """This method inserts or returns a concept claim."""
119
+
120
+ @abstractmethod
121
+ def upsert_anchor(self, anchor: Anchor) -> Anchor:
122
+ """This method inserts or returns an anchor by canonical locator."""
123
+
124
+ @abstractmethod
125
+ def get_anchor(self, *, repo_id: str, anchor_id: str) -> Anchor | None:
126
+ """This method fetches one anchor by id."""
127
+
128
+ @abstractmethod
129
+ def add_grounding(self, grounding: ConceptGrounding) -> ConceptGrounding:
130
+ """This method inserts or returns an active concept grounding."""
131
+
132
+ @abstractmethod
133
+ def add_memory_link(self, memory_link: ConceptMemoryLink) -> ConceptMemoryLink:
134
+ """This method inserts or returns an active concept-memory link."""
135
+
136
+ @abstractmethod
137
+ def add_evidence(self, evidence: ConceptEvidence) -> ConceptEvidence:
138
+ """This method appends one evidence pointer for a concept graph record."""
139
+
140
+ @abstractmethod
141
+ def create_graph_patch(self, patch: GraphPatch) -> GraphPatch:
142
+ """This method stores one future graph-patch proposal record."""
143
+
144
+ @abstractmethod
145
+ def get_concept_bundle(self, *, repo_id: str, concept_ref: str) -> dict[str, Any] | None:
146
+ """This method returns one concept plus directly related graph records."""
147
+
148
+ @abstractmethod
149
+ def find_concepts_for_memory_ids(self, *, repo_id: str, memory_ids: Sequence[str]) -> Sequence[dict[str, Any]]:
150
+ """This method returns concept-link matches for displayed memory ids."""
151
+
152
+ @abstractmethod
153
+ def search_concepts_by_text(self, *, repo_id: str, query: str, limit: int) -> Sequence[dict[str, Any]]:
154
+ """This method returns deterministic concept matches for query text."""
155
+
156
+
82
157
  class IEpisodesRepo(ABC):
83
158
  """This interface defines persistence operations for episodes and events."""
84
159