shellbrain 0.1.23__tar.gz → 0.1.25__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 (223) hide show
  1. {shellbrain-0.1.23 → shellbrain-0.1.25}/PKG-INFO +1 -1
  2. shellbrain-0.1.25/app/boot/migrations.py +115 -0
  3. shellbrain-0.1.25/app/core/contracts/concepts.py +212 -0
  4. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/contracts/requests.py +40 -1
  5. shellbrain-0.1.25/app/core/entities/concepts.py +302 -0
  6. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/entities/telemetry.py +4 -0
  7. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/interfaces/repos.py +75 -0
  8. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/interfaces/unit_of_work.py +2 -0
  9. shellbrain-0.1.25/app/core/use_cases/manage_concepts.py +460 -0
  10. shellbrain-0.1.25/app/core/use_cases/read_concepts.py +435 -0
  11. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/use_cases/read_memory.py +7 -0
  12. shellbrain-0.1.25/app/migrations/versions/20260421_0013_concept_context_graph.py +220 -0
  13. shellbrain-0.1.25/app/migrations/versions/20260422_0014_concept_read_telemetry.py +36 -0
  14. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/admin/init.py +5 -2
  15. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/cli/handlers.py +52 -0
  16. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/cli/hydration.py +8 -0
  17. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/cli/main.py +44 -3
  18. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/cli/schema_validation.py +18 -0
  19. shellbrain-0.1.25/app/periphery/db/models/concepts.py +247 -0
  20. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/models/registry.py +2 -1
  21. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/models/telemetry.py +4 -0
  22. shellbrain-0.1.25/app/periphery/db/repos/relational/concepts_repo.py +774 -0
  23. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/uow.py +2 -0
  24. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/telemetry/operation_summary.py +47 -1
  25. {shellbrain-0.1.23 → shellbrain-0.1.25}/pyproject.toml +1 -1
  26. {shellbrain-0.1.23 → shellbrain-0.1.25}/shellbrain.egg-info/PKG-INFO +1 -1
  27. {shellbrain-0.1.23 → shellbrain-0.1.25}/shellbrain.egg-info/SOURCES.txt +8 -0
  28. shellbrain-0.1.23/app/boot/migrations.py +0 -61
  29. {shellbrain-0.1.23 → shellbrain-0.1.25}/README.md +0 -0
  30. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/__init__.py +0 -0
  31. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/__main__.py +0 -0
  32. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/boot/__init__.py +0 -0
  33. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/boot/_dsn_resolution.py +0 -0
  34. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/boot/admin_db.py +0 -0
  35. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/boot/config.py +0 -0
  36. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/boot/create_policy.py +0 -0
  37. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/boot/db.py +0 -0
  38. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/boot/embeddings.py +0 -0
  39. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/boot/home.py +0 -0
  40. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/boot/read_policy.py +0 -0
  41. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/boot/repos.py +0 -0
  42. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/boot/retrieval.py +0 -0
  43. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/boot/thresholds.py +0 -0
  44. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/boot/update_policy.py +0 -0
  45. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/boot/use_cases.py +0 -0
  46. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/config/__init__.py +0 -0
  47. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/config/defaults/create_policy.yaml +0 -0
  48. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/config/defaults/read_policy.yaml +0 -0
  49. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/config/defaults/runtime.yaml +0 -0
  50. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/config/defaults/thresholds.yaml +0 -0
  51. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/config/defaults/update_policy.yaml +0 -0
  52. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/config/loader.py +0 -0
  53. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/__init__.py +0 -0
  54. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/contracts/__init__.py +0 -0
  55. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/contracts/errors.py +0 -0
  56. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/contracts/responses.py +0 -0
  57. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/entities/__init__.py +0 -0
  58. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/entities/associations.py +0 -0
  59. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/entities/episodes.py +0 -0
  60. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/entities/evidence.py +0 -0
  61. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/entities/facts.py +0 -0
  62. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/entities/guidance.py +0 -0
  63. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/entities/identity.py +0 -0
  64. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/entities/memory.py +0 -0
  65. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/entities/runtime_context.py +0 -0
  66. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/entities/session_state.py +0 -0
  67. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/entities/utility.py +0 -0
  68. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/interfaces/__init__.py +0 -0
  69. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/interfaces/clock.py +0 -0
  70. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/interfaces/config.py +0 -0
  71. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/interfaces/embeddings.py +0 -0
  72. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/interfaces/idgen.py +0 -0
  73. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/interfaces/retrieval.py +0 -0
  74. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/interfaces/session_state_store.py +0 -0
  75. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/policies/__init__.py +0 -0
  76. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/policies/_shared/__init__.py +0 -0
  77. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/policies/_shared/executor.py +0 -0
  78. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/policies/_shared/side_effects.py +0 -0
  79. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/policies/create_policy/__init__.py +0 -0
  80. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/policies/create_policy/pipeline.py +0 -0
  81. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/policies/read_policy/__init__.py +0 -0
  82. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/policies/read_policy/bm25.py +0 -0
  83. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/policies/read_policy/context_pack_builder.py +0 -0
  84. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/policies/read_policy/expansion.py +0 -0
  85. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/policies/read_policy/fusion_rrf.py +0 -0
  86. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/policies/read_policy/lexical_query.py +0 -0
  87. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/policies/read_policy/pipeline.py +0 -0
  88. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/policies/read_policy/scoring.py +0 -0
  89. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/policies/read_policy/seed_retrieval.py +0 -0
  90. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/policies/update_policy/__init__.py +0 -0
  91. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/policies/update_policy/pipeline.py +0 -0
  92. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/use_cases/__init__.py +0 -0
  93. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/use_cases/build_guidance.py +0 -0
  94. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/use_cases/create_memory.py +0 -0
  95. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/use_cases/manage_session_state.py +0 -0
  96. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/use_cases/record_episode_sync_telemetry.py +0 -0
  97. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/use_cases/record_model_usage_telemetry.py +0 -0
  98. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/use_cases/record_operation_telemetry.py +0 -0
  99. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/use_cases/sync_episode.py +0 -0
  100. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/core/use_cases/update_memory.py +0 -0
  101. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/migrations/__init__.py +0 -0
  102. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/migrations/env.py +0 -0
  103. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/migrations/versions/20260226_0001_initial_schema.py +0 -0
  104. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/migrations/versions/20260312_0002_add_hard_invariants.py +0 -0
  105. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/migrations/versions/20260312_0003_drop_create_confidence.py +0 -0
  106. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/migrations/versions/20260313_0004_episode_sync_hardening.py +0 -0
  107. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/migrations/versions/20260313_0005_evidence_episode_event_refs.py +0 -0
  108. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/migrations/versions/20260318_0006_usage_telemetry_schema.py +0 -0
  109. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/migrations/versions/20260319_0007_identity_session_guidance.py +0 -0
  110. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/migrations/versions/20260320_0008_instance_metadata_and_backup_safety.py +0 -0
  111. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/migrations/versions/20260410_0009_frontier_memory_family.py +0 -0
  112. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/migrations/versions/20260414_0010_model_usage_telemetry.py +0 -0
  113. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/migrations/versions/20260414_0011_usage_problem_tokens_multi_solution_metrics.py +0 -0
  114. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/migrations/versions/20260415_0012_read_pack_cost_and_read_roi.py +0 -0
  115. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/migrations/versions/__init__.py +0 -0
  116. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/onboarding_assets/__init__.py +0 -0
  117. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/onboarding_assets/claude/CLAUDE.md +0 -0
  118. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/onboarding_assets/claude/skills/shellbrain-session-start/SKILL.md +0 -0
  119. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/onboarding_assets/claude/skills/shellbrain-usage-review/SKILL.md +0 -0
  120. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/onboarding_assets/codex/AGENTS.md +0 -0
  121. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/onboarding_assets/codex/shellbrain-session-start/SKILL.md +0 -0
  122. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/onboarding_assets/codex/shellbrain-session-start/agents/openai.yaml +0 -0
  123. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/onboarding_assets/codex/shellbrain-session-start/assets/shellbrain-large.svg +0 -0
  124. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/onboarding_assets/codex/shellbrain-session-start/assets/shellbrain-small.svg +0 -0
  125. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/onboarding_assets/codex/shellbrain-session-start/assets/shellbrain_logo.png +0 -0
  126. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/onboarding_assets/codex/shellbrain-session-start/references/request-shapes.md +0 -0
  127. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/onboarding_assets/codex/shellbrain-session-start/references/session-workflow.md +0 -0
  128. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/onboarding_assets/codex/shellbrain-usage-review/SKILL.md +0 -0
  129. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/onboarding_assets/codex/shellbrain-usage-review/agents/openai.yaml +0 -0
  130. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/onboarding_assets/codex/shellbrain-usage-review/assets/shellbrain-small.svg +0 -0
  131. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/onboarding_assets/codex/shellbrain-usage-review/assets/shellbrain_logo.png +0 -0
  132. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/onboarding_assets/cursor/skills/shellbrain-session-start/SKILL.md +0 -0
  133. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/onboarding_assets/cursor/skills/shellbrain-usage-review/SKILL.md +0 -0
  134. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/__init__.py +0 -0
  135. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/admin/__init__.py +0 -0
  136. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/admin/agent_behavior_analysis.py +0 -0
  137. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/admin/analytics.py +0 -0
  138. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/admin/analytics_diagnostics.py +0 -0
  139. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/admin/analytics_queries.py +0 -0
  140. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/admin/backup.py +0 -0
  141. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/admin/destructive_guard.py +0 -0
  142. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/admin/doctor.py +0 -0
  143. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/admin/external_runtime.py +0 -0
  144. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/admin/init_errors.py +0 -0
  145. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/admin/instance_guard.py +0 -0
  146. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/admin/machine_state.py +0 -0
  147. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/admin/managed_runtime.py +0 -0
  148. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/admin/model_usage_backfill.py +0 -0
  149. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/admin/privileges.py +0 -0
  150. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/admin/repo_state.py +0 -0
  151. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/admin/restore.py +0 -0
  152. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/admin/storage_setup.py +0 -0
  153. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/admin/upgrade.py +0 -0
  154. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/cli/__init__.py +0 -0
  155. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/cli/presenter_json.py +0 -0
  156. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/__init__.py +0 -0
  157. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/engine.py +0 -0
  158. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/models/__init__.py +0 -0
  159. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/models/associations.py +0 -0
  160. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/models/episodes.py +0 -0
  161. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/models/evidence.py +0 -0
  162. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/models/experiences.py +0 -0
  163. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/models/instance_metadata.py +0 -0
  164. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/models/memories.py +0 -0
  165. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/models/metadata.py +0 -0
  166. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/models/utility.py +0 -0
  167. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/models/views.py +0 -0
  168. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/repos/__init__.py +0 -0
  169. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/repos/relational/__init__.py +0 -0
  170. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/repos/relational/associations_repo.py +0 -0
  171. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/repos/relational/episodes_repo.py +0 -0
  172. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/repos/relational/evidence_repo.py +0 -0
  173. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/repos/relational/experiences_repo.py +0 -0
  174. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/repos/relational/memories_repo.py +0 -0
  175. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/repos/relational/read_policy_repo.py +0 -0
  176. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/repos/relational/telemetry_repo.py +0 -0
  177. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/repos/relational/utility_repo.py +0 -0
  178. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/repos/semantic/__init__.py +0 -0
  179. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/repos/semantic/keyword_retrieval_repo.py +0 -0
  180. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/repos/semantic/semantic_retrieval_repo.py +0 -0
  181. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/db/session.py +0 -0
  182. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/embeddings/__init__.py +0 -0
  183. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/embeddings/local_provider.py +0 -0
  184. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/embeddings/query_vector_search.py +0 -0
  185. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/episodes/__init__.py +0 -0
  186. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/episodes/claude_code.py +0 -0
  187. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/episodes/codex.py +0 -0
  188. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/episodes/cursor.py +0 -0
  189. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/episodes/launcher.py +0 -0
  190. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/episodes/model_usage.py +0 -0
  191. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/episodes/normalization.py +0 -0
  192. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/episodes/poller.py +0 -0
  193. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/episodes/poller_lock.py +0 -0
  194. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/episodes/source_discovery.py +0 -0
  195. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/episodes/tool_filter.py +0 -0
  196. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/identity/__init__.py +0 -0
  197. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/identity/claude_hook_install.py +0 -0
  198. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/identity/claude_runtime.py +0 -0
  199. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/identity/codex_runtime.py +0 -0
  200. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/identity/compatibility.py +0 -0
  201. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/identity/cursor_statusline.py +0 -0
  202. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/identity/resolver.py +0 -0
  203. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/metrics/__init__.py +0 -0
  204. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/metrics/artifacts.py +0 -0
  205. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/metrics/browser.py +0 -0
  206. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/metrics/queries.py +0 -0
  207. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/metrics/render_html.py +0 -0
  208. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/metrics/service.py +0 -0
  209. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/onboarding/__init__.py +0 -0
  210. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/onboarding/host_assets.py +0 -0
  211. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/session_state/__init__.py +0 -0
  212. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/session_state/file_store.py +0 -0
  213. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/telemetry/__init__.py +0 -0
  214. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/telemetry/session_selection.py +0 -0
  215. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/telemetry/sync_summary.py +0 -0
  216. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/validation/__init__.py +0 -0
  217. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/validation/integrity_validation.py +0 -0
  218. {shellbrain-0.1.23 → shellbrain-0.1.25}/app/periphery/validation/semantic_validation.py +0 -0
  219. {shellbrain-0.1.23 → shellbrain-0.1.25}/setup.cfg +0 -0
  220. {shellbrain-0.1.23 → shellbrain-0.1.25}/shellbrain.egg-info/dependency_links.txt +0 -0
  221. {shellbrain-0.1.23 → shellbrain-0.1.25}/shellbrain.egg-info/entry_points.txt +0 -0
  222. {shellbrain-0.1.23 → shellbrain-0.1.25}/shellbrain.egg-info/requires.txt +0 -0
  223. {shellbrain-0.1.23 → shellbrain-0.1.25}/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.23
3
+ Version: 0.1.25
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,115 @@
1
+ """Packaged Alembic bootstrap helpers for installed-shellbrain database migrations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from importlib.resources import as_file, files
6
+ import importlib.metadata
7
+
8
+ from alembic import command
9
+ from alembic.config import Config
10
+ from alembic.script import ScriptDirectory
11
+ from alembic.script.revision import ResolutionError
12
+
13
+ from app.boot.admin_db import get_admin_db_dsn, get_backup_dir, get_backup_mirror_dir, get_instance_mode_default
14
+ from app.boot.db import get_optional_db_dsn
15
+ from app.periphery.admin.destructive_guard import backup_and_verify_before_destructive_action
16
+ from app.periphery.admin.instance_guard import ensure_instance_metadata, fetch_instance_metadata
17
+ from app.periphery.admin.privileges import reconcile_app_role_privileges
18
+
19
+
20
+ class DatabaseRevisionAheadOfInstalledPackageError(RuntimeError):
21
+ """Raised when the target database revision is newer than the installed package knows about."""
22
+
23
+
24
+ def upgrade_database(revision: str = "head") -> None:
25
+ """Apply packaged Alembic migrations to the configured database."""
26
+
27
+ config = Config()
28
+ admin_dsn = get_admin_db_dsn()
29
+ with as_file(files("app").joinpath("migrations")) as migrations_path:
30
+ config.set_main_option("script_location", str(migrations_path))
31
+ script = ScriptDirectory.from_config(config)
32
+ if _database_has_shellbrain_objects(admin_dsn):
33
+ _assert_database_revision_is_known(admin_dsn=admin_dsn, script=script)
34
+ backup_and_verify_before_destructive_action(
35
+ admin_dsn=admin_dsn,
36
+ backup_root=get_backup_dir(),
37
+ mirror_root=get_backup_mirror_dir(),
38
+ )
39
+ config.set_main_option("sqlalchemy.url", admin_dsn)
40
+ command.upgrade(config, revision)
41
+ if fetch_instance_metadata(admin_dsn) is None:
42
+ ensure_instance_metadata(
43
+ admin_dsn,
44
+ instance_mode=get_instance_mode_default(),
45
+ created_by="app.admin.migrate",
46
+ notes="Stamped by packaged migration runner.",
47
+ )
48
+ app_dsn = get_optional_db_dsn()
49
+ if app_dsn:
50
+ reconcile_app_role_privileges(admin_dsn=admin_dsn, app_dsn=app_dsn)
51
+
52
+
53
+ def _database_has_shellbrain_objects(admin_dsn: str) -> bool:
54
+ """Return whether the target database already contains Shellbrain-managed tables."""
55
+
56
+ import psycopg
57
+
58
+ with psycopg.connect(admin_dsn.replace("+psycopg", "")) as conn:
59
+ with conn.cursor() as cur:
60
+ cur.execute(
61
+ """
62
+ SELECT EXISTS (
63
+ SELECT 1
64
+ FROM information_schema.tables
65
+ WHERE table_schema = 'public'
66
+ AND table_name IN ('memories', 'episodes', 'episode_events', 'operation_invocations')
67
+ )
68
+ """
69
+ )
70
+ return bool(cur.fetchone()[0])
71
+
72
+
73
+ def _assert_database_revision_is_known(*, admin_dsn: str, script: ScriptDirectory) -> None:
74
+ """Fail early with a user-facing error when the database revision is newer than this package."""
75
+
76
+ current_revision = _fetch_database_revision(admin_dsn)
77
+ if current_revision is None:
78
+ return
79
+ try:
80
+ script.get_revision(current_revision)
81
+ except ResolutionError as exc:
82
+ installed_version = _installed_shellbrain_version()
83
+ raise DatabaseRevisionAheadOfInstalledPackageError(
84
+ "Installed Shellbrain package "
85
+ f"({installed_version}) cannot manage database revision {current_revision}. "
86
+ "This database was likely migrated by a newer Shellbrain release than the one currently installed. "
87
+ "Upgrade Shellbrain to a build that includes this revision, then rerun `shellbrain init` or "
88
+ "`shellbrain admin migrate`."
89
+ ) from exc
90
+
91
+
92
+ def _fetch_database_revision(admin_dsn: str) -> str | None:
93
+ """Return the current alembic revision when present."""
94
+
95
+ import psycopg
96
+
97
+ try:
98
+ with psycopg.connect(admin_dsn.replace("+psycopg", "")) as conn:
99
+ with conn.cursor() as cur:
100
+ cur.execute("SELECT version_num FROM alembic_version")
101
+ row = cur.fetchone()
102
+ except psycopg.Error:
103
+ return None
104
+ if row is None or row[0] is None:
105
+ return None
106
+ return str(row[0])
107
+
108
+
109
+ def _installed_shellbrain_version() -> str:
110
+ """Return the installed Shellbrain package version when available."""
111
+
112
+ try:
113
+ return importlib.metadata.version("shellbrain")
114
+ except importlib.metadata.PackageNotFoundError:
115
+ return "dev"
@@ -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