brainlayer 1.5.72__tar.gz → 1.5.74__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 (264) hide show
  1. {brainlayer-1.5.72 → brainlayer-1.5.74}/PKG-INFO +1 -1
  2. {brainlayer-1.5.72 → brainlayer-1.5.74}/pyproject.toml +1 -1
  3. {brainlayer-1.5.72 → brainlayer-1.5.74}/server.json +2 -2
  4. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/__init__.py +1 -1
  5. brainlayer-1.5.74/src/brainlayer/_build.py +1 -0
  6. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/backup_daily.py +4 -0
  7. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/maintenance_calendar.py +31 -3
  8. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/observability_backup.py +87 -6
  9. brainlayer-1.5.72/src/brainlayer/_build.py +0 -1
  10. {brainlayer-1.5.72 → brainlayer-1.5.74}/.gitignore +0 -0
  11. {brainlayer-1.5.72 → brainlayer-1.5.74}/LICENSE +0 -0
  12. {brainlayer-1.5.72 → brainlayer-1.5.74}/README.md +0 -0
  13. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/hotlane_brainbar_daemon.py +0 -0
  14. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/backup-daily.sh +0 -0
  15. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/brainlayer-env-run.sh +0 -0
  16. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/brainlayer.env.example +0 -0
  17. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.brainlayer.backup-daily.plist +0 -0
  18. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.brainlayer.daemon.plist +0 -0
  19. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.brainlayer.decay.plist +0 -0
  20. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.brainlayer.drain.plist +0 -0
  21. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.brainlayer.health-check.plist +0 -0
  22. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.brainlayer.hotlane-brainbar.plist +0 -0
  23. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.brainlayer.index.plist +0 -0
  24. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.brainlayer.jsonl-backup.plist +0 -0
  25. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.brainlayer.log-cap.plist +0 -0
  26. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.brainlayer.maintenance-nightly.plist +0 -0
  27. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.brainlayer.maintenance-weekly.plist +0 -0
  28. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.brainlayer.maintenance.plist +0 -0
  29. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.brainlayer.observability.plist +0 -0
  30. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.brainlayer.p0-counter.plist +0 -0
  31. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.brainlayer.repair-fts.plist +0 -0
  32. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.brainlayer.t3-ingest.plist +0 -0
  33. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.brainlayer.throughput-watchdog.plist +0 -0
  34. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.brainlayer.tier0-watchdog.plist +0 -0
  35. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.brainlayer.wal-checkpoint.plist +0 -0
  36. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.brainlayer.watch.plist +0 -0
  37. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/com.etanhey.brainlayer-fleet-watchdog.plist +0 -0
  38. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/fleet-watchdog.sh +0 -0
  39. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/install.sh +0 -0
  40. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/jsonl-backup.sh +0 -0
  41. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/launchd/throughput-watchdog.py +0 -0
  42. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/release-verify-signatures.sh +0 -0
  43. {brainlayer-1.5.72 → brainlayer-1.5.74}/scripts/tier0-watchdog.sh +0 -0
  44. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/__main__.py +0 -0
  45. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/_helpers.py +0 -0
  46. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/agent_profiles.py +0 -0
  47. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/agent_provenance.py +0 -0
  48. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/alarm.py +0 -0
  49. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/archive_collapse.py +0 -0
  50. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/archive_lifecycle.py +0 -0
  51. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/backup_retention_invariant.py +0 -0
  52. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/badge_state.py +0 -0
  53. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/bitemporal.py +0 -0
  54. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/brainbar_activation.py +0 -0
  55. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/brainbar_auto_activation.py +0 -0
  56. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/brainbar_hybrid_helper.py +0 -0
  57. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/brainbar_identity.py +0 -0
  58. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/cachedelete_purge.swift +0 -0
  59. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/calibrate.py +0 -0
  60. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/chunk_origin.py +0 -0
  61. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/chunk_origin_backfill.py +0 -0
  62. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/chunk_origin_wipe.py +0 -0
  63. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/chunk_write.py +0 -0
  64. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/classify.py +0 -0
  65. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/claude_paths.py +0 -0
  66. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/cli/__init__.py +0 -0
  67. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/cli/wizard.py +0 -0
  68. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/cli_jobs.py +0 -0
  69. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/cli_new.py +0 -0
  70. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/cloud_backfill.py +0 -0
  71. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/clustering.py +0 -0
  72. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/component_jobs.py +0 -0
  73. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/config.py +0 -0
  74. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/consolidation_plan.py +0 -0
  75. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/content_class.py +0 -0
  76. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/correction_judge.py +0 -0
  77. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/data/agents_registry.yaml +0 -0
  78. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/data/sandbox_seeds/skill-eval-baseline.json +0 -0
  79. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/db_shrink.py +0 -0
  80. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/decay.py +0 -0
  81. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/decay_backfill.py +0 -0
  82. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/decay_job.py +0 -0
  83. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/dedupe.py +0 -0
  84. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/dedupe_merge.py +0 -0
  85. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/deploy_drift.py +0 -0
  86. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/doctor.py +0 -0
  87. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/drain.py +0 -0
  88. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/drain_liveness.py +0 -0
  89. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/drive_credentials.py +0 -0
  90. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/embeddings.py +0 -0
  91. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/engine.py +0 -0
  92. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/enrichment_replay.py +0 -0
  93. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/__init__.py +0 -0
  94. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/abcde_enrich_runner.py +0 -0
  95. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/abcde_variants.py +0 -0
  96. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/abcde_variants.yaml +0 -0
  97. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/benchmark.py +0 -0
  98. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/enrichment_gold.py +0 -0
  99. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/enrichment_graders.py +0 -0
  100. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/enrichment_judge.py +0 -0
  101. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/enrichment_llm_judge.py +0 -0
  102. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/enrichment_quality_benchmark.py +0 -0
  103. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/experiment_store.py +0 -0
  104. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/fixtures/README.md +0 -0
  105. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/labeling/enrichment-labeler.html +0 -0
  106. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/phoenix_gate/__init__.py +0 -0
  107. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/phoenix_gate/__main__.py +0 -0
  108. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/phoenix_gate/baseline_store.py +0 -0
  109. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/phoenix_gate/cli.py +0 -0
  110. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/phoenix_gate/models.py +0 -0
  111. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/phoenix_gate/phoenix_client.py +0 -0
  112. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/phoenix_gate/regression_gate.py +0 -0
  113. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/phoenix_gate/triggers.py +0 -0
  114. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/eval/pilot_artifact_report.py +0 -0
  115. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/fallback_replay.py +0 -0
  116. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/git_learning.py +0 -0
  117. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/health_check.py +0 -0
  118. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/hook_python.py +0 -0
  119. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/hooks/__init__.py +0 -0
  120. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/hooks/indexer.py +0 -0
  121. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/import_sweep.py +0 -0
  122. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/index_admission.py +0 -0
  123. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/index_budget.py +0 -0
  124. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/index_completeness.py +0 -0
  125. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/index_new.py +0 -0
  126. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/index_watchdog.py +0 -0
  127. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/ingest/__init__.py +0 -0
  128. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/ingest/codex.py +0 -0
  129. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/ingest/t3.py +0 -0
  130. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/ingest_denylist.py +0 -0
  131. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/ingest_guard.py +0 -0
  132. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/isolation_proof.py +0 -0
  133. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/job_alerts.py +0 -0
  134. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/job_lifecycle_health.py +0 -0
  135. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/jobs.py +0 -0
  136. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/jsonl_backup.py +0 -0
  137. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/kg/__init__.py +0 -0
  138. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/kg_cleanup.py +0 -0
  139. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/kg_judge.py +0 -0
  140. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/kg_promotion.py +0 -0
  141. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/kg_repo.py +0 -0
  142. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/kg_review_session.py +0 -0
  143. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/kg_session_finish.py +0 -0
  144. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/kg_session_harvest.py +0 -0
  145. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/launchd_consolidation.py +0 -0
  146. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/launchd_install.py +0 -0
  147. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/launchd_primitive.py +0 -0
  148. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/launchd_revert.py +0 -0
  149. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/lexical_defense.py +0 -0
  150. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/lexical_defense_dictionary.json +0 -0
  151. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/log_cap.py +0 -0
  152. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/maintenance.py +0 -0
  153. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/maintenance_control.py +0 -0
  154. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/mcp/__init__.py +0 -0
  155. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/mcp/_format.py +0 -0
  156. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/mcp/_shared.py +0 -0
  157. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/mcp/enrich_handler.py +0 -0
  158. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/mcp/entity_handler.py +0 -0
  159. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/mcp/palette.py +0 -0
  160. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/mcp/search_handler.py +0 -0
  161. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/mcp/store_handler.py +0 -0
  162. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/mcp/tags_handler.py +0 -0
  163. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/mcp_socket_config.py +0 -0
  164. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/mcp_stdio_bridge.py +0 -0
  165. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/memory_types.py +0 -0
  166. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/migrate.py +0 -0
  167. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/migration_custody.py +0 -0
  168. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/migration_journal.py +0 -0
  169. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/migration_runtime.py +0 -0
  170. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/notification_policy.py +0 -0
  171. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/observability_surface.py +0 -0
  172. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/observability_transport.py +0 -0
  173. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/p0_longitudinal_count.py +0 -0
  174. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/parent_death.py +0 -0
  175. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/paths.py +0 -0
  176. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pause.py +0 -0
  177. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/phonetic.py +0 -0
  178. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/__init__.py +0 -0
  179. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/agent_enrichment.py +0 -0
  180. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/analyze_communication.py +0 -0
  181. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/batch_extraction.py +0 -0
  182. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/brain_graph.py +0 -0
  183. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/chat_tags.py +0 -0
  184. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/chunk.py +0 -0
  185. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/classify.py +0 -0
  186. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/cloud_scrub.py +0 -0
  187. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/cluster_sampling.py +0 -0
  188. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/code_intelligence.py +0 -0
  189. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/correction_detection.py +0 -0
  190. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/correction_mining.py +0 -0
  191. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/digest.py +0 -0
  192. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/enrichment_prompts.py +0 -0
  193. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/enrichment_results.py +0 -0
  194. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/enrichment_tiers.py +0 -0
  195. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/entity_extraction.py +0 -0
  196. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/entity_resolution.py +0 -0
  197. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/extract.py +0 -0
  198. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/extract_claude_desktop.py +0 -0
  199. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/extract_corrections.py +0 -0
  200. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/extract_markdown.py +0 -0
  201. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/extract_whatsapp.py +0 -0
  202. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/frustration_mining.py +0 -0
  203. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/git_overlay.py +0 -0
  204. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/kg_extraction.py +0 -0
  205. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/kg_extraction_groq.py +0 -0
  206. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/longitudinal_analyzer.py +0 -0
  207. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/obsidian_export.py +0 -0
  208. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/operation_grouping.py +0 -0
  209. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/plan_linking.py +0 -0
  210. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/rate_limiter.py +0 -0
  211. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/relation_backfill.py +0 -0
  212. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/relation_verification.py +0 -0
  213. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/sanitize.py +0 -0
  214. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/secret_scrub.py +0 -0
  215. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/semantic_style.py +0 -0
  216. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/sentiment.py +0 -0
  217. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/session_history.py +0 -0
  218. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/style_embed.py +0 -0
  219. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/style_index.py +0 -0
  220. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/tag_entity_promotion.py +0 -0
  221. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/temporal_chains.py +0 -0
  222. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/time_batcher.py +0 -0
  223. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/unified_timeline.py +0 -0
  224. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/pipeline/write_queue.py +0 -0
  225. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/provenance.py +0 -0
  226. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/provenance_autosupersede.py +0 -0
  227. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/provenance_integration.py +0 -0
  228. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/queue_io.py +0 -0
  229. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/queue_merge.py +0 -0
  230. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/reembed_backfill.py +0 -0
  231. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/retired_services.py +0 -0
  232. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/runtime_store.py +0 -0
  233. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/sandbox_db.py +0 -0
  234. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/scoping.py +0 -0
  235. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/scrub_at_rest.py +0 -0
  236. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/search_fanout.py +0 -0
  237. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/search_profile.py +0 -0
  238. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/search_repo.py +0 -0
  239. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/service_supervisor.py +0 -0
  240. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/session_repo.py +0 -0
  241. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/setup.py +0 -0
  242. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/socket_hygiene.py +0 -0
  243. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/source_class_migration.py +0 -0
  244. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/spotlight.py +0 -0
  245. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/storage.py +0 -0
  246. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/store.py +0 -0
  247. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/supervisor_adapters.py +0 -0
  248. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/supervisor_child.py +0 -0
  249. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/supervisor_guard.py +0 -0
  250. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/supervisor_jobs.py +0 -0
  251. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/system_prompt_guard.py +0 -0
  252. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/t3_linkage_alarm.py +0 -0
  253. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/t3_provenance.py +0 -0
  254. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/t3_sources.py +0 -0
  255. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/tag_normalization.py +0 -0
  256. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/taxonomy.json +0 -0
  257. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/telemetry.py +0 -0
  258. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/timestamp_iso.py +0 -0
  259. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/types.py +0 -0
  260. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/vector_store.py +0 -0
  261. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/wal_checkpoint.py +0 -0
  262. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/watcher.py +0 -0
  263. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/watcher_bridge.py +0 -0
  264. {brainlayer-1.5.72 → brainlayer-1.5.74}/src/brainlayer/writer_telemetry.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: brainlayer
3
- Version: 1.5.72
3
+ Version: 1.5.74
4
4
  Summary: Persistent local memory for AI agents — 16 BrainBar MCP tools, semantic search, knowledge graph, SQLite
5
5
  Project-URL: Homepage, https://brainlayer.etanheyman.com
6
6
  Project-URL: Repository, https://github.com/EtanHey/brainlayer
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "brainlayer"
3
- version = "1.5.72"
3
+ version = "1.5.74"
4
4
  description = "Persistent local memory for AI agents — 16 BrainBar MCP tools, semantic search, knowledge graph, SQLite"
5
5
  license = {text = "Apache-2.0"}
6
6
  readme = "README.md"
@@ -3,7 +3,7 @@
3
3
  "name": "io.github.etanhey/brainlayer",
4
4
  "title": "BrainLayer",
5
5
  "description": "Persistent local memory for AI agents \u2014 semantic search, knowledge graph, and 16 BrainBar MCP tools with ToolAnnotations over SQLite.",
6
- "version": "1.5.72",
6
+ "version": "1.5.74",
7
7
  "websiteUrl": "https://brainlayer.etanheyman.com",
8
8
  "repository": {
9
9
  "url": "https://github.com/EtanHey/brainlayer",
@@ -14,7 +14,7 @@
14
14
  "registryType": "pypi",
15
15
  "registryBaseUrl": "https://pypi.org",
16
16
  "identifier": "brainlayer",
17
- "version": "1.5.72",
17
+ "version": "1.5.74",
18
18
  "runtimeHint": "pipx",
19
19
  "transport": {
20
20
  "type": "stdio"
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- __version__ = "1.5.72"
5
+ __version__ = "1.5.74"
6
6
  # Git sha the distributed package was built from; stamped by the release build, None in a source tree.
7
7
  # scripts/sprint_gate.py reads it in "keg" mode to prove the served package is the code under test.
8
8
  # No runtime `str | None` annotation: launchd/install.sh imports this under /usr/bin/python3 (3.9).
@@ -0,0 +1 @@
1
+ BUILD_SHA = "d64d5a5486a7cc5013cef9135e615fdfc22c076f"
@@ -86,6 +86,7 @@ SNAPSHOT_RECEIPT_RESERVE_SECONDS = 60
86
86
  BACKUP_LOCAL_MAX_AGE_HOURS_ENV = "BRAINLAYER_BACKUP_LOCAL_MAX_AGE_HOURS"
87
87
  BACKUP_REUSE_VERIFIED_MAX_AGE_HOURS_ENV = "BRAINLAYER_BACKUP_REUSE_VERIFIED_MAX_AGE_HOURS"
88
88
  BACKUP_SUPERVISED_CHILD_ENV = "BRAINLAYER_BACKUP_SUPERVISED_CHILD"
89
+ BACKUP_INVOCATION_ENV = "BRAINLAYER_BACKUP_INVOCATION_ID"
89
90
  BACKUP_SQLITE_CHECK_TIMEOUT_ENV = "BRAINLAYER_BACKUP_SQLITE_CHECK_TIMEOUT_SECONDS"
90
91
  BACKUP_DRIVE_RETENTION_ENV = "BRAINLAYER_BACKUP_DRIVE_RETENTION"
91
92
  DRIVE_UPLOAD_DEADLINE_FLOOR_ENV = "BRAINLAYER_DRIVE_UPLOAD_DEADLINE_FLOOR_SECONDS"
@@ -2924,6 +2925,9 @@ def run_backup(
2924
2925
  "retention_deleted": [],
2925
2926
  "local_gzip_retention_deleted": [],
2926
2927
  }
2928
+ invocation = os.environ.get(BACKUP_INVOCATION_ENV, "")
2929
+ if re.fullmatch(r"[0-9a-f]{32}", invocation):
2930
+ result["backup_invocation_id"] = invocation # This body runs only after staging-lock admission.
2927
2931
 
2928
2932
  def record_reclamation_status(status: str, error: str | None) -> None:
2929
2933
  result["attempt_reclamation"] = status
@@ -7,6 +7,7 @@ import math
7
7
  import os
8
8
  import signal
9
9
  import time
10
+ import uuid
10
11
  from contextlib import ExitStack, asynccontextmanager
11
12
  from dataclasses import dataclass, field, replace
12
13
  from functools import partial
@@ -14,6 +15,7 @@ from pathlib import Path
14
15
 
15
16
  from . import maintenance_control
16
17
  from .backup_daily import (
18
+ BACKUP_INVOCATION_ENV,
17
19
  DEFAULT_SNAPSHOT_TIMEOUT_SECONDS,
18
20
  SNAPSHOT_RECEIPT_RESERVE_SECONDS,
19
21
  default_snapshot_timeout_seconds,
@@ -222,7 +224,12 @@ async def _execute_step(
222
224
  raise RuntimeError("calendar child birth unknown")
223
225
  custody.record(child.pid, birth)
224
226
  os.write(guard.stdin.fileno(), f"+{child.pid}\n".encode())
225
- record(directory, event="spawn", step=step.name, pid=child.pid)
227
+ identity = (
228
+ {"backup_invocation_id": env[BACKUP_INVOCATION_ENV]}
229
+ if step.name == "backup-daily" and env.get(BACKUP_INVOCATION_ENV)
230
+ else {}
231
+ )
232
+ record(directory, event="spawn", step=step.name, pid=child.pid, **identity)
226
233
  os.write(gate, b"R")
227
234
  budget, held, clock = backup_deadline(step), False, time.monotonic
228
235
  if deadline is not None:
@@ -264,9 +271,26 @@ async def _window(directory, step, now_fn, sleep_fn, stop):
264
271
  return not stop.is_set() and 4 <= now_fn().hour < 6
265
272
 
266
273
 
267
- def finish(directory, state, step, code, date, defer_after, missed=False, stopped=False, *, reason=None, replaces=None):
274
+ def finish(
275
+ directory,
276
+ state,
277
+ step,
278
+ code,
279
+ date,
280
+ defer_after,
281
+ missed=False,
282
+ stopped=False,
283
+ *,
284
+ reason=None,
285
+ replaces=None,
286
+ backup_invocation_id=None,
287
+ ):
268
288
  status = "stopped" if stopped else "deferred" if code == 75 else "ok" if code == 0 else "failed"
269
- detail = {key: value for key, value in dict(reason=reason, replaces=replaces).items() if value is not None}
289
+ detail = {
290
+ key: value
291
+ for key, value in dict(reason=reason, replaces=replaces, backup_invocation_id=backup_invocation_id).items()
292
+ if value is not None
293
+ }
270
294
  record(directory, event="finished", step=step.name, status=status, returncode=code, **detail)
271
295
  key = KEYS.get(step.name)
272
296
  notice = None
@@ -478,12 +502,14 @@ async def run_calendar(
478
502
  BRAINLAYER_SUPERVISOR_SOCKET=str(client.path),
479
503
  )
480
504
  env.pop("BRAINLAYER_BACKUP_SUPERVISED_CHILD", None)
505
+ env.pop(BACKUP_INVOCATION_ENV, None)
481
506
  for step in steps:
482
507
  active_step = step.name
483
508
  if stop.is_set():
484
509
  record(directory, event="finished", step=step.name, status="skipped", returncode=None)
485
510
  continue
486
511
  code, missed, reason, step_failed = 1, False, None, False
512
+ invocation = uuid.uuid4().hex if step.name == "backup-daily" else None
487
513
  try:
488
514
  bounded = step
489
515
  if step.name == "index":
@@ -511,6 +537,7 @@ async def run_calendar(
511
537
  BRAINLAYER_LAUNCHD_SERVICE=_service_name(step),
512
538
  XPC_SERVICE_NAME=f"com.brainlayer.{_service_name(step)}",
513
539
  )
540
+ | ({BACKUP_INVOCATION_ENV: invocation} if invocation else {})
514
541
  )
515
542
  try:
516
543
  async with step_hold(client, guard, child_env, step, now_fn) as held_env:
@@ -567,6 +594,7 @@ async def run_calendar(
567
594
  stopped,
568
595
  reason=reason,
569
596
  replaces="maintenance-nightly" if weekly_substitution and step.name == "maintenance-weekly" else None,
597
+ backup_invocation_id=invocation,
570
598
  )
571
599
  active_step = None
572
600
  if all(results.get(n) == "ok" for n in ("maintenance-weekly", "decay", "repair-fts")):
@@ -1,11 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import json
4
+ import math
4
5
  import os
6
+ import re
5
7
  import subprocess
6
8
  from datetime import UTC, datetime
7
9
  from pathlib import Path
8
- from typing import Any, Callable, Mapping
10
+ from typing import Any, Callable, Mapping, Sequence
9
11
 
10
12
  from brainlayer import backup_daily, jsonl_backup
11
13
  from brainlayer.backup_daily import _backup_log_path
@@ -173,8 +175,69 @@ def _db_snapshot_freshness(snapshot: dict[str, Any] | None, now: datetime) -> tu
173
175
  return "fresh", None
174
176
 
175
177
 
176
- def _local_snapshot(records: list[dict[str, Any]]) -> dict[str, Any] | None:
177
- real = [r for r in records if r.get("backup_log_provenance") == "real"]
178
+ def _read_calendar(path: Path) -> tuple[list[dict[str, Any]], str, int]:
179
+ """Retain complete evidence; a damaged append is a barrier, never an invisible join."""
180
+ try:
181
+ lines = path.read_bytes().splitlines(keepends=True)
182
+ except FileNotFoundError:
183
+ return [], "missing", 0
184
+ except OSError:
185
+ return [], "malformed", 0
186
+ records, skipped = [], 0
187
+ for line in lines:
188
+ try:
189
+ row = json.loads(line)
190
+ if not line.endswith(b"\n") or not isinstance(row, dict):
191
+ raise ValueError("incomplete calendar record")
192
+ except ValueError:
193
+ records.append({"event": "journal-gap"})
194
+ skipped += 1
195
+ else:
196
+ records.append(row)
197
+ return records, "read" if len(records) > skipped else "malformed" if lines else "empty", skipped
198
+
199
+
200
+ def _terminal_upload_error(local: dict[str, Any], calendar: Sequence[dict[str, Any]]) -> str | None:
201
+ """Only an admitted receipt's unique invocation can bind a terminal result."""
202
+ invocation = local.get("backup_invocation_id")
203
+ if not isinstance(invocation, str) or not re.fullmatch(r"[0-9a-f]{32}", invocation):
204
+ return None # Legacy timestamps prove no ownership, including lock-losing contenders.
205
+ started, seen = None, False
206
+ outcome = None
207
+ for row in calendar:
208
+ if row.get("event") in {"runner", "journal-gap"} and started is not None and outcome is None:
209
+ return None
210
+ if row.get("backup_invocation_id") != invocation:
211
+ continue
212
+ if row.get("step") != "backup-daily":
213
+ return None
214
+ ts = row.get("ts")
215
+ if type(ts) not in (int, float) or not math.isfinite(ts):
216
+ return None
217
+ if row.get("event") == "spawn":
218
+ if seen:
219
+ return None
220
+ started, seen = ts, True
221
+ elif row.get("event") == "finished":
222
+ status, code = row.get("status"), row.get("returncode")
223
+ if (
224
+ started is None
225
+ or outcome is not None
226
+ or ts < started
227
+ or status not in {"stopped", "failed", "ok"}
228
+ or type(code) is not int
229
+ ):
230
+ return None
231
+ outcome = f"Backup daily {status}, exit {code}; upload incomplete (no verified completion receipt)"
232
+ return outcome
233
+
234
+
235
+ def _local_snapshot(records: list[dict[str, Any]], *, calendar: Sequence[dict[str, Any]] = ()) -> dict[str, Any] | None:
236
+ real = [
237
+ r
238
+ for r in records
239
+ if r.get("backup_log_provenance") == "real" and r.get("error_type") != "BackupAlreadyRunningError"
240
+ ]
178
241
  latest = {r["snapshot"]: r for r in real if isinstance(r.get("snapshot"), str)}
179
242
  # Cleanup receipts for older copies cannot replace the newest snapshot's display.
180
243
  local = max(
@@ -188,14 +251,19 @@ def _local_snapshot(records: list[dict[str, Any]]) -> dict[str, Any] | None:
188
251
  (r for r in reversed(list(latest.values())) if r.get("upload_state") in {"failed", "abandoned"}), None
189
252
  )
190
253
  error = failed or (real[-1] if real and (real[-1].get("error") or real[-1].get("verification_error")) else {})
254
+ terminal_error = (
255
+ _terminal_upload_error(local, calendar)
256
+ if local.get("upload_state") in {"pending", "in_progress"} and not local.get("uploaded")
257
+ else None
258
+ )
191
259
  created = backup_daily._snapshot_created_time(local)
192
260
  return {
193
261
  "last_at": created.astimezone(UTC).isoformat().replace("+00:00", "Z") if created else None,
194
262
  "destination": Path(local["snapshot"]).name,
195
263
  "local_verified": local.get("local_verified") is True,
196
264
  "uploaded": local.get("uploaded") is True,
197
- "upload_state": local.get("upload_state", "pending"),
198
- "upload_error": error.get("error") or error.get("verification_error"),
265
+ "upload_state": "failed" if terminal_error else local.get("upload_state", "pending"),
266
+ "upload_error": terminal_error or error.get("error") or error.get("verification_error"),
199
267
  "local_integrity": local.get("local_integrity"),
200
268
  "local_integrity_pragma": local.get("local_integrity_pragma"),
201
269
  }
@@ -379,6 +447,19 @@ def build_backups_section(
379
447
  max_age_seconds=DEFAULT_JSONL_BACKUP_MAX_AGE_SECONDS,
380
448
  )
381
449
  snapshot, error_type, all_daily_errors = _daily_snapshot(daily_records)
450
+ local_snapshot = _local_snapshot(daily_records)
451
+ if local_snapshot is not None and local_snapshot["upload_state"] in {"pending", "in_progress"}:
452
+ control = Path(
453
+ env.get("BRAINLAYER_SUPERVISOR_SOCKET") or Path.home() / ".local/share/brainlayer/supervisor/control.sock"
454
+ ).expanduser()
455
+ calendar_path = control.parent / "calendar/runs.jsonl"
456
+ calendar, calendar_status, skipped = _read_calendar(calendar_path)
457
+ calendar_input = record_input(calendar_path, status=calendar_status, rows_or_bytes=None, skipped_lines=skipped)
458
+ inputs.append(calendar_input)
459
+ if calendar_input.get("status") == "future":
460
+ return _unmeasurable(f"input mtime is later than generated_at: {calendar_input['path']}", inputs)
461
+ if calendar_status == "read":
462
+ local_snapshot = _local_snapshot(daily_records, calendar=calendar)
382
463
  if error_type == "drive_credentials_missing" and _drive_token_is_usable(backup_daily.DEFAULT_TOKEN_PATH):
383
464
  error_type = "drive_credentials_restored_backup_pending"
384
465
  if error_type is None and health_issue is not None and health.state in {"invalid", "stale", "failed"}:
@@ -446,6 +527,6 @@ def build_backups_section(
446
527
  "disabled_dir_present": disabled_present,
447
528
  },
448
529
  "db_snapshot": snapshot,
449
- **({"local_snapshot": _local_snapshot(daily_records)} if _local_snapshot(daily_records) is not None else {}),
530
+ **({"local_snapshot": local_snapshot} if local_snapshot is not None else {}),
450
531
  "error_type": error_type,
451
532
  }
@@ -1 +0,0 @@
1
- BUILD_SHA = "bfd456ed149a3b573153318a684f8e4fbc6babb8"
File without changes
File without changes
File without changes