specsmith 0.14.1.dev546__tar.gz → 0.15.0.dev553__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 (301) hide show
  1. {specsmith-0.14.1.dev546/src/specsmith.egg-info → specsmith-0.15.0.dev553}/PKG-INFO +57 -3
  2. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/README.md +56 -2
  3. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/pyproject.toml +2 -1
  4. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/__init__.py +1 -1
  5. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/cli.py +426 -8
  6. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/compliance/__init__.py +7 -0
  7. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/compliance/reporter.py +33 -8
  8. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/config.py +1 -1
  9. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/governance_logic.py +25 -0
  10. specsmith-0.15.0.dev553/src/specsmith/wi_store.py +362 -0
  11. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553/src/specsmith.egg-info}/PKG-INFO +57 -3
  12. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith.egg-info/SOURCES.txt +4 -1
  13. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_cli.py +2 -2
  14. specsmith-0.15.0.dev553/tests/test_compliance_governance.py +1001 -0
  15. specsmith-0.15.0.dev553/tests/test_wi_lifecycle.py +937 -0
  16. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/LICENSE +0 -0
  17. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/setup.cfg +0 -0
  18. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/epistemic/__init__.py +0 -0
  19. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/epistemic/belief.py +0 -0
  20. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/epistemic/certainty.py +0 -0
  21. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/epistemic/failure_graph.py +0 -0
  22. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/epistemic/py.typed +0 -0
  23. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/epistemic/recovery.py +0 -0
  24. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/epistemic/session.py +0 -0
  25. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/epistemic/stress_tester.py +0 -0
  26. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/epistemic/trace.py +0 -0
  27. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/__main__.py +0 -0
  28. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/__init__.py +0 -0
  29. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/broker.py +0 -0
  30. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/chat_runner.py +0 -0
  31. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/cleanup.py +0 -0
  32. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/context_seed.py +0 -0
  33. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/core.py +0 -0
  34. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/dispatch/__init__.py +0 -0
  35. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/dispatch/_status.py +0 -0
  36. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/dispatch/dag.py +0 -0
  37. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/dispatch/dispatcher.py +0 -0
  38. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/dispatch/events.py +0 -0
  39. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/dispatch/result.py +0 -0
  40. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/endpoints.py +0 -0
  41. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/events.py +0 -0
  42. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/execution_profiles.py +0 -0
  43. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/fallback.py +0 -0
  44. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/hf_leaderboard.py +0 -0
  45. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/hf_sync.py +0 -0
  46. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/indexer.py +0 -0
  47. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/llm_client.py +0 -0
  48. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/mcp.py +0 -0
  49. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/memory.py +0 -0
  50. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/model_intelligence.py +0 -0
  51. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/model_profiles.py +0 -0
  52. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/orchestrator.py +0 -0
  53. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/permissions.py +0 -0
  54. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/profiles.py +0 -0
  55. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/provider_registry.py +0 -0
  56. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/repl.py +0 -0
  57. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/router.py +0 -0
  58. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/rules.py +0 -0
  59. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/runner.py +0 -0
  60. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/safety.py +0 -0
  61. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/spawner.py +0 -0
  62. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/suggester.py +0 -0
  63. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/teams.py +0 -0
  64. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/tools.py +0 -0
  65. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/verifier.py +0 -0
  66. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/voice.py +0 -0
  67. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/architect.py +0 -0
  68. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/auditor.py +0 -0
  69. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/auth.py +0 -0
  70. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/block_export.py +0 -0
  71. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/channel.py +0 -0
  72. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/ci_manager.py +0 -0
  73. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/commands/__init__.py +0 -0
  74. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/commands/intelligence.py +0 -0
  75. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/compliance/_compat.py +0 -0
  76. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/compliance/checker.py +0 -0
  77. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/compliance/evidence.py +0 -0
  78. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/compliance/regulations.py +0 -0
  79. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/compressor.py +0 -0
  80. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/console_utils.py +0 -0
  81. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/context_orchestrator.py +0 -0
  82. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/context_window.py +0 -0
  83. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/credit_analyzer.py +0 -0
  84. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/credits.py +0 -0
  85. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/datasources/__init__.py +0 -0
  86. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/datasources/base.py +0 -0
  87. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/datasources/citations.py +0 -0
  88. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/datasources/fpd.py +0 -0
  89. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/datasources/odp.py +0 -0
  90. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/datasources/patentsview.py +0 -0
  91. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/datasources/pfw.py +0 -0
  92. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/datasources/ppubs.py +0 -0
  93. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/datasources/ptab.py +0 -0
  94. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/differ.py +0 -0
  95. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/doctor.py +0 -0
  96. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/drive.py +0 -0
  97. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/editor.py +0 -0
  98. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/epistemic/__init__.py +0 -0
  99. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/epistemic/belief.py +0 -0
  100. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/epistemic/certainty.py +0 -0
  101. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/epistemic/failure_graph.py +0 -0
  102. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/epistemic/recovery.py +0 -0
  103. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/epistemic/stress_tester.py +0 -0
  104. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/esdb/__init__.py +0 -0
  105. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/esdb/_license.py +0 -0
  106. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/esdb/bridge.py +0 -0
  107. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/esdb/sqlite_store.py +0 -0
  108. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/eval/__init__.py +0 -0
  109. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/eval/builtins.py +0 -0
  110. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/eval/runner.py +0 -0
  111. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/executor.py +0 -0
  112. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/exporter.py +0 -0
  113. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/governance_store.py +0 -0
  114. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/governance_yaml.py +0 -0
  115. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/__init__.py +0 -0
  116. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/app.py +0 -0
  117. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/main_window.py +0 -0
  118. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/session_tab.py +0 -0
  119. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/theme.py +0 -0
  120. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/widgets/__init__.py +0 -0
  121. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/widgets/chat_view.py +0 -0
  122. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/widgets/input_bar.py +0 -0
  123. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/widgets/provider_bar.py +0 -0
  124. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/widgets/token_meter.py +0 -0
  125. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/widgets/tool_panel.py +0 -0
  126. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/widgets/update_checker.py +0 -0
  127. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/worker.py +0 -0
  128. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/history_search.py +0 -0
  129. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/importer.py +0 -0
  130. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/instinct.py +0 -0
  131. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/integrations/__init__.py +0 -0
  132. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/integrations/agent_skill.py +0 -0
  133. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/integrations/aider.py +0 -0
  134. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/integrations/base.py +0 -0
  135. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/integrations/claude_code.py +0 -0
  136. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/integrations/codity.py +0 -0
  137. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/integrations/copilot.py +0 -0
  138. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/integrations/cursor.py +0 -0
  139. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/integrations/gemini.py +0 -0
  140. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/integrations/windsurf.py +0 -0
  141. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/issue_reporter.py +0 -0
  142. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/languages.py +0 -0
  143. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/ledger.py +0 -0
  144. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/mcp_generator.py +0 -0
  145. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/mcp_server.py +0 -0
  146. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/migrations/__init__.py +0 -0
  147. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/migrations/m001_governance_yaml.py +0 -0
  148. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/migrations/m002_agents_slim.py +0 -0
  149. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/migrations/m003_compliance_init.py +0 -0
  150. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/migrations/m004_ledger_esdb.py +0 -0
  151. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/migrations/m005_agent_run_tool.py +0 -0
  152. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/migrations/m006_session_governance.py +0 -0
  153. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/migrations/runner.py +0 -0
  154. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/ollama_cmds.py +0 -0
  155. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/patent.py +0 -0
  156. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/paths.py +0 -0
  157. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/phase.py +0 -0
  158. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/plugins.py +0 -0
  159. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/profiles.py +0 -0
  160. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/rate_limits.py +0 -0
  161. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/releaser.py +0 -0
  162. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/requirements.py +0 -0
  163. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/requirements_parser.py +0 -0
  164. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/retrieval.py +0 -0
  165. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/safe_write.py +0 -0
  166. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/scaffolder.py +0 -0
  167. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/serve.py +0 -0
  168. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/session.py +0 -0
  169. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/session_init.py +0 -0
  170. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/session_store.py +0 -0
  171. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/__init__.py +0 -0
  172. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/ai_agents.py +0 -0
  173. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/cloud.py +0 -0
  174. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/corporate.py +0 -0
  175. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/cross_platform.py +0 -0
  176. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/data_engineering.py +0 -0
  177. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/devops.py +0 -0
  178. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/docs.py +0 -0
  179. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/embedded.py +0 -0
  180. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/governance.py +0 -0
  181. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/hardware.py +0 -0
  182. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/mobile.py +0 -0
  183. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/platform_engineering.py +0 -0
  184. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/productivity.py +0 -0
  185. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/software_engineering.py +0 -0
  186. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/specsmith_skills.py +0 -0
  187. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/ssh.py +0 -0
  188. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/web_backend.py +0 -0
  189. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills_builder.py +0 -0
  190. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/sync.py +0 -0
  191. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/agents.md.j2 +0 -0
  192. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
  193. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
  194. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/community/contributing.md.j2 +0 -0
  195. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
  196. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
  197. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/community/license-MIT.j2 +0 -0
  198. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
  199. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/community/security.md.j2 +0 -0
  200. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
  201. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
  202. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
  203. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
  204. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
  205. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/editorconfig.j2 +0 -0
  206. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/gitattributes.j2 +0 -0
  207. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/gitignore.j2 +0 -0
  208. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/go/go.mod.j2 +0 -0
  209. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/go/main.go.j2 +0 -0
  210. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
  211. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
  212. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
  213. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
  214. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
  215. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
  216. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/roles.md.j2 +0 -0
  217. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/rules.md.j2 +0 -0
  218. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
  219. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
  220. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/verification.md.j2 +0 -0
  221. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/js/package.json.j2 +0 -0
  222. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/ledger.md.j2 +0 -0
  223. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/python/cli.py.j2 +0 -0
  224. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/python/init.py.j2 +0 -0
  225. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
  226. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/readme.md.j2 +0 -0
  227. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
  228. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/rust/main.rs.j2 +0 -0
  229. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
  230. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
  231. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
  232. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
  233. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
  234. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
  235. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
  236. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/tool_installer.py +0 -0
  237. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/toolrules.py +0 -0
  238. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/tools.py +0 -0
  239. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/trace.py +0 -0
  240. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/updater.py +0 -0
  241. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/upgrader.py +0 -0
  242. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/validator.py +0 -0
  243. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/vcs/__init__.py +0 -0
  244. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/vcs/base.py +0 -0
  245. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/vcs/bitbucket.py +0 -0
  246. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/vcs/github.py +0 -0
  247. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/vcs/gitlab.py +0 -0
  248. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/vcs_commands.py +0 -0
  249. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/wireframes.py +0 -0
  250. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/workspace.py +0 -0
  251. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith.egg-info/dependency_links.txt +0 -0
  252. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith.egg-info/entry_points.txt +0 -0
  253. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith.egg-info/requires.txt +0 -0
  254. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith.egg-info/top_level.txt +0 -0
  255. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_CMD_001.py +0 -0
  256. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_agent_profiles.py +0 -0
  257. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_agent_run_feedback.py +0 -0
  258. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_agent_runner_ready.py +0 -0
  259. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_ai_client.py +0 -0
  260. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_ai_intelligence.py +0 -0
  261. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_auditor.py +0 -0
  262. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_channel.py +0 -0
  263. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_chat_diff_decision.py +0 -0
  264. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_chat_runner_openai_compat.py +0 -0
  265. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_chat_stdin_protocol.py +0 -0
  266. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_cli_workflows_history_drive.py +0 -0
  267. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_compliance.py +0 -0
  268. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_compressor.py +0 -0
  269. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_dispatch.py +0 -0
  270. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_e2e_nexus.py +0 -0
  271. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_endpoints_cli.py +0 -0
  272. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_endpoints_store.py +0 -0
  273. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_epistemic.py +0 -0
  274. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_esdb_license.py +0 -0
  275. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_esdb_sqlite.py +0 -0
  276. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_fallback_chain.py +0 -0
  277. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_importer.py +0 -0
  278. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_integrations.py +0 -0
  279. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_integrations_codity.py +0 -0
  280. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_intelligence.py +0 -0
  281. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_issue_reporter.py +0 -0
  282. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_mcp_client.py +0 -0
  283. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_mcp_server.py +0 -0
  284. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_new_modules.py +0 -0
  285. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_nexus.py +0 -0
  286. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_permissions.py +0 -0
  287. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_phase1_4_new.py +0 -0
  288. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_phase34_completion.py +0 -0
  289. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_rate_limits.py +0 -0
  290. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_req_248_262.py +0 -0
  291. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_req_358_359.py +0 -0
  292. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_scaffolder.py +0 -0
  293. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_skill_marketplace.py +0 -0
  294. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_skills_mcp.py +0 -0
  295. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_smoke.py +0 -0
  296. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_suggester.py +0 -0
  297. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_tools.py +0 -0
  298. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_validator.py +0 -0
  299. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_vcs.py +0 -0
  300. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_warp_parity.py +0 -0
  301. {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_warp_parity_followup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specsmith
3
- Version: 0.14.1.dev546
3
+ Version: 0.15.0.dev553
4
4
  Summary: AEE governance toolkit for AI-assisted development — session preflight gates, multi-agent dispatch, requirements↔test traceability, ESDB persistence, MCP server, and skills for Warp, Cursor, Claude Code, Copilot, Windsurf, and Aider.
5
5
  Author: Layer1Labs Silicon, Inc.
6
6
  License-Expression: MIT
@@ -363,6 +363,14 @@ agent:
363
363
 
364
364
  ## AI Compliance & Governance
365
365
 
366
+ > **DISCLAIMER — Best-effort only.** specsmith is designed to *help* teams build
367
+ > auditable, explainable AI systems, but **it does not guarantee compliance** with
368
+ > any law or regulation. Regulations change frequently; final compliance determination
369
+ > is solely the responsibility of the end user. Layer1Labs makes no legal warranty.
370
+ > Found outdated coverage or a missing regulation?
371
+ > [Open a ticket](https://github.com/layer1labs/specsmith/issues) — we actively
372
+ > maintain the regulation database and welcome compliance PRs.
373
+
366
374
  specsmith is designed from the ground up for **auditable, explainable, and human-overseen AI**.
367
375
  It implements concrete compliance mechanisms mapped to the two major regulatory frameworks
368
376
  that govern AI systems in production today.
@@ -501,8 +509,8 @@ specsmith export --format markdown > compliance-report.md
501
509
  specsmith export --format json > compliance-report.json
502
510
  ```
503
511
 
504
- This report is suitable for submission to regulators, internal audit teams, or
505
- SOC-2 / ISO-42001 reviewers.
512
+ This report is suitable as a starting point for audit evidence, but is **not a legal
513
+ certification**. Always verify with qualified counsel before regulatory submission.
506
514
 
507
515
  ### Compliance per Session and per Project
508
516
 
@@ -594,6 +602,52 @@ specsmith run
594
602
 
595
603
  ---
596
604
 
605
+ ## Work Item (WI) Lifecycle
606
+
607
+ Every accepted `specsmith preflight` mints a **Work Item** — a unique ID such as
608
+ `WI-3A9F1C02` that tracks user intent through the full governance lifecycle.
609
+ WIs are persisted to `.specsmith/workitems.json` and evolve through defined states:
610
+
611
+ | State | Meaning |
612
+ |---|---|
613
+ | `open` | Minted by preflight; work in progress |
614
+ | `implemented` | `specsmith verify` reached equilibrium (auto-set) |
615
+ | `promoted` | Elevated to a formal REQ-NNN via `specsmith wi promote` |
616
+ | `closed` | Done; maps to an existing requirement |
617
+ | `archived` | Deferred; may be re-opened |
618
+ | `rejected` | Explicitly rejected |
619
+
620
+ ```bash
621
+ # See all open work items
622
+ specsmith wi list --status open
623
+
624
+ # View full details of a WI
625
+ specsmith wi show WI-3A9F1C02
626
+
627
+ # Close a WI (change covered by an existing REQ)
628
+ specsmith wi close WI-3A9F1C02 --reason "covered by REQ-042"
629
+
630
+ # Promote a WI to a new requirement (new behaviour, no existing REQ)
631
+ specsmith wi promote WI-3A9F1C02 \
632
+ --title "System must retry on transient HTTP 5xx failures" \
633
+ --domain governance
634
+ specsmith sync # regenerate REQUIREMENTS.md
635
+
636
+ # Set kind label
637
+ specsmith wi tag WI-3A9F1C02 --kind bug
638
+
639
+ # Import historical WIs from LEDGER.md
640
+ specsmith wi import --from-ledger
641
+ ```
642
+
643
+ **When to promote vs close:** Promote (`wi promote`) when the change introduces new
644
+ behaviour not covered by any existing REQ and the pattern is expected to recur.
645
+ Close (`wi close`) for bug fixes, refactors, and chores that already have a matching REQ.
646
+
647
+ Full documentation: [`docs/site/wi-lifecycle.md`](docs/site/wi-lifecycle.md)
648
+
649
+ ---
650
+
597
651
  ## Nexus
598
652
 
599
653
  The Nexus runtime is specsmith's local-first agentic REPL — a
@@ -285,6 +285,14 @@ agent:
285
285
 
286
286
  ## AI Compliance & Governance
287
287
 
288
+ > **DISCLAIMER — Best-effort only.** specsmith is designed to *help* teams build
289
+ > auditable, explainable AI systems, but **it does not guarantee compliance** with
290
+ > any law or regulation. Regulations change frequently; final compliance determination
291
+ > is solely the responsibility of the end user. Layer1Labs makes no legal warranty.
292
+ > Found outdated coverage or a missing regulation?
293
+ > [Open a ticket](https://github.com/layer1labs/specsmith/issues) — we actively
294
+ > maintain the regulation database and welcome compliance PRs.
295
+
288
296
  specsmith is designed from the ground up for **auditable, explainable, and human-overseen AI**.
289
297
  It implements concrete compliance mechanisms mapped to the two major regulatory frameworks
290
298
  that govern AI systems in production today.
@@ -423,8 +431,8 @@ specsmith export --format markdown > compliance-report.md
423
431
  specsmith export --format json > compliance-report.json
424
432
  ```
425
433
 
426
- This report is suitable for submission to regulators, internal audit teams, or
427
- SOC-2 / ISO-42001 reviewers.
434
+ This report is suitable as a starting point for audit evidence, but is **not a legal
435
+ certification**. Always verify with qualified counsel before regulatory submission.
428
436
 
429
437
  ### Compliance per Session and per Project
430
438
 
@@ -516,6 +524,52 @@ specsmith run
516
524
 
517
525
  ---
518
526
 
527
+ ## Work Item (WI) Lifecycle
528
+
529
+ Every accepted `specsmith preflight` mints a **Work Item** — a unique ID such as
530
+ `WI-3A9F1C02` that tracks user intent through the full governance lifecycle.
531
+ WIs are persisted to `.specsmith/workitems.json` and evolve through defined states:
532
+
533
+ | State | Meaning |
534
+ |---|---|
535
+ | `open` | Minted by preflight; work in progress |
536
+ | `implemented` | `specsmith verify` reached equilibrium (auto-set) |
537
+ | `promoted` | Elevated to a formal REQ-NNN via `specsmith wi promote` |
538
+ | `closed` | Done; maps to an existing requirement |
539
+ | `archived` | Deferred; may be re-opened |
540
+ | `rejected` | Explicitly rejected |
541
+
542
+ ```bash
543
+ # See all open work items
544
+ specsmith wi list --status open
545
+
546
+ # View full details of a WI
547
+ specsmith wi show WI-3A9F1C02
548
+
549
+ # Close a WI (change covered by an existing REQ)
550
+ specsmith wi close WI-3A9F1C02 --reason "covered by REQ-042"
551
+
552
+ # Promote a WI to a new requirement (new behaviour, no existing REQ)
553
+ specsmith wi promote WI-3A9F1C02 \
554
+ --title "System must retry on transient HTTP 5xx failures" \
555
+ --domain governance
556
+ specsmith sync # regenerate REQUIREMENTS.md
557
+
558
+ # Set kind label
559
+ specsmith wi tag WI-3A9F1C02 --kind bug
560
+
561
+ # Import historical WIs from LEDGER.md
562
+ specsmith wi import --from-ledger
563
+ ```
564
+
565
+ **When to promote vs close:** Promote (`wi promote`) when the change introduces new
566
+ behaviour not covered by any existing REQ and the pattern is expected to recur.
567
+ Close (`wi close`) for bug fixes, refactors, and chores that already have a matching REQ.
568
+
569
+ Full documentation: [`docs/site/wi-lifecycle.md`](docs/site/wi-lifecycle.md)
570
+
571
+ ---
572
+
519
573
  ## Nexus
520
574
 
521
575
  The Nexus runtime is specsmith's local-first agentic REPL — a
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "specsmith"
7
- version = "0.14.1.dev546"
7
+ version = "0.15.0.dev553"
8
8
  description = "AEE governance toolkit for AI-assisted development — session preflight gates, multi-agent dispatch, requirements↔test traceability, ESDB persistence, MCP server, and skills for Warp, Cursor, Claude Code, Copilot, Windsurf, and Aider."
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -248,3 +248,4 @@ ignore_errors = true
248
248
 
249
249
  [tool.pytest.ini_options]
250
250
  testpaths = ["tests"]
251
+ pythonpath = ["src"]
@@ -8,4 +8,4 @@ from importlib.metadata import version as _pkg_version
8
8
  try:
9
9
  __version__: str = _pkg_version("specsmith")
10
10
  except PackageNotFoundError: # running from source without install
11
- __version__ = "0.14.1" # fallback: keep in sync with pyproject.toml
11
+ __version__ = "0.15.0" # fallback: keep in sync with pyproject.toml
@@ -2430,11 +2430,12 @@ def verify_release() -> None:
2430
2430
 
2431
2431
  # GitHub release
2432
2432
  try:
2433
- result = subprocess.run(
2433
+ result = subprocess.run( # noqa: S603, S607 — argv is a fixed, trusted CLI invocation
2434
2434
  ["gh", "release", "view", f"v{__version__}", "--json", "tagName"],
2435
2435
  capture_output=True,
2436
2436
  text=True,
2437
2437
  timeout=10,
2438
+ check=False,
2438
2439
  )
2439
2440
  if result.returncode == 0:
2440
2441
  console.print(f" [green]\u2713[/green] GitHub Release: v{__version__}")
@@ -3183,7 +3184,10 @@ def checkpoint_cmd(project_dir: str, as_json: bool) -> None:
3183
3184
  wal = root / ".chronomemory" / "events.wal"
3184
3185
  if wal.exists():
3185
3186
  with ChronoStore(root) as store:
3186
- esdb_ok = store.chain_valid()
3187
+ # Issue #202: chain_valid() may return non-bool (e.g. None or 0)
3188
+ # in some chronomemory versions for an intact chain. Treat any
3189
+ # value that is not the literal False as valid.
3190
+ esdb_ok = store.chain_valid() is not False
3187
3191
  esdb_records = store.record_count()
3188
3192
  except Exception: # noqa: BLE001
3189
3193
  pass
@@ -3260,8 +3264,10 @@ def checkpoint_cmd(project_dir: str, as_json: bool) -> None:
3260
3264
  r2_plain = f" Project : {project_name}"
3261
3265
  console.print(_arow(f" Project : [bold]{project_name}[/bold]", r2_plain))
3262
3266
 
3263
- r3_plain = f" Phase : {phase_emoji} {phase_label} ({phase_pct}%)"
3264
- console.print(_arow(r3_plain, r3_plain, wide=1 if phase_emoji else 0))
3267
+ # Emoji omitted from the anchor box: full-width glyphs vary by terminal
3268
+ # and break the fixed-width box alignment unpredictably (GH #align).
3269
+ r3_plain = f" Phase : {phase_label} ({phase_pct}%)"
3270
+ console.print(_arow(r3_plain, r3_plain))
3265
3271
 
3266
3272
  r4_plain = (
3267
3273
  f" Health : {health_icon} clean"
@@ -7278,8 +7284,12 @@ def tools_scan_cmd(project_dir: str, as_json: bool, fpga: bool) -> None:
7278
7284
  version = ""
7279
7285
  if path_found:
7280
7286
  try:
7281
- r = subprocess.run(
7282
- [exe, "--version"], capture_output=True, text=True, timeout=5
7287
+ r = subprocess.run( # noqa: S603, S607 — exe comes from a trusted hardcoded map
7288
+ [exe, "--version"],
7289
+ capture_output=True,
7290
+ text=True,
7291
+ timeout=5,
7292
+ check=False,
7283
7293
  )
7284
7294
  ver_out = (r.stdout + r.stderr).strip().splitlines()
7285
7295
  if ver_out:
@@ -8117,6 +8127,395 @@ def notebook_replay(slug: str, project_dir: str) -> None:
8117
8127
  main.add_command(notebook_group)
8118
8128
 
8119
8129
 
8130
+ # ---------------------------------------------------------------------------
8131
+ # specsmith wi — Work Item lifecycle management
8132
+ # ---------------------------------------------------------------------------
8133
+
8134
+
8135
+ @main.group(name="wi")
8136
+ def wi_group() -> None:
8137
+ """Manage the lifecycle of Work Items (WIs).
8138
+
8139
+ Work Items are governance breadcrumbs minted by ``specsmith preflight``.
8140
+ Every accepted preflight produces a WI such as ``WI-3A9F1C02``. WIs
8141
+ evolve through the following states:
8142
+
8143
+ \b
8144
+ open created by preflight; work in progress
8145
+ implemented verify reached equilibrium (auto-set by specsmith verify)
8146
+ promoted WI elevated to a formal REQ-NNN (new requirement)
8147
+ closed done; maps to an existing REQ; no new requirement needed
8148
+ archived abandoned or deferred; may be re-opened
8149
+ rejected explicitly rejected
8150
+
8151
+ State machine:
8152
+
8153
+ \b
8154
+ open → implemented → promoted
8155
+ → closed
8156
+ → archived
8157
+ → archived
8158
+ → rejected
8159
+ archived → open (un-defer)
8160
+
8161
+ When to promote a WI to a REQ:
8162
+
8163
+ \b
8164
+ - The change introduced new behavior not covered by any existing requirement.
8165
+ - The pattern is expected to recur and needs permanent test coverage.
8166
+ - The WI's ``requirement_ids`` list was empty at preflight time.
8167
+
8168
+ When to close (not promote):
8169
+
8170
+ \b
8171
+ - Bug fix against an existing REQ.
8172
+ - Refactoring or performance work within existing requirements.
8173
+ - Docs / chore work with no new functionality.
8174
+ """
8175
+
8176
+
8177
+ @wi_group.command(name="list")
8178
+ @click.option("--project-dir", type=click.Path(exists=True), default=".")
8179
+ @click.option(
8180
+ "--status",
8181
+ "filter_status",
8182
+ default="",
8183
+ help="Filter by status: open|implemented|promoted|closed|archived|rejected.",
8184
+ )
8185
+ @click.option("--json", "as_json", is_flag=True, default=False)
8186
+ def wi_list_cmd(project_dir: str, filter_status: str, as_json: bool) -> None:
8187
+ """List work items, optionally filtered by status."""
8188
+ import json as _json
8189
+
8190
+ from specsmith.wi_store import WorkItemStore
8191
+
8192
+ root = Path(project_dir).resolve()
8193
+ store = WorkItemStore(root)
8194
+ items = store.list_by_status(filter_status or None)
8195
+
8196
+ if as_json:
8197
+ click.echo(_json.dumps([i.to_dict() for i in items], indent=2))
8198
+ return
8199
+
8200
+ if not items:
8201
+ console.print("[dim]No work items found.[/dim]")
8202
+ return
8203
+
8204
+ _STATUS_COLOR = {
8205
+ "open": "cyan",
8206
+ "implemented": "green",
8207
+ "promoted": "bold green",
8208
+ "closed": "dim",
8209
+ "archived": "yellow",
8210
+ "rejected": "red",
8211
+ }
8212
+ console.print(f"[bold]Work Items[/bold] ({root.name})\n")
8213
+ for item in items:
8214
+ color = _STATUS_COLOR.get(item.status, "white")
8215
+ req_tag = f" [{', '.join(item.requirement_ids)}]" if item.requirement_ids else ""
8216
+ promoted_tag = f" → {item.promoted_to_req}" if item.promoted_to_req else ""
8217
+ console.print(
8218
+ f" [{color}]{item.id}[/{color}] "
8219
+ f"[{color}]{item.status:12s}[/{color}] "
8220
+ f"[dim]{item.kind:9s}[/dim] "
8221
+ f"{item.intent[:60]}"
8222
+ f"[dim]{req_tag}{promoted_tag}[/dim]"
8223
+ )
8224
+
8225
+
8226
+ @wi_group.command(name="show")
8227
+ @click.argument("wi_id")
8228
+ @click.option("--project-dir", type=click.Path(exists=True), default=".")
8229
+ @click.option("--json", "as_json", is_flag=True, default=False)
8230
+ def wi_show_cmd(wi_id: str, project_dir: str, as_json: bool) -> None:
8231
+ """Show full details for a work item."""
8232
+ import json as _json
8233
+
8234
+ from specsmith.wi_store import WorkItemStore
8235
+
8236
+ root = Path(project_dir).resolve()
8237
+ store = WorkItemStore(root)
8238
+ item = store.get(wi_id.upper())
8239
+ if item is None:
8240
+ console.print(f"[red]Work item {wi_id!r} not found.[/red]")
8241
+ raise SystemExit(1)
8242
+
8243
+ if as_json:
8244
+ click.echo(_json.dumps(item.to_dict(), indent=2))
8245
+ return
8246
+
8247
+ console.print(f"\n[bold cyan]{item.id}[/bold cyan]")
8248
+ console.print(f" Status : {item.status}")
8249
+ console.print(f" Kind : {item.kind}")
8250
+ console.print(f" Intent : {item.intent}")
8251
+ console.print(f" Created : {item.created_at}")
8252
+ console.print(f" Updated : {item.updated_at}")
8253
+ console.print(f" Verified : {item.verified}")
8254
+ console.print(f" Req IDs : {', '.join(item.requirement_ids) or '(none)'}")
8255
+ console.print(f" Test IDs : {', '.join(item.test_case_ids) or '(none)'}")
8256
+ if item.promoted_to_req:
8257
+ console.print(f" Promoted : [green]{item.promoted_to_req}[/green]")
8258
+ if item.closed_at:
8259
+ console.print(f" Closed : {item.closed_at}")
8260
+ if item.closed_reason:
8261
+ console.print(f" Reason : {item.closed_reason}")
8262
+
8263
+
8264
+ @wi_group.command(name="close")
8265
+ @click.argument("wi_id")
8266
+ @click.option("--project-dir", type=click.Path(exists=True), default=".")
8267
+ @click.option("--reason", default="", help="Reason for closing (optional).")
8268
+ def wi_close_cmd(wi_id: str, project_dir: str, reason: str) -> None:
8269
+ """Close a work item (done; maps to an existing requirement)."""
8270
+ from specsmith.wi_store import WorkItemError, WorkItemStore
8271
+
8272
+ root = Path(project_dir).resolve()
8273
+ store = WorkItemStore(root)
8274
+ try:
8275
+ item = store.set_status(wi_id.upper(), "closed", reason=reason)
8276
+ except WorkItemError as exc:
8277
+ console.print(f"[red]{exc}[/red]")
8278
+ raise SystemExit(1) from exc
8279
+ console.print(f"[green]\u2713[/green] {item.id} → closed")
8280
+ try:
8281
+ from specsmith.ledger import add_entry
8282
+
8283
+ add_entry(
8284
+ root,
8285
+ description=f"wi_close {item.id}: {reason or 'done'}",
8286
+ entry_type="wi_close",
8287
+ author="specsmith",
8288
+ )
8289
+ except Exception: # noqa: BLE001
8290
+ pass
8291
+
8292
+
8293
+ @wi_group.command(name="archive")
8294
+ @click.argument("wi_id")
8295
+ @click.option("--project-dir", type=click.Path(exists=True), default=".")
8296
+ @click.option("--reason", default="", help="Reason for archiving (optional).")
8297
+ def wi_archive_cmd(wi_id: str, project_dir: str, reason: str) -> None:
8298
+ """Archive a work item (abandoned or deferred).
8299
+
8300
+ Archived WIs may be re-opened with ``specsmith wi tag --kind <kind>`` or
8301
+ by using ``specsmith preflight`` for the same intent again.
8302
+ """
8303
+ from specsmith.wi_store import WorkItemError, WorkItemStore
8304
+
8305
+ root = Path(project_dir).resolve()
8306
+ store = WorkItemStore(root)
8307
+ try:
8308
+ item = store.set_status(wi_id.upper(), "archived", reason=reason)
8309
+ except WorkItemError as exc:
8310
+ console.print(f"[red]{exc}[/red]")
8311
+ raise SystemExit(1) from exc
8312
+ console.print(f"[yellow]\u2714[/yellow] {item.id} → archived")
8313
+ try:
8314
+ from specsmith.ledger import add_entry
8315
+
8316
+ add_entry(
8317
+ root,
8318
+ description=f"wi_archive {item.id}: {reason or 'deferred'}",
8319
+ entry_type="wi_archive",
8320
+ author="specsmith",
8321
+ )
8322
+ except Exception: # noqa: BLE001
8323
+ pass
8324
+
8325
+
8326
+ @wi_group.command(name="promote")
8327
+ @click.argument("wi_id")
8328
+ @click.option("--project-dir", type=click.Path(exists=True), default=".")
8329
+ @click.option("--title", default="", help="REQ title (defaults to WI intent).")
8330
+ @click.option(
8331
+ "--domain",
8332
+ default="overflow",
8333
+ help="Requirements domain YAML to append to (default: overflow).",
8334
+ )
8335
+ @click.option("--json", "as_json", is_flag=True, default=False)
8336
+ def wi_promote_cmd(wi_id: str, project_dir: str, title: str, domain: str, as_json: bool) -> None:
8337
+ """Promote a work item to a formal requirement (REQ-NNN).
8338
+
8339
+ Creates a new requirement entry in ``docs/requirements/<domain>.yml``,
8340
+ writes the REQ-NNN back to the WI record, and runs ``specsmith sync``
8341
+ to regenerate REQUIREMENTS.md.
8342
+
8343
+ Example:
8344
+
8345
+ \b
8346
+ # WI introduced new retry logic not covered by any existing REQ
8347
+ specsmith wi promote WI-3A9F1C02 \\
8348
+ --title "Exporter must retry on transient HTTP failures" \\
8349
+ --domain overflow
8350
+ """
8351
+ import json as _json
8352
+
8353
+ from specsmith.wi_store import WorkItemError, WorkItemStore
8354
+
8355
+ root = Path(project_dir).resolve()
8356
+ store = WorkItemStore(root)
8357
+
8358
+ item = store.get(wi_id.upper())
8359
+ if item is None:
8360
+ console.print(f"[red]Work item {wi_id!r} not found.[/red]")
8361
+ raise SystemExit(1)
8362
+ if item.is_terminal() and item.status != "implemented":
8363
+ console.print(
8364
+ f"[red]Cannot promote {wi_id}: already in terminal state {item.status!r}.[/red]"
8365
+ )
8366
+ raise SystemExit(1)
8367
+
8368
+ # ── Find the domain YAML file ──────────────────────────────────────────
8369
+ req_dir = root / "docs" / "requirements"
8370
+ yaml_path = req_dir / f"{domain}.yml"
8371
+ if not yaml_path.is_file():
8372
+ # Fall back to overflow.yml; create if missing
8373
+ yaml_path = req_dir / "overflow.yml"
8374
+
8375
+ # ── Determine next REQ-NNN ────────────────────────────────────────────
8376
+ import re
8377
+
8378
+ import yaml # type: ignore[import-untyped]
8379
+
8380
+ all_req_ids: list[int] = []
8381
+ for yf in req_dir.glob("*.yml"):
8382
+ try:
8383
+ entries = yaml.safe_load(yf.read_text(encoding="utf-8")) or []
8384
+ for entry in entries:
8385
+ if isinstance(entry, dict):
8386
+ m = re.match(r"REQ-(\d+)", str(entry.get("id", "")))
8387
+ if m:
8388
+ all_req_ids.append(int(m.group(1)))
8389
+ except Exception: # noqa: BLE001
8390
+ pass
8391
+ next_num = (max(all_req_ids) + 1) if all_req_ids else 400
8392
+ new_req_id = f"REQ-{next_num}"
8393
+
8394
+ # ── Build REQ entry ───────────────────────────────────────────────────
8395
+ req_title = title.strip() or item.intent[:120] or f"Work item {item.id}"
8396
+
8397
+ # ── Append to domain YAML ─────────────────────────────────────────────
8398
+ yaml_path.parent.mkdir(parents=True, exist_ok=True)
8399
+ existing_text = yaml_path.read_text(encoding="utf-8") if yaml_path.is_file() else ""
8400
+ entry_yaml = (
8401
+ f"- id: {new_req_id}\n"
8402
+ f" title: {req_title}\n"
8403
+ f" description: >-\n"
8404
+ f" Promoted from {item.id}. {item.intent}\n"
8405
+ f" source: {item.id}\n"
8406
+ f" status: planned\n"
8407
+ )
8408
+ yaml_path.write_text(
8409
+ (existing_text.rstrip() + "\n" + entry_yaml) if existing_text.strip() else entry_yaml,
8410
+ encoding="utf-8",
8411
+ )
8412
+
8413
+ # ── Update WI record ──────────────────────────────────────────────────
8414
+ try:
8415
+ store.promote_to_req(item.id, new_req_id)
8416
+ except WorkItemError as exc:
8417
+ console.print(f"[red]{exc}[/red]")
8418
+ raise SystemExit(1) from exc
8419
+
8420
+ # ── Ledger entry ──────────────────────────────────────────────────────
8421
+ try:
8422
+ from specsmith.ledger import add_entry
8423
+
8424
+ add_entry(
8425
+ root,
8426
+ description=f"wi_promote {item.id} → {new_req_id}: {req_title}",
8427
+ entry_type="wi_promote",
8428
+ author="specsmith",
8429
+ )
8430
+ except Exception: # noqa: BLE001
8431
+ pass
8432
+
8433
+ if as_json:
8434
+ click.echo(
8435
+ _json.dumps(
8436
+ {
8437
+ "wi_id": item.id,
8438
+ "promoted_to": new_req_id,
8439
+ "req_file": str(yaml_path.relative_to(root)),
8440
+ },
8441
+ indent=2,
8442
+ )
8443
+ )
8444
+ return
8445
+
8446
+ console.print(
8447
+ f"[green]\u2713[/green] {item.id} → [bold green]{new_req_id}[/bold green]\n"
8448
+ f" Title : {req_title}\n"
8449
+ f" File : {yaml_path.relative_to(root)}\n"
8450
+ f" Next : run [bold]specsmith sync[/bold] to regenerate REQUIREMENTS.md"
8451
+ )
8452
+
8453
+
8454
+ @wi_group.command(name="tag")
8455
+ @click.argument("wi_id")
8456
+ @click.option(
8457
+ "--kind",
8458
+ required=True,
8459
+ type=click.Choice(["feature", "bug", "chore", "spike", "refactor", "docs"]),
8460
+ help="WI kind / classification label.",
8461
+ )
8462
+ @click.option("--project-dir", type=click.Path(exists=True), default=".")
8463
+ def wi_tag_cmd(wi_id: str, kind: str, project_dir: str) -> None:
8464
+ """Set the kind / classification label on a work item."""
8465
+ from specsmith.wi_store import WorkItemError, WorkItemStore
8466
+
8467
+ root = Path(project_dir).resolve()
8468
+ store = WorkItemStore(root)
8469
+ try:
8470
+ item = store.tag(wi_id.upper(), kind)
8471
+ except WorkItemError as exc:
8472
+ console.print(f"[red]{exc}[/red]")
8473
+ raise SystemExit(1) from exc
8474
+ console.print(f"[green]\u2713[/green] {item.id} → kind={item.kind}")
8475
+
8476
+
8477
+ @wi_group.command(name="import")
8478
+ @click.option("--project-dir", type=click.Path(exists=True), default=".")
8479
+ @click.option(
8480
+ "--from-ledger",
8481
+ "from_ledger",
8482
+ is_flag=True,
8483
+ default=True,
8484
+ help="Import WIs from LEDGER.md work_proposal entries (default: on).",
8485
+ )
8486
+ def wi_import_cmd(project_dir: str, from_ledger: bool) -> None:
8487
+ """Import work items from LEDGER.md into .specsmith/workitems.json.
8488
+
8489
+ Useful for projects that already have WIs in their ledger but haven't
8490
+ yet run the ``wi`` command group. Existing WIs are never overwritten.
8491
+ """
8492
+ from specsmith.wi_store import WorkItemStore
8493
+
8494
+ root = Path(project_dir).resolve()
8495
+ store = WorkItemStore(root)
8496
+ imported = 0
8497
+ if from_ledger:
8498
+ for cand in ["docs/LEDGER.md", "LEDGER.md"]:
8499
+ lp = root / cand
8500
+ if lp.is_file():
8501
+ imported += store.import_from_ledger(lp)
8502
+ break
8503
+ if imported:
8504
+ console.print(f"[green]\u2713[/green] Imported {imported} work item(s) from LEDGER.md")
8505
+ else:
8506
+ console.print("[dim]No new work items found to import.[/dim]")
8507
+
8508
+
8509
+ def _now_ts() -> str:
8510
+ """Return current UTC timestamp as ISO-8601 string."""
8511
+ import time
8512
+
8513
+ return time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
8514
+
8515
+
8516
+ main.add_command(wi_group)
8517
+
8518
+
8120
8519
  # ---------------------------------------------------------------------------
8121
8520
  # Workflow — parameterised command snippets (Warp-style Workflows)
8122
8521
  # ---------------------------------------------------------------------------
@@ -10044,7 +10443,9 @@ def esdb_status_cmd(project_dir: str, as_json: bool) -> None:
10044
10443
  try:
10045
10444
  with store as s: # type: ignore[attr-defined]
10046
10445
  record_count = s.record_count()
10047
- chain_ok = s.chain_valid()
10446
+ # Issue #202: chain_valid() may return non-bool in some chronomemory
10447
+ # versions for an intact chain. Only treat literal False as invalid.
10448
+ chain_ok = s.chain_valid() is not False
10048
10449
  if ESDB_BACKEND == "sqlite":
10049
10450
  sqlite_db = root / ".specsmith" / "esdb.sqlite3"
10050
10451
  backend_label = f"SQLite (free, MIT) — {sqlite_db}"
@@ -11477,6 +11878,13 @@ main.add_command(context_group)
11477
11878
  def compliance_group() -> None:
11478
11879
  """EU and North American AI regulation compliance checking and reporting.
11479
11880
 
11881
+ DISCLAIMER: specsmith compliance checks are provided on a best-effort basis.
11882
+ Results are NOT a guarantee of legal compliance. Laws and regulations change
11883
+ frequently; the user is solely responsible for determining and maintaining
11884
+ actual compliance. Layer1Labs makes no warranty of fitness for regulatory
11885
+ submission. File tickets for outdated or missing regulation coverage at
11886
+ https://github.com/layer1labs/specsmith/issues
11887
+
11480
11888
  Supported regulations (May 2026):\n
11481
11889
  eu-ai-act EU AI Act 2024/1689\n
11482
11890
  nist-rmf NIST AI RMF 1.0 + AI 600-1 GenAI Profile\n
@@ -11538,10 +11946,20 @@ def compliance_check_cmd(project_dir: str, regulation: str, as_json: bool) -> No
11538
11946
  output = {
11539
11947
  "results": [r.to_dict() for r in results],
11540
11948
  "checked": len(results),
11949
+ "disclaimer": (
11950
+ "specsmith compliance checks are best-effort only and do NOT constitute "
11951
+ "legal advice or guarantee of compliance. Verify with qualified counsel."
11952
+ ),
11541
11953
  }
11542
11954
  click.echo(_json.dumps(output, indent=2))
11543
11955
  return
11544
11956
 
11957
+ console.print(
11958
+ "[dim]\u26a0 DISCLAIMER: Results are best-effort only. specsmith does not guarantee "
11959
+ "compliance. Laws change \u2014 verify with qualified counsel. "
11960
+ "File issues at https://github.com/layer1labs/specsmith/issues[/dim]\n"
11961
+ )
11962
+
11545
11963
  _STATUS_ICON = {
11546
11964
  "compliant": "[green]\u2714[/green]",
11547
11965
  "partial": "[yellow]\u26a0[/yellow]",
@@ -11644,7 +12062,7 @@ def compliance_audit_cmd(project_dir: str, as_json: bool) -> None:
11644
12062
  written = checker.store_results_to_esdb(results)
11645
12063
 
11646
12064
  reporter = ComplianceReporter(results)
11647
- summary = reporter._summary_dict()
12065
+ summary = reporter.summary_dict() # public API — use summary_dict, not _summary_dict
11648
12066
  summary["esdb_records_written"] = written
11649
12067
 
11650
12068
  if as_json: